Integrate current task recovery and accepted planning contracts

Why:
Preserve work merged by concurrent tasks while adopting versioned dependency workspaces.

Evidence:
SELF task receipts record conflict detection, all 96 task/recovery/cutover cases, all 33 evidence cases and 5 component identity cases. Documents links and requirements were replayed after preserving both planning entries.

Impact:
Keep upstream idempotent sync, local resume and source-external receipt rules; adapt fixed-guidelines readiness and ignored component identity validation. Remove only obsolete index links and retain their physical Git metadata.

Refs:
Authoritative main57bcb17ea212a531186b6e21617a7f3bea65a791; Documents4a26798000c39cc59ba0c2cc6328f5c8f10dcb32; dependency-workspace R15.
This commit is contained in:
2026-10-13 17:38:24 +00:00
72 changed files with 8387 additions and 98 deletions
@@ -1,6 +1,6 @@
# feature/d1-closeout-evidence 任务卡
任务主记录:PR #517 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/517 ;状态:进行中;owner:weichen
任务主记录:PR #517 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/517 ;状态:已完成(回填);owner:weichen
## 基线与授权
@@ -69,7 +69,7 @@
| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) |
|---|---|---|---|---|---|
## 结果与验证(完成后填写)
## 结果与验证
- 结果:归档卡 `.task/archive/feature-svc-d1-identity-flow.md` 已回填 GATE 合入/CI 与 SELF 的 lifecycle 结论。Review 与清理仍是 NOT_RUN。
- 验证:三次 `make test-lifecycle` 收据在文末 JSON。通过的一次是 `1a4650d89e589321bd4fe1831e9f0c5a3dd9e476292cb81599f046fbcc77474a`(exit 0,HEAD `2df298affe3e`)。登录、rdm.ping、全轨部署 NOT_RUN。
@@ -245,3 +245,9 @@
}
```
| 同步前验收 | 55cecae703cf8c4f33185e9e4556597c11817b3b | 1e71ab0e2ff739c1f85e2d8b04cb7f7a8e279b46 | 2026-10-13T07:35:27Z |
## 闭合记录(card-autoclose 回填)
- 依据:merge ff3fb4a7ebe432ab21c6b9668abc9823aca2fdd1(PR #517)已包含于 origin/main,分支成果已落盘;本段为合入后回填。
- 合并主题:Merge pull request 'Record the D1 closeout evidence' (#517) from feature/d1-closeout-evidence into main
- 归档:随闭合移入 .task/archive/;任务执行期的过程证据见原任务记录与 PR。
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"pr": 534, "url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/534", "head": "ccbbdec74b11a47693955bfa72cde16c4b586cb1", "merge_sha": "415f9ac58ece9d9b63bd9b3fea39978bb847fcce", "merged_by": "weichen", "merged_at": "2026-10-13T16:53:16Z"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,106 @@
# IAM I1 最终 Dev 组合:独立元数据与规范 Review
日期:2026-10-13 UTC。审阅者:`/root/i1_stage8_docs_review`,native Codex 独立审阅智能体;未参与本次实现或任务卡修订。只读取各仓,报告与收据仅写 /tmp。没有 Git mutation、平台账号批准、pins 修改或 RDM 源码 Review。
结论:**固定组合的文档/规范符合性通过;Critical 0、Important 0、Minor 0(原任务卡 Minor 已独立复审闭合)。** 当前没有发现范围扩大、提供者回退或文档契约失配。此结论不放行尚未完成的 Dev 当前 HEAD CI,亦不声称 I1 后续全模型、部署或清理完成。
## 固定对象与 diff
- Dev:`/home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries`。
- 初审 base:`1e5c6b9c10ba77ed34663fd670138621a17342bd`。
- 阶段 9 已纳入的同步 base:`e793e9804a1f5ecf49b29a40b4baac90ceb04e55`。
- 初审 head:`a8c42d9a59fcd355a9c9d7ee3e0ed5b6742380fd`。
- 元数据整改复审 head:`19b02b3cad9ff9ff19f6f7dbd04bfb0b11293f3f`。
- 阶段 9 最终复审 head:`ccbbdec74b11a47693955bfa72cde16c4b586cb1`。
- 初审对象:`1e5c6b9c10ba77ed34663fd670138621a17342bd..a8c42d9a59fcd355a9c9d7ee3e0ed5b6742380fd`。
- 元数据整改结论对象:`1e5c6b9c10ba77ed34663fd670138621a17342bd..19b02b3cad9ff9ff19f6f7dbd04bfb0b11293f3f`;增量复审对象:`a8c42d9a59fcd355a9c9d7ee3e0ed5b6742380fd..19b02b3cad9ff9ff19f6f7dbd04bfb0b11293f3f`。
- 初审差异仅 PROJECT 的 4 个新增行(3 个文档链接)、Documents gitlink 与本任务卡/14 个自有记录文件,共 17 个文件;没有业务源码、UI、提供者或治理实现修改。
- Documents pin:`a7ff466d9ae91fc67a53d2bf4991f47fc63a2a4c`;与归档 PR99 actual-merge 记录一致,并以本地祖先检查确认包含已独立审阅的 `ba9d76426ded94b0ab760b25201c3a389541b4ee`、`1f3bd54cfba7518bf5d52cbef3d52a03743513bd`。
- 提供者/组件与 base 完全相同:Backend `5d5fc9891c0eb8994545ccb8b740535d9b99fb0e`、Core `5773e74086791731059730bd3726dc8c9cd1381f`、Frontend `eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b`、UI `2c4322ef56df64ad72f65907d25b048a74bb5ffc`、Guidelines `2f5b19872be2a4597838a4131ad75d1be089ee5e`。没有以旧本地 pins 覆盖已纳入主干的能力。
初审读取 a8c42d9 的固定任务卡内容;初审时工作树另有该任务卡未提交修改,独立 receipt 的 status/diff 摘要完整保留。未将活动工作树内容计入固定提交结论。初审时交付者计划追加 RDM 的真实最终结果及当前 Dev 输出,新增 metadata 提交须独立核对差异/源码等价,并对新实际 HEAD 取得 CI。
## 先重放、后作者材料
先执行以下最小集,再读取作者任务卡和归档记录:
```text
RECEIPT=/tmp/iam-i1-dev-final-independent-doccheck.json CMD='git diff --check 1e5c6b9c10ba77ed34663fd670138621a17342bd..a8c42d9a59fcd355a9c9d7ee3e0ed5b6742380fd && python3 /tmp/iam-i1-u1-doccheck.py' make evidence
```
完整 SELF 收据:`/tmp/iam-i1-dev-final-independent-doccheck.json`;exit=0;receipt_sha256=`85971f4697137937a1f4a3b96a12694d5615d748e6fcc00f249a4aa7e04691dc`。before/after head 均为上述 Dev head,Documents 子对象另记为 a7ff466。固定父 SHA 与组件 SHA 未混用。
检查通过 diff 空白、原统一方案摘要 `39b8e9a6e078dc509bd80118c1807ce6ed23e4466e5902b51f4bfa255d55c0a1`、87 个当前本地链接目标、R1–R20 唯一追溯、17 稳定 action/scope、扩展申请四要素、legacy 与最终多职边界、冻结 RDM 规范修订入口及固定初始 08 核心规则。
补充静态 metadata 检查通过:3 个 PROJECT 新链接目标、Documents 实际 pin 与归档记录及两个被审提交祖先关系、所有提供者和 Guidelines pin 对 base 不变、批准投影来源原文与归档 authenticated API 摘要一致。完整 SELF 收据:`/tmp/iam-i1-dev-final-independent-metadata-check.json`;exit=0;receipt_sha256=`c28d53679d0cad41ee666a747c591e92748d4fb08addf6d8f918c2ddbe69cad1`。其精确单行命令由收据 command 字段保存;它仅进行本地 Git/文件/记录检查,没有重新请求远端。第一次辅助命令因 CMD 含实际换行被 evidence 在执行前拒绝,随后改为单行编码命令才实际运行;该拒绝不计业务结果。
所有本地检查来源为 SELF,独立身份不将工具来源升级为 GATE 或 REPLAY。
## 规范、授权和范围
- PROJECT 第 15–17 行准确限定已批准统一方案的首批 I1 U1–U2,导航到合同和结果记录;新增链接均指向实际固定 Documents 内容,不把列入规划当成全目标已完成。
- 任务卡第 10–15、49–50、889–894 行分别保留原实施授权、阶段 6 “批准”、阶段 7 “确认”的原对象,并记后续投影 r1 明确批准。原批准方案摘要保持;投影原文摘要 `3eee5714cce974ce13229b3e184bc3aa763a5e0819fdf7dcf088dafe68b1ed2a` 与 RDM 4ee4eb99 原 blob 一致。
- I1 当前 legacy 单绑定、管理员无隐含业务访问、cap/停用/换岗收口、私人资源边界及单目标投影与已审合同一致。多职、资料/目录恢复、矩阵 UI、完整资源职责、epoch、迁移、全产品浏览器/模型、部署和工作区清理没有据此关闭或启动。
- Guidelines 和 merge-queue policy 属本次 base 已包含的主干内容。policy/merge-queue.md 页首明确 approved/pending-activation、执行模式未切换;本任务没有把它当作已启用的自动队列或跳过既有同步、当前 HEAD CI、独立 Review 和平台准入条件。
- Documents 归档记录有 PR98/99 的各自 head、实际 merge_sha、时间/执行账号及准入观察;父仓实际 pin 匹配 PR99 合入记录。Docs 无 workflow/required context 的 N/A 不替代 Dev 的 CI。
## Finding:Minor M1(初审发现,已闭合)
位置:`.task/feature-iam-i1-permission-boundaries.md:12,14,73,75,89,91`(固定 a8c42d9 对象)。当前交付模式仍写“仅 I1 实施与本地自检;阶段 6 出口保留人工评审”;未标快照的旧结果/合入节还写阶段 6 尚未完成、正式阶段 8 NOT_RUN。这与页首阶段 7 已通过、进入 8–9,以及本次用户明确批准 r1 修复并继续交付的范围不完全一致,恢复者可能重复请求旧阶段批准。
最小修订:将原 delivery mode 明确标为历史授权,并记录当前 r1 修复的连续实施/测试/Review/CI/合入来源与边界;旧“结果与验证”“合入与清理”标题标明原阶段 6 快照,当前以末尾集成记录为准。不修改旧批准对象、数值或收据。交付者已被通知,可随真实 RDM 结果和最终 Dev metadata 一起收口;属于文字/状态整改,不要求权限或组件变化。
## 历史结果与最终准入
固定卡第 892 行写 RDM 当前 CI2997 仍运行、未代签合入,是该提交时的候选快照。任务来信提供了后续 RDM PR360 实际合入 `9eb8c616ef5f4431fb2dd83a3f5267bbaa725af6` 及 Actions2997/job4517 成功的结果;这些后续真实记录应由交付者原样保存到最终 metadata,而不能改写历史收据或用旧 PASS 冒充新候选。本人没有重跑 RDM 源码/真实 HTTP,RDM 两路 Review 与 13 组 HTTP 的有效对象继续由其独立记录负责。
`projection-source-link-verified.json` 明确 verified_access 为 authenticated repository owner API,200 与固定原文摘要相符;卡第 893 行也明确 RDM 为私仓。本人只重核记录结构与本地 blob,没有独立远端 API 重验,不声明该资源未认证公开可见。服务器返回的旧 html_url 不提升为权威访问入口,不重试旧域名;实际合同链接仍为当前 git-home。
初审时 Dev 最终 make test 正在独立运行并输出到源码外 `/tmp/iam-i1-dev-final-composition-test.json`;初审未读取或代签其最终结果;现已导入的实际结果及元数据复审见下节。无论该本地 SELF 是否成功,交付者仍须核验最终实际 HEAD 的 test、test-pg、svc-realcombo 等全部必需 CI、运行身份/SHA/链接及平台 stale guard;缺检查、运行中或失败不能合入。
初审 readiness 为文档/组件范围与规范一致、元数据 Minor 待闭合,最终验证与 CI 分别待核验。以下最终复审覆盖元数据整改及已追加的真实结果,不修改初审历史依据。
## 最终元数据增量复审与问题闭合
最终审阅 head:`19b02b3cad9ff9ff19f6f7dbd04bfb0b11293f3f`。相对 a8c42d9 的 9 个变更文件仅为本任务卡和自有 artifacts;固定业务源码、PROJECT、Documents/提供者/Guidelines pins、policy、治理和 workflow 完全等价。只对这一增量独立重放,不重复未变化的业务测试。
精确命令:
```text
RECEIPT=/tmp/iam-i1-dev-final-independent-metadata-v2.json CMD='git diff --check a8c42d9a59fcd355a9c9d7ee3e0ed5b6742380fd..19b02b3cad9ff9ff19f6f7dbd04bfb0b11293f3f && git diff --exit-code a8c42d9a59fcd355a9c9d7ee3e0ed5b6742380fd..19b02b3cad9ff9ff19f6f7dbd04bfb0b11293f3f -- . ":(exclude).task"' make evidence
```
完整 SELF 收据:`/tmp/iam-i1-dev-final-independent-metadata-v2.json`;exit=0;receipt_sha256=`0c92b8806e6bc9b4d446d42ff459339fdfe88eca35fe94df6a626883d1c90127`。before/after head 均为 19b02b3,检查期间工作树 clean。
M1 闭合:实施者将当前任务卡第 12 行标为原交付模式快照,在第 13、15 行明确当前投影 r1 修复的连续实施/验证/Review/当前 HEAD CI/合入及停止边界。第 74、90 行的旧结果/合入/清理节已标为原阶段 6 快照,并指向末尾当前记录。旧对象和原始结果没有被改写。本人检查固定新对象,确认这就是初审建议的语义,未参与修订。
第 936–940 行及新增 artifacts 保存了 RDM PR360 fast-forward-only 实际合入结果与精确 head/merge_sha `9eb8c616ef5f4431fb2dd83a3f5267bbaa725af6`;归档 GATE 记录中的 run2997 与 job4517 build-and-test 均 completed/success,head 相符。记录保留平台执行身份/workflow/来源,同时本地 evidence 仍为 SELF,不把包装摘要提升为 GATE。本人重核这些归档字段的一致性,没有新远端 API 运行或 RDM 源码 Review。旧“运行中”状态明确为当时历史,不与当前结果混用。
新增 Dev make test 原始收据为 `.task/artifacts/iam-i1-stage8/dev-final-composition-test.json`,command=make test、exit=0、source=SELF、receipt_sha256=`a08bc3d477d4d9bd33a37412685cc9f5372a39acaf58e02f1796c51903fa900e`,before/after head 都是 a8c42d9。执行中任务卡存在元数据修改,原始 dirty 状态及摘要保留;当前记录也明示此点,没有冒称整棵工作树完全固定。收据与最终 metadata 的业务/组件等价关系由本次 diff 重放辅助核验;它仍不替代 19b02b3 或后续最终实际 HEAD 的全部必需 CI。
RDM 闭合 PR362 为独立 metadata 对象,当前卡写仍待其 Review/CI;没有提前宣称已合入。Dev 合入与 RDM 主 PR/闭合 PR 分开记录。部署、生产迁移、U3–U9 和工作区清理仍没有完成或新增授权声明。
**最终结论:上述固定 Dev diff 的元数据、Documents 组合及规范符合性 Review 通过,Critical 0、Important 0、Minor 0。** 原 Minor 的发现与闭合保留。当前 Review scope 为本次 metadata/文档/组件组合,不承担 RDM 源码审查或替代当前 HEAD CI。交付者仍须核验最新 base/head、最终实际 HEAD 的 test/test-pg/svc-realcombo、执行身份与运行链接、平台 stale guard 及 PR 准入,之后才能声明 Dev 已真实合入。继续追加 metadata 会形成新 HEAD,须按影响核对等价并取得该 HEAD 的必需 CI。
## 阶段 9 同步后的最终映射复审
当前结论对象:Dev base `e793e9804a1f5ecf49b29a40b4baac90ceb04e55`、head `ccbbdec74b11a47693955bfa72cde16c4b586cb1`。增量复审是 `19b02b3cad9ff9ff19f6f7dbd04bfb0b11293f3f..ccbbdec74b11a47693955bfa72cde16c4b586cb1`:5 个文件,仅本任务卡/自有 artifacts 及上游归档卡 8 行,没有新的业务或文档契约变化。
先独立重放,再阅读该增量记录;精确命令:
```text
RECEIPT=/tmp/iam-i1-dev-stage9-independent-sync-review.json CMD='git diff --check 19b02b3cad9ff9ff19f6f7dbd04bfb0b11293f3f..ccbbdec74b11a47693955bfa72cde16c4b586cb1 && git diff --exit-code 19b02b3cad9ff9ff19f6f7dbd04bfb0b11293f3f..ccbbdec74b11a47693955bfa72cde16c4b586cb1 -- . ":(exclude).task" && git diff --exit-code e793e9804a1f5ecf49b29a40b4baac90ceb04e55..ccbbdec74b11a47693955bfa72cde16c4b586cb1 -- .task/archive && git merge-base --is-ancestor e793e9804a1f5ecf49b29a40b4baac90ceb04e55 ccbbdec74b11a47693955bfa72cde16c4b586cb1' make evidence
```
完整 SELF 收据:`/tmp/iam-i1-dev-stage9-independent-sync-review.json`;exit=0;receipt_sha256=`0c371458919f8a808c21fa7def2b9c33d819436a0e93f853e87bb05c0489c391`。before/after head 均为 ccbbdec7,检查前后工作树 clean。
核验结果:
- 除 .task 以外的整个源码树与 19b02b3 完全一致,因而 PROJECT、Documents、全部提供者/Guidelines pins、policy、治理、workflow 及原批准摘要保持既有已审关系。没有重复执行不受影响的完整业务测试,也没有由主干同步推出模型/浏览器/部署通过。
- 上游 `.task/archive/feature-rdm-increment-settings-duties.md` 的 8 行追加与 e793e980 中的版本完全一致,是同步纳入已有主干成果;本任务未改写或代审另一任务的验收。最终 head 也实际包含该同步 base,未用旧 base 冒称已纳入新 main。
- 本任务卡 Review 行及末尾“Dev最终Review与候选固定”记录忠实引用 19b02b3 的 0 finding 结论,声明后续 metadata 提交另核等价;对应报告与工具收据完整保存。源码等价收据保持 SELF,一次路径语法拒绝不冒充业务失败或通过。
- 当前 HEAD 的 test/test-pg/svc-realcombo 必须分别完成的条件保留。当前卡没有提前宣称 Dev PR、Dev CI、Dev 合入或清理完成;源码外收据策略没有被描述成 merge queue 已启用。
**最新复审结论:base e793e980/head ccbbdec7 的 metadata、Documents 组合及规范映射 Review 通过,Critical 0、Important 0、Minor 0。** 原 Minor 与闭合依据继续保留。此次不新核验远端 CI 或平台准入,交付者应对最终实际 HEAD 和当次最新 base 执行全部必需 CI/stale guard/PR 准入核验;本地 origin/main 名称和本次祖先关系不是未来远端不再推进的证明。
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"http_status": 200, "data": null}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,89 @@
# IAM I1 阶段 8 独立文档 Review
日期:2026-10-13 UTC。审阅者:`/root/i1_stage8_docs_review`,native Codex 独立审阅智能体。未参与本次实现或修订;未修改任何仓库;整改由实施者完成,本人复审。此次为指定 Documents diff 的独立文档审阅,覆盖需求符合性、一致性、范围、公开契约、证据与维护性;不是完整业务源码 Review、受信 CI 或平台非作者账号批准。
结论:**Documents 文档 Review 通过;当前 Critical 0、Important 0、Minor 0,全部已记录问题闭合。** 此结论只适用于下列固定 diff,不声明其他仓当前源码、PR、CI、合入或部署已完成。
## 固定对象
- Documents 工作区:`/home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/modules/documents`。
- base:`129cc3579d9c9e3edfb46c99270d65f3e1dad0a0`。
- 初审 head:`b4a2573742d1377d432704f0114832d0af5a3c7b`。
- 首轮整改复审 head:`30bceb748fdb01f56ef622c6bc490b2115f62725`。
- 最终复审/本结论 head:`ba9d76426ded94b0ab760b25201c3a389541b4ee`。
- 正式审阅 diff:`129cc3579d9c9e3edfb46c99270d65f3e1dad0a0...ba9d76426ded94b0ab760b25201c3a389541b4ee`,5 个文件:批准方案、I1 合同、阶段 6 实施记录、阶段 7 验收记录、INDEX。
- 整改 diff:`b4a2573742d1377d432704f0114832d0af5a3c7b...30bceb748fdb01f56ef622c6bc490b2115f62725`,仅修改合同页首授权状态与 INDEX 的 IAM 状态文字。没有改动权限语义或批准方案。
- 最后一项整改 diff:`30bceb748fdb01f56ef622c6bc490b2115f62725...ba9d76426ded94b0ab760b25201c3a389541b4ee`,仅合同第 108–109 行两句,明确 Backend 原快照与后续组合须重新固定核验。
- 批准原文文件 SHA256:`39b8e9a6e078dc509bd80118c1807ce6ed23e4466e5902b51f4bfa255d55c0a1`;独立重放三次均核验保持此摘要。原方案的草案状态是保存的历史批准对象,不要求改写它而破坏摘要。
## 先重放、后阅读作者材料
在读取作者验收/自检材料及任务卡收据之前,已独立运行最小重放集。命令和完整脱敏输出由 Dev 的现代 evidence.py 保存,来源均为 **SELF**;独立审阅身份不把工具来源提升为 GATE 或 REPLAY。
初审命令:
```text
RECEIPT=/tmp/iam-i1-stage8-independent-docs-review.json CMD='git -C /home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/modules/documents diff --check 129cc3579d9c9e3edfb46c99270d65f3e1dad0a0...b4a2573742d1377d432704f0114832d0af5a3c7b && python3 /tmp/iam-i1-u1-doccheck.py' python3 /home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/scripts/evidence.py
```
初审收据:`/tmp/iam-i1-stage8-independent-docs-review.json`;exit=0;receipt_sha256=`3604658204d53c94e905b7f5281c7f1ebb0507c6b5ffc6fe12923f6ff54ba8e6`。
复审命令:
```text
RECEIPT=/tmp/iam-i1-stage8-independent-docs-review-v2.json CMD='git -C /home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/modules/documents diff --check 129cc3579d9c9e3edfb46c99270d65f3e1dad0a0...30bceb748fdb01f56ef622c6bc490b2115f62725 && python3 /tmp/iam-i1-u1-doccheck.py' python3 /home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/scripts/evidence.py
```
复审收据:`/tmp/iam-i1-stage8-independent-docs-review-v2.json`;exit=0;receipt_sha256=`1a77cf93f374019a86a81a62bde91b0c21c362a555f27e577de476a8e113e290`。
最终复审命令:
```text
RECEIPT=/tmp/iam-i1-stage8-independent-docs-review-v3.json CMD='git -C /home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/modules/documents diff --check 129cc3579d9c9e3edfb46c99270d65f3e1dad0a0...ba9d76426ded94b0ab760b25201c3a389541b4ee && python3 /tmp/iam-i1-u1-doccheck.py' python3 /home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/scripts/evidence.py
```
最终复审收据:`/tmp/iam-i1-stage8-independent-docs-review-v3.json`;exit=0;receipt_sha256=`6a39ff76afb42b5c9a4f91b38616db713ff6195f95a9f53f56c4801a7c36681a`。再次通过 diff 空白、批准原文摘要、87 个链接目标、R1–R20 与 17 个稳定动作及其余 doccheck 判据。
evidence 的执行 cwd 是 Dev;三次收据记录 Dev HEAD `4292fe3c6d9e7b2e874b137f72b8433756ecde1f` 及组合状态。被审 Documents 的完整 SHA 则明确固定在命令 diff 参数中,并在读取前后以 git rev-parse 和 clean status 核对。不能将 Dev HEAD 当成 Documents HEAD。
最小重放覆盖差异空白、批准原文摘要、当前本地链接目标、R1–R20 各一次追溯、17 个稳定 action/scope、公开申请四要素、I1 legacy 与后续多职边界、RDM 三份规范修订入口及固定 RDM R0 的 08 核心 R1–R5 保持。脚本读取 RDM 的冻结规范文档,不修改该仓;它不验证 Markdown anchor、平台链接身份或业务行为。
## 需求与范围审阅
- 批准方案 R2/R10、KTD4 与 U4/U5 明确一职多人、一人多职、项目明确选用 binding,并要求完整路径判定,不拼接不同角色的 grant 与资源范围。I1 合同第 15、21、24–27、77–92、174 行保持这一设计,将当前单绑定兼容与后续最终模型分开,没有以 legacy 实现取代用户的多职裁定。
- 原方案 R7、KTD3/KTD4 与 I1 合同第 14、28–29、60–62、96–105、135 行一致:系统管理员管理系统主数据,管理员身份和 Host.IsAdmin 不隐含业务项目、正文、原件、草稿或审计访问。独立 audit.read 与当前完整 doc.read 的聚合兼容限制有明示。
- 17 个 I1 稳定动作保持系统/项目 scope,旧入口有映射,未知 ID 不隐式变成别名。系统动作不可由 project.settings 或项目覆盖获得;创建者仍先验平台与角色 cap。
- IAM-P/D/R/C 及补充 IAM-H/K 均标为公开申请或集成缺口,规定提供者/消费者版本、失败拒绝与兼容方式,没有把保存合同当成导出实现。完整资料/目录/恢复、多绑定、项目选用、资源职责、UI、epoch 与迁移继续归属 U3–U9。
- RDM adoption 逐项维护 R1–R20 到既有 UR/SR 和后续单元的追溯;原 ID 与 08 核心规则保留。本 Review 不把映射完整等同于 R1–R20 行为关闭。
## 问题及闭合
### Important D1 — 授权终点的当前表述与阶段 7 已通过冲突(已闭合)
初审位置:`docs/proposals/2026-10-13-iam-i1-permission-contract.md:6`,在原本地实施终点的基础上裸写“未授权推送、PR、合入”,但 `2026-10-13-iam-i1-acceptance.md:3–5` 已记录用户阶段 7 确认并按 policy 进入 8–9。继续原表述会使后续执行者从两个当前入口读到相冲突的交付边界。
实施者在 `30bceb748fdb01f56ef622c6bc490b2115f62725` 将原终点明确为历史,并关联阶段 6/7 的通过和当前 Review/PR/CI/合入责任,同时保留迁移、部署、清理和后续增量未授权。本人检查整改 diff 与复审收据,确认闭合;无需改写批准方案原文。
### Minor D2 — INDEX 仍显示阶段 7 待验收(已闭合)
初审位置:`docs/proposals/INDEX.md:12–13`。该导航把已通过的阶段 7 显示为待用户验收,容易导致重复请求批准和错误恢复阶段。
实施者在同一复审提交更新为实施评审及阶段 7 已通过、当前进入 8–9;本人复审确认与 acceptance 第 3–5 行一致。闭合。
### Minor D3 — 公开能力表应注明其历史固定提供者(已闭合)
位置:`docs/proposals/2026-10-13-iam-i1-permission-contract.md:108–115,121–123`。2.11.0、owner+valid 等现有能力叙述对应 I1 原固定 Backend `0f192a481388184df39f81c28b0587a7e16ec3ca`;它与阶段 7 固定组合相符。当前同步中的 Dev 提供者已前进到 2.12,目录已有额外 Name/Search,因此“当前”一词容易被未来消费者读成所有组合的即时事实。
建议后续组合状态收口时在此表标明“原 I1 合同的 Backend 0f192a48 快照”,并把新的固定组合能力放在当前任务记录,继续分别核验提供者与消费者。该差异不改变 I1 规则、不要求扩大 IAM-D 或启动 U3,也不构成当前文档 Review 阻断。本人未对正在变化的 RDM 工作树作固定业务结论。
实施者在 `ba9d76426ded94b0ab760b25201c3a389541b4ee` 按此建议修订合同第 108–109 行,明确原 Backend 完整 SHA、2.11 为原快照且不代表后续主干能力,同步组合仍须实际固定核验。本人独立检查相对首轮复审对象的 diff,确认仅此两句;最终完整最小重放通过,原文摘要不变,D3 闭合。未参与修订。
## 证据和诚实边界
重放之后核对了阶段 7 引用的 4 个完整作者/前期审阅收据:Dev `ea7b7758…`、RDM `6e684a90…`、独立 focused `6bbb0f74…`、独立 HTTP `c7edde36…`,其命令、exit=0、before/after head 与报告列出的对应历史对象一致,均保留 SELF。报告承认编译/夹具/确认流失败和零用例不能计为业务通过。
阶段 6 页第 73 行把旧测试和缺项表明示为当时快照,阶段 7 页明示其固定对象、用户决定、全产品浏览器与真实模型对照缺项,以及 PostgreSQL、多实例、epoch、恢复、多职和完整三权的后续归属;没有声称部署、生产数据验收或完整 R1–R20 已关闭。
此审阅只重新执行文档最小检查;没有重新运行业务 make test、HTTP、浏览器或真实模型,因此不以作者历史收据替代这些路径的当前重放。另一个指定源码审阅及最终组合验证负责其对应结论。平台所需非作者账号批准、当前 HEAD 的可信 CI、最新 base/head、冲突和 PR 准入仍须由交付者独立核验;本 Review 不能替代这些条件。
就上述固定 Documents diff 而言,全部 Important/Minor 已闭合,权限设计/需求追溯和证据边界一致,可进入下一交付门禁。base/head 或规范语义变化时按影响复审。
@@ -0,0 +1 @@
{"pr": 98, "url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Documents/pulls/98", "head": "ba9d76426ded94b0ab760b25201c3a389541b4ee", "merge_sha": "3cf263962bd106529ee0531c8415cb16eecedfe3", "base": "main", "merged_by": "weichen", "merged_at": "2026-10-13T15:39:54Z"}
@@ -0,0 +1 @@
{"pr": 98, "state": "open", "merged": false, "base": "129cc3579d9c9e3edfb46c99270d65f3e1dad0a0", "head": "ba9d76426ded94b0ab760b25201c3a389541b4ee", "mergeable": true, "draft": false, "status": {"http_status": 200, "data": {"state": "pending", "sha": "ba9d76426ded94b0ab760b25201c3a389541b4ee", "total_count": 0, "statuses": null, "repository": {"id": 19, "owner": {"id": 1, "login": "weichen", "login_name": "", "source_id": 0, "full_name": "", "email": "weichen@home.local", "avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665", "html_url": "https://git-home.u1680832.nyat.app:30319/weichen", "language": "", "is_admin": false, "last_login": "0001-01-01T00:00:00Z", "created": "2026-09-06T14:39:07Z", "restricted": false, "active": false, "prohibit_login": false, "location": "", "website": "", "description": "", "visibility": "public", "followers_count": 0, "following_count": 0, "starred_repos_count": 0, "username": "weichen"}, "name": "Agent-System-Documents", "full_name": "weichen/Agent-System-Documents", "description": "系统文档与过程记录仓:架构决策、方案与验证记录、插件开发指南;不含产品代码。", "empty": false, "private": false, "fork": false, "template": false, "mirror": false, "size": 1447, "language": "", "languages_url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Documents/languages", "html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Documents", "url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Documents", "link": "", "ssh_url": "ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Documents.git", "clone_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Documents.git", "original_url": "", "website": "", "stars_count": 0, "forks_count": 0, "watchers_count": 1, "branch_count": 76, "open_issues_count": 0, "open_pr_counter": 3, "release_counter": 0, "default_branch": "main", "archived": false, "created_at": "2026-09-28T07:07:06Z", "updated_at": "2026-10-13T15:39:22Z", "archived_at": "1970-01-01T00:00:00Z", "permissions": {"admin": true, "push": true, "pull": true}, "has_code": true, "has_issues": true, "internal_tracker": {"enable_time_tracker": true, "allow_only_contributors_to_track_time": true, "enable_issue_dependencies": true}, "has_wiki": true, "has_pull_requests": true, "has_projects": true, "projects_mode": "all", "has_releases": true, "has_packages": true, "has_actions": true, "ignore_whitespace_conflicts": false, "allow_merge_commits": true, "allow_rebase": true, "allow_rebase_explicit": true, "allow_squash_merge": true, "allow_fast_forward_only_merge": true, "allow_merge_update": true, "allow_rebase_update": true, "allow_manual_merge": false, "autodetect_manual_merge": false, "default_delete_branch_after_merge": false, "default_merge_style": "merge", "default_update_style": "merge", "default_allow_maintainer_edit": true, "avatar_url": "", "internal": false, "mirror_interval": "", "object_format_name": "sha1", "mirror_updated": "0001-01-01T00:00:00Z", "mirror_last_sync_at": "0001-01-01T00:00:00Z", "topics": [], "licenses": []}, "commit_url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Documents/commits/ba9d76426ded94b0ab760b25201c3a389541b4ee", "url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Documents/commits/ba9d76426ded94b0ab760b25201c3a389541b4ee/status"}}, "protection": {"http_status": 200, "data": {"branch_name": "main", "rule_name": "main", "priority": 1, "enable_push": false, "enable_push_whitelist": false, "push_whitelist_usernames": [], "push_whitelist_teams": [], "push_whitelist_deploy_keys": false, "enable_force_push": false, "enable_force_push_allowlist": false, "force_push_allowlist_usernames": [], "force_push_allowlist_teams": [], "force_push_allowlist_deploy_keys": false, "enable_merge_whitelist": false, "merge_whitelist_usernames": [], "merge_whitelist_teams": [], "enable_bypass_allowlist": false, "bypass_allowlist_usernames": [], "bypass_allowlist_teams": [], "enable_status_check": false, "status_check_contexts": null, "required_approvals": 0, "enable_approvals_whitelist": false, "approvals_whitelist_username": [], "approvals_whitelist_teams": [], "block_on_rejected_reviews": false, "block_on_official_review_requests": false, "block_on_outdated_branch": true, "dismiss_stale_approvals": false, "ignore_stale_approvals": false, "require_signed_commits": false, "protected_file_patterns": "", "unprotected_file_patterns": "", "block_admin_merge_override": false, "created_at": "2026-09-30T03:46:04Z", "updated_at": "2026-09-30T03:46:04Z"}}}
@@ -0,0 +1 @@
{"http_status": 200, "data": null}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,65 @@
# IAM I1 宿主改名投影合同补充:独立文档 Review
日期:2026-10-13 UTC。审阅者:`/root/i1_stage8_docs_review`,native Codex 独立审阅智能体。未参与 §8 编制或 RDM 实现,未修改仓库,没有 Git mutation、平台批准或 pins 操作。此任务只审 Documents 的指定补充 diff。
**结论:文档语义 Review 通过,Critical 0、Important 0、Minor 0。** §8 与批准的 r1 修订对象一致,没有把保存合同等同于实现、测试或运行通过。文档合入仍等待来源链接可访问性验证,以及交付者对最新 base/head、当前 HEAD CI 和平台准入的核验。
## 固定对象
- Documents 工作区:`/home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/modules/documents`。
- branch:`feature/iam-i1-projection-contract`。
- base:`3cf263962bd106529ee0531c8415cb16eecedfe3`。
- head:`1f3bd54cfba7518bf5d52cbef3d52a03743513bd`。
- 审阅 diff:`3cf263962bd106529ee0531c8415cb16eecedfe3...1f3bd54cfba7518bf5d52cbef3d52a03743513bd`;仅 `docs/proposals/2026-10-13-iam-i1-permission-contract.md` 第 183–193 行新增 §8,其余文本与 pins 不变。
- 批准来源对象:RDM `4ee4eb99a95460d6660f05a67181357b67e2e956:docs/proposals/2026-10-13-iam-i1-host-projection-amendment.md`。
- 来源原文 SHA256:`3eee5714cce974ce13229b3e184bc3aa763a5e0819fdf7dcf088dafe68b1ed2a`,以本地 Git 该完整提交的 blob 独立计算,与 §8 完全一致。
- 原 IAM 统一方案文件摘要仍为 `39b8e9a6e078dc509bd80118c1807ce6ed23e4466e5902b51f4bfa255d55c0a1`。
批准来源提交页首仍为“待用户审阅”,属于当时完整原文快照;当前 RDM 主记录页首已另记本会话的明确批准、原文摘要和“实施与验证正在进行”。§8 使用完整原批准对象及摘要,没有由旧页首错误推出修订尚未批准,也没有静默改写该批准快照。用户批准依据来自本任务授权及当前批准记录;本 Review 不代替用户或平台账号签名。
## 独立最小重放(先于作者材料)
先以固定 Documents 完整 SHA 执行 diff 空白检查与 doccheck,再读取批准提案正文及作者材料。现代 evidence.py 的执行 cwd 在 Dev,完整脱敏命令/输出与对象信息位于下列收据;来源均为 **SELF**,不会提升成 GATE 或 REPLAY。
```text
RECEIPT=/tmp/iam-i1-projection-docs-review.json CMD='git -C /home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/modules/documents diff --check 3cf263962bd106529ee0531c8415cb16eecedfe3...1f3bd54cfba7518bf5d52cbef3d52a03743513bd && python3 /tmp/iam-i1-u1-doccheck.py' python3 /home/weichen/projects/Agent-System-Dev-wt-feature-iam-i1-permission-boundaries/scripts/evidence.py
```
检查收据:`/tmp/iam-i1-projection-docs-review.json`,exit=0,receipt_sha256=`840e780179f411a0061f55d87cd85d930111bda47576e3dc37eea9a6fc7c2c7c`。
收据父 Dev before/after 均为 `eca92e99207ca054f96e502f5f5969b02c26da51`;submodules 中 Documents before/after 均明确为 `1f3bd54cfba7518bf5d52cbef3d52a03743513bd`。父 SHA 不是 Documents SHA,审阅 diff 对象已另行固定。Documents 检查前后 HEAD 相同且工作树 clean。
最小集覆盖 diff 空白、原统一方案摘要、87 个当前本地链接目标、R1–R20 一次追溯、17 个稳定 action/scope、扩展申请四要素、legacy 与多职边界、冻结 RDM 三份规范入口及固定初始 RDM 08 核心规则。全部通过;脚本不验证新增 HTTPS 链接的远端可访问性,也不执行业务路径。
另以本地 Git 完整来源提交计算批准修订原文摘要,并通过 evidence 保存。实际命令:
```text
python3 -c 'import hashlib,subprocess; p="docs/proposals/2026-10-13-iam-i1-host-projection-amendment.md"; d=hashlib.sha256(subprocess.check_output(["git","-C","/home/weichen/projects/Agent-System-RDM-wt-feature-iam-i1-permission-boundaries","show","4ee4eb99a95460d6660f05a67181357b67e2e956:"+p])).hexdigest(); print("Approved projection snapshot SHA256:",d); assert d=="3eee5714cce974ce13229b3e184bc3aa763a5e0819fdf7dcf088dafe68b1ed2a"'
```
摘要收据:`/tmp/iam-i1-projection-approved-snapshot-review.json`,exit=0,receipt_sha256=`bbf6c21fefaa5018942192570e5692bf3b8afbe3abbda1f3f2bef6e93d2815ab`。原文 blob 与期望摘要一致;此记录只证明本地原文身份,不证明远端已经推送。
## 需求与语义核对
| 合同位置 | 批准来源位置 | 结论 |
|---|---|---|
| §8 第 185 行,唯一来源及批准摘要 | r1 第 1–4、75–78 行与当前批准状态记录 | 原文来源固定,当前批准与历史快照分开;正文维护在 RDM 一处 |
| 第 187 行,实际 actor 授权与单目标物理投影 | r1 第 23–33、35–37 行 | 实际认证 actor 保持请求身份,当前 project.settings/cap/关系/状态为权威;创建者 scoped Host 仅执行已核实 hostID 的改名,不重新授权或向其他动作传递 |
| 第 187 行,无 doc.read 的合法管理与 Native work 边界 | r1 第 35–37、64、70 行 | 管理设置资格可独立授予;投影元数据查找不扩大正文、原件、私聊、私稿或 Native work 的访问 |
| 第 189 行,同主体持久意图与受限恢复 | r1 第 28、33、39–44、69 行 | 同事务持久意图固定 actor、域项目、host、创建者、目标与版本;恢复重验当前实际 actor,只恢复已证实同目标;未知 failed/create 和归属变化拒绝,非 ready 的读/work不开放 |
| 第 191 行,两入口 DTO、脱敏与审计身份 | r1 第 30、32、56、64、70 行 | 原请求 Host 负责审计实际操作者;命令与 HTTP 保持各自 DTO,禁止 creator raw settings 或投影句柄外泄;插件来源 Actor 与业务 Owner/evidence.actor 明确区分 |
| 第 193 行,公开边界与验证出口 | r1 第 23、44、51、56–71 行 | 不新增 Backend 公开符号,不放宽 owner-only 规则,不改 pins;最终验收仍要求合法、越权、撤权、归属、恢复、两入口及真实 HTTP,用文档保存不能关闭 I1 |
第 191 行的审计字段解释还核对了固定 Backend `5d5fc9891c0eb8994545ccb8b740535d9b99fb0e` 的 `internal/app/hostcaps.go:273–279`:Audit 写入 Owner=h.owner、Actor=plugin:pluginID,并保留 evidence。该源码证据解释字段角色;它不是当前 RDM 接线已经正确或审计运行通过的声明。
§8 为摘要采纳,并明确引用完整批准正文;当前资格包括具体成员关系、角色有效态、动作定义、平台/角色 cap、覆盖与生命周期,最终写入前重验等完整条件仍以该批准正文和原合同共同约束。不要求在摘要重复全部实现步骤,也没有缩减这些条件。
## Findings 和合入 readiness
Critical:无。Important:无。Minor:无。无需改写原批准方案或扩大公开接口范围。
**文档 Review readiness:PASS(上述固定 diff;本地检查来源 SELF)。**
**跨仓来源 URL 可访问性:NOT_VERIFIED。** 第 185 行的固定 RDM 来源提交目前没有本轮远端访问验证收据。本地 blob 核验不替代 HTTPS/平台可访问性。交付者应在包含该提交的 RDM 最终分支正式推送后验证实际 URL,再决定 Documents 合入;不能仅因链接格式合法计为链接通过。
**RDM 实现、当前产品运行验收、HTTP、业务测试、受信 CI、PR 与合入:本 Review 未重放或核验。** RDM 正在实施;此文档 Review 不声称修复或产品行为已经完成。最终源码 Review、组合验证、平台账号批准和 CI 仍各自承担原门禁。后续 base/head 或 §8 语义变化须按影响复审。
@@ -0,0 +1 @@
{"pr": 99, "url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Documents/pulls/99", "head": "1f3bd54cfba7518bf5d52cbef3d52a03743513bd", "merge_sha": "a7ff466d9ae91fc67a53d2bf4991f47fc63a2a4c", "merged_by": "weichen", "merged_at": "2026-10-13T16:24:57Z"}
@@ -0,0 +1 @@
{"pr": 99, "base": "3cf263962bd106529ee0531c8415cb16eecedfe3", "head": "1f3bd54cfba7518bf5d52cbef3d52a03743513bd", "mergeable": true, "required_approvals": 0, "stale_guard": true, "ci": "N/A: no workflow or required context", "source_verified": {"api_path": "/contents/docs/proposals/2026-10-13-iam-i1-host-projection-amendment.md?ref=4ee4eb99a95460d6660f05a67181357b67e2e956", "http_status": 200, "html_url": "https://git-panel.u1680832.nyat.app:30319/weichen/Agent-System-RDM/src/commit/4ee4eb99a95460d6660f05a67181357b67e2e956/docs/proposals/2026-10-13-iam-i1-host-projection-amendment.md", "sha256": "3eee5714cce974ce13229b3e184bc3aa763a5e0819fdf7dcf088dafe68b1ed2a", "verified_access": "authenticated repository owner API"}}
@@ -0,0 +1 @@
{"api_path": "/contents/docs/proposals/2026-10-13-iam-i1-host-projection-amendment.md?ref=4ee4eb99a95460d6660f05a67181357b67e2e956", "http_status": 200, "html_url": "https://git-panel.u1680832.nyat.app:30319/weichen/Agent-System-RDM/src/commit/4ee4eb99a95460d6660f05a67181357b67e2e956/docs/proposals/2026-10-13-iam-i1-host-projection-amendment.md", "sha256": "3eee5714cce974ce13229b3e184bc3aa763a5e0819fdf7dcf088dafe68b1ed2a", "verified_access": "authenticated repository owner API"}
@@ -0,0 +1 @@
{"pr": 360, "url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-RDM/pulls/360", "head": "9eb8c616ef5f4431fb2dd83a3f5267bbaa725af6", "merge_sha": "9eb8c616ef5f4431fb2dd83a3f5267bbaa725af6", "method": "fast-forward-only", "merged_by": "weichen", "merged_at": "2026-10-13T16:26:51Z"}
@@ -0,0 +1 @@
{"pr": 362, "url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-RDM/pulls/362", "head": "6fcb256205c2384abed35d3b6ab96ca7216e9297", "merge_sha": "6fcb256205c2384abed35d3b6ab96ca7216e9297", "merged_by": "weichen", "merged_at": "2026-10-13T16:45:33Z"}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"http_status": 200, "data": null}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,45 @@
# IAM I1 RDM card-close metadata review: synchronized candidate
Reviewer: Codex independent child `/root/i1_stage8_security`; author/coordinator `/root`.
Timestamp: 2026-10-13T16:43:34.299020+00:00.
Repository: `/home/weichen/projects/Agent-System-RDM-wt-feature-iam-i1-permission-boundaries`.
Current fixed base: `0d3662398bb6fec2ed69083ed5e236a589dc700c`.
Current fixed metadata head: `6fcb256205c2384abed35d3b6ab96ca7216e9297`.
Prior reviewed closure head: `908c26a8d95bd88b5ea3cfc632921ad2a900f8ef`; prior report SHA256 `db5f764d20ee2ca61a9ace237fb20ee3be677716dda89f21923489d952f41686`.
Verdict: **metadata Review PASS, 0 findings; prior closure review remains valid on the synchronized candidate**. It is ready for PR362's actual current-head CI gate. This report does not establish the synchronized candidate's merge or green CI. Closure remains NOT_MERGED pending new-head GATE and the coordinator's merge verification. No repeated business Go test is required for this metadata-only mapping.
## Independent minimum replay
The only new command receipt for this remapping is `/tmp/iam-i1-rdm-card-close-resynced-review-replay.json`; source SELF; exit 0; receipt SHA256 `0306d8f19b063a9471970a3312003d652b6c2e69e93737ccfb9026c8858aabfa`. Before/after HEAD equal the current fixed head and both worktree snapshots are clean. The modern Dev evidence writer ran in source-external RECEIPT mode because the owned card is already archived.
Executed command:
`git diff --check 0d3662398bb6fec2ed69083ed5e236a589dc700c 6fcb256205c2384abed35d3b6ab96ca7216e9297 && git diff --exit-code 0d3662398bb6fec2ed69083ed5e236a589dc700c HEAD -- internal plugins pins .gitea go.mod go.sum main.go && git diff --exit-code 908c26a8d95bd88b5ea3cfc632921ad2a900f8ef HEAD -- internal plugins pins .gitea go.mod go.sum main.go`
Full output is empty because all three checks pass. Business source/tests, provider pins, CI configuration, Go module and main files are unchanged against both the new authoritative base and the prior reviewed closure. Local evidence remains SELF and is not upgraded to REPLAY/GATE.
## Exact mapping and scope
The synchronized head is a merge of parents `908c26a8d95bd88b5ea3cfc632921ad2a900f8ef` and `0d3662398bb6fec2ed69083ed5e236a589dc700c`. Against the former reviewed closure, its entire delta is nine added lines in the already-archived upstream task `.task/archive/feature-rdm-increment-duties-perms.md`: an upstream retrospective acceptance record. No code/configuration/pin or owned-card/evidence content changes occur. The owned archived IAM card and its four artifacts are byte-equivalent to the prior reviewed closure under a direct read-only diff.
Against the new base, the closure remains exactly five files: the owned IAM card moved from `.task/feature-iam-i1-permission-boundaries.md` to `.task/archive/feature-iam-i1-permission-boundaries.md`, plus `rdm-actual-merge.json`, `rdm-final-gate.json`, `rdm-final-source-equivalence.json` and `rdm-merge-response.json` under `.task/artifacts/iam-i1-stage8/`. The other task's nine-line record is inherited base content and does not enlarge this closure PR's scope. No unrelated task is closed by this candidate.
The prior 0-findings review verified the owned card status 已完成, actual PR360 main-record URL and merged source `9eb8c616ef5f4431fb2dd83a3f5267bbaa725af6`, with CI2997/job4517/fast-forward-only/force=false consistency. Its four committed JSON files exactly matched the original coordinator `/tmp` artifacts. Their contents are unchanged after synchronization, so those findings/closure checks are preserved:
| Artifact | SHA256 |
| --- | --- |
| rdm-actual-merge.json | `1aa50f120ef26fa662a288c99cc8370cca3a43ab0678b63d7e6d6209fbe84376` |
| rdm-final-gate.json | `fa0549a5f3003e783447536711956cf2bf8c5ee2914da007f30c3ecceb6cd4ac` |
| rdm-final-source-equivalence.json | `66c3580304fc1e29e62d7ee50da07fee1629461ef465bb84db5dbbc3fc06ef0e` |
| rdm-merge-response.json | `ceba31d730406d21d426eceb2b44e570976fb4666be00617bd53fa91a1b7ac41` |
The prior independent closure receipt remains `/tmp/iam-i1-rdm-card-close-review-replay.json`, SELF, exit 0, receipt SHA256 `e2edcdcf8da7f6ce67fd873a567e78c2c896476b4780c21f826ef26b83f9500b`; it is historical proof for the old closure, not the synchronized object's new receipt.
## Synchronization and honest delivery state
The author task-sync record `/tmp/iam-i1-rdm-card-close-resync.json` has source SELF, exit 0, receipt SHA256 `2254cecab0731a9af42f0540854127ccffc47bc5efd2594291daf3a8f1047178`; it binds old head 908c26a8 to new head 6fcb2562 and records precisely the inherited nine-line archive delta plus sync_base 0d366239. The missing-active-card warning is preserved rather than hidden; review evidence is correctly stored outside source in RECEIPT mode.
The coordinator reports the stale 908 candidate's fast-forward-only merge attempt was rejected when main advanced, and PR362 remains awaiting its refreshed gate. This review does not independently mutate/query the platform. CI3001 on an old head cannot establish CI for `6fcb256205c2384abed35d3b6ab96ca7216e9297`; likewise PR360's CI2997 only proves its original merged source. The coordinator must verify the new run/job's exact head, current base freshness, conflicts, platform requirements and actual merge result. This metadata review permits proceeding to that check; it is not a platform approval or merge claim.
Workspace, branches, ignored products and temporary scenes remain preserved. No repository write, Git mutation, credential access/logging, business rerun or cleanup was performed by this reviewer. Any further candidate change requires delta verification; business/configuration/pin changes require broader review.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"http_status": 200, "data": null}
@@ -0,0 +1,32 @@
[
{
"original": "/tmp/project-member-rdm-final-gate-2973.json",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json",
"sha256": "c66c14f86bfeb60578ce1d694b1070c770a1c951b9368c3d7406729fa7494b00",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
},
{
"original": "/tmp/project-member-rdm-actual-merge-354.json",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json",
"sha256": "bffb0c17ee3e2042aceea5263db1e71c22010e5119018b180bfc9287a49fc6b1",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
},
{
"original": "/tmp/project-member-rdm-upstream-final-review.md",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md",
"sha256": "919b78f85f0b6a5426494c4f47e4dda98a997422f10385c6e9481327751faca2",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
},
{
"original": "/tmp/project-member-rdm-tag-final-review.md",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md",
"sha256": "b67566a39c913652a5349a41c0b574fa8a9e7382a6b5963b4affdb73ecbe5cf9",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
},
{
"original": "/tmp/project-member-rdm-synced-final-test.json",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json",
"sha256": "ec5d2b2cd64ebf43bd3c9a811eb1e1be2821d9e3a6376b78babe84234683748a",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
}
]
@@ -0,0 +1,12 @@
{
"actual_merge": "249d7980028f035124f6a74dd9cae132084b81c5",
"tested_head": "7243a7044c9a4d96292efbb88acc219cac08d321",
"tree": "a29f99852c0d49cf9138698c4bcdee356de36dcd",
"pins": {
"modules/backend": "5d5fc9891c0eb8994545ccb8b740535d9b99fb0e",
"modules/frontend": "eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b",
"modules/documents": "047d362c72ec2c095ec14e1d2f2d152f94471faf",
"modules/core": "5773e74086791731059730bd3726dc8c9cd1381f",
"modules/ui": "2c4322ef56df64ad72f65907d25b048a74bb5ffc"
}
}
@@ -0,0 +1,15 @@
import subprocess,sys
from pathlib import Path
base=sys.argv[1]
allowed_prefixes=('.task/artifacts/project-member-access-receipts/',)
allowed={'.task/feature-project-member-access.md','.task/archive/feature-project-member-access.md'}
files=subprocess.check_output(['git','diff','--name-only',base,'HEAD'],text=True).splitlines()
assert files and all(p in allowed or p.startswith(allowed_prefixes) for p in files),files
card=Path('.task/archive/feature-project-member-access.md')
assert card.is_file() and not Path('.task/feature-project-member-access.md').exists()
s=card.read_text()
assert '状态:已完成' in s and 'https://git-home.u1680832.nyat.app:30319/weichen/' in s.splitlines()[2]
assert '8788' in s
subprocess.run(['git','diff','--check',base,'HEAD'],check=True)
print('Scoped archive check PASS: only this task card and its original receipts changed; product and unrelated cards unchanged.')
for p in files: print(p)
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,454 @@
{
"run": {
"id": 2952,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
"previous_attempt_url": null,
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952",
"display_title": "Record merged-component final sync evidence",
"path": "ci.yaml@refs/pull/526/head",
"event": "pull_request",
"run_attempt": 1,
"run_number": 1520,
"repository_id": 0,
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"status": "completed",
"actor": {
"id": 1,
"login": "weichen",
"login_name": "",
"source_id": 0,
"full_name": "",
"email": "1+weichen@noreply.git-panel.u1680832.nyat.app",
"avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2026-09-06T14:39:07Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "weichen"
},
"trigger_actor": {
"id": 1,
"login": "weichen",
"login_name": "",
"source_id": 0,
"full_name": "",
"email": "1+weichen@noreply.git-panel.u1680832.nyat.app",
"avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2026-09-06T14:39:07Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "weichen"
},
"repository": {
"id": 29,
"owner": {
"id": 1,
"login": "weichen",
"login_name": "",
"source_id": 0,
"full_name": "",
"email": "1+weichen@noreply.git-panel.u1680832.nyat.app",
"avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2026-09-06T14:39:07Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "weichen"
},
"name": "Agent-System-Dev",
"full_name": "weichen/Agent-System-Dev",
"description": "开发集成仓:以 submodule 固定全部模块组合,承载跨仓构建、测试编排与原生(非容器)开发环境;发布物在 Agent-System-Releases。",
"empty": false,
"private": false,
"fork": false,
"template": false,
"mirror": false,
"size": 23204,
"language": "Shell",
"languages_url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/languages",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev",
"url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev",
"link": "",
"ssh_url": "ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git",
"clone_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 1,
"branch_count": 46,
"open_issues_count": 1,
"open_pr_counter": 8,
"release_counter": 0,
"default_branch": "main",
"archived": false,
"created_at": "2026-09-29T08:29:40Z",
"updated_at": "2026-10-13T11:54:42Z",
"archived_at": "1970-01-01T00:00:00Z",
"permissions": {
"admin": false,
"push": false,
"pull": false
},
"has_code": true,
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": true,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": true,
"projects_mode": "all",
"has_releases": true,
"has_packages": true,
"has_actions": true,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"allow_fast_forward_only_merge": true,
"allow_merge_update": true,
"allow_rebase_update": true,
"allow_manual_merge": false,
"autodetect_manual_merge": false,
"default_delete_branch_after_merge": false,
"default_merge_style": "merge",
"default_update_style": "merge",
"default_allow_maintainer_edit": true,
"avatar_url": "",
"internal": false,
"mirror_interval": "",
"object_format_name": "sha1",
"mirror_updated": "0001-01-01T00:00:00Z",
"mirror_last_sync_at": "0001-01-01T00:00:00Z",
"topics": [],
"licenses": []
},
"conclusion": "success",
"pull_requests": [
{
"id": 1488,
"number": 526,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/pulls/526",
"head": {
"ref": "feature/project-member-access",
"sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"repo": {
"id": 29,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev",
"name": "Agent-System-Dev"
}
},
"base": {
"ref": "main",
"sha": "d2c23f3a55a77711ded4328aa6215d9469c2b420",
"repo": {
"id": 29,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev",
"name": "Agent-System-Dev"
}
}
}
],
"started_at": "2026-10-13T11:54:43Z",
"completed_at": "2026-10-13T12:03:33Z"
},
"jobs": [
{
"id": 4419,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/jobs/4419",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952/jobs/4419",
"run_id": 2952,
"run_url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
"name": "test",
"labels": [
"ubuntu-latest"
],
"run_attempt": 1,
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"status": "completed",
"conclusion": "success",
"runner_id": 3,
"runner_name": "home-runner",
"steps": [
{
"name": "Checkout",
"number": 0,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T11:54:53Z"
},
{
"name": "Install Go 1.27.1",
"number": 1,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:53Z",
"completed_at": "2026-10-13T11:54:58Z"
},
{
"name": "Install Node 22",
"number": 2,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:58Z",
"completed_at": "2026-10-13T11:55:01Z"
},
{
"name": "Install house-style Python packages",
"number": 3,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:55:01Z",
"completed_at": "2026-10-13T11:55:05Z"
},
{
"name": "make test (boundaries, pins, libs, core, backend, frontend, ui, agent-command)",
"number": 4,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:55:05Z",
"completed_at": "2026-10-13T11:59:43Z"
},
{
"name": "Build the single binary",
"number": 5,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:59:43Z",
"completed_at": "2026-10-13T12:00:04Z"
}
],
"created_at": "2026-10-13T11:54:42Z",
"started_at": "2026-10-13T11:54:43Z",
"completed_at": "2026-10-13T12:00:06Z"
},
{
"id": 4420,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/jobs/4420",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952/jobs/4420",
"run_id": 2952,
"run_url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
"name": "test-pg",
"labels": [
"ubuntu-latest"
],
"run_attempt": 1,
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"status": "completed",
"conclusion": "success",
"runner_id": 3,
"runner_name": "home-runner",
"steps": [
{
"name": "Checkout",
"number": 0,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T11:54:53Z"
},
{
"name": "Install Go 1.27.1",
"number": 1,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:53Z",
"completed_at": "2026-10-13T11:54:57Z"
},
{
"name": "Install house-style Python packages",
"number": 2,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:57Z",
"completed_at": "2026-10-13T11:55:02Z"
},
{
"name": "Install PostgreSQL, pgvector and Redis",
"number": 3,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:55:02Z",
"completed_at": "2026-10-13T11:56:09Z"
},
{
"name": "Start PostgreSQL and Redis",
"number": 4,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:56:09Z",
"completed_at": "2026-10-13T11:56:12Z"
},
{
"name": "Backend tests against real PostgreSQL and Redis (required, no silent skip)",
"number": 5,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:56:12Z",
"completed_at": "2026-10-13T11:56:36Z"
},
{
"name": "Two-process HTTP acceptance over shared PostgreSQL (U7, required)",
"number": 6,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:56:36Z",
"completed_at": "2026-10-13T11:57:02Z"
},
{
"name": "RDM lifecycle pin is three fixed SHAs",
"number": 7,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:57:02Z",
"completed_at": "2026-10-13T11:57:02Z"
},
{
"name": "Clone Agent-System-RDM with nested pins (reviewed allowlist addition)",
"number": 8,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:57:02Z",
"completed_at": "2026-10-13T11:58:24Z"
},
{
"name": "Install Node 22",
"number": 9,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:58:24Z",
"completed_at": "2026-10-13T11:58:27Z"
},
{
"name": "Build the real agent-system binary",
"number": 10,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:58:27Z",
"completed_at": "2026-10-13T11:58:47Z"
},
{
"name": "Real-combination lifecycle gate (make test-lifecycle, required)",
"number": 11,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:58:47Z",
"completed_at": "2026-10-13T12:03:31Z"
}
],
"created_at": "2026-10-13T11:54:42Z",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T12:03:33Z"
},
{
"id": 4421,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/jobs/4421",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952/jobs/4421",
"run_id": 2952,
"run_url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
"name": "svc-realcombo",
"labels": [
"ubuntu-latest"
],
"run_attempt": 1,
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"status": "completed",
"conclusion": "success",
"runner_id": 3,
"runner_name": "home-runner",
"steps": [
{
"name": "Checkout",
"number": 0,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T11:54:53Z"
},
{
"name": "Install Go 1.27.1",
"number": 1,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:53Z",
"completed_at": "2026-10-13T11:54:57Z"
},
{
"name": "Install Node 22",
"number": 2,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:57Z",
"completed_at": "2026-10-13T11:55:01Z"
},
{
"name": "Build the real agent-system binary",
"number": 3,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:55:01Z",
"completed_at": "2026-10-13T11:56:42Z"
},
{
"name": "Clone Agent-System-RDM with nested pins (reviewed allowlist addition)",
"number": 4,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:56:42Z",
"completed_at": "2026-10-13T11:57:05Z"
},
{
"name": "Run real-combination lifecycle gates (SQLite, U3, required)",
"number": 5,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:57:05Z",
"completed_at": "2026-10-13T11:57:33Z"
}
],
"created_at": "2026-10-13T11:54:42Z",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T11:57:34Z"
}
],
"verified_head": "7243a7044c9a4d96292efbb88acc219cac08d321"
}
@@ -0,0 +1,20 @@
[
{
"component": "backend",
"merged": "5d5fc9891c0eb8994545ccb8b740535d9b99fb0e",
"tree": "f2c80faac929a26ca51036dfd2aa54b6dec8553f",
"tested": "d26f3cf2e864a76ad0b868fd968da3257cc7bb44"
},
{
"component": "frontend",
"merged": "eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b",
"tree": "95498c511e440dc3711c626c0f8cd04fb81b84af",
"tested": "40c2afe05449b30e4ed92991487f4eac57221366"
},
{
"component": "documents",
"merged": "047d362c72ec2c095ec14e1d2f2d152f94471faf",
"tree": "eb46876d3a10f4c0b37eb134fc22f40c2b3b1216",
"tested": "6c096b9360094bec9f5d8c9a6db0c701da463fca"
}
]
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
# RDM v0.4.0 tag 消费独立复审
结论:PASS;本增量无 P1/P2 findings。审阅者 `/root/backend_review` 未参与产品实现,仅执行只读审阅、独立临时测试和隔离产品 smoke。
审阅范围:RDM `589f030a5f5b7b12fb9dfd7014a93fb98ff6a9f9` → `b03f27354b309d5d2d44bee0ab42718f37cea241`。四项 pin 与远端已发布 `v0.4.0` annotated tag 的 peeled commit 及本地 tag 一致:Backend `5d5fc9891c0eb8994545ccb8b740535d9b99fb0e`,Core `5773e74086791731059730bd3726dc8c9cd1381f`,Frontend `eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b`,UI `2c4322ef56df64ad72f65907d25b048a74bb5ffc`。Core 直 pin 与 Backend 内嵌 Core 一致;Backend/Frontend 的完整源码树与此前验收对象一致。
独立重放使用仓内默认 `go.mod`、空 `GOFLAGS/GOWORK`,实际模块路径指向 `pins/`。项目、注册、canonical ID、私域、发布/epoch、职责与审计正文边界测试均通过。正式 `bin/agent-system-rdm-product` 在隔离 `/tmp` 数据和空闲端口启动:验证真实 `/proc` executable、React 根页及 JS asset、匿名 commands=401、认证后的项目/私域/发布命令注册;自有进程已停止,诊断数据保留,未触及 8788。
实际正式构建对象为 `0bb8bcc7f727954fc36f32978bf427379fcb435e`;到审阅 HEAD `b03f273...` 的 `git diff -- ':!.task'` 为空。Manifest 的构建对象及作者正式 make test 收据与该事实一致;不要求 manifest 冒称新的证据提交。已核实际 binary SHA256 `2ad5559aa8bce7b67dde0d3f1a41707f0808e1f2f447b6db0a2167995866a2e5`、dist 摘要 `3f1646dd90abaf03`、实际 served JS SHA256 `e7d21720387057e5592e386a9b1e292383956b30d4fb74b2835350fd4e9db4e4` 与现有 manifest/产物匹配。
原始现代工具收据(均保持 SELF;独立执行身份单独用于 REPLAY attestation):
- `/tmp/project-member-rdm-tag-independent-tests.json` — PASS,默认 go.mod 与聚焦测试。
- `/tmp/project-member-rdm-tag-independent-smoke.json` — PASS,真实正式产品入口。
- `/tmp/project-member-rdm-tag-independent-pins-product.json` — 原始 FAIL 保留;四 tag 核验已通过,失败原因是审阅脚本误断言 manifest 构建 SHA 必须等于证据 HEAD。
- `/tmp/project-member-rdm-tag-independent-pins-product-v2.json` — PASS,按真实构建对象核验等价性及实际产物摘要。
RDM 自身旧版 `scripts/evidence.sh` 会写任务卡,本轮改用 Dev 的现代 wrapper 在 RDM cwd 的 RECEIPT 模式,未改产品、任务卡或索引。Root 的授权任务证据写入不改变上述固定产品对象。最终同步后的当前 HEAD CI、平台准入及 FF 合入由 root 另行核验;本报告不沿用旧 CI 作为新门禁,未执行部署。
@@ -0,0 +1,16 @@
# RDM 上游同步增量独立复审
结论:PASS;本增量无 P1/P2 findings。审阅者 `/root/backend_review` 未参与实现,未修改源码、任务卡或索引,未操作 8788。
对象:`b03f27354b309d5d2d44bee0ab42718f37cea241` → `a4edf708336398552af6cf6f65f88807473d460c`。独立执行时 HEAD 已为证据提交 `c058bfcf651c42b2dfc9c93ec7cb1f1036d3fd95`;现代收据内先执行 `git diff --exit-code a4edf708 HEAD -- . ':!.task'`,确认为同一产品、治理脚本及 pins 对象。
账号 query/name 转发保留 canonical 项目注册与命令包装;目录读取先检查 member.manage,姓名仅随受管目录 DTO 返回,未增加联系方式。默认 go.mod、空 GOFLAGS 的账号目录、项目注册/canonical ID、成员权限/override/archive 相关测试通过。post-merge 和 task-finish 仅提示显式 task-close,4 个真实临时 Git 仓库治理用例通过;未自动扫描、归档、提交或推送其他任务卡。四 pins 与 go.mod 未变化。
原始现代工具收据(均保持 SELF;独立执行身份另作 attestation):
- `/tmp/project-member-rdm-upstream-independent-tests-v2.json` — PASS,默认模块账号/项目/权限重放。
- `/tmp/project-member-rdm-upstream-independent-governance-v2.json` — PASS,make test-governance,4 用例。
- `/tmp/project-member-rdm-upstream-independent-tests.json` — 首轮 HEAD guard FAIL,测试 NOT_RUN;保留。
- `/tmp/project-member-rdm-upstream-independent-governance.json` — 首轮 HEAD guard FAIL,治理测试 NOT_RUN;保留。
已在独立重放后核验作者完整测试收据。此前 tag/正式产品/组合 Review 在未受影响范围保留;当前待合入 HEAD 的 CI、平台准入及实际合入由 root 单独核验,不以旧 CI 放行新 HEAD。
+913 -1
View File
@@ -22,7 +22,7 @@
- 适用状态:新方向,已核对当前项目骨架、库计划入口及 Guidelines 多仓/采纳规则;用户批准 r1 方案及重构、自检,追加 R15 在途分支保护。
- 主记录路径/版本:Documents `docs/proposals/2026-10-13-versioned-dependencies-and-workspaces.md` r1;分支 `feature/dependency-workspace-plan`。
- Documents 候选:commit `7ba50e5b2dce226b4b962ea787222a4b08f0e94c`;独立工作区 `/home/weichen/projects/Agent-System-Documents-wt-feature-dependency-workspace-plan`。Documents 由 components.lock.json 显式固定;旧物理检出已保留;保留外部工作区及其 Git 管理目录,后续回收须先保存并解除依赖。
- Documents 候选:commit `4a26798000c39cc59ba0c2cc6328f5c8f10dcb32`;独立工作区 `/home/weichen/projects/Agent-System-Documents-wt-feature-dependency-workspace-plan`。Documents 由 components.lock.json 显式固定;旧物理检出已保留;保留外部工作区及其 Git 管理目录,后续回收须先保存并解除依赖。
- 对应里程碑:U1–U8;当前 U1–U7 实施收尾,U8/正式放行待后续节点。
## 需求分析
@@ -9793,3 +9793,915 @@ ce-simplify-code 的 reuse/quality/efficiency 三个独立只读扫描完成。
"receipt_sha256": "d65203bc505ba8ed4286fda05a7afe78be5b4cc538018796436e263c27882dfa"
}
```
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```json
{
"schema": 1,
"source": "SELF",
"timestamp": "2026-10-13T17:24:29.129477+00:00",
"command": "make task-sync",
"command_sha256": "6c0e3c8fbb3f43d01548180c9d9c147ce1c1c32ba1e78d3383961de470fe0d52",
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace",
"common_dir": "/home/weichen/projects/Agent-System-Dev/.git",
"before": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "7f50152402d0e4bb18f9ce32d5bafca6610ee5971e172a7842b4036866f7eed6",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after": null,
"after_error": "Git object could not be recorded: submodule status",
"exit_code": 2,
"output": "make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace'\n[worktree] before-sync: recursive component checks passed\nAuto-merging AGENTS.md\nAuto-merging Makefile\nCONFLICT (content): Merge conflict in Makefile\nAuto-merging PROJECT.md\nCONFLICT (content): Merge conflict in PROJECT.md\nCONFLICT (modify/delete): deps/development-guidelines deleted in HEAD and modified in origin/main. Version origin/main of deps/development-guidelines left in tree.\nCONFLICT (modify/delete): modules/documents deleted in HEAD and modified in origin/main. Version origin/main of modules/documents left in tree.\nAuto-merging policy/adoption.md\nCONFLICT (content): Merge conflict in policy/adoption.md\nAuto-merging policy/delivery.md\nAuto-merging policy/governance.md\nAuto-merging scripts/evidence.py\nAuto-merging scripts/task.sh\nCONFLICT (content): Merge conflict in scripts/task.sh\nAutomatic merge failed; fix conflicts and then commit the result.\nmake[1]: *** [Makefile:58: task-sync] Error 1\nmake[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace'\n",
"output_sha256": "88f6526b3d2e3efc5dd2a0f32e35357000e767bdd732997498b03657c48b09f6",
"receipt_sha256": "19ae7d12d909588a857c55da83b54cecfeeba10757f87c5149e242be2825637a"
}
```
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```json
{
"schema": 1,
"source": "SELF",
"timestamp": "2026-10-13T17:30:11.070684+00:00",
"command": "python3 /tmp/dependency-check-docs-final-01a1345f.py",
"command_sha256": "5dc2d73a4dc7fb5db16a8dd47ac36f84e5a98aeabd44a3f0b6162062e9e01a37",
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace",
"common_dir": "/home/weichen/projects/Agent-System-Dev/.git",
"before": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nUU Makefile\nM PROJECT.md\n M components.lock.json\nM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nA policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nM scripts/evidence.py\nUU scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nA tests/test_task_recovery.py\n",
"tracked_diff_sha256": "c4595c2f66ae31ac1102933582b000626535f1112c5b5c68d044520bab1e9110",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nUU Makefile\nM PROJECT.md\n M components.lock.json\nM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nA policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nM scripts/evidence.py\nUU scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nA tests/test_task_recovery.py\n",
"tracked_diff_sha256": "c4595c2f66ae31ac1102933582b000626535f1112c5b5c68d044520bab1e9110",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after_error": null,
"exit_code": 0,
"output": "SELF 32c7fa6c10e89c9775b8d84495a2b54edb461f128e9321d2cbbf030dd84a5adf /home/weichen/projects/Agent-System-Documents-wt-feature-dependency-workspace-plan/docs/proposals/2026-10-13-versioned-dependencies-and-workspaces.md\nSELF b90d57e1dfe172bc34c9527e2875d5a10df611822e0cd92501d76a4f15ec5fd9 /home/weichen/projects/Agent-System-Documents-wt-feature-dependency-workspace-plan/docs/proposals/2026-10-13-versioned-dependencies-implementation-plan.md\nSELF ae88e212f58502a9adcbe4926224e48d0467c683858781152679db3b02d03e4e /home/weichen/projects/Agent-System-Documents-wt-feature-dependency-workspace-plan/docs/proposals/INDEX.md\nSELF 60a9307b298d99939c12189643a2abfd397cccf4cc809ee2d4f8008b9d1d492c /home/weichen/projects/Development-Guidelines-wt-feature-versioned-dependencies/README.md\nSELF f0fb916ff17cf1b079b7c89c8a34380839317c45a8e9e415bdf2da10392a80e9 /home/weichen/projects/Development-Guidelines-wt-feature-versioned-dependencies/standards/multi-repo.md\nSELF bd1ce8f432732cced1a3edce42e593ba5219ae3231b395e6480b3208cb4b1d2b /home/weichen/projects/Development-Guidelines-wt-feature-versioned-dependencies/standards/collaboration.md\nSELF ff6d51d5b1426b256a94c7c87e86e47ff9cb7337fd1c5edf9edcce42de29e4e8 /home/weichen/projects/Development-Guidelines-wt-feature-versioned-dependencies/workflows/adoption.md\nPASS: R1-R15, U1-U8, general/project separation, relative links: 120\n",
"output_sha256": "9017bed6f0be47083e45201b05be5345c0982c246935448d52cbe47b40887630",
"receipt_sha256": "97b5eb903e4f3ce6ac0691f19bc02f588730749a310c0500cdfca6cf49564ce5"
}
```
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```json
{
"schema": 1,
"source": "SELF",
"timestamp": "2026-10-13T17:34:39.569763+00:00",
"command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p test_component_governance.py -v",
"command_sha256": "47968df6b40cd41363f5167484d183a24656112c4994b8d5a9efb8f4dc97af4e",
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace",
"common_dir": "/home/weichen/projects/Agent-System-Dev/.git",
"before": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nM Makefile\nM PROJECT.md\n M components.lock.json\nM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nA policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nM scripts/evidence.py\nUU scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\n M tests/test_component_governance.py\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nAM tests/test_task_recovery.py\n",
"tracked_diff_sha256": "7b3dc3344653c085f97dbc7486b5b52bd8959b28903c6817f29d1a3c98e92f35",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nM Makefile\nM PROJECT.md\n M components.lock.json\nM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nA policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nM scripts/evidence.py\nUU scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\n M tests/test_component_governance.py\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nAM tests/test_task_recovery.py\n",
"tracked_diff_sha256": "7b3dc3344653c085f97dbc7486b5b52bd8959b28903c6817f29d1a3c98e92f35",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after_error": null,
"exit_code": 1,
"output": "test_before_sync_rejects_component_git_lock (test_component_governance.ComponentGovernanceTests.test_before_sync_rejects_component_git_lock) ... ok\ntest_evidence_captures_ignored_component_revision_and_dirty_bytes (test_component_governance.ComponentGovernanceTests.test_evidence_captures_ignored_component_revision_and_dirty_bytes) ... ok\ntest_new_layout_cannot_use_receipt_without_component_identity (test_component_governance.ComponentGovernanceTests.test_new_layout_cannot_use_receipt_without_component_identity) ... FAIL\ntest_receipts_reject_component_path_escape (test_component_governance.ComponentGovernanceTests.test_receipts_reject_component_path_escape) ... ok\ntest_startup_receipt_rejects_changed_ignored_component_objects (test_component_governance.ComponentGovernanceTests.test_startup_receipt_rejects_changed_ignored_component_objects) ... FAIL\n\n======================================================================\nFAIL: test_new_layout_cannot_use_receipt_without_component_identity (test_component_governance.ComponentGovernanceTests.test_new_layout_cannot_use_receipt_without_component_identity)\n----------------------------------------------------------------------\nTraceback (most recent call last):\n File \"/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace/tests/test_component_governance.py\", line 83, in test_new_layout_cannot_use_receipt_without_component_identity\n with self.assertRaises(module.EvidenceError):\n ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: EvidenceError not raised\n\n======================================================================\nFAIL: test_startup_receipt_rejects_changed_ignored_component_objects (test_component_governance.ComponentGovernanceTests.test_startup_receipt_rejects_changed_ignored_component_objects)\n----------------------------------------------------------------------\nTraceback (most recent call last):\n File \"/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace/tests/test_component_governance.py\", line 72, in test_startup_receipt_rejects_changed_ignored_component_objects\n with self.assertRaises(module.EvidenceError):\n ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^\nAssertionError: EvidenceError not raised\n\n----------------------------------------------------------------------\nRan 5 tests in 0.377s\n\nFAILED (failures=2)\n",
"output_sha256": "d4a2f12874327b8e7d7551167d276ae8e1daba0efd79b208ad053b49b40a589e",
"receipt_sha256": "30317956e19fa7cb8cee19d7e1e47994086a451d7c7207d18f32588d6bac85e3"
}
```
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```json
{
"schema": 1,
"source": "SELF",
"timestamp": "2026-10-13T17:35:16.198481+00:00",
"command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p test_component_governance.py -v",
"command_sha256": "47968df6b40cd41363f5167484d183a24656112c4994b8d5a9efb8f4dc97af4e",
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace",
"common_dir": "/home/weichen/projects/Agent-System-Dev/.git",
"before": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nM Makefile\nM PROJECT.md\n M components.lock.json\nM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nA policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nMM scripts/evidence.py\nM scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\n M tests/test_component_governance.py\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nAM tests/test_task_recovery.py\n",
"tracked_diff_sha256": "fb7b1579e69e584c1a0eabb026236ba1ed4cebd1d79686222be1031a9058f6c8",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nM Makefile\nM PROJECT.md\n M components.lock.json\nM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nA policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nMM scripts/evidence.py\nM scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\n M tests/test_component_governance.py\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nAM tests/test_task_recovery.py\n",
"tracked_diff_sha256": "fb7b1579e69e584c1a0eabb026236ba1ed4cebd1d79686222be1031a9058f6c8",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after_error": null,
"exit_code": 0,
"output": "test_before_sync_rejects_component_git_lock (test_component_governance.ComponentGovernanceTests.test_before_sync_rejects_component_git_lock) ... ok\ntest_evidence_captures_ignored_component_revision_and_dirty_bytes (test_component_governance.ComponentGovernanceTests.test_evidence_captures_ignored_component_revision_and_dirty_bytes) ... ok\ntest_new_layout_cannot_use_receipt_without_component_identity (test_component_governance.ComponentGovernanceTests.test_new_layout_cannot_use_receipt_without_component_identity) ... ok\ntest_receipts_reject_component_path_escape (test_component_governance.ComponentGovernanceTests.test_receipts_reject_component_path_escape) ... ok\ntest_startup_receipt_rejects_changed_ignored_component_objects (test_component_governance.ComponentGovernanceTests.test_startup_receipt_rejects_changed_ignored_component_objects) ... ok\n\n----------------------------------------------------------------------\nRan 5 tests in 0.374s\n\nOK\n",
"output_sha256": "4213c6f805ee08deeab4844b9abb9fc01d965190252353668f5d412985141734",
"receipt_sha256": "7ef330e608df2955baeb27a8e6f32de087b0d4bc3e1b6a2be213f8c54e731913"
}
```
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```json
{
"schema": 1,
"source": "SELF",
"timestamp": "2026-10-13T17:35:16.893701+00:00",
"command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p test_evidence.py -v",
"command_sha256": "1b4ded68a6722bae73cb4621aafe2c771e0231106f440ba1931e04c42b1c6993",
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace",
"common_dir": "/home/weichen/projects/Agent-System-Dev/.git",
"before": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nM Makefile\nM PROJECT.md\n M components.lock.json\nM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nA policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nMM scripts/evidence.py\nM scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\n M tests/test_component_governance.py\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nAM tests/test_task_recovery.py\n",
"tracked_diff_sha256": "3acf05a851a18e7d1f68bd8623001a841207b8af4665f754de47791e61b68d8e",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nM Makefile\nM PROJECT.md\n M components.lock.json\nM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nA policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nMM scripts/evidence.py\nM scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\n M tests/test_component_governance.py\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nAM tests/test_task_recovery.py\n",
"tracked_diff_sha256": "3acf05a851a18e7d1f68bd8623001a841207b8af4665f754de47791e61b68d8e",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after_error": null,
"exit_code": 0,
"output": "test_after_snapshot_failure_keeps_command_exit_and_output (test_evidence.EvidenceTests.test_after_snapshot_failure_keeps_command_exit_and_output) ... ok\ntest_all_persisted_and_displayed_text_is_sanitized (test_evidence.EvidenceTests.test_all_persisted_and_displayed_text_is_sanitized) ... ok\ntest_authorization_forms_are_redacted_in_capture_console_and_import (test_evidence.EvidenceTests.test_authorization_forms_are_redacted_in_capture_console_and_import) ... ok\ntest_authorization_forms_are_redacted_on_direct_card_capture (test_evidence.EvidenceTests.test_authorization_forms_are_redacted_on_direct_card_capture) ... ok\ntest_before_after_heads_do_not_relabel_changed_command (test_evidence.EvidenceTests.test_before_after_heads_do_not_relabel_changed_command) ... ok\ntest_capture_does_not_overwrite_an_existing_receipt (test_evidence.EvidenceTests.test_capture_does_not_overwrite_an_existing_receipt) ... ok\ntest_capture_without_card_and_import_without_rerun (test_evidence.EvidenceTests.test_capture_without_card_and_import_without_rerun) ... ok\ntest_child_failure_code_is_preserved (test_evidence.EvidenceTests.test_child_failure_code_is_preserved) ... ok\ntest_command_line_token_arguments_are_redacted (test_evidence.EvidenceTests.test_command_line_token_arguments_are_redacted) ... ok\ntest_dirty_and_untracked_contents_have_object_digests (test_evidence.EvidenceTests.test_dirty_and_untracked_contents_have_object_digests) ... ok\ntest_failed_child_exit_survives_receipt_write_failure (test_evidence.EvidenceTests.test_failed_child_exit_survives_receipt_write_failure) ... ok\ntest_fixed_candidate_capture_preserves_checkout (test_evidence.EvidenceTests.test_fixed_candidate_capture_preserves_checkout) ... ok\ntest_full_output_is_preserved_not_only_tail (test_evidence.EvidenceTests.test_full_output_is_preserved_not_only_tail) ... ok\ntest_import_missing_card_fails_without_losing_receipt (test_evidence.EvidenceTests.test_import_missing_card_fails_without_losing_receipt) ... ok\ntest_import_rejects_unredacted_authorization_with_valid_checksums (test_evidence.EvidenceTests.test_import_rejects_unredacted_authorization_with_valid_checksums) ... ok\ntest_import_retry_is_idempotent (test_evidence.EvidenceTests.test_import_retry_is_idempotent) ... ok\ntest_invalid_field_types_and_forged_source_are_rejected (test_evidence.EvidenceTests.test_invalid_field_types_and_forged_source_are_rejected) ... ok\ntest_known_secret_environment_value_is_redacted_without_label (test_evidence.EvidenceTests.test_known_secret_environment_value_is_redacted_without_label) ... ok\ntest_linked_worktree_import_preserves_source_identity (test_evidence.EvidenceTests.test_linked_worktree_import_preserves_source_identity) ... ok\ntest_missing_card_does_not_execute (test_evidence.EvidenceTests.test_missing_card_does_not_execute) ... ok\ntest_missing_required_snapshot_fields_are_rejected (test_evidence.EvidenceTests.test_missing_required_snapshot_fields_are_rejected) ... ok\ntest_nested_cwd_records_untracked_files_from_repository_root (test_evidence.EvidenceTests.test_nested_cwd_records_untracked_files_from_repository_root) ... ok\ntest_output_digest_checked_even_if_receipt_digest_recomputed (test_evidence.EvidenceTests.test_output_digest_checked_even_if_receipt_digest_recomputed) ... ok\ntest_pipeline_failure_is_recorded_and_returned (test_evidence.EvidenceTests.test_pipeline_failure_is_recorded_and_returned) ... ok\ntest_quoted_credentials_with_spaces_are_fully_redacted (test_evidence.EvidenceTests.test_quoted_credentials_with_spaces_are_fully_redacted) ... ok\ntest_receipt_write_failure_cannot_claim_success (test_evidence.EvidenceTests.test_receipt_write_failure_cannot_claim_success) ... ok\ntest_recorder_environment_does_not_leak_into_nested_commands (test_evidence.EvidenceTests.test_recorder_environment_does_not_leak_into_nested_commands) ... ok\ntest_source_cannot_be_promoted_by_environment (test_evidence.EvidenceTests.test_source_cannot_be_promoted_by_environment) ... ok\ntest_tamper_is_rejected_before_card_append (test_evidence.EvidenceTests.test_tamper_is_rejected_before_card_append) ... ok\ntest_unrelated_repo_cannot_import (test_evidence.EvidenceTests.test_unrelated_repo_cannot_import) ... ok\ntest_validate_precheck_checks_result_and_current_base (test_evidence.EvidenceTests.test_validate_precheck_checks_result_and_current_base) ... ok\ntest_validate_precheck_rejects_successful_arbitrary_command (test_evidence.EvidenceTests.test_validate_precheck_rejects_successful_arbitrary_command) ... ok\ntest_validation_purpose_is_not_injected_into_measured_command (test_evidence.EvidenceTests.test_validation_purpose_is_not_injected_into_measured_command) ... ok\n\n----------------------------------------------------------------------\nRan 33 tests in 4.004s\n\nOK\n",
"output_sha256": "127878268d0ab7659c9f40e2b3d0489c0cd5df0b3c92b849ff0895ae100ac8f1",
"receipt_sha256": "824adfc92d549d7c8031c1349d6ff97489ce489e94ec210ed9c399d4af9a9b90"
}
```
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
```json
{
"schema": 1,
"source": "SELF",
"timestamp": "2026-10-13T17:37:19.209871+00:00",
"command": "git diff --check",
"command_sha256": "466c2f308b48c7661d646fdd068fbecea974c665fe65dbf8ed508f224180ce0b",
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-dependency-workspace",
"common_dir": "/home/weichen/projects/Agent-System-Dev/.git",
"before": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nM Makefile\nM PROJECT.md\n M components.lock.json\nMM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nAM policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nMM scripts/evidence.py\nM scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\n M tests/test_component_governance.py\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nAM tests/test_task_recovery.py\n",
"tracked_diff_sha256": "9239af815fe3ee8133c873887d83c36a6ed7525587839a7605df670e67aca889",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after": {
"head": "7a1ff23341f535483c8abcb8ce3fee67b13519c7",
"branch": "feature/dependency-workspace",
"target_branch": "main",
"target_head": "57bcb17ea212a531186b6e21617a7f3bea65a791",
"status": "R .task/feature-d1-closeout-evidence.md -> .task/archive/feature-d1-closeout-evidence.md\nA .task/archive/feature-iam-i1-permission-boundaries.md\nR .task/feature-project-member-access.md -> .task/archive/feature-project-member-access.md\nR .task/feature-rdm-increment-settings-duties.md -> .task/archive/feature-rdm-increment-settings-duties.md\nA .task/artifacts/iam-i1-stage8/dev-actual-merge.json\nA .task/artifacts/iam-i1-stage8/dev-before-merge-sync.json\nA .task/artifacts/iam-i1-stage8/dev-before-pr-sync.json\nA .task/artifacts/iam-i1-stage8/dev-final-composition-test.json\nA .task/artifacts/iam-i1-stage8/dev-final-gate.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-doccheck.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-check.json\nA .task/artifacts/iam-i1-stage8/dev-final-independent-metadata-v2.json\nA .task/artifacts/iam-i1-stage8/dev-final-review.md\nA .task/artifacts/iam-i1-stage8/dev-final-source-equivalence-v2.json\nA .task/artifacts/iam-i1-stage8/dev-merge-response.json\nA .task/artifacts/iam-i1-stage8/dev-published-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/dev-stage9-independent-sync-review.json\nA .task/artifacts/iam-i1-stage8/docs-review.md\nA .task/artifacts/iam-i1-stage8/documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/documents-merge-response.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v2.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review-v3.json\nA .task/artifacts/iam-i1-stage8/independent-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-approved-snapshot-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.json\nA .task/artifacts/iam-i1-stage8/projection-docs-review.md\nA .task/artifacts/iam-i1-stage8/projection-documents-actual-merge.json\nA .task/artifacts/iam-i1-stage8/projection-documents-final-gate.json\nA .task/artifacts/iam-i1-stage8/projection-source-link-verified.json\nA .task/artifacts/iam-i1-stage8/rdm-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-actual-merge.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-final-gate-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-merge-response-v2.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-resynced-review-replay.json\nA .task/artifacts/iam-i1-stage8/rdm-card-close-review.md\nA .task/artifacts/iam-i1-stage8/rdm-card-close.json\nA .task/artifacts/iam-i1-stage8/rdm-final-gate.json\nA .task/artifacts/iam-i1-stage8/rdm-final-source-equivalence.json\nA .task/artifacts/iam-i1-stage8/rdm-merge-response.json\nA .task/artifacts/project-member-access-receipts/downstream-final-records-manifest.json\nA .task/artifacts/project-member-access-receipts/project-member-actual-merge.json\nA .task/artifacts/project-member-access-receipts/project-member-archive-check.py\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-check.json\nA .task/artifacts/project-member-access-receipts/project-member-dev-archive-sync.json\nA .task/artifacts/project-member-access-receipts/project-member-final-gate.json\nA .task/artifacts/project-member-access-receipts/project-member-merged-components.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json\nA .task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md\nA .task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md\n M .task/feature-dependency-workspace.md\nA .task/feature-merge-queue-policy-draft.md\nM AGENTS.md\nM Makefile\nM PROJECT.md\n M components.lock.json\nMM policy/adoption.md\nM policy/delivery.md\nM policy/governance.md\nAM policy/merge-queue.md\nM policy/platform-admission.md\nM policy/tool-adaptation-matrix.md\nMM scripts/evidence.py\nM scripts/task.sh\nM tests/integration/rdm-increment/acceptance_scenarios.sh\n M tests/test_component_governance.py\nM tests/test_evidence.py\nA tests/test_merge_queue_trial.py\nM tests/test_task.py\nAM tests/test_task_recovery.py\n",
"tracked_diff_sha256": "9239af815fe3ee8133c873887d83c36a6ed7525587839a7605df670e67aca889",
"untracked": {},
"submodules": "",
"components": {
"manifest_sha256": "c8cddfff753bee796e6a75f9c22b5392f4b2cfeee340dadc61ff82e71238318b",
"components": {
"Logging-System": {
"state": "missing"
},
"Error-Code-System": {
"state": "missing"
},
"Agent-System-Core": {
"state": "missing"
},
"Agent-System-UI": {
"state": "missing"
},
"Agent-System-Frontend": {
"head": "6ed7b9322c5733f76b206a35cd78649ba385d83b",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Native": {
"head": "6ddd3da8df5ccc532f5b06f0aa8d49662e6f049e",
"branch": "feature/dependency-live-edit-probe",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-Intent": {
"state": "missing"
},
"Agent-Command": {
"state": "missing"
},
"Agent-Squad": {
"state": "missing"
},
"Agent-System-Backend": {
"head": "fffd5790cfab317fadafb40fa55a11bab6e9a847",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Development-Guidelines": {
"head": "1a842553b6a7432e5a85aaae43a45a7a7ea58195",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
},
"Agent-System-Documents": {
"head": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c",
"branch": "",
"status": "",
"tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"untracked": {}
}
},
"lock_sha256": "5492ea46784fcb12d1b93d2cf940bc9bcb20ffc414faab2c7a456460ad21f6f7",
"state_sha256": "ac06a71f0e86aa99311f2ccdf0cff3ba6aed282080c7c57b767317a2ec8d14cd"
}
},
"after_error": null,
"exit_code": 0,
"output": "",
"output_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"receipt_sha256": "11be0539e5d021b0ceda9d1e9d1859457e95b8b39dc8d5ca1b48c9108f4f8f12"
}
```
File diff suppressed because one or more lines are too long
+6 -2
View File
@@ -28,8 +28,9 @@
完整脱敏收据(不要求已有任务卡);按输出完成必读。`SHARED_WORKSPACE_BUSY / SYNC_REQUIRED /
REMOTE_UNVERIFIED` 均不得进入写入流程;失败后排除原因再启动,不把缓存远端当最新事实。
- 新任务运行 `make task-start NAME=feature/<slug> PRECHECK_RECEIPT=/tmp/<本次唯一名称>.json`,
建立独立 worktree 与任务卡并导入首次收据。恢复已有任务在原任务工作区导入收据:
`IMPORT_RECEIPT=/tmp/<本次唯一名称>.json make evidence`。任务中途不重复启动检查。
建立独立 worktree 与任务卡并导入首次收据。恢复已有登记任务在原 worktree 用
`make task-resume PRECHECK_RECEIPT=/tmp/<本次唯一名称>.json` 验证并原样导入收据。
默认 delivery 要求严格 READY;局部恢复接口、启用条件与旧收据处理见 [开发门禁](policy/governance.md#启动与恢复)。任务中途不重复启动检查。
- **分支层级**:任务分支一律从权威 `origin/main` 切(`task-start` 已强制);同批互不依赖的
子任务用同一 R0 的兄弟分支。确有顺序依赖需从父 feature 分支切子分支时(collaboration.md
允许的堆叠例外):启动命令增加 `PARENT=feature/<父slug> PARENT_PR=<父PR链接>`,
@@ -38,6 +39,9 @@
base 改回 main,方可声明可合入(分支保护要求 head 含 origin/main,未同步必被拦)。
- **验收、请求审核、合入前**各运行一次 `make task-sync`;完成声明的 precheck、task-sync、
测试三段输出由 `make evidence` 写入任务卡(见「证据与验证门禁」),不手抄。
- **多个分支交付 / CI 调度**:先读 [合入调度](policy/merge-queue.md),核对采纳状态、协调者、
记录及当前窗口。新模式尚未启用时保留既有同步节点;启用后最终同步至合入核验共用窗口,
同基线 `task-sync` 只核验,固定后检查用源码外 RECEIPT 保存(见 [证据流程](policy/governance.md#候选固定前后))。
- 合入后由工作区 owner 确认所有写者退出,在**已登记任务 worktree 根目录**运行
`TASK_WRITERS_STOPPED=1 make task-finish`。父子仓改动、未跟踪/ignored 唯一文件先保存或显式处置;删除被拒时
保留现场并按原因处理,禁止强删兜底。放弃未合入工作用
+6 -1
View File
@@ -31,13 +31,15 @@ PLUGINS := plugins
COMBO := core=$(shell git -C $(CORE) rev-parse --short HEAD 2>/dev/null)+backend=$(shell git -C $(BACKEND) rev-parse --short HEAD 2>/dev/null)+frontend=$(shell git -C $(FRONTEND) rev-parse --short HEAD 2>/dev/null)+ui=$(shell git -C $(UI) rev-parse --short HEAD 2>/dev/null)+agentcmd=$(shell git -C $(COMMAND) rev-parse --short HEAD 2>/dev/null)+documents=$(shell git -C $(DOCUMENTS) rev-parse --short HEAD 2>/dev/null)+native=$(shell git -C $(NATIVE) rev-parse --short HEAD 2>/dev/null)+squad=$(shell git -C $(SQUAD) rev-parse --short HEAD 2>/dev/null)+intent=$(shell git -C $(INTENT) rev-parse --short HEAD 2>/dev/null)
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null)+$(COMBO)
.PHONY: help sync status workspace-prepare component-edit component-unlink workspace-status workspace-transition build frontend svc svc-list svc-info svc-commits svc-history svc-update svc-recover svc-watchdog test-backend test-backend-pg test-multi-instance test-lifecycle test-frontend test-ui test-core test-agentcmd test-pins test-libs dev pin clean setup precheck task-start task-sync task-close task-finish facts-verify evidence version
.PHONY: help sync status workspace-prepare component-edit component-unlink workspace-status workspace-transition build frontend svc svc-list svc-info svc-commits svc-history svc-update svc-recover svc-watchdog test-backend test-backend-pg test-multi-instance test-lifecycle test-frontend test-ui test-core test-agentcmd test-pins test-libs dev pin clean setup precheck task-start task-resume task-sync task-close task-finish facts-verify evidence version
version:
@echo "agent-system $(VERSION)"
TASK := scripts/task.sh
export PRECHECK_RECEIPT RECEIPT IMPORT_RECEIPT TASK_WRITERS_STOPPED
TASK_WORK_MODE ?= delivery
export TASK_WORK_MODE
TASK_PARENT_BRANCH ?= $(PARENT)
TASK_PARENT_PR ?= $(PARENT_PR)
export TASK_PARENT_BRANCH TASK_PARENT_PR
@@ -54,6 +56,9 @@ task-start:
@if [ -z "$(NAME)" ]; then echo "usage: make task-start NAME=feature/<slug>"; exit 2; fi
@bash $(TASK) start "$(NAME)"
task-resume:
@bash $(TASK) resume
task-sync:
@bash $(TASK) sync
+6
View File
@@ -18,6 +18,10 @@
实施进展和命令证据见任务卡,正式验收、共享部署及发布仍按原审批边界。
[项目依赖与过渡规则](policy/dependencies.md) 是具体工作入口。
- [用户、职位角色与分层权限统一方案 r1](.workspace/Agent-System-Documents/docs/proposals/2026-10-13-identity-role-permission-plan.md):用户已批准,首批仅 I1(U1–U2);
[权限合同](.workspace/Agent-System-Documents/docs/proposals/2026-10-13-iam-i1-permission-contract.md) 冻结边界,
[I1 实施候选与评审记录](.workspace/Agent-System-Documents/docs/proposals/2026-10-13-iam-i1-review.md) 维护实际结果与剩余限制;后续单元须另行授权。
- [快慢通道展示与动态工作摘要方案 r1.1](.workspace/Agent-System-Documents/docs/proposals/2026-10-12-fast-slow-channel-display.md):
对话即时答复、后台动态发现与来源、四层阅读、真实状态、并发/恢复及 U1–U4;
2026-10-12 方案设计已批准(阶段 1–4),首批仅 U1;
@@ -57,6 +61,8 @@ U2 起实施与部署分别评审。
## 验证
规范修订:[最终验证与合入调度 r1](policy/merge-queue.md) 及[U1–U6 实施计划](.workspace/Agent-System-Documents/docs/proposals/2026-10-13-merge-queue-implementation-plan.md)已批准。通用规范与计划已分别经 PR 合入,本候选组合固定实际合入 SHA,见[采纳记录](policy/adoption.md)。同步幂等化、显式局部恢复和源码外证据基础已实施;Dev 最新组合验收及平台调度模式启用仍按各自门禁办理。
`make setup` 启用钩子。新 clone 无需递归克隆;启动门禁提供固定规则,
`make workspace-prepare` 准备固定应用与资料。`make component-edit NAME=Agent-Native`
按消费方实际版本创建功能仓编辑分支并生成本地 go.work;解除用 `make component-unlink`。
+1 -1
View File
@@ -11,7 +11,7 @@
"commit": "1a842553b6a7432e5a85aaae43a45a7a7ea58195"
},
"Agent-System-Documents": {
"commit": "7ba50e5b2dce226b4b962ea787222a4b08f0e94c"
"commit": "4a26798000c39cc59ba0c2cc6328f5c8f10dcb32"
}
}
}
+5 -2
View File
@@ -6,12 +6,14 @@
- 过程文档位置:.workspace/Agent-System-Documents(docs/records/)
- 版本权威:components.lock.json;规则内容版本由该提交的 VERSION 标识,历史提交保留原 gitlink
- 批准/生效依据:Dev PR#1(19/19 正负例 + make test);guidelines PR#1
- 合入调度采纳基线:`0.1.0-draft.11`,实际合入提交 `2f5b19872be2a4597838a4131ad75d1be089ee5e`(Guidelines PR #5);本次依赖候选的固定规范包含该提交;最终来源仅由 components.lock.json 决定。基础门禁继续执行,合入调度流程单独记 approved/pending-activation;Dev 组合验收、平台正负例和全部写入者覆盖完成前不切换交付模式。
- 合入调度过程计划来源:Documents PR #96 实际合入 `129cc3579d9c9e3edfb46c99270d65f3e1dad0a0`,包含既有主干文档及获批 U1–U6 计划;当前进展以任务/PR 记录为准。
| 规范/工作流 | 适用条件与范围 | 执行方式/证据 |
|---|---|---|
| core/baseline.md | 日常 | manual |
| workflows/delivery.md(含启动自检 §1) | 交付 | 本地命令检查;首次收据与 BUSY/SYNC/REMOTE_UNVERIFIED 语义见 policy/governance.md |
| standards/collaboration.md | 并行/同步节点 | **enforced(本地)**:pre-commit 拒绝集成分支直提与坏分支名(负例:hook-main/badbranch 拒绝输出);节点同步由 task-sync 落卡 |
| standards/collaboration.md | 并行/同步节点 | **enforced(本地命令)**:分支、现场、组件检查;task-sync 实际合并时记录,同基线只核验。最终平台与阶段授权另验 |
| 提交格式(主题行/四段 body) | 全部提交 | 主题行 enforced(local),body manual;任务工具生成四段 body,历史 PR 仅作旧版本证据 |
| standards/verification.md | 验收 | 本地 make test-governance + 组合测试;当前证据与历史 scratch 记录分开 |
| standards/multi-repo.md | 跨仓/版本依赖 | manual;受控历史迁移通道已于 2026-09-30 行使一次(documents/records/2026-09-30-history-migration.md) |
@@ -20,6 +22,7 @@
| standards/tool-adaptation.md(draft.8) | 为工具创建规则/钩子实例 | 本组合 CLI/git 级实例已登记:policy/tool-adaptation-matrix.md(A1–A7 逐行定级+正负例证据) |
| 同上(zcode 实例) | zcode 客户端写路径 | policy/tool-adaptation-zcode.md:PreToolUse 写守卫;脚本负例与客户端接线分开,客户端 pending-live |
| core/baseline.md「规范层级」+ documentation.md「记忆分层/机制化」(draft.9) | 层级效力、记忆权威、经验机制化 | manual:本仓 policy/ 仅收紧不放宽;记忆四层按条文执行(任务卡=任务记忆,documents/records=项目记忆,Dev 仓 AGENTS.md 指针已就位) |
| draft.11 合入调度候选 | approved/pending-activation;本候选组合固定实际合入 SHA,Dev 验收待完成 | CLI/文档已有 SELF、独立 REPLAY 和历史固定对象 GATE;当前新组合须另验。Issue #518 已建且协调者已指定,平台正负例、所有写入者覆盖及真实试行未完成;现行准入条件保留 |
## 项目差异
@@ -29,7 +32,7 @@
| delivery.md §2、design-verification.md 的轻量流程默认做法 | 按 [policy/delivery.md](delivery.md) 保留需求、方案、实施与验收的人工节点;代码 Review 与 PR 合入交由智能体,冲突解决且当前 HEAD 的 CI 通过后合入;小任务简化篇幅,阶段内可迭代 | 2026-10-12 用户明确要求智能体 Review 后合入,合入前解决冲突且 CI 通过;其他人工决策与高后果双钥匙边界保留 | weichen;Review、CI 或平台准入条件变化时复查 |
- 历史记录(2026-09-30)报告 11 个组合仓 main 禁直推、拒绝陈旧候选;当前平台能力须独立重验,本地脚本测试不替代远端证据。
- 当前规范内容以 components.lock.json 固定源码及其 VERSION 为准。治理可靠性修复的命令与证据约定见 [开发门禁](governance.md),本地与客户端/平台能力分别登记;本轮不改变分支保护、发布授权或通用库版本。
- 规范源码以 components.lock.json 固定内容及其 VERSION 为准;流程启用以本采纳状态及项目条件为准,固定源码不代替实际能力证明。治理可靠性修复的命令与证据约定见 [开发门禁](governance.md),本地与客户端/平台能力分别登记;本轮不改变分支保护、发布授权或通用库版本。
## 2026-10-13 版本依赖采纳增量
+7
View File
@@ -46,6 +46,11 @@
正式测试和最终 Review 的顺序不限制设计阶段试验、实施期测试或提前审阅。
文本合并无冲突不证明组合兼容;合入后仍核验真实内容与被测候选是否一致。
多个就绪任务的最终验证与合入按 [合入调度](merge-queue.md) 的采纳状态执行。
新模式生效后,阶段 7–9 在同一目标交付窗口内完成;对象未变时各节点重复核验,
不因记录检查再创建提交或重跑有效 CI。窗口领取不代替人工结论、独立 Review 或平台准入;
未生效时继续既有同步规则。固定后的证据按 [源码外收据流程](governance.md#候选固定前后) 保存。
## 长期方向与任务衔接
用户提出大方向、长期目标或跨任务规划时,必须在项目中留存可接续的主记录,不能仅保留
@@ -169,6 +174,8 @@
本流程由智能体执行,任务卡模板和本地提示不构成平台强制门禁。平台能力按
[能力矩阵](tool-adaptation-matrix.md) 核验;分支保护变更仍由用户按双钥匙边界执行。
交付窗口覆盖普通 PR、闭合 PR、机器人及紧急通道;coordination 仍为 manual 时如实登记,
当前目标在窗口内被外部推进则建立新尝试,不继续使用旧候选的绿色结果。
### 清理与恢复
+34 -2
View File
@@ -20,10 +20,23 @@ make task-start NAME=feature/my-task PRECHECK_RECEIPT=/tmp/my-task-precheck.json
同一收据不可覆盖。首次检查失败时处理原因,使用新路径重新启动。主干在两步间前进时,
重新确认新的启动基线,不能把旧收据移花接木到新对象。
恢复已有任务仍先捕获本次启动检查,再在原任务工作区用
`IMPORT_RECEIPT=/tmp/my-task-resume.json make evidence` 导入;不重新建分支。
恢复已有登记任务先捕获本次启动检查,再在原任务 worktree 用
`make task-resume PRECHECK_RECEIPT=/tmp/my-task-resume.json` 验证并原样导入;不重新建分支。
默认 `TASK_WORK_MODE=delivery`,继续要求严格 READY 和当前目标一致。
工作区忙或落后时先由 owner 保存现场并同步;远端不可达时只继续不依赖新鲜基线的阅读和分析。
局部恢复接口已具备,流程启用仍以 [合入调度](merge-queue.md#采纳顺序与停止条件) 的采纳条件为准。
启用后,既有任务可以显式选择 local,保持原 R0,标记落后,继续已授权局部工作:
```bash
TASK_WORK_MODE=local RECEIPT=/tmp/my-local-resume.json CMD="make precheck" make evidence
TASK_WORK_MODE=local make task-resume PRECHECK_RECEIPT=/tmp/my-local-resume.json
```
LOCAL_READY 只用于局部恢复;新任务入口始终校验严格 READY,正式验收与合入另行同步。
恢复核验实际 worktree/卡片/分支、R0 祖先关系及源码外原始收据;脏现场、Git 操作、组件漂移和未知远端仍拒绝。
旧收据允许作为历史证据原样导入,不自动成为当前恢复或交付准入;格式继续为 schema 1。
堆叠任务使用 `PARENT=feature/parent PARENT_PR=<父PR链接>`。父分支须包含本批主干 R0;
卡片同时记录父分支、父 SHA 和父 PR。父先合入,子同步最新 main 并改回 main 为 PR base。
@@ -39,6 +52,9 @@ make task-start NAME=feature/my-task PRECHECK_RECEIPT=/tmp/my-task-precheck.json
已登记组件的 HEAD、分支、dirty/差异与唯一内容摘要,不能只用父仓 HEAD 代表开发组合。
历史布局继续拒绝未初始化、冲突、指针漂移及未保存子仓改动。
`task-sync` 对同一基线重复调用只核验,保留 HEAD、索引和卡片;实际合并新目标才追加一次记录。
输出完整 sync_base、记录完成后的 tested_head、checked_at 及 changed;changed 表示是否实际纳入新目标,组件仍须核对。
## 本地记录与独立证据
本地 `make evidence` 一律生成 SELF。`SRC=GATE/REPLAY` 不可把本地执行升级为权威来源。
@@ -53,6 +69,22 @@ PR 合入由智能体执行:先完成有效 Review,再同步并解决冲突
命令含敏感值时展示脱敏形式,并记录原命令摘要。执行前后对象分别记录;命令改变 HEAD
时不把执行前 SHA 冒充执行后对象。不能读取执行后状态时明确记录缺项。
### 候选固定前后
固定前,完成同步、必要检查、任务卡及本地收据提交,核对干净的组件组合,再读取和推送最终 HEAD。
将这个 head、base、完整组件及相关配置引用到调度尝试;任务卡表内“记录前对象”不当作最终候选。
固定后,本地命令使用源码外唯一 RECEIPT 保存完整输出,平台 CI/Review/合入结果写调度记录:
```bash
RECEIPT=/tmp/my-attempt-worktree-check.json CMD="make test-worktree" make evidence
```
执行者选择位于当前 checkout 和 Git 元数据之外的未用绝对路径,工具保留 before/after、原命令退出码和 SELF 来源。
这是 manual 流程,工具不提供工作树冻结或路径范围的 OS 强制隔离。命令改变源码、组件或相关配置时,
保留实际记录,重新建立尝试及受影响验证;新增提交必须核验新 HEAD 的必需 CI。
后续实际合入/清理后按授权闭合任务,再原样导入已保存收据;不向仍冻结的候选追加记录提交或补写未来结果。
凭据从环境或受保护文件引用,避免出现在命令字面量。脱敏是补充防护,不是允许输出秘密。
执行脚本不通过 shell tracing 暴露环境;管道任何一段失败应传回非零退出码。
工具写入失败本身也必须报错,不能只保留一个看似成功的退出状态。
+137
View File
@@ -0,0 +1,137 @@
# 最终验证与合入调度(候选条文 r1)
状态:approved(r1 条文作为实施计划基线);执行模式:未切换;日期:2026-10-13(Asia/Shanghai);规范采纳负责人:weichen。
r1 条文来源提交为 913b214f2826a50b3dab65f79d9ebf83e84f2519;Documents 实施与测试计划 r1@ba4044d57e38d0887dd425d052abf26b20a28bf4 已于 2026-10-13 获用户「批准」。阶段结论与执行进展按 [迭代交付](delivery.md) 记录在任务主记录,候选固定后的结论保存在关联 PR 与源码外收据中;规范及计划批准不等于模式已启用。
现行规则仍以根 AGENTS.md、[迭代交付](delivery.md)、[开发门禁](governance.md) 和已采纳的固定规范来源为准。
本分支已实施 CLI 同步/恢复及源码外证据基础,自检依据见任务主记录及固定后记录;通用条文和实施计划已经各自 PR 合入,本候选组合固定实际合入版本。线上队列、CI 分流与平台保护尚未切换,不承诺自动调度能力已就位。
## 通用规范与项目职责
通用正文的唯一候选来源是 Development-Guidelines 的 `standards/merge-queue.md`,
配套模板为该仓 `templates/merge-queue.md`,候选内容版本 `0.1.0-draft.11`。
本仓仅细化目标、入口、阶段、预算和采纳条件,不复制通用调度正文。
通用候选已经 [Guidelines PR #5](https://git-home.u1680832.nyat.app:30319/weichen/Development-Guidelines/pulls/5) 合入为 `2f5b19872be2a4597838a4131ad75d1be089ee5e`;本候选 components.lock.json 固定的规范包含该提交及上述文件。Dev 组合验收、平台正负例、全部正常写入者覆盖及模式切换条件满足前,本文件保持 approved/pending-activation,不标 active。
Dev 目标身份使用实际托管实例、仓库 ID 与 `refs/heads/main`;其他组件仓各有自己的目标队列。
跨仓组合按任务中的依赖关系先交付组件,再固定父仓组合;保留其他任务已经合入的依赖和治理能力。
队列仅安排工作,受保护分支最终准入继续由 Gitea 或等价受信入口负责。
## 项目调度记录
采纳后的首版使用每个目标一份 Gitea 调度 Issue,由一个明确协调者维护,标为 manual。
任务卡引用 Issue 条目及尝试标识,原任务仍是授权、需求和阶段的状态权威。
共享记录已建立:[Dev main 调度记录 #518](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/issues/518),包含实际托管实例、仓库 ID 和目标引用。用户已指定当前交付智能体负责后续人工协调,weichen 保留阶段评审和平台保护操作;具体任期与接管约束以该记录为准。
记录仍为准备中,不开放领取,不自动向其他任务分配工作;角色分工不代替启用条件。
必须记录目标、条目、执行者、源 HEAD、依赖、顺序、尝试、最终 base/head、组件清单、
检查定义及相关配置、实际 CI 链接/身份、Review 对象、真实合入结果和暂停/恢复原因。
平台结果先保存于调度记录;本地命令仍用 `make evidence` 保存完整 SELF 收据。
候选固定后新增命令收据使用源码之外的唯一绝对 `RECEIPT` 路径,不立即提交进被测分支。
收据之后按已授权闭合流程原样导入;不能手抄、补写或自行提升来源。
候选固定前完成任务卡、必要收据和其他需提交内容,再推送最终 HEAD。
固定后如果必须提交新内容,即使是任务卡,也建立新尝试并核验新 HEAD 的必需 CI;不复用旧提交状态放行。
合入 SHA 和清理结果在实际发生后回填,不能提前将未来合入或清理标为已完成。
闭合 PR 进入同一队列;可在授权范围内批量闭合已合入任务,保留每个真实主 PR 和结果。
## 拟替换的启动与同步要求
正式采纳时须一起修订根 AGENTS.md、`policy/governance.md` 与 `scripts/task.sh` 的对应入口;
不能仅新增本文就宣布以下能力有效。
| 场景 | 拟采用动作 | 当前实现边界 |
|---|---|---|
| 新任务启动 | 保留唯一 precheck 收据与 `task-start`,从最新权威 main 建独立工作区 | 现有命令保留 |
| 恢复落后任务的局部工作 | 核对现场、授权和落后状态,记录待最终同步;允许已授权局部编辑 | 已实现显式 local/LOCAL_READY 及 task-resume;默认仍严格,流程待采纳启用 |
| 其他任务合入、排队等待 | 更新落后/依赖提示,不自动同步各分支或触发完整 CI | 无自动调度能力,不能宣称已接线 |
| 领取最终交付窗口 | 成功 fetch,运行 `make task-sync`,实际合并最新 main、处置冲突、物化固定组件 | 使用真实同步及祖先检查,保留脏状态/远端失败拒绝 |
| 窗口内再次到达验收、审核、合入节点 | 再查最新目标和候选;未变只核验,不创建元数据提交 | 已实现同基线不提交,保留组件核对和完整最终 SHA |
| base/head、组件或相关配置变化 | 保留旧结果对象范围,重新建立尝试并按影响补测/复审 | 当前 HEAD 的全部必需 CI 仍必须实际通过 |
SYNC_REQUIRED 不整体降级为 READY;local 与 delivery 用独立结果和验证用途区分。
已同步启动收据验证、恢复入口及回归,写守卫保留原分支检查,不宣称已校验阶段批准。
共享工作区忙、未知远端和活动 Git 操作继续拒绝相应写入。
幂等化的判据是:成功 fetch、目标已包含、递归组件检查通过时,重复核验不改变 HEAD、索引和提交内容;
仍产生可复核的实际输出。任务真正需要纳入新目标时保留 merge 与对应对象记录。
所有候选身份使用必要记录提交完成后的最终 HEAD,不能把记录提交前的 SHA 当作最终被测对象。
## 拟调整的交付阶段
人工评审和独立 Review 要求不变;提前审阅可以并行,最终有效性核验和受影响重放在窗口内完成。
入队与领取不构成人工批准,也不授权跳过缺失阶段。
| 原阶段 | 采纳后的调度衔接 |
|---|---|
| 1–6 需求、设计、计划、实施 | 各任务并行推进,在既有授权内局部检查;内容就绪时登记交付条目 |
| 7 正式测试与验收 | 领取窗口后实际同步最新 main,固定候选,完成正式验证并取得必要人工结论 |
| 8 代码 Review | 对同一固定候选核验有效 Review、独立重放和问题闭合;同步或整改后按影响复审 |
| 9 合入 | 保持窗口,核验最新 base/head、全部必需 CI 和平台准入,经 PR 合入并查询真实结果 |
| 10 核验与收口 | 核对合入内容和组件后释放窗口;部署、清理另按原授权,闭合 PR 单独排队 |
等待人工结论超过预算时进入 blocked 并安全释放窗口;再次领取时判断原结论及证据是否仍适用。
窗口不得长期持有等待新的需求或方案批准;必要前置安排应在入队时说明。
普通失败和需要决策只阻塞当前条目及依赖项;未知合入结果则保持该目标在 reconciling,先对账。
## CI 资源与检查
本草案只定义后续分配要求;`.gitea/workflows/ci.yaml` 当前行为保持原样。
后续将局部反馈与最终准入的触发和资源安排区分,不通过跳过必需作业返回绿色来节省成本。
当前 workflow 中的 `test`、`test-pg`、`svc-realcombo` 等作业须按最终已批准集合核验;
平台状态上下文的完整名称、运行身份和被测 SHA 从当次实际运行核对,不从历史文档直接照抄。
建议首轮人工试行预算,待本文件及试行计划获批后使用:
- 每个目标一个最终候选;其独立作业可在实际 runner 能力内并行。
- 最大无进展时间 20 分钟,单次窗口预算 90 分钟;有效进展、延长及原因记入尝试。
- 已知基础设施失败最多额外重试一次;代码失败直接退出整改,不自动重复跑完整 CI。
- 等待队列每 30 分钟复查一次;最终准入优先,但不无限延后其他目标、main 验证或发布检查。
- 全局 runner 并发预算在试行前读取实际容量后登记;未核验容量时按现有资源安排,不凭建议数值调整平台。
预算是试行参数,长期值由真实耗时和等待情况复盘决定。
容量不足时先等待 runner,再领取目标窗口;不得持有另一个仓库窗口去等待组件窗口。
取消仅针对失效且归属明确的当前尝试,其他任务有效的局部检查继续运行。
## 平台与接管边界
现有 [平台准入所有者操作](platform-admission.md) 是历史准备材料,执行前仍需当场重验。
最新只读配置观察、命令和对象由本任务 evidence 收据保存;配置读取属于 SELF,不证明拒绝路径已经有效。
本草案不修改分支保护、批准数或白名单。
人工协调期间,全部正常合入者按窗口约定行动。没有执行端覆盖全部写入者及原子准入的正负例时,能力上限为 manual。
发现外部目标推进,立即判定本轮候选失效,保留结果并建立新尝试;不能以目标锁的本地存在绕过平台拒绝。
自动模式未来必须具备原子持久领取和合入入口的旧执行者拒绝;租约到期不直接授权接管。
合入请求超时先核对 PR 和目标真实状态,旧执行者退出后才能安全重试或释放。
需要调整平台保护时,由 Agent 准备具体配置、回退和隔离验证命令,用户按根 AGENTS.md 双钥匙要求确认并亲手执行。
至少验证合法候选可合入,以及缺检查、失败检查、陈旧候选和无权限推进被拒。
人工首版验证旧执行者确认退出后交接及未知结果对账;自动接管启用前另须验证实际合入入口拒绝旧代次。
当前不运行这些平台试验,也不影响其他进行中任务。
## 采纳顺序与停止条件
1. 人工审阅通用候选、Dev 条文及记录模板;确认同步时机、阶段衔接、预算和恢复边界。
2. 在通用仓完成候选修订 Review 与其文档验证,按授权经 PR 合入;宿主采纳完整固定 SHA。
3. 另行提交实施计划,覆盖 task-sync 幂等化、恢复/写守卫兼容、源码外收据、CI 分配和能力矩阵。
4. 在隔离场景完成治理脚本正负例;涉及脚本必须运行 `make test-governance`。
5. 跨仓语言依赖/应用源码锁正式推进前运行 Dev `make test`;最终对象的 CI/构建及平台准入遵循现行规则。
6. 完成所有者平台操作和对应验证,登记真实协调者与调度 Issue,才切换新交付模式。
7. 用三个就绪任务试行,记录同步轮数、CI 次数/耗时、废弃运行、排队和恢复,复盘后决定扩大。
第 2 步规范文本合入或第 5 步指针推进均不自动将新模式标 active/enforced。
迁移期保留现行准入规则,直到新条文、命令和平台条件一致;未满足时暂停模式切换,已授权局部开发可继续。
回退先停止新领取并对账活动合入,再恢复旧同步流程,保留尝试和证据历史。
| 验收 ID | 需验证的行为 | 本轮状态 |
|---|---|---|
| MQ1 | A/B/C 正常顺序交付;各任务轮到后最终同步一次,无外部推进时不因其他正常合入反复跑最终 CI | NOT_RUN(后续隔离试行) |
| MQ2 | 同目标重复领取被拒,不同目标可在资源预算内并行 | NOT_RUN(后续机制验证) |
| MQ3 | 同步后目标未变,重复核验不改 HEAD;固定后记录不改变候选 | 本地 CLI/证据回归已执行(SELF,原始输出见任务卡);平台试行 NOT_RUN |
| MQ4 | 新 HEAD、base 或组合不能使用旧 CI/Review 直接放行 | NOT_RUN(后续正负例) |
| MQ5 | 冲突、代码失败、等待人工决定超时释放窗口,不阻塞无依赖任务 | NOT_RUN(后续试行) |
| MQ6 | 紧急插队有依据,受影响候选失效;跨仓依赖和组件能力不回退 | NOT_RUN(后续试行) |
| MQ7 | 请求超时、协调者退出先对账;不能仅因租约过期让旧新执行者同时合入 | NOT_RUN(后续恢复验证) |
| MQ8 | 平台拒绝未满足准入者,合法固定候选可合入;manual 能力如实登记,自动接管另验证旧代次拒绝 | NOT_RUN(所有者操作后验证) |
| MQ9 | 文档链接、入口、版本、单一来源、状态与模板字段一致 | 本轮执行;原始输出见任务卡 SELF 收据 |
这些验收 ID 用于实施与验收追溯;本分支已完成可独立实施的 CLI/证据基础、规则与模板准备及临时真实 Git 场景自检。固定规范采纳、实际模式切换、平台正负例和真实 CI/三任务试行仍待各自门禁,未执行项保持 NOT_RUN;当前进展与原始证据统一见任务卡。
+50 -1
View File
@@ -5,6 +5,22 @@
## 已核实的差距
本轮读取结果见 `.task/feature-merge-queue-policy-draft.md` 的原始 SELF 收据(2026-10-13;
命令 `python3 /tmp/mq-read-platform-20261013.py`)。观察对象 main 为
`ff3fb4a7ebe432ab21c6b9668abc9823aca2fdd1`:禁直推/强推、陈旧分支阻断开启,
必需状态检查关闭,管理员强制合入覆盖未阻断。此为配置观察,不是拒绝路径通过证明。
PR #513 的固定 head `9a3c205b0b93185172cb6b31f6793b3a4d71ea58` 状态列表实际包含以下三个上下文;
该次记录未核验它们的最终通过结果,不能据此合入该 PR。
```text
ci / test (pull_request)
ci / test-pg (pull_request)
ci / svc-realcombo (pull_request)
```
仓级 runner 查询为空,不代表实例/组织共享 runner 不存在;总体容量与预算仍待核验。
执行以下操作前重查 main、保护配置和当次 PR/运行,不把本次读配置当长期授权或能力保证。
2026-10-05 读取 Dev 的 main 分支保护 API,观察到禁直推与陈旧分支拦截开启,
必需状态检查关闭、批准数为 0。读取历史 PR head 的状态 API,实际检查名为
`ci / test (pull_request)`。完整命令与输出由 evidence 工具记录在
@@ -15,8 +31,9 @@
1. 在 Gitea 的 Agent-System-Dev 仓库设置中打开 main 的分支保护,先保留当前配置截图或导出。
2. 确认本次修复 PR 的固定 head 已实际运行 CI,并在提交状态中核对完整检查名。
3. 启用必需状态检查,选择实际的 `ci / test (pull_request)`;保持禁直推及陈旧分支拦截。
3. 启用必需状态检查,逐项选择当次核验的 test、test-pg、svc-realcombo 三个完整 PR 上下文;保持禁直推、禁强推及陈旧分支拦截。
不用仅在合入后运行的 `ci / test (push)` 替代 PR 检查。
建议同时启用“管理员遵守分支保护”,关闭管理员强制合入覆盖;该配置也由所有者亲手执行。
4. 批准数暂不随此修复自动调整。若另行启用非作者批准,先确认有可用且符合权限要求的
独立审核账号;不能把切换 Agent 角色当独立账号,也不能盲设阈值使单账号仓库无法交付。
5. 在隔离的测试 PR 上验证:无检查、检查失败和陈旧候选均不可合入;合法且检查通过的
@@ -26,6 +43,38 @@
任一判据未满足时暂停合入并保留测试对象。配置调整失败由所有者对照保存的配置恢复;
不把“配置 API 返回成功”写成“门禁已有效”。其他组合仓分别核验,不外推 Dev 的结果。
## 可评审配置与恢复
以下是待所有者执行的最小字段变更,不是已经执行的 API 请求;批准数、白名单和其他策略保持原值。
在 Gitea 仓库设置 → Branches → main 对照这些字段保存即可。
API 使用 PATCH `/api/v1/repos/weichen/Agent-System-Dev/branch_protections/main`,只改变指定字段,
语义依据 [官方 API](https://docs.gitea.com/api/operations/repo-edit-branch-protection/) 和
[分支保护说明](https://docs.gitea.com/1.27/usage/access-control/protected-branches/)。
```json
{
"enable_push": false,
"enable_force_push": false,
"block_on_outdated_branch": true,
"enable_status_check": true,
"status_check_contexts": [
"ci / test (pull_request)",
"ci / test-pg (pull_request)",
"ci / svc-realcombo (pull_request)"
],
"block_admin_merge_override": true
}
```
所有者先通过 GET 同一资源保存完整旧配置到仓外受保护文件;恢复只写回本次涉及的这六类字段,
使用保存时的实际值,避免覆盖同时发生的其他配置调整。根 AGENTS.md 的双钥匙边界对恢复同样适用,Agent 不自行恢复保护。
凭据只从环境或受保护文件引用,不放请求 URL、日志或提交;不生成带 token 字面量的 curl 示例。
验证对象由所有者和协调者在动作前指定:优先隔离保护规则/测试 PR,记录实际 head/base 和预期副作用。
需要作用于 Dev 时单独确认该测试对象及合入/撤回安排;不为构造测试直推 main、发布或改写历史。
临时仓的 fixture CI 只证明保护机制,Dev workflow 的仓库 allowlist 和完整业务 CI 仍需在实际 Dev 候选核验。
缺检查/失败/陈旧/无权推进的拒绝与合法路径全部有 GATE/REPLAY 后,再更新能力矩阵并判断是否可切换调度模式。
## CI 信任前提
本次 workflow 修复减少 checkout token 对候选代码的暴露;仍须由平台维护者核验
+6 -4
View File
@@ -2,13 +2,13 @@
适配对象:通过 shell/git 操作本仓的执行者。要求来自固定的 Development-Guidelines
`standards/tool-adaptation.md` 与根 AGENTS.md;本表登记机制范围,不复制另一套规则。
当前修订为治理可靠性修复候选;实际验证记录见 `.task/feature-governance-reliability.md`
及其关联 PR。历史 19/19 临时测试不代替本次回归。
历史治理可靠性记录见 `.task/feature-governance-reliability.md`;本轮调度与恢复候选的
实际 SELF 命令记录见 `.task/feature-merge-queue-policy-draft.md`。历史测试不代替当前对象回归。
| 要求 | 执行能力及范围 | 机制 | 复验入口 |
|---|---|---|---|
| A1 启动 | 本地命令阻断;执行者首次调用仍属 manual | precheck 区分忙/落后/远端未核实;start 验证首次收据 | `tests/test_task.py`、`tests/test_evidence.py` |
| A2 同步 | 本地命令阻断;最终准入由平台承担 | 合并父仓、保护组件分支、物化固定指针、递归核对 | `tests/test_task.py`、`make test-worktree` |
| A1 启动/恢复 | 本地命令阻断;首次调用及阶段授权仍属 manual | 默认严格 READY;显式 local 验证既有任务/R0及 LOCAL_READY;start 固定严格用途,resume 验证后导入 | `tests/test_task.py`、`tests/test_task_recovery.py`、`tests/test_evidence.py` |
| A2 同步 | 本地命令阻断;最终准入由平台承担 | 合并父仓、保护组件分支、物化固定指针、同基线幂等、完整最终 SHA | `tests/test_task.py`、`make test-worktree` |
| A3 集成分支 | 本地提交闸;平台状态须独立核验 | pre-commit 拒绝 main/master 与坏分支名 | 本地 hook 负例;远端缺 CI/陈旧候选/直推等负例另验 |
| A4 提交格式 | 主题行 enforced(local),body manual | commit-msg 校验宽度/句点;任务工具生成四段 body | `tests/test_task.py`;人工核对 PR/卡片同源 |
| A5 回收 | 本地命令检查;写者退出由 owner 确认 | 登记根目录、锁/操作状态、父子仓与唯一文件、合入核验 | `tests/test_task.py` |
@@ -16,6 +16,8 @@
| A7 证据 | 本地 SELF 收据;外部来源独立核验 | 首次捕获、完整脱敏输出/摘要、对象记录、原样导入 | `tests/test_evidence.py`;CI/审阅链接另核 |
| A8 阶段评审与迭代 | manual(人工/Agent 执行);前序人工决策,智能体 Review/合入;模板和提示不构成批准身份校验或全流程阻断 | policy/delivery.md;任务卡分别记录阶段结论、Review、冲突、当前 HEAD 的 CI 和合入;post-merge 默认仅提示 | `tests/test_task.py` 核对模板及钩子不自动写入;智能体核对 Review、冲突及匹配 HEAD 的 CI/平台准入;人工批准范围仍须核验 |
| A9 长期方向与后续任务 | manual;模板不校验规划有效性或自动调度任务 | policy/delivery.md;PROJECT.md 提供规划入口,任务卡关联规划/里程碑并记录下一步建议 | `tests/test_task.py` 核对生成字段与未授权默认值;人工核对当前规划、进展、重复任务和建议依据 |
| A10 交付窗口 | manual(待启用);无自动互斥或接管 | policy/merge-queue.md;Issue #518 与协调者已登记,本候选固定实际合入规范版本;Dev 组合验收、平台正负例及全部写入者覆盖待完成 | tests/test_merge_queue_trial.py 临时 Git 场景 SELF;平台/真实 CI 三任务试行 NOT_RUN |
| A11 固定后证据 | manual 选择源码外位置;工具捕获绝对未用路径/原始输出;无 OS 冻结 | policy/governance.md;RECEIPT 捕获,后续授权闭合再原样导入 | `tests/test_evidence.py` 固定对象、权限、覆盖拒绝、原样导入与幂等 |
## 失败处理
+77 -6
View File
@@ -249,19 +249,83 @@ def read_receipt(filename):
return value
def validate_precheck(receipt):
def task_context(current=None):
"""Verify an existing task checkout; this is not an approval identity."""
current = snapshot() if current is None else current
root = Path(git_text("rev-parse", "--show-toplevel")).resolve()
branch = current["branch"]
if not re.fullmatch(r"(?:feature|fix|hotfix|release)/[A-Za-z0-9._-]+", branch):
raise EvidenceError("Local recovery requires a task branch")
records = [row.split(b"\0") for row in git("worktree", "list", "--porcelain", "-z").split(b"\0\0") if row]
matches = [row for row in records if row[0].startswith(b"worktree ")
and Path(os.fsdecode(row[0][9:])).resolve() == root]
if len(matches) != 1 or not records or matches[0] == records[0]:
raise EvidenceError("Recovery requires a registered linked task worktree")
entry = matches[0]
if any(field.startswith((b"bare", b"detached", b"prunable")) for field in entry) or (
b"branch refs/heads/" + branch.encode() not in entry):
raise EvidenceError("Task worktree registration is not valid")
if (root / ".task").is_symlink():
raise EvidenceError("Task registration must belong to the current checkout")
card = find_card()
if card.is_symlink() or card.resolve().parent != root / ".task":
raise EvidenceError("Task registration must belong to the current checkout")
content = card.read_text()
locations = re.findall(r"^- 工作区:(.+?)\s*[((]worktree[))];分支:([^\s]+)\s*$", content, re.M)
bases = re.findall(r"^- 权威仓:.*;目标分支:([^;]+);R0(initial_base_sha)= ([0-9a-f]+)\s*$", content, re.M)
if len(locations) != 1 or Path(locations[0][0]).resolve() != root or locations[0][1] != branch:
raise EvidenceError("Task card belongs to a different worktree or branch")
if len(bases) != 1 or bases[0][0] != current["target_branch"] or not GIT_SHA.fullmatch(bases[0][1]):
raise EvidenceError("Task card has no valid target and initial baseline")
r0 = bases[0][1]
if not current["target_head"]:
raise EvidenceError("Task target is unverified; fetch it first")
for tip in (current["head"], current["target_head"]):
git("merge-base", "--is-ancestor", r0, tip)
check = subprocess.run([sys.executable, str(Path(__file__).with_name("check-worktree.py")), "before-sync"],
capture_output=True, text=True)
if check.returncode:
raise EvidenceError("Task workspace is not ready: " + (check.stdout + check.stderr).strip())
return {"root": root, "r0": r0}
def validate_precheck(receipt, purpose="start"):
if purpose not in ("start", "resume-delivery", "resume-local"):
raise EvidenceError("Unknown precheck validation purpose")
after = receipt["after"]
current = snapshot()
if receipt["command"] not in ("make precheck", "bash scripts/task.sh precheck"):
raise EvidenceError("Task start requires a precheck receipt")
if receipt["exit_code"] != 0 or not re.search(r"^\[verdict\] READY(?:\s|$)", receipt["output"], re.M):
raise EvidenceError("Precheck receipt is not READY")
expected = "LOCAL_READY" if purpose == "resume-local" else "READY"
verdicts = re.findall(r"^\[verdict\] ([A-Z_]+)(?:\s|$)", receipt["output"], re.M)
if receipt["exit_code"] != 0 or verdicts != [expected]:
raise EvidenceError("Precheck receipt is not " + expected)
if after is None or receipt["after_error"] is not None:
raise EvidenceError("Precheck object capture is incomplete")
if receipt["before"]["head"] != current["head"] or after["head"] != current["head"]:
raise EvidenceError("Precheck source HEAD has changed")
if after["target_branch"] != current["target_branch"] or not after["target_head"] or after["target_head"] != current["target_head"]:
if current.get("components") is not None and any(
obj.get("components") != current["components"] for obj in (receipt["before"], after)):
raise EvidenceError("Precheck ordinary component objects have changed or are missing")
if after["target_branch"] != current["target_branch"] or not after["target_head"]:
raise EvidenceError("Precheck authoritative target has changed")
if purpose != "resume-local" and after["target_head"] != current["target_head"]:
raise EvidenceError("Precheck authoritative target has changed")
if purpose.startswith("resume-"):
context = task_context(current)
try:
Path(receipt["cwd"]).resolve().relative_to(context["root"])
except ValueError:
raise EvidenceError("Precheck belongs to a different task worktree")
if any(obj["branch"] != current["branch"] or obj["target_branch"] != current["target_branch"]
for obj in (receipt["before"], after)):
raise EvidenceError("Precheck belongs to a different task branch")
git("merge-base", "--is-ancestor", context["r0"], after["target_head"])
if purpose == "resume-local":
try:
git("merge-base", "--is-ancestor", after["target_head"], current["target_head"])
except EvidenceError:
raise EvidenceError("Precheck target history has rewound or diverged") from None
def find_card():
@@ -313,6 +377,12 @@ def main():
try:
if os.environ.get("SRC", "SELF") not in ("", "SELF"):
raise EvidenceError("Local evidence is SELF; GATE/REPLAY require external execution identity")
if sys.argv[1:] == ["--local-context"]:
context = task_context()
print("[task-state] registered=" + str(context["root"]) + " initial_base=" + context["r0"])
return 0
if sys.argv[1:]:
raise EvidenceError("Unknown evidence arguments")
capture, imported, validated = (os.environ.get(key) for key in
("RECEIPT", "IMPORT_RECEIPT", "VALIDATE_RECEIPT"))
command = os.environ.get("CMD", "")
@@ -321,7 +391,7 @@ def main():
if imported or validated:
receipt = read_receipt(imported or validated)
if validated:
validate_precheck(receipt)
validate_precheck(receipt, os.environ.get("VALIDATE_RECEIPT_PURPOSE", "start"))
report(receipt, "precheck validated")
else:
card = find_card()
@@ -338,7 +408,8 @@ def main():
source_cwd, source_common = str(Path.cwd().resolve()), common_dir()
timestamp = datetime.datetime.now(datetime.timezone.utc).isoformat()
child_env = os.environ.copy()
for key in ("CMD", "SRC", "RECEIPT", "IMPORT_RECEIPT", "VALIDATE_RECEIPT", "TAIL"):
for key in ("CMD", "SRC", "RECEIPT", "IMPORT_RECEIPT", "VALIDATE_RECEIPT", "TAIL",
"VALIDATE_RECEIPT_PURPOSE"):
child_env.pop(key, None)
result = subprocess.run(["bash", "-o", "pipefail", "-c", command],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=child_env)
+80 -24
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# 任务启动门禁:precheck / start / sync / close / finish(配套 Makefile 同名目标)。
# 任务启动门禁:precheck / start / resume / sync / close / finish(配套 Makefile 同名目标)。
# 规范依据:collaboration.md 共同基线与同步节点、治理清理;delivery.md §1/§5。
set -euo pipefail
@@ -19,10 +19,25 @@ fetch_target() {
|| { echo "[verdict] REMOTE_UNVERIFIED — target commit missing" >&2; return 6; }
}
check_worktree() { python3 "${SCRIPT_DIR}/check-worktree.py" "$1"; }
check_startup_rules() {
if ! check_worktree rules; then
echo "[verdict] RULES_UNVERIFIED — fixed startup reading unavailable; preserve the workspace and retry" >&2
return 7
fi
}
main_worktree_root() { git worktree list --porcelain -z | python3 -c 'import os,sys; print(os.fsdecode(sys.stdin.buffer.read().split(bytes([0]),1)[0][9:]))'; }
work_mode() {
case "${TASK_WORK_MODE:-delivery}" in
delivery|local) printf '%s\n' "${TASK_WORK_MODE:-delivery}" ;;
*) die "TASK_WORK_MODE must be delivery or local" ;;
esac
}
cmd_precheck() {
need_repo
local mode
mode=$(work_mode)
fetch_target
local branch head rmain dirty sub_drift sub_uninit
branch=$(git rev-parse --abbrev-ref HEAD)
@@ -100,11 +115,21 @@ cmd_precheck() {
echo "[facts] WARN policy/facts.md 不存在——外部事实登记表缺失(AGENTS.md 证据与验证门禁)"
fi
echo "[required-reading] core/baseline.md, workflows/delivery.md §1$([ -f policy/delivery.md ] && echo ", policy/delivery.md")$([ "$dirty" -gt 0 ] && echo ", standards/collaboration.md(树脏=他人或未收尾现场,不得写入)")"
echo "[R0] $(echo "$rmain" | cut -c1-10)(完整:$rmain)"
if [ "$mode" = local ]; then
echo "[target] ${rmain}(observed; task initial baseline is reported separately)"
else
echo "[R0] $(echo "$rmain" | cut -c1-10)(完整:$rmain)"
fi
if [ "$dirty" -gt 0 ] || [ "${sub_drift:-0}" -gt 0 ]; then
echo "[verdict] SHARED_WORKSPACE_BUSY — 工作树不干净,不得写入;先收尾或经 owner 确认"
exit 3
fi
if [ "$mode" = local ]; then
python3 "${SCRIPT_DIR}/evidence.py" --local-context || return 2
check_startup_rules || return $?
echo "[verdict] LOCAL_READY — existing task may continue authorized local work; final delivery still requires latest-target sync and checks"
return 0
fi
if ! check_worktree before-sync; then
echo "[verdict] SHARED_WORKSPACE_BUSY — component or active operation check failed; preserve the workspace"
exit 3
@@ -113,10 +138,7 @@ cmd_precheck() {
echo "[verdict] SYNC_REQUIRED — ${branch} 缺少 origin/${TARGET_BRANCH} 的 ${behind} 个提交;主检出 pull --ff-only,任务分支 make task-sync"
exit 4
fi
if ! check_worktree rules; then
echo "[verdict] RULES_UNVERIFIED — fixed startup reading unavailable; preserve the workspace and retry" >&2
return 7
fi
check_startup_rules || return $?
echo "[verdict] READY — 保留本次 precheck receipt 后建任务工作区:PRECHECK_RECEIPT=/tmp/task-precheck.json make task-start NAME=feature/your-branch"
}
@@ -127,7 +149,7 @@ cmd_start() {
fetch_target
[ -n "${PRECHECK_RECEIPT:-}" ] || die "PRECHECK_RECEIPT required: capture RECEIPT=/tmp/task-precheck.json CMD='make precheck' make evidence first"
PRECHECK_RECEIPT=$(realpath -- "$PRECHECK_RECEIPT")
VALIDATE_RECEIPT="$PRECHECK_RECEIPT" bash "${SCRIPT_DIR}/evidence.sh"
VALIDATE_RECEIPT="$PRECHECK_RECEIPT" VALIDATE_RECEIPT_PURPOSE=start bash "${SCRIPT_DIR}/evidence.sh"
check_worktree before-sync
# 已合入的同名分支不得重建(2026-10-05 实测:合入后再 task-start 同名会从新 main 长出
# 第二段历史,空卡覆盖已合入任务卡,两轮证据差点丢失)。复核/追加沿用原分支或换新 slug。
@@ -246,6 +268,14 @@ ${parent_note}
| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) |
|---|---|---|---|---|---|
## 交付调度
- 调度状态:未入队;调度记录:无
- entry_id:无;attempt_id:无;窗口执行者:无
- 固定候选:无(base/head、组件与相关配置引用实际尝试)
- 调度依据:policy/merge-queue.md;新模式启用前按既有交付门禁
- 固定后证据:源码外 RECEIPT;实际结果后按授权原样导入和闭合
## 结果与验证(完成后填写)
- 结果:
@@ -281,22 +311,44 @@ EOF
echo "[started] branch=${name} worktree=${wt} R0=$(echo "$rmain" | cut -c1-10)"
}
cmd_resume() {
need_repo
local mode
mode=$(work_mode)
fetch_target
[ -n "${PRECHECK_RECEIPT:-}" ] || die "PRECHECK_RECEIPT required: capture the current task precheck before resume"
local receipt
receipt=$(realpath -- "$PRECHECK_RECEIPT")
VALIDATE_RECEIPT="$receipt" VALIDATE_RECEIPT_PURPOSE="resume-${mode}" bash "${SCRIPT_DIR}/evidence.sh"
check_startup_rules || return $?
IMPORT_RECEIPT="$receipt" bash "${SCRIPT_DIR}/evidence.sh"
echo "[resumed] work_mode=${mode} source_head=$(git rev-parse HEAD) observed_target=$(git rev-parse "origin/${TARGET_BRANCH}")"
}
cmd_sync() {
need_repo
fetch_target
check_worktree before-sync
git merge --no-edit "origin/${TARGET_BRANCH}" \
-m "Merge authoritative ${TARGET_BRANCH} into the task branch" \
-m "Why: include the current integration baseline before verification." \
-m "Evidence: fetched origin/${TARGET_BRANCH}=$(git rev-parse "origin/${TARGET_BRANCH}")." \
-m "Impact: integrate upstream changes without rewriting task history." \
-m "Refs: task-sync"
git merge-base --is-ancestor "origin/${TARGET_BRANCH}" HEAD || die "sync incomplete"
local base head card branch slug pc changed=0 ancestry_status
base=$(git rev-parse "origin/${TARGET_BRANCH}")
if git merge-base --is-ancestor "$base" HEAD; then
:
else
ancestry_status=$?
[ "$ancestry_status" -eq 1 ] || die "cannot verify target ancestry"
git merge --no-edit "$base" \
-m "Merge authoritative ${TARGET_BRANCH} into the task branch" \
-m "Why: include the current integration baseline before verification." \
-m "Evidence: fetched origin/${TARGET_BRANCH}=${base}." \
-m "Impact: integrate upstream changes without rewriting task history." \
-m "Refs: task-sync"
changed=1
fi
git merge-base --is-ancestor "$base" HEAD || die "sync incomplete"
check_worktree before-update
check_worktree materialize
check_worktree after-sync
local base head card branch slug pc
base=$(git rev-parse "origin/${TARGET_BRANCH}"); head=$(git rev-parse HEAD)
head=$(git rev-parse HEAD)
branch=$(git rev-parse --abbrev-ref HEAD)
slug=$(echo "$branch" | tr '/' '-')
card=".task/${slug}.md"
@@ -311,18 +363,21 @@ cmd_sync() {
done
fi
if [ -n "$card" ] && [ -f "$card" ]; then
printf '| 同步前验收 | %s | %s | %s |\n' "$base" "$head" "$(date -u +%FT%TZ)" >> "$card"
git add "$card"
git commit -q -m "Record the sync checkpoint" \
-m "Why: bind the task validation checkpoint to the latest integration baseline." \
-m "Evidence: SELF component ownership and fixed-source checks; sync_base=${base}; candidate=${head}." \
-m "Impact: task metadata only." -m "Refs: ${card}"
if [ "$changed" -eq 1 ]; then
printf '| 同步(记录前对象) | %s | %s | %s |\n' "$base" "$head" "$(date -u +%FT%TZ)" >> "$card"
git add "$card"
git commit -q -m "Record the sync checkpoint" \
-m "Why: bind the task validation checkpoint to the integration baseline." \
-m "Evidence: SELF component ownership and fixed-source checks; sync_base=${base}; before_record=${head}." \
-m "Impact: task metadata only." -m "Refs: ${card}" -- "$card"
fi
# JSON receipts carry before/after state; older table rows remain readable.
python3 "${SCRIPT_DIR}/check-evidence.py" "$card"
else
echo "[warn] 找不到分支 ${branch} 的任务卡,同步记录未写入" >&2
fi
echo "[synced] sync_base=$(echo "$base" | cut -c1-10) tested_head=$(echo "$head" | cut -c1-10) checked_at=$(date -u +%FT%TZ)"
head=$(git rev-parse HEAD)
echo "[synced] sync_base=${base} tested_head=${head} checked_at=$(date -u +%FT%TZ) changed=${changed}"
echo "[next] 跑正式验收(make test 等),证据写入任务卡"
}
@@ -538,8 +593,9 @@ cmd_finish() {
case "${1:-}" in
precheck) shift; cmd_precheck "$@" ;;
start) shift; cmd_start "$@" ;;
resume) shift; cmd_resume "$@" ;;
sync) shift; cmd_sync "$@" ;;
close) shift; cmd_close "$@" ;;
finish) shift; cmd_finish "$@" ;;
*) echo "usage: task.sh <precheck|start|sync|close|finish> [args]"; exit 2 ;;
*) echo "usage: task.sh <precheck|start|resume|sync|close|finish> [args]"; exit 2 ;;
esac
@@ -1,7 +1,11 @@
#!/usr/bin/env bash
# P8 第八节十场景验收(提案 rdm-settings-members-duties-perms-increment §8)。
# 走真实 dev 服务 HTTP(--auth 会话),多账号多角色;输出逐场景 PASS/FAIL。
# 用法:BASE=http://127.0.0.1:8788 ADMIN_USER=weichen ADMIN_PASS=<密码> ./acceptance_scenarios.sh
# 走真实服务 HTTP(--auth 会话),多账号多角色;输出逐场景 PASS/FAIL。
# v0.4.0 版:RDM 命令面用 rdm.project.create 的 RID(不再直用基座项目);
# 场景 2 姓名过滤全量断言(基座 v0.4.0+ AccountSearcher);setRole→set-role(#350)。
# 前置:ADMIN 账号须为基座管理员(改密门已过)且已登记 RDM 域管理员
# (组合二进制 -bootstrap-admin <owner>,仅空台账生效)。
# 用法:BASE=http://127.0.0.1:8799 ADMIN_USER=rootadmin ADMIN_PASS=<密码> ./acceptance_scenarios.sh
set -u
BASE="${BASE:-http://127.0.0.1:8788}"
ADMIN_USER="${ADMIN_USER:?需要管理员账号}"
@@ -33,19 +37,27 @@ JA="$T/admin"; login "$ADMIN_USER" "$ADMIN_PASS" "$JA"
say "== 准备:账号与两项目 =="
TS=$(date +%s)
# 建号:非管理员负责人 owner2 / 普通成员 mem1 / 三权三人 w1 a1 r1(密码同式)
# 建号:非管理员负责人 owner2 / 普通成员 mem1 / 三权三人 w1 a1 r1(密码同式;name=角色-<u>)
for u in owner2 mem1 w1 a1 r1; do
resp=$(api "$JA" POST /api/admin/users "{\"owner\":\"$u\",\"name\":\"角色-$u\",\"password\":\"Pass-$TS-x8z\",\"isAdmin\":false}")
[ "$(echo "$resp" | code)" = "200" ] || say " ($u 已存在或其他:$(echo "$resp" | code))"
done
# 各自完成改密门(登录→改密)
# 各自完成改密门(登录→改密);基座 #195 起改密撤销旧会话 → 用新密码重登刷新 jar
for u in owner2 mem1 w1 a1 r1; do
J="$T/$u"; login "$u" "Pass-$TS-x8z" "$J"
api "$J" POST /api/auth/password "{\"current\":\"Pass-$TS-x8z\",\"next\":\"Pass2-$TS\"}" >/dev/null
login "$u" "Pass2-$TS" "$J"
done
JPASS="Pass2-$TS"
# 场景 10 前置数据 + 项目创建走 owner2(非管理员)
RDM() { # jar cmd json
api "$1" POST "/api/commands/$2" "{\"params\":$3}" | body
}
PAYLOAD() { # stdin json → payload 子对象(命令应答信封 {payload,receipt})
python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["payload"], ensure_ascii=False))'
}
# 基座项目(场景 1/10 用):owner2(非管理员)创建
JO="$T/owner2"
P1=$(api "$JO" POST /api/projects "{\"name\":\"验收甲-$TS\"}")
PID1=$(echo "$P1" | body | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' 2>/dev/null)
@@ -53,9 +65,15 @@ P2=$(api "$JO" POST /api/projects "{\"name\":\"验收乙-$TS\"}")
PID2=$(echo "$P2" | body | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' 2>/dev/null)
[ -n "${PID1:-}" ] && [ -n "${PID2:-}" ] && ok "准备:两项目创建($PID1 / $PID2)" || { bad "准备:项目创建" "$P1"; exit 1; }
RDM() { # jar cmd json
api "$1" POST "/api/commands/$2" "{\"params\":$3}" | body
}
# RDM 项目(场景 2-8 用):域管理员建项(创建者自动为 owner)+ 绑定基座项目;
# owner2 入项为 owner 后域管理员自移出——owner2 成为唯一 owner(场景 3b 前提)
RID=$(RDM "$JA" rdm.project.create "{\"name\":\"验收RDM甲-$TS\"}" | python3 -c 'import json,sys; print(json.load(sys.stdin)["payload"]["projectId"])' 2>/dev/null)
[ -n "${RID:-}" ] && ok "准备:RDM 项目创建($RID)" || { bad "准备:RDM 项目创建" ""; exit 1; }
RDM "$JA" rdm.project.bind "{\"hostProjectId\":\"$PID1\",\"projectId\":\"$RID\"}" >/dev/null
out=$(RDM "$JA" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"owner2\",\"role\":\"owner\"}")
echo "$out" | grep -q '"owner"' || { bad "准备:owner2 入项" "$out"; exit 1; }
out=$(RDM "$JA" rdm.project.member.remove "{\"projectId\":\"$RID\",\"member\":\"$ADMIN_USER\"}")
echo "$out" | grep -q '"removed":true' && ok "准备:owner2 为 RDM 项目唯一 owner(管理员自移出)" || { bad "准备:管理员自移出" "$out"; exit 1; }
say "== 场景 1:受管项写入拒绝(user/project 层,含手造请求)=="
r=$(api "$JO" PUT /api/settings/user '{"models":{"chat":{"model":"m-hack"}}}' | code)
@@ -66,51 +84,68 @@ r=$(api "$JO" PUT "/api/settings/project/$PID1" '{"models":{"chat":{"apiKey":"sk
r=$(api "$JO" PUT /api/settings/system '{"models":{"chat":{"model":"x"}}}' | code)
[ "$r" = "403" ] && ok "1c 非管理员写系统面 403" || bad "1c" "$r"
say "== 场景 2:目录查找成员(账号/分页;姓名过滤待发版 tag 后全量)=="
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$PID1\",\"limit\":5}")
n=$(echo "$out" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(len(d.get("accounts",[])))' 2>/dev/null)
say "== 场景 2:目录查找成员(账号/分页 + 姓名过滤 v0.4.0 全量)=="
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"limit\":5}")
n=$(echo "$out" | python3 -c 'import json,sys; d=json.load(sys.stdin)["payload"]; print(len(d.get("accounts",[])))' 2>/dev/null)
[ "${n:-0}" -gt 0 ] && ok "2a 目录分页浏览($n 条)" || bad "2a" "$out"
# 2b 姓名子串「角色-w」→ 仅 w1(角色-w1),姓名随行、检索无游标
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"query\":\"角色-w\",\"limit\":20}")
r=$(echo "$out" | python3 -c 'import json,sys
d=json.load(sys.stdin)["payload"]; a=d.get("accounts",[])
print("ok" if len(a)==1 and a[0]["owner"]=="w1" and a[0].get("name")=="角色-w1" and d.get("next","")=="" else json.dumps(d,ensure_ascii=False))' 2>/dev/null)
[ "$r" = "ok" ] && ok "2b 姓名过滤「角色-w」仅 w1 且姓名随行无游标" || bad "2b" "$r"
# 2c 账号子串大小写不敏感「MEM」→ 仅 mem1(角色-mem1)
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"query\":\"MEM\",\"limit\":20}")
r=$(echo "$out" | python3 -c 'import json,sys
d=json.load(sys.stdin)["payload"]; a=d.get("accounts",[])
print("ok" if len(a)==1 and a[0]["owner"]=="mem1" and a[0].get("name")=="角色-mem1" else json.dumps(d,ensure_ascii=False))' 2>/dev/null)
[ "$r" = "ok" ] && ok "2c 账号过滤「MEM」(不区分大小写)仅 mem1" || bad "2c" "$r"
# 2d 多命中(角色- 前缀 5 人)+ limit 截断
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"query\":\"角色\",\"limit\":3}")
r=$(echo "$out" | python3 -c 'import json,sys
d=json.load(sys.stdin)["payload"]; a=d.get("accounts",[])
print("ok" if len(a)==3 and all(str(e.get("name","")).startswith("角色-") for e in a) else json.dumps(d,ensure_ascii=False))' 2>/dev/null)
[ "$r" = "ok" ] && ok "2d 多命中姓名检索按 limit 截断(3/5)" || bad "2d" "$r"
say "== 场景 3:重复添加与最后负责人保护 =="
RDM "$JO" rdm.project.member.add "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
out=$(RDM "$JO" rdm.project.member.add "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"owner\"}")
RDM "$JO" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
out=$(RDM "$JO" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"owner\"}")
echo "$out" | grep -q "已是成员" && ok "3a 重复添加拒绝且不隐式变更" || bad "3a" "$out"
out=$(RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"owner2\",\"role\":\"member\"}")
out=$(RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"owner2\",\"role\":\"member\"}")
echo "$out" | grep -q "最后一位负责人" && ok "3b 降级唯一负责人被拒" || bad "3b" "$out"
out=$(RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"owner\"}")
out=$(RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"owner\"}")
echo "$out" | grep -q '"role":"owner"' && ok "3c 显式升级成功" || bad "3c" "$out"
RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
# 成员补充:三权三人入项目
for u in w1 a1 r1; do RDM "$JO" rdm.project.member.add "{\"projectId\":\"$PID1\",\"member\":\"$u\"}" >/dev/null; done
for u in w1 a1 r1; do RDM "$JO" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"$u\"}" >/dev/null; done
say "== 场景 4:文档目录与职责分配对象校验 =="
# 建文档(经 RDM 世界初始化:用 rdm.init 或模板?最小:rdm.duty.catalog 应答;docId 误提交由场景 5 的 assign 覆盖
cat_out=$(RDM "$JO" rdm.duty.catalog "{\"projectId\":\"$PID1\"}")
echo "$cat_out" | python3 -c 'import json,sys; d=json.load(sys.stdin); assert "docs" in d' 2>/dev/null && ok "4a duty.catalog 目录可读" || bad "4a" "$cat_out"
cat_out=$(RDM "$JO" rdm.duty.catalog "{\"projectId\":\"$RID\"}")
echo "$cat_out" | python3 -c 'import json,sys; assert "docs" in json.load(sys.stdin)["payload"]' 2>/dev/null && ok "4a duty.catalog 目录可读" || bad "4a" "$cat_out"
# 章节误提交:构造不存在的 docId → assign 拒绝
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$PID1\",\"docId\":\"section-not-doc\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$RID\",\"docId\":\"section-not-doc\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
echo "$out" | grep -qE "不存在|失败|错误" && ok "4b 不存在对象整笔拒绝" || bad "4b" "$out"
say "== 场景 5:非成员职责目标被拒;移出成员保存被拒 =="
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$PID1\",\"docId\":\"any\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$RID\",\"docId\":\"any\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
echo "$out" | grep -q "成员" && ok "5a 非成员职责目标被拒" || bad "5a" "$out"
# mem1 移出后 setRole 保存拒绝
RDM "$JO" rdm.project.member.remove "{\"projectId\":\"$PID1\",\"member\":\"mem1\"}" >/dev/null
out=$(RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"owner\"}")
# mem1 移出后 set-role 保存拒绝
RDM "$JO" rdm.project.member.remove "{\"projectId\":\"$RID\",\"member\":\"mem1\"}" >/dev/null
out=$(RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"owner\"}")
echo "$out" | grep -q "不是" && ok "5b 移出成员的成员面操作被拒" || bad "5b" "$out"
say "== 场景 6:批量整批拒绝(预检列原因)=="
out=$(RDM "$JO" rdm.review.assign.doc.batch "{\"projectId\":\"$PID1\",\"docs\":[{\"docId\":\"x1\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"},{\"docId\":\"x2\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}]}")
out=$(RDM "$JO" rdm.review.assign.doc.batch "{\"projectId\":\"$RID\",\"docs\":[{\"docId\":\"x1\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"},{\"docId\":\"x2\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}]}")
echo "$out" | grep -q "整批拒绝" && ok "6 批量含非成员整批拒绝并列原因" || bad "6" "$out"
say "== 场景 7:单成员解释与矩阵同源 =="
chk=$(RDM "$JO" rdm.perm.check "{\"projectId\":\"$PID1\",\"member\":\"owner2\"}")
mtx=$(RDM "$JO" rdm.perm.matrix "{\"projectId\":\"$PID1\"}")
chk=$(RDM "$JO" rdm.perm.check "{\"projectId\":\"$RID\",\"member\":\"owner2\"}")
mtx=$(RDM "$JO" rdm.perm.matrix "{\"projectId\":\"$RID\"}")
same=$(python3 - "$chk" "$mtx" <<'PY'
import json,sys
c=json.loads(sys.argv[1]); m=json.loads(sys.argv[2])
c=json.loads(sys.argv[1])["payload"]; m=json.loads(sys.argv[2])["payload"]
row=[r for r in m.get("rows",[]) if r["member"]==c["member"]]
if not row: print("no-row"); sys.exit(1)
if not row: print("no-row"); sys.exit(0)
ca={a["action"]:(a["allowed"],a.get("label"),a.get("scope")) for a in c["actions"]}
ra={a["action"]:(a["allowed"],a.get("label"),a.get("scope")) for a in row[0]["actions"]}
print("same" if ca==ra else "diff")
@@ -119,15 +154,15 @@ PY
[ "$same" = "same" ] && ok "7 单成员详情与矩阵单元格一致" || bad "7" "$same"
# 普通成员自省:a1 查自己
ja="$T/a1"
out=$(RDM "$ja" rdm.perm.check "{\"projectId\":\"$PID1\",\"member\":\"a1\"}")
out=$(RDM "$ja" rdm.perm.check "{\"projectId\":\"$RID\",\"member\":\"a1\"}")
echo "$out" | grep -q '"actions"' && ok "7b 普通成员自省可用" || bad "7b" "$out"
say "== 场景 8:系统动作不可项目覆盖 =="
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$PID1\",\"member\":\"a1\",\"action\":\"project.create\",\"allow\":true}")
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$RID\",\"member\":\"a1\",\"action\":\"project.create\",\"allow\":true}")
echo "$out" | grep -q "系统范围" && ok "8a project.create 覆盖被服务端拒绝" || bad "8a" "$out"
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$PID1\",\"member\":\"a1\",\"action\":\"doc.write\",\"allow\":true}")
echo "$out" | grep -q '"ok"' || echo "$out" | grep -q 'ok' && ok "8b 项目范围动作覆盖可用" || bad "8b" "$out"
out=$(RDM "$JO" rdm.perm.unset "{\"projectId\":\"$PID1\",\"member\":\"a1\",\"action\":\"doc.write\"}")
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$RID\",\"member\":\"a1\",\"action\":\"doc.write\",\"allow\":true}")
echo "$out" | grep -q '"allow":true' && ok "8b 项目范围动作覆盖可用" || bad "8b" "$out"
out=$(RDM "$JO" rdm.perm.unset "{\"projectId\":\"$RID\",\"member\":\"a1\",\"action\":\"doc.write\"}")
echo "$out" | grep -q '"restored":true' && ok "8c 恢复默认(实际撤销)" || bad "8c" "$out"
say "== 场景 9:迟到响应/断网(UI 行为)=="
+24
View File
@@ -59,6 +59,30 @@ class ComponentGovernanceTests(unittest.TestCase):
self.assertNotEqual(result.returncode,0,'a hidden component writer must block synchronization')
self.assertTrue((self.child/'.git/index.lock').exists())
def test_startup_receipt_rejects_changed_ignored_component_objects(self):
spec=importlib.util.spec_from_file_location('component_evidence_validation',SCRIPTS/'evidence.py')
module=importlib.util.module_from_spec(spec); spec.loader.exec_module(module)
self.run_git(self.root,'update-ref','refs/remotes/origin/main','HEAD')
before=module.snapshot()
receipt=module.create_receipt('make precheck','[verdict] READY\n',0,before,before,
timestamp='2026-10-13T00:00:00+00:00',cwd=str(self.root),
git_common_dir=module.common_dir())
module.validate_precheck(receipt)
(self.child/'value').write_text('changed after startup')
with self.assertRaises(module.EvidenceError):
module.validate_precheck(receipt)
def test_new_layout_cannot_use_receipt_without_component_identity(self):
spec=importlib.util.spec_from_file_location('component_evidence_legacy',SCRIPTS/'evidence.py')
module=importlib.util.module_from_spec(spec); spec.loader.exec_module(module)
self.run_git(self.root,'update-ref','refs/remotes/origin/main','HEAD')
before=module.snapshot();before.pop('components')
receipt=module.create_receipt('make precheck','[verdict] READY\n',0,before,before,
timestamp='2026-10-13T00:00:00+00:00',cwd=str(self.root),
git_common_dir=module.common_dir())
with self.assertRaises(module.EvidenceError):
module.validate_precheck(receipt)
def test_receipts_reject_component_path_escape(self):
data=json.loads((self.root/'components.json').read_text())
data['components'][0]['path']='../outside'
+23 -1
View File
@@ -68,7 +68,8 @@ class EvidenceTests(unittest.TestCase):
def run_evidence(self, command=None, cwd=None, **values):
env = os.environ.copy()
for key in ("CMD", "SRC", "RECEIPT", "IMPORT_RECEIPT", "VALIDATE_RECEIPT"):
for key in ("CMD", "SRC", "RECEIPT", "IMPORT_RECEIPT", "VALIDATE_RECEIPT",
"VALIDATE_RECEIPT_PURPOSE", "TASK_WORK_MODE"):
env.pop(key, None)
if command is not None:
env["CMD"] = command
@@ -103,6 +104,27 @@ class EvidenceTests(unittest.TestCase):
self.assertEqual(result.returncode, 7)
self.assertIn('"exit_code": 7', self.card.read_text())
def test_validation_purpose_is_not_injected_into_measured_command(self):
data = self.capture("printf '%s' \"${VALIDATE_RECEIPT_PURPOSE-unset}\"",
VALIDATE_RECEIPT_PURPOSE="resume-local")
self.assertEqual(data["output"], "unset")
def test_fixed_candidate_capture_preserves_checkout(self):
self.git("add", ".task/main.md")
self.git("commit", "-qm", "Save fixture card before validation")
head = self.git("rev-parse", "HEAD")
card = self.card.read_bytes()
index = self.git("ls-files", "--stage")
data = self.capture("printf 'fixed candidate check\\n'")
self.assertEqual(data["before"]["head"], head)
self.assertEqual(data["after"]["head"], head)
self.assertEqual(data["output"], "fixed candidate check\n")
self.assertEqual(self.git("rev-parse", "HEAD"), head)
self.assertEqual(self.git("ls-files", "--stage"), index)
self.assertEqual(self.card.read_bytes(), card)
self.assertEqual(self.git("status", "--porcelain"), "")
self.assertEqual(self.receipt.stat().st_mode & 0o777, 0o600)
def test_capture_without_card_and_import_without_rerun(self):
self.card.unlink()
data = self.capture("printf 'once\\n' >> invocation; cat invocation")
+80
View File
@@ -0,0 +1,80 @@
"""Real disposable Git scenarios; these do not claim CI or automatic queue locking."""
import unittest
import test_task as lifecycle
class QueueTrialTests(unittest.TestCase):
def setUp(self):
self.fixture = lifecycle.TaskLifecycleTests(methodName="runTest")
self.fixture.setUp()
self.addCleanup(self.fixture.doCleanups)
def create_task(self, branch):
f = self.fixture
wt = f.root / branch.replace("/", "-")
f.git(f.repo, "worktree", "add", "-b", branch, str(wt), "origin/main")
f.record_task_card(wt)
name = branch.split("/")[1]
(wt / name).write_text(name + "\n")
f.git(wt, "add", name)
f.git(wt, "commit", "-m", "Add independent fixture change")
return wt
def test_sequential_delivery_does_not_sync_waiting_branches(self):
f = self.fixture
branches = ["feature/a", "feature/b", "feature/c"]
worktrees = {branch: self.create_task(branch) for branch in branches}
waiting = {branch: f.git(wt, "rev-parse", "HEAD").stdout for branch, wt in worktrees.items()}
f.advance_remote()
for position, branch in enumerate(branches):
wt = worktrees[branch]
f.task(wt, "sync")
candidate = f.git(wt, "rev-parse", "HEAD").stdout
second = f.task(wt, "sync")
self.assertIn("changed=0", second.stdout)
self.assertEqual(f.git(wt, "rev-parse", "HEAD").stdout, candidate)
self.assertEqual(f.git(wt, "status", "--porcelain").stdout, "")
f.git(f.repo, "merge", "--no-ff", branch, "-m", "Merge fixture candidate")
f.git(f.repo, "push", "origin", "main")
for pending in branches[position + 1:]:
self.assertEqual(f.git(worktrees[pending], "rev-parse", "HEAD").stdout, waiting[pending])
for name in ("a", "b", "c"):
self.assertEqual((f.repo / name).read_text(), name + "\n")
def test_conflicted_task_does_not_block_an_independent_healthy_task(self):
f = self.fixture
conflict = self.create_task("feature/conflict")
healthy = self.create_task("feature/healthy")
(conflict / "tracked").write_text("task choice\n")
f.git(conflict, "commit", "-am", "Conflicting task edit")
(f.repo / "tracked").write_text("target choice\n")
f.git(f.repo, "commit", "-am", "Target edit")
f.git(f.repo, "push", "origin", "main")
failed = f.task(conflict, "sync", check=False)
self.assertNotEqual(failed.returncode, 0)
self.assertNotIn("[synced]", failed.stdout)
self.assertIn("UU tracked", f.git(conflict, "status", "--porcelain").stdout)
succeeded = f.task(healthy, "sync")
self.assertIn("[synced]", succeeded.stdout)
self.assertEqual((healthy / "tracked").read_text(), "target choice\n")
self.assertEqual((healthy / "healthy").read_text(), "healthy\n")
def test_external_target_advance_requires_a_new_candidate(self):
f = self.fixture
task = self.create_task("feature/a")
f.task(task, "sync")
original = f.git(task, "rev-parse", "HEAD").stdout
f.advance_remote()
target = f.git(f.repo, "rev-parse", "HEAD").stdout.strip()
result = f.task(task, "sync")
current = f.git(task, "rev-parse", "HEAD").stdout
self.assertNotEqual(current, original)
self.assertIn("changed=1", result.stdout)
f.git(task, "merge-base", "--is-ancestor", target, "HEAD")
self.assertEqual((task / "a").read_text(), "a\n")
self.assertEqual((task / "new-main").read_text(), "new main\n")
if __name__ == "__main__":
unittest.main()
+92 -1
View File
@@ -26,7 +26,8 @@ class TaskLifecycleTests(unittest.TestCase):
"GIT_AUTHOR_NAME": "Lifecycle Test", "GIT_AUTHOR_EMAIL": "test@example.invalid",
"GIT_COMMITTER_NAME": "Lifecycle Test", "GIT_COMMITTER_EMAIL": "test@example.invalid"})
for key in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GITEA_TOKEN", "PRECHECK_RECEIPT",
"TASK_PARENT_BRANCH", "TASK_PARENT_PR", "FORCE_ABANDON", "TASK_TARGET_BRANCH"):
"TASK_PARENT_BRANCH", "TASK_PARENT_PR", "FORCE_ABANDON", "TASK_TARGET_BRANCH",
"TASK_WORK_MODE", "VALIDATE_RECEIPT_PURPOSE"):
self.env.pop(key, None)
self.git(self.root, "init", "--bare", "--initial-branch=main", str(self.remote))
# receive-pack 默认在后台跑 gc --auto,与 TemporaryDirectory 清理竞态
@@ -69,6 +70,20 @@ class TaskLifecycleTests(unittest.TestCase):
self.git(self.repo, "commit", "-m", "Advance main")
self.git(self.repo, "push", "origin", "main")
def record_task_card(self, wt):
branch = self.git(wt, "branch", "--show-current").stdout.strip()
r0 = self.git(wt, "rev-parse", "origin/main").stdout.strip()
card = wt / ".task" / (branch.replace("/", "-") + ".md")
card.parent.mkdir(exist_ok=True)
card.write_text(
f"# {branch}\n任务主记录:fixture;状态:进行中;owner:Lifecycle Test\n"
f"- 权威仓:fixture;目标分支:main;R0(initial_base_sha)= {r0}\n"
f"- 工作区:{wt}(worktree);分支:{branch}\n"
)
self.git(wt, "add", str(card.relative_to(wt)))
self.git(wt, "commit", "-m", "Record fixture task")
return card
def add_submodule(self):
child = self.root / "component"
self.git(self.root, "init", "--initial-branch=main", str(child))
@@ -105,6 +120,76 @@ class TaskLifecycleTests(unittest.TestCase):
reading = next(line for line in result.stdout.splitlines() if line.startswith("[required-reading]"))
self.assertIn("policy/delivery.md", reading)
def test_sync_same_base_preserves_head_and_card(self):
wt = self.worktree()
card = self.record_task_card(wt)
head = self.git(wt, "rev-parse", "HEAD").stdout.strip()
content = card.read_bytes()
index = self.git(wt, "ls-files", "--stage").stdout
for _ in range(2):
result = self.task(wt, "sync")
self.assertEqual(self.git(wt, "rev-parse", "HEAD").stdout.strip(), head)
self.assertEqual(card.read_bytes(), content)
self.assertEqual(self.git(wt, "ls-files", "--stage").stdout, index)
self.assertEqual(self.git(wt, "status", "--porcelain").stdout, "")
self.assertIn("changed=0", result.stdout)
self.assertIn(f"tested_head={head}", result.stdout)
def test_sync_new_base_reports_actual_final_head(self):
wt = self.worktree()
card = self.record_task_card(wt)
self.advance_remote()
base = self.git(self.repo, "rev-parse", "HEAD").stdout.strip()
result = self.task(wt, "sync")
head = self.git(wt, "rev-parse", "HEAD").stdout.strip()
self.git(wt, "merge-base", "--is-ancestor", base, head)
self.assertIn(f"sync_base={base}", result.stdout)
self.assertIn(f"tested_head={head}", result.stdout)
self.assertIn("changed=1", result.stdout)
content = card.read_bytes()
self.task(wt, "sync")
self.assertEqual(self.git(wt, "rev-parse", "HEAD").stdout.strip(), head)
self.assertEqual(card.read_bytes(), content)
def test_sync_preserves_dirty_parent_and_staged_changes(self):
for staged in (False, True):
with self.subTest(staged=staged):
wt = self.worktree(name="feature/staged" if staged else "feature/dirty")
head = self.git(wt, "rev-parse", "HEAD").stdout.strip()
(wt / "tracked").write_text("keep owner work\n")
if staged:
self.git(wt, "add", "tracked")
index = self.git(wt, "ls-files", "--stage").stdout
result = self.task(wt, "sync", check=False)
self.assertNotEqual(result.returncode, 0)
self.assertEqual(self.git(wt, "rev-parse", "HEAD").stdout.strip(), head)
self.assertEqual(self.git(wt, "ls-files", "--stage").stdout, index)
self.assertEqual((wt / "tracked").read_text(), "keep owner work\n")
self.git(self.repo, "worktree", "remove", "--force", str(wt))
def test_sync_rejects_unreachable_target_without_changing_head(self):
wt = self.worktree()
self.record_task_card(wt)
head = self.git(wt, "rev-parse", "HEAD").stdout.strip()
self.git(wt, "remote", "set-url", "origin", str(self.root / "missing.git"))
result = self.task(wt, "sync", check=False)
self.assertNotEqual(result.returncode, 0)
self.assertIn("REMOTE_UNVERIFIED", result.stdout)
self.assertEqual(self.git(wt, "rev-parse", "HEAD").stdout.strip(), head)
def test_sync_conflict_is_not_reported_as_synced(self):
wt = self.worktree()
self.record_task_card(wt)
(wt / "tracked").write_text("task choice\n")
self.git(wt, "commit", "-am", "Task edit")
(self.repo / "tracked").write_text("target choice\n")
self.git(self.repo, "commit", "-am", "Target edit")
self.git(self.repo, "push", "origin", "main")
result = self.task(wt, "sync", check=False)
self.assertNotEqual(result.returncode, 0)
self.assertNotIn("[synced]", result.stdout)
self.assertIn("UU tracked", self.git(wt, "status", "--porcelain").stdout)
def test_sync_materializes_updated_component(self):
child = self.add_submodule()
wt = self.worktree()
@@ -396,6 +481,7 @@ class TaskLifecycleTests(unittest.TestCase):
(wt / ".task/feature-test.md").write_text("# Task\n")
self.git(wt, "add", ".task")
self.git(wt, "commit", "-m", "Create task card")
self.advance_remote()
hook = self.repo / ".git/hooks/pre-commit"
hook.write_text("#!/bin/sh\nexit 1\n")
hook.chmod(0o755)
@@ -611,6 +697,11 @@ class TaskLifecycleTests(unittest.TestCase):
self.assertIn(f"{field}:无", card)
for field in ("当前阶段", "当前增量", "方案引用", "实施计划引用", "测试计划引用"):
self.assertIn(field + ":", card)
self.assertIn("## 交付调度\n", card)
queue = card.split("## 交付调度\n", 1)[1].split("\n## ", 1)[0]
self.assertIn("调度状态:未入队", queue)
for field in ("调度记录", "entry_id", "attempt_id", "窗口执行者", "固定候选"):
self.assertIn(field + ":无", queue)
self.assertIn("## 关联方向与规划\n", card)
planning = card.split("## 关联方向与规划\n", 1)[1].split("\n## ", 1)[0]
for field in ("适用状态", "主记录路径/版本", "对应里程碑"):
+321
View File
@@ -0,0 +1,321 @@
"""Local recovery is task-scoped and cannot grant delivery readiness."""
import json
import unittest
import test_task as lifecycle
class TaskRecoveryTests(unittest.TestCase):
def setUp(self):
self.fixture = lifecycle.TaskLifecycleTests(methodName="runTest")
self.fixture.setUp()
self.addCleanup(self.fixture.doCleanups)
self.wt = self.fixture.worktree()
self.card = self.fixture.record_task_card(self.wt)
self.receipt_number = 0
def precheck(self, mode="local", cwd=None):
f = self.fixture
return f.task(cwd or self.wt, "precheck", check=False,
env=f.env | {"TASK_WORK_MODE": mode})
def capture(self, mode="local"):
f = self.fixture
self.receipt_number += 1
path = f.root / f"recovery-{self.receipt_number}.json"
result = f.run_cmd(self.wt, "bash", "scripts/evidence.sh", check=False,
env=f.env | {"TASK_WORK_MODE": mode, "RECEIPT": str(path),
"CMD": "make precheck"})
self.assertEqual(result.returncode, 0, result.stdout)
return path
def resume(self, receipt, mode="local", cwd=None):
f = self.fixture
return f.task(cwd or self.wt, "resume", check=False,
env=f.env | {"TASK_WORK_MODE": mode, "PRECHECK_RECEIPT": str(receipt)})
def save_card_change(self):
f = self.fixture
f.git(self.wt, "add", str(self.card.relative_to(self.wt)))
f.git(self.wt, "commit", "-m", "Update fixture registration")
def test_local_precheck_allows_known_lag_without_changing_head(self):
f = self.fixture
head = f.git(self.wt, "rev-parse", "HEAD").stdout
f.advance_remote()
strict = self.precheck(mode="delivery")
self.assertNotEqual(strict.returncode, 0)
self.assertIn("SYNC_REQUIRED", strict.stdout)
local = self.precheck()
self.assertEqual(local.returncode, 0, local.stdout)
self.assertIn("[verdict] LOCAL_READY", local.stdout)
self.assertNotIn("[verdict] READY", local.stdout)
self.assertEqual(f.git(self.wt, "rev-parse", "HEAD").stdout, head)
def test_local_precheck_never_advertises_delivery_even_when_current(self):
result = self.precheck()
self.assertEqual(result.returncode, 0, result.stdout)
self.assertIn("[verdict] LOCAL_READY", result.stdout)
self.assertNotIn("[verdict] READY", result.stdout)
def test_local_precheck_rejects_main_and_missing_registration(self):
result = self.precheck(cwd=self.fixture.repo)
self.assertNotEqual(result.returncode, 0, result.stdout)
self.card.unlink()
self.save_card_change()
result = self.precheck()
self.assertNotEqual(result.returncode, 0, result.stdout)
def test_local_precheck_rejects_foreign_registration(self):
self.card.write_text(self.card.read_text().replace(str(self.wt), str(self.fixture.repo)))
self.save_card_change()
result = self.precheck()
self.assertNotEqual(result.returncode, 0, result.stdout)
def test_local_precheck_rejects_wrong_branch_registration(self):
self.card.write_text(self.card.read_text().replace("分支:feature/test", "分支:feature/other"))
self.save_card_change()
self.assertNotEqual(self.precheck().returncode, 0)
def test_local_precheck_rejects_invalid_baseline(self):
f = self.fixture
r0 = f.git(self.wt, "rev-parse", "origin/main").stdout.strip()
self.card.write_text(self.card.read_text().replace(r0, "0" * 40))
self.save_card_change()
self.assertNotEqual(self.precheck().returncode, 0)
def test_local_precheck_rejects_dirty_state_and_unknown_remote(self):
f = self.fixture
(self.wt / "tracked").write_text("preserve current edit\n")
result = self.precheck()
self.assertNotEqual(result.returncode, 0)
self.assertIn("SHARED_WORKSPACE_BUSY", result.stdout)
f.git(self.wt, "commit", "-am", "Save owner edit")
f.git(self.wt, "remote", "set-url", "origin", str(f.root / "missing.git"))
result = self.precheck()
self.assertNotEqual(result.returncode, 0)
self.assertIn("REMOTE_UNVERIFIED", result.stdout)
def test_unknown_work_mode_is_rejected(self):
result = self.precheck(mode="anything")
self.assertNotEqual(result.returncode, 0, result.stdout)
def test_local_resume_imports_original_receipt_without_sync(self):
f = self.fixture
receipt = self.capture()
original = receipt.read_bytes()
head = f.git(self.wt, "rev-parse", "HEAD").stdout
f.advance_remote()
result = self.resume(receipt)
self.assertEqual(result.returncode, 0, result.stdout)
self.assertIn("[resumed]", result.stdout)
self.assertEqual(f.git(self.wt, "rev-parse", "HEAD").stdout, head)
self.assertEqual(receipt.read_bytes(), original)
self.assertIn(json.loads(original)["receipt_sha256"], self.card.read_text())
current = f.git(self.wt, "rev-parse", "origin/main").stdout.strip()
self.assertNotEqual(json.loads(original)["after"]["target_head"], current)
def assert_history_change_rejected(self, receipt):
f = self.fixture
before = self.card.read_bytes()
original = receipt.read_bytes()
head = f.git(self.wt, "rev-parse", "HEAD").stdout
result = self.resume(receipt)
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertIn("Precheck target history has rewound or diverged", result.stdout)
self.assertNotIn("[resumed]", result.stdout)
self.assertEqual(self.card.read_bytes(), before)
self.assertEqual(receipt.read_bytes(), original)
self.assertEqual(f.git(self.wt, "rev-parse", "HEAD").stdout, head)
def test_local_resume_rejects_target_rewind_before_import(self):
f = self.fixture
r0 = f.git(self.wt, "rev-parse", "origin/main").stdout.strip()
f.advance_remote()
receipt = self.capture()
observed = json.loads(receipt.read_text())["after"]["target_head"]
self.assertNotEqual(observed, r0)
# Only this test's disposable bare remote is rewritten.
f.git(f.remote, "update-ref", "refs/heads/main", r0, observed)
# Reproduce recovery after another client operation refreshed the target.
f.git(self.wt, "fetch", "origin", "+refs/heads/main:refs/remotes/origin/main")
self.assert_history_change_rejected(receipt)
def test_local_resume_rejects_divergent_target_before_import(self):
f = self.fixture
r0 = f.git(self.wt, "rev-parse", "origin/main").stdout.strip()
f.advance_remote()
receipt = self.capture()
observed = json.loads(receipt.read_text())["after"]["target_head"]
f.git(f.repo, "switch", "--detach", r0)
(f.repo / "divergent-main").write_text("different target history\n")
f.git(f.repo, "add", "divergent-main")
f.git(f.repo, "commit", "-m", "Create divergent fixture history")
divergent = f.git(f.repo, "rev-parse", "HEAD").stdout.strip()
f.git(f.repo, "push", "origin", "HEAD:refs/heads/divergent")
self.assertEqual(f.git(f.repo, "merge-base", "--is-ancestor", observed,
divergent, check=False).returncode, 1)
# Both targets retain R0; only normal ancestry may permit recovery.
f.git(f.remote, "update-ref", "refs/heads/main", divergent, observed)
f.git(self.wt, "fetch", "origin", "+refs/heads/main:refs/remotes/origin/main")
self.assert_history_change_rejected(receipt)
def test_make_resume_exports_the_selected_mode_and_receipt(self):
f = self.fixture
receipt = self.capture()
result = f.run_cmd(self.wt, "make", "-f", str(lifecycle.SOURCE / "Makefile"),
"task-resume", check=False,
env=f.env | {"TASK_WORK_MODE": "local", "PRECHECK_RECEIPT": str(receipt)})
self.assertEqual(result.returncode, 0, result.stdout)
self.assertIn("[resumed]", result.stdout)
def test_local_receipt_cannot_start_a_task_or_resume_for_delivery(self):
f = self.fixture
receipt = self.capture()
before = self.card.read_bytes()
delivery = self.resume(receipt, mode="delivery")
self.assertNotEqual(delivery.returncode, 0, delivery.stdout)
self.assertEqual(self.card.read_bytes(), before)
start = f.task(self.wt, "start", "feature/bypass", check=False,
env=f.env | {"PRECHECK_RECEIPT": str(receipt), "TASK_WORK_MODE": "local",
"VALIDATE_RECEIPT_PURPOSE": "resume-local"})
self.assertNotEqual(start.returncode, 0, start.stdout)
self.assertFalse((f.root / "repo-wt-feature-bypass").exists())
def test_strict_resume_rejects_target_advance(self):
f = self.fixture
receipt = self.capture(mode="delivery")
head = f.git(self.wt, "rev-parse", "HEAD").stdout
f.advance_remote()
rejected = self.resume(receipt, mode="delivery")
self.assertNotEqual(rejected.returncode, 0)
self.assertNotIn("[resumed]", rejected.stdout)
self.assertEqual(f.git(self.wt, "rev-parse", "HEAD").stdout, head)
def test_strict_resume_imports_current_ready_receipt(self):
receipt = self.capture(mode="delivery")
result = self.resume(receipt, mode="delivery")
self.assertEqual(result.returncode, 0, result.stdout)
def test_resume_rejects_changed_source_head(self):
receipt = self.capture()
f = self.fixture
(self.wt / "tracked").write_text("new task revision\n")
f.git(self.wt, "commit", "-am", "Change source after precheck")
before = self.card.read_bytes()
result = self.resume(receipt)
self.assertNotEqual(result.returncode, 0)
self.assertEqual(self.card.read_bytes(), before)
def test_resume_rejects_another_worktree_with_same_head(self):
f = self.fixture
other = f.root / "other-worktree"
r0 = f.git(self.wt, "rev-parse", "origin/main").stdout.strip()
other_card = self.wt / ".task/feature-other.md"
other_card.write_text(
"# Other task\n任务主记录:fixture;状态:进行中;owner:Lifecycle Test\n"
f"- 权威仓:fixture;目标分支:main;R0(initial_base_sha)= {r0}\n"
f"- 工作区:{other}(worktree);分支:feature/other\n")
f.git(self.wt, "add", ".task/feature-other.md")
f.git(self.wt, "commit", "-m", "Register second fixture task")
f.git(f.repo, "worktree", "add", "-b", "feature/other", str(other), "HEAD")
# The main checkout has an older HEAD; align this owned fixture branch to the task HEAD.
f.git(other, "merge", "--ff-only", "feature/test")
receipt = self.capture(mode="delivery")
self.assertEqual(f.git(other, "rev-parse", "HEAD").stdout,
f.git(self.wt, "rev-parse", "HEAD").stdout)
result = self.resume(receipt, mode="delivery", cwd=other)
self.assertNotEqual(result.returncode, 0)
def test_unknown_validation_purpose_is_rejected(self):
receipt = self.capture(mode="delivery")
f = self.fixture
result = f.run_cmd(self.wt, "bash", "scripts/evidence.sh", check=False,
env=f.env | {"VALIDATE_RECEIPT": str(receipt),
"VALIDATE_RECEIPT_PURPOSE": "ignore"})
self.assertNotEqual(result.returncode, 0, result.stdout)
class WorkspaceRecoveryTests(unittest.TestCase):
"""New-format recovery keeps its branch and fixes startup rule availability."""
def setUp(self):
import test_workspace_cutover as cutover
self.fixture = cutover.WorkspaceCutoverTests(methodName="runTest")
self.fixture.setUp()
self.addCleanup(self.fixture.doCleanups)
f = self.fixture
f.adopt()
self.wt = f.worktree()
r0 = f.git(self.wt, "rev-parse", "origin/main").stdout.strip()
self.card = self.wt / ".task/feature-old.md"
self.card.parent.mkdir()
self.card.write_text("# Recovery\n任务主记录:fixture;状态:进行中;owner:Cutover Test\n"
f"- 权威仓:fixture;目标分支:main;R0(initial_base_sha)= {r0}\n"
f"- 工作区:{self.wt}(worktree);分支:feature/old\n")
f.git(self.wt, "add", ".task")
f.git(self.wt, "commit", "-m", "Register current task")
self.env = f.env | {"TASK_WORK_MODE": "local"}
def precheck(self):
return self.fixture.task(self.wt, "precheck", env=self.env, check=False)
def test_local_recovery_verifies_fixed_rules_without_sync_or_application_materialization(self):
f = self.fixture
head = f.git(self.wt, "rev-parse", "HEAD").stdout
(f.repo / "new-main").write_text("main advanced\n")
f.git(f.repo, "add", "new-main")
f.git(f.repo, "commit", "-m", "Advance main")
f.git(f.repo, "push", "origin", "main")
result = self.precheck()
self.assertEqual(result.returncode, 0, result.stdout)
self.assertIn("[verdict] LOCAL_READY", result.stdout)
self.assertIn("[rules]", result.stdout)
self.assertNotIn("[verdict] READY", result.stdout)
self.assertEqual(f.git(self.wt, "rev-parse", "HEAD").stdout, head)
self.assertFalse((self.wt / ".workspace").exists())
def test_local_recovery_refuses_missing_fixed_rules_before_readiness(self):
f = self.fixture
lock = self.wt / "components.lock.json"
record = json.loads(lock.read_text())
record["components"]["Rules"]["commit"] = "0" * 40
lock.write_text(json.dumps(record))
f.git(self.wt, "commit", "-am", "Pin unavailable rules")
before = self.card.read_bytes()
result = self.precheck()
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertNotIn("[verdict] LOCAL_READY", result.stdout)
self.assertEqual(self.card.read_bytes(), before)
self.assertFalse((self.wt / ".workspace").exists())
def test_resume_rechecks_fixed_rules_before_importing_receipt(self):
f = self.fixture
receipt = f.base / "resume.json"
f.call(self.wt, "bash", "scripts/evidence.sh", env=self.env | {"RECEIPT": str(receipt), "CMD": "make precheck"})
# The cache is not an application overlay; a changed rule source cannot
# turn a formerly valid local precheck into current startup authority.
rules = list((f.base / "cache").rglob("core/baseline.md"))
self.assertTrue(rules, "fixed startup rules were never prepared")
rules[0].write_text("owner changed rules\n")
before = self.card.read_bytes()
result = f.task(self.wt, "resume", env=self.env | {"PRECHECK_RECEIPT": str(receipt)}, check=False)
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertNotIn("[resumed]", result.stdout)
self.assertEqual(self.card.read_bytes(), before)
self.assertEqual(rules[0].read_text(), "owner changed rules\n")
def test_local_resume_preserves_registered_edit_branch_and_unsaved_component(self):
f = self.fixture
f.workspace(self.wt, "edit", "--name", "App", "--branch", "feature/component-owner")
child = self.wt / ".workspace/App"
(child / "content").write_text("preserve author edit\n")
receipt = f.base / "resume-edit.json"
f.call(self.wt, "bash", "scripts/evidence.sh", env=self.env | {"RECEIPT": str(receipt), "CMD": "make precheck"})
result = f.task(self.wt, "resume", env=self.env | {"PRECHECK_RECEIPT": str(receipt)})
self.assertIn("[resumed]", result.stdout)
self.assertEqual((child / "content").read_text(), "preserve author edit\n")
self.assertEqual(f.git(child, "branch", "--show-current").stdout.strip(), "feature/component-owner")
if __name__ == "__main__":
unittest.main()