Skip to content

Commit bd3ef1d

Browse files
authored
chore(发布): 准备 0.7.13 (#65)
* fix(控制面): 未发布分支告警、复核退出码与任务关闭 未 push 的开发线不再把 next/start 卡成 needs_repair;task close 拒绝符号链接工作树;dry-run 与复核拒绝按契约执行。 * fix(控制面): loop 失败退出码与 overlay 事件缺口 task loop/daemon 在复核失败时非零退出;事件追加失败标记 overlay 不完整;merge --dry-run --push 改为真实预检。 * chore(发布): 准备 0.7.13 把 feat/dev_0814 上的控制面诚实性与任务关闭收口收进 0.7.13。 版本停在 0.7.x,不改 0.7.12 历史,不发明新功能。 * test(控制面): 缺远端告警不再当 FAIL next / Console 在仅缺 origin/<branch> 时保持 ready;测试改为断言 WARN 契约。 --------- Co-authored-by: DandreYang <13072547+Dandre126@users.noreply.github.com>
1 parent f321e39 commit bd3ef1d

26 files changed

Lines changed: 1631 additions & 210 deletions

CHANGELOG.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,45 @@
22

33
## Unreleased
44

5+
## 0.7.13 - 2026-09-01
6+
7+
对使用者的影响:未 push 的开发线不再把 `dyro next` / `dyro start`
8+
卡成 needs_repair;doctor 只 WARN 缺 `origin/<branch>``line spawn`
9+
从父线本地 HEAD 起,不再跟过期远端。`task create` 可多仓、默认本机
10+
adapter,并把 Profile `verify` 写成门禁。`task review` 拒绝时非零退出。
11+
`--dry-run host compile` / `proof export` 不再落盘;本地 Profile 的
12+
`task gates --dry-run` 会真跑门禁,外部 Profile 则拒绝在本机执行。
13+
`task merge --dry-run` 会探测冲突并 abort。新增 `task close`
14+
15+
- Missing `origin/<line.branch>` is a doctor WARN, not FAIL. Dyro still
16+
does not push; `line create` prints the `git push -u` command to run
17+
yourself. `dyro next` / `dyro start` stay ready when that is the only
18+
gap. `line spawn` uses the parent line's local branch, not a stale
19+
`origin/<parent.branch>`.
20+
- `task create --repository` may be repeated. New tasks copy Profile
21+
`repositories.*.verify` into `[[gates]]`, default executor/reviewer to
22+
the first configured adapter, require the line worktree to sit on
23+
`line.branch` before releasing a dependency, rotate `events.jsonl`
24+
instead of failing at 2 MiB, keep status writes if event append fails,
25+
and discard a leftover `receipt.md` at the start of each run.
26+
- `--dry-run` no longer writes host projections, proof zip files, or a
27+
fake merged task. Gate dry-run executes the gate argv on a local
28+
Profile; an external Profile refuses to run argv on the operator host.
29+
`task review` exits non-zero on reject, including a binding mismatch,
30+
without treating that reject as an uncertain supervised action.
31+
`task close` removes the task worktree and `task/<id>` branch after
32+
done/failed: symlink mounts are refused, done close requires a clean
33+
tree already merged into `line.branch`, and failed close force-removes
34+
a dirty tree. Empty-`verify` multi-repo tasks get unique
35+
`diff-check-<repo>` gate names. Overlay event readers stitch
36+
`events.jsonl.<seq>` archives when the current file is missing and
37+
ignore non-seq suffixes such as `.bak`. A failed event append still
38+
writes task status, and marks overlay events incomplete via
39+
`.dyro/events.gap`. `task loop` / `task daemon` exit non-zero when a
40+
review or run returns `failed`. Merge `--dry-run --push` actually runs
41+
`git push --dry-run` and says so. Dispatch Skill no longer cites a
42+
nonexistent `--mode` flag.
43+
544
## 0.7.12 - 2026-08-23
645

746
- Fix `dyro update` for uv-managed installs that were pinned with an exact

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ The dashboard surfaces workspace health, attention, task execution counts, activ
3333
- Gates are executed by the orchestrator; an agent's self-report is not evidence of success.
3434
- Review is bound to the execution receipt and exact per-repository task HEADs; source drift invalidates it.
3535
- A task needs independent review before it becomes `done`; merge and push require explicit confirmation by default.
36-
- A completed dependency releases downstream work only after its exact task HEADs are integrated into the owning development line.
36+
- A completed dependency releases downstream work only after its exact task HEADs are integrated into the owning development line **and** that line worktree is on `line.branch` (enforced). Detached/wrong-branch is a merge/dispatch preflight, not Proof decay.
3737
- Executable configuration is represented as argv arrays. The core never runs TOML-provided shell strings.
3838

3939
## Architecture and flow diagrams
@@ -646,7 +646,7 @@ This README is maintained in English, Simplified Chinese, Korean, Spanish, Frenc
646646

647647
## Current boundaries
648648

649-
DyroEngineeringFlow provides a complete local workflow loop and policy controls for keeping stricter teams in planning-only local mode. It does not create remote repositories, ship SaaS credentials, or provision external runners; it does provide a portable evidence-package contract for external execution. The optional local dispatch harness ships as `experiments.local_agent_dispatch` and is available as `dyro dispatch …`; it is advisory and never replaces gates, review, signoff, or merge. Local multi-repository merges are preflighted and recovered as one operation; remote Git servers cannot provide atomic cross-repository push, so partial push failure is recorded for recovery. Automatic merge requires permission in both the task manifest and local policy. It is available under the [MIT License](LICENSE) and as [`dyro` on PyPI](https://pypi.org/project/dyro/).
649+
DyroEngineeringFlow provides a complete local workflow loop and policy controls for keeping stricter teams in planning-only local mode. It does not create remote repositories, ship SaaS credentials, provision external runners, or `git push` unless `policy.allow_push` is on and the command is explicit. Unpublished `origin/<line.branch>` is a doctor WARN, not a FAIL. It does provide a portable evidence-package contract for external execution. The optional local dispatch harness ships as `experiments.local_agent_dispatch` and is available as `dyro dispatch …`; it is advisory and never replaces gates, review, signoff, or merge. Local multi-repository merges are preflighted and recovered as one operation; remote Git servers cannot provide atomic cross-repository push, so partial push failure is recorded for recovery. Automatic merge requires permission in both the task manifest and local policy. `--dry-run` means no Dyro writes and, for merge, a real conflict probe that is aborted. It is available under the [MIT License](LICENSE) and as [`dyro` on PyPI](https://pypi.org/project/dyro/).
650650

651651
### Graph Engineering (optional reading)
652652

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
# Dyro missing-origin / 诚实性 / 任务关闭 会审
2+
3+
Date: 2026-08-31
4+
5+
Scope: 未发布开发线的 doctor/next 行为、`task create` 多仓与门禁、`events.jsonl` 轮转、`--dry-run` / 复核退出码、`task close` 与 leftover receipt。不是 `task review` PASS,不是 Proof,不是发版。
6+
7+
SSOT: 当前工作区源码(`feat/dev_0814` 工作树,相对生产基线的未提交变更)。本记录不是交付门。
8+
9+
## Rules
10+
11+
1. 每位评审员只写自己的签字章节,不改写他人章节。
12+
2. 源码和现场契约高于会话里的设计口头约定与同批席位意见。
13+
3. 无法证明标 `须人工核`
14+
4. 仲裁只去重、裁定冲突、输出 P0/P1/P2 与 Go/No-Go。
15+
5. 本会审不 merge、不 signoff、不发布。commit/push 是用户本轮另授的交付动作,不是会审授权。
16+
17+
## Frozen Baseline (2026-08-31)
18+
19+
| Object | Ref | SHA | Date |
20+
| --- | --- | --- | --- |
21+
| 生产基线 | `origin/main` | `f321e39df4b3994657e483d58e27d191a6765011` | 2026-08-23 |
22+
| 当前开发线 | `feat/dev_0814`(与 `origin/main` 同 SHA,其上为本波未提交修复) | 同上 + working tree | 2026-08-31 |
23+
| `origin/feat/dev_0814` | 落后本工作树所基于的 main | `6986f63de6bc65ee0a33cb6dc6d3fbe89368a22d` ||
24+
| 当前 `origin/release` | **不存在** |||
25+
| 历史 `origin/release/v0.6.1` | 历史线,不是当前生产 | `d90835e701658d31e78c196ab252825ead1c96f9` ||
26+
27+
**不得默认 main 的说明:** 协议默认生产是 `origin/release`。本仓当前没有 `origin/release`,生产线按 `origin/main` @ `f321e39` 记录。`main` 相对该生产基线领先 0 commit。先前 delivery-physics 会审曾用当时的 `origin/main` 当已发布基线;本轮因缺少现行 `origin/release` 继续用 `origin/main`,并显式写出原因。
28+
29+
`origin/feat/dev_0814` 落后 `origin/main` 22 commit。本波是在已与 `origin/main` 对齐的 `feat/dev_0814` 上的行为修复,不是从过期远端功能分支分叉。
30+
31+
## 先前会审
32+
33+
已检索 `docs/reviews/``docs/superpowers/reviews/`
34+
35+
- 同开发线、**同主题**(missing-origin / dry-run 诚实性 / `task close`):**已检索·无先前会审**
36+
- 同仓不同主题:`docs/reviews/2026-08-19-slash-review-and-task-merge.md`(斜杠包装层);`docs/superpowers/reviews/2026-08-15*``2026-08-16-delivery-physics-shipped-implementation-adversarial-review-board.md`(交付物理 / Proof)。那些 P0/P1 不在本波范围,**不记为本波已闭环**
37+
38+
本目录沿用 `docs/reviews/`(与 2026-08-19 记录同一约定)。
39+
40+
## 席位
41+
42+
| Seat | Dispatch | Window | Status |
43+
| --- | --- | --- | --- |
44+
| security | 第一批派出 | ≥10 min,首派开始计时 | 交卷 ~15.7 min |
45+
| silent-failure | 第一批派出 | 同上 | 交卷 ~11.3 min |
46+
| python-cli | 第一批派出 | 同上 | 交卷 ~13.3 min |
47+
48+
`逾期未交`。主席在交卷后对席位主张做了源码复核,并修了交卷后仍成立的 P1(见仲裁「交卷后补丁」)。
49+
50+
---
51+
52+
# Security Review Section
53+
54+
Reviewer: security
55+
Time: 2026-08-31
56+
Verdict: Conditional Go
57+
58+
P0: none. P1: two (close confused-deputy; merge `--dry-run` mutates the line). Leftover `receipt.md` symlink delete-through and event-archive glob injection: 无 P0/P1 (disproved or fail-closed).
59+
60+
### SEC-P1-01 — `close_task` jail is check/use split; `--force` can retarget the line worktree
61+
62+
Severity: P1. Path: `src/dyro/tasks.py` remove loop vs jail only in validate loop.
63+
64+
Trigger: Task is `failed` (or `done`). Loop 1 sees a real task worktree. Before loop 2, `destination` is replaced with a symlink pointing at the line worktree. Then `task close --yes`.
65+
66+
Impact: Loop 2 did not re-run path jail. `git worktree remove --force` can realpath-match the line worktree.
67+
68+
Disprove attempt: Static symlink-at-mount and symlink-at-task-root are refused. Tests only cover that static case.
69+
70+
Must-fix: Re-apply path jail immediately before `worktree remove`.
71+
72+
### SEC-P1-02 — `task merge --dry-run` is a real merge on the line, not a no-op
73+
74+
Severity: P1. Path: `src/dyro/tasks.py` dry-run merge; `src/dyro/cli.py` `--yes` copy.
75+
76+
Trigger: `dyro task merge <id> --dry-run`.
77+
78+
Impact: Dry-run runs `git merge --no-ff --no-commit` on the line worktree, then abort. Overlay is not written; git is mutated until abort.
79+
80+
Disprove attempt: Product CHANGELOG discloses probe-and-abort. `--help` at seat time still said dry-run does not write Git.
81+
82+
### P2 (security)
83+
84+
- SEC-P2-01 local `run_gates(dry_run=True)` executes argv (documented).
85+
- SEC-P2-02 leftover receipt unlink is POSIX-safe for symlink delete-through; leftover only deletes `task.directory/receipt.md`.
86+
- SEC-P2-03 event archives name-scoped and fail-closed.
87+
- SEC-P2-04 line-branch check does not walk parent symlinks.
88+
- SEC-P2-05 review binding CLI `failed` ≠ task status `failed`.
89+
90+
Hunts 无 P0: leftover symlink delete-through disproved; event glob injection disproved as P0/P1; static close jail mitigated, TOCTOU was P1-01.
91+
92+
Independent check complete.
93+
94+
---
95+
96+
# Silent-Failure Review Section
97+
98+
Reviewer: silent-failure
99+
Time: 2026-08-31
100+
Verdict: Conditional Go
101+
102+
任务路径 9 项已闭环。席位交卷时:**开发线 merge/sync 仍把 `probed.append` 放在 `git()` 之后**。无 P0「CLI/overlay 把失败报成成功」。
103+
104+
### SF-1 — P1(交卷时开放)
105+
106+
位置:`src/dyro/workspace.py` `_merge_line_repositories_locked``line merge` / `line sync`(含 `--dry-run`)在 `git merge --no-ff --no-commit` 超时后,`probed.append``git()` 之后,当前仓可留下 `MERGE_HEAD`。CLI 不会假成功。任务 merge 路径当时已先 append 再 git。
107+
108+
### SF-2 — P2
109+
110+
`set_status` 写入 status 后 `append_event` 失败:状态文件已变;overlay 缺 `task_status` 行且在日志仍合法时 `complete=True`。CLI 不假成功。Ledger 有 `event_append_failed` + `error_code`
111+
112+
### 已闭环(席位对照当时源码)
113+
114+
1. `set_status` 吞掉 `EventLogError` 无痕迹 — 已闭环(静默无痕迹)。Overlay 完整性见 SF-2。
115+
2. 缺 current `events.jsonl` 却有 archive 当成空且 complete — 已闭环。
116+
3. `_event_archive_files` 吃进 `.bak` — 已闭环。
117+
4. 任务 merge dry-run 超时留下 `MERGE_HEAD` — 任务路径已闭环。开发线路径为 SF-1。
118+
5. `close_task` `-d` 测 overlay HEAD — 已闭环(对 `line.branch` 做 ancestor,再 `-D`)。仍非多仓原子。
119+
6. 绑定失败 raise 导致监督 UNCERTAIN — 已闭环(`return "failed"``ActionStatus.FAILED`)。
120+
7. external dry-run 执行门禁 argv — 已闭环。
121+
8. cwd-git 走到 overlay — 已闭环。
122+
9. 重复 `diff-check` 名 — 已闭环。
123+
10. leftover receipt symlink 跳过 — 已闭环(`unlink` 链接本身)。
124+
125+
Independent check complete.
126+
127+
---
128+
129+
# CLI Contract Review Section
130+
131+
Reviewer: python-cli
132+
Time: 2026-08-31
133+
Verdict: Conditional Go
134+
135+
五条指定契约在写路径上成立。交卷时剩下的是 CLI 诚实性缺口。
136+
137+
### 交卷时 P1
138+
139+
1. 全局 `--dry-run` 帮助仍声称不写 Git,但 `task merge --dry-run` 会真实 `git merge``src/dyro/cli.py` `_add_common`
140+
2. `task create --dry-run` 不执行空 adapters 拒绝。空 adapter 检查在 dry-run early-return 之后。
141+
142+
### 交卷时 P2
143+
144+
- `task merge --dry-run --push` 文案声称并推送,push 探测被 `git(..., dry_run=True)` 跳过。
145+
- `task loop` / `task daemon` 对复核 `"failed"` 不非零退出。
146+
- 事件归档 `str.isdigit()` 会把 Unicode 数字当归档名。
147+
- `done` 关闭的 dirty / ancestor 门没有自动化测试。
148+
- 轮转测试有一句恒真断言。
149+
150+
### 已闭环(席位)
151+
152+
1. `--dry-run` 不写 Dyro overlay。
153+
2. 本地 gate dry-run 仍执行 argv;外部 dry-run 不执行 argv。
154+
3. `task review` 拒绝(含 binding mismatch)非零退出;不 `set_status(failed)`
155+
4. 受监督 apply 把 `"failed"` 映射为 FAILED 而非 UNCERTAIN。
156+
5. `task close`:done 要干净且已是 `line.branch` ancestor;failed 用 `--force`;拒绝 symlink mount。
157+
6.`verify` 每仓唯一门禁名;空 adapters 在写路径拒绝。
158+
7. 事件轮转 `events.jsonl.<seq>`;忽略 `.bak`;缺 current 仍缝归档。
159+
160+
Independent check complete.
161+
162+
---
163+
164+
# Chair independent checks
165+
166+
主席在席位交卷后对照**当前**源码复核,不把席位票当事实。
167+
168+
1. 无现行 `origin/release`。生产基线 = `origin/main` `f321e39`。已确认。
169+
2. `close_task` 静态 symlink / 任务根 symlink:源码 `_assert_task_worktree_path` 沿 leaf→root 拒绝 symlink,且 resolved 必须严格落在 worktree_root 下。测试 `test_task_close_refuses_symlink_mount_and_keeps_line_worktree``test_task_close_refuses_symlinked_task_root` 绿。
170+
3. SEC-P1-01 双循环 TOCTOU:交卷时成立。交卷后 mutate 循环在 `worktree remove` 前再次 `_assert_task_worktree_path` + `_validate_task_worktree`。同源进程在两次循环之间替换路径会被第二次 jail 拦住。仍不是跨进程锁。
171+
4. SEC-P1-02:本波产品契约就是 merge `--dry-run` 做真实 `--no-ff --no-commit` 探测再 abort(CHANGELOG / README 已写)。这不是「声称没跑 Git」。`--help` 交卷后已改成与 README 一致。不升为 P0,不阻断本波 commit。
172+
5. SF-1 开发线 merge:交卷时成立。交卷后 `workspace.py` 改为先 `probed.append``git()`。测试 `test_line_merge_timeout_still_aborts_merge_head` 绿。
173+
6. `task create --dry-run` 空 adapters:交卷后检查移到 early-return 之前。同一测试覆盖写路径与 dry-run,均 exit 2。
174+
7. 事件归档 Unicode digit:交卷后 `suffix.isascii() and suffix.isdigit()`
175+
8. 恒真断言:交卷后改为 `records[0]["seq"] == 1`
176+
177+
## 交卷后补丁(相对席位读到的树)
178+
179+
|| 动作 |
180+
| --- | --- |
181+
| SF-1 开发线 merge 超时 | `workspace.py` 先登记 probed |
182+
| python-cli P1 空 adapters dry-run | `cmd_task_create` 先拒绝再 dry-run return |
183+
| python-cli P1 `--help` | `--dry-run` 帮助与 README 对齐 |
184+
| python-cli P2 Unicode 归档名 | `isascii()` |
185+
| python-cli P2 恒真断言 | 断言 seq 从 1 起 |
186+
| SEC-P1-01 remove 前再 jail | mutate 循环再次校验路径 |
187+
188+
---
189+
190+
# Final Arbitration
191+
192+
Arbiter: 会审主席
193+
Time: 2026-08-31
194+
195+
Final verdict: **Go for commit + push `feat/dev_0814`。No-Go for merge / tag / release / 生产。**
196+
197+
会审 Go 不构成 merge、signoff、发版。用户本轮另外授权了 commit 与 push。
198+
199+
## P0
200+
201+
无。没有已证实的「本 CLI 在操作员未确认时会自己 push / 发布 / 删掉开发线 worktree(静态路径)」路径。SEC-P1-01 的静态 symlink 已拒绝;交卷后 remove 前再 jail。同用户进程 TOCTOU 降为残余 P2:同一用户已能直接删 line worktree。
202+
203+
## P1(本波已闭环)
204+
205+
1. 未 push 的 `origin/<line.branch>` 不再把 next/start 卡成 needs_repair;doctor WARN。
206+
2. `line spawn` 从父线本地 HEAD 起。
207+
3. `task create --repository` 可重复;Profile `verify` 进门禁;空 verify 使用 `diff-check-<repo_id>`
208+
4. leftover `receipt.md` 在新一轮执行开始时删除(含 symlink)。
209+
5. `events.jsonl``events.jsonl.<seq>` 轮转;读者忽略非 seq 后缀;缺 current 仍缝归档。
210+
6. `set_status` 在事件追加失败时保留状态写入并 ledger `error_code`
211+
7. `task review` 绑定/哈希不匹配返回 `failed`,CLI 非零,监督层 FAILED 而非 UNCERTAIN;任务可留在 `review` 以便改 `review.md`
212+
8. 外部 Profile 的 gates `--dry-run` 不在本机执行 argv。
213+
9. `task close` 拒绝 symlink mount / 任务根 symlink;done 要求干净且已合入 `line.branch`;failed 才 `--force`;remove 前再校验路径。
214+
10. 任务 merge 与开发线 merge 的 dry-run 探测:先登记 probed,超时仍 abort `MERGE_HEAD`
215+
11. 空 adapters 在写路径与 `--dry-run` 均拒绝。
216+
217+
## P1(已接受残差,不阻断本波 push)
218+
219+
- **Merge `--dry-run` 会短暂改 line 的 index / `MERGE_HEAD` 再 abort。** 这是本波明确的冲突探测契约,不是静默成功。抛开探测改成 `merge-tree` / 一次性 clone 是后续产品选择,不是本波 P0。
220+
221+
## P2
222+
223+
- overlay 在 `event_append_failed` 后仍可对缺行日志报 complete(CLI 不假成功)。
224+
- `task loop` / `task daemon` 对 review `"failed"` 仍退出 0。
225+
- `task merge --dry-run --push` 不真正预检 push。
226+
- done 关闭的 dirty / 未合入路径缺专项测试(实现已有门)。
227+
- 本地 gates `--dry-run` 仍执行 argv(已文档化)。
228+
229+
## Go / No-Go
230+
231+
| 对象 | 结论 |
232+
| --- | --- |
233+
| 提交本波到 `feat/dev_0814` | **Go**(用户本轮授权 commit) |
234+
| 推送到 `origin/feat/dev_0814` | **Go**(用户本轮授权 push;push ≠ 发布) |
235+
| 合并进 `origin/main` / 打 tag / 发版 | **No-Go** |
236+
| 用本会审代替 `task review` / Proof | **No-Go** |
237+
238+
## 测试证据
239+
240+
命令(无 pipeline 吞退出码):
241+
242+
```text
243+
.venv/bin/python -m unittest tests.test_review_remediation
244+
```
245+
246+
摘要:`Ran 26 tests in 13.826s` / `OK`(交卷后、remove 再 jail 之前的全模块)。
247+
248+
```text
249+
.venv/bin/python -m unittest tests.test_review_remediation tests.test_tasks tests.test_workspace tests.test_events tests.test_cli.StartTests tests.test_blueprint tests.test_continuation_supervision tests.test_hub
250+
```
251+
252+
摘要:`Ran 215 tests in 109.964s` / `OK` / exit 0。含 remove 再 jail 之后的工作树。stdout 中有预期的 `错误:任务 T1 复核拒绝``错误:未配置任何 Agent adapter,无法创建任务`(断言非零退出)。
253+
254+
未执行:完整 `tests/` 全仓、CI、真实多仓工作区上的 `task close` 对抗替换。标 **未执行**
255+
256+
`test_legacy_board_status_stays_on_protocol_id` 不在本命令内。历史会话曾在隔离运行时看到 JSON `UNSAFE_FILE`;本波未改 integrations,**须人工核** 是否为环境问题。
257+
258+
## 须人工核
259+
260+
1. Windows junction:`Path.is_symlink()` 对 junction 可能为假。本波在 macOS 上验证。
261+
2. 真实 `subprocess.TimeoutExpired` 杀 git 子进程后,abort 是否总成功。测试用「merge 返回后再抛」模拟。
262+
3. 把 merge dry-run 改成完全不碰 line worktree,是否值得下一刀产品变更。
263+
264+
## Next human Dyro command
265+
266+
无发明。本会审不查询未命名工作区的 `dyro next`。交付动作是用户已授权的 commit + push `feat/dev_0814`

0 commit comments

Comments
 (0)