From 77bdbdbc744ce641d7150573cb19372c076eb042 Mon Sep 17 00:00:00 2001 From: WeiCHEN Date: Wed, 23 Sep 2026 17:35:25 +0800 Subject: [PATCH] feat(ops): add stable record_id column to FEATURE-MATRIX Make matrix_states / docs apply / evidence gates key by kebab-case record_id (module name as transitional fallback). Wire docs project for MATRIX with EVIDENCE_REQUIRED on done. Keep all status values and historical paragraphs unchanged; reject rename/duplicate IDs. --- .doc/ops/CURRENT.md | 7 +- .../short-term/2026-09-23-matrix-record-id.md | 57 +++++++ ...-daemon-implementation-undertaking-plan.md | 9 + .doc/status/FEATURE-MATRIX.md | 58 +++---- configs/agent-governance.json | 2 +- scripts/agentctl.py | 84 ++++++++-- scripts/tests/test_agentctl.py | 155 +++++++++++++++++- 7 files changed, 323 insertions(+), 49 deletions(-) create mode 100644 .doc/ops/short-term/2026-09-23-matrix-record-id.md diff --git a/.doc/ops/CURRENT.md b/.doc/ops/CURRENT.md index 57a837e1..e30d891d 100644 --- a/.doc/ops/CURRENT.md +++ b/.doc/ops/CURRENT.md @@ -18,10 +18,11 @@ | owner | task | branch | worktree | mutex | status | |---|---|---|---|---|---| +| Cursor | matrix-record-id-2026-09-23 | feature/matrix-record-id-2026-09-23 | .worktrees/matrix-record-id-2026-09-23 | matrix-record-id | in_progress | | Cursor | w2-closeout-2026-09-23 | feature/w2-closeout-2026-09-23 | .worktrees/w2-closeout-2026-09-23 | w2-closeout | done | -| Cursor | current-projection-2026-09-23 | feature/current-projection-2026-09-23 | .worktrees/current-projection-2026-09-23 | current-projection | in_progress | -| Cursor | agentctl-daemon-2026-09-23 | feature/agentctl-daemon-2026-09-23 | .worktrees/agentctl-daemon-2026-09-23 | agentctl-daemon | in_progress | -| Cursor | agentctl-handoff-2026-09-23 | feature/agentctl-handoff-2026-09-23 | .worktrees/agentctl-handoff-2026-09-23 | agentctl-handoff | in_progress | +| Cursor | current-projection-2026-09-23 | feature/current-projection-2026-09-23 | .worktrees/current-projection-2026-09-23 | current-projection | done | +| Cursor | agentctl-daemon-2026-09-23 | feature/agentctl-daemon-2026-09-23 | .worktrees/agentctl-daemon-2026-09-23 | agentctl-daemon | done | +| Cursor | agentctl-handoff-2026-09-23 | feature/agentctl-handoff-2026-09-23 | .worktrees/agentctl-handoff-2026-09-23 | agentctl-handoff | done | | Cursor | agentctl-claim-2026-09-23 | feature/agentctl-claim-2026-09-23 | .worktrees/agentctl-claim-2026-09-23 | agentctl-claim | done | | Cursor | agent-governance-config-2026-09-23 | feature/agent-governance-config-2026-09-23 | .worktrees/agent-governance-config-2026-09-23 | agent-governance-config | done | | Cursor | coordination-db-daemon-impl-plan-2026-09-23 | feature/coordination-db-daemon-impl-plan-2026-09-23 | .worktrees/coordination-db-daemon-impl-plan-2026-09-23 | coordination-db-daemon-impl-plan | done | diff --git a/.doc/ops/short-term/2026-09-23-matrix-record-id.md b/.doc/ops/short-term/2026-09-23-matrix-record-id.md new file mode 100644 index 00000000..9cee73c4 --- /dev/null +++ b/.doc/ops/short-term/2026-09-23-matrix-record-id.md @@ -0,0 +1,57 @@ +--- +title: "W3-U6:FEATURE-MATRIX 稳定 record_id" +task_id: matrix-record-id-2026-09-23 +status: in_progress +created: 2026-09-23 +updated: 2026-09-23 +owner: Cursor +task_type: implementation +task_tier: single +policy_revision: "agent-governance-2026-09-21-r1 @ 713b7cbe6ffc066323f7e8d2d783bf3aaffb5c81" +branch: feature/matrix-record-id-2026-09-23 +worktree: .worktrees/matrix-record-id-2026-09-23 +base_dev_sha: "713b7cbe6ffc066323f7e8d2d783bf3aaffb5c81" +write_scope: ["scripts", "configs", ".doc"] +allowed_environments: [] +mutex: matrix-record-id +review_state: pending +integration_state: pending +deployment: not_required +cleanup: pending +cleanup_owner: "独立维护者" +cleanup_trigger: "合入 local_dev 且无进程占用后复查" +remote_sync: not_requested +--- + +# W3-U6:FEATURE-MATRIX 稳定 record_id + +## 用户目标与授权 + +- 用户目标:完成度矩阵增加稳定 kebab-case `record_id` 列;`matrix_states` / docs apply 以该 ID 为键;无证据不得升 `done`;任务 close 不自动升 MATRIX。 +- 授权:W3-U6 实施;不 push;不集成(由父代理合入);不改各行状态值;不改设计方案全文。 +- 禁止:扩大业务写环境;触碰 `production_ready` / gap-matrix 发布判定。 + +## 范围 + +- `.doc/status/FEATURE-MATRIX.md`:完成度表 header + 27 行首列 `record_id` +- `scripts/agentctl.py`:`matrix_states`、FEATURE-MATRIX header、replacement 首列校验、投影错误提示 +- `configs/agent-governance.json`:DOC_RULES header +- unittest:无证据升 done、lineage 保留、close 不升 done、重复/改名拒绝 + +## 验收 + +1. 无证据升 `done`(行更新与 `@document`)→ `EVIDENCE_REQUIRED` +2. 未知列 / Wave 0 等尾部段落在 `@document` 编辑后保留 +3. `task close` 不改变 MATRIX 行状态 +4. 重复 `record_id` / 改名 / 缺 ID → `INVALID_DOCUMENT` 或 `INVALID_REQUEST` +5. `unittest discover` 全绿;`production_ready` 未改 + +## 收口 + +| 字段 | 值 | +|---|---| +| review_state | pending | +| integration_state | pending | +| deployment | not_required | +| cleanup | pending | +| remote_sync | not_requested | diff --git a/.doc/remediation/2026-09-23-coordination-db-daemon-implementation-undertaking-plan.md b/.doc/remediation/2026-09-23-coordination-db-daemon-implementation-undertaking-plan.md index d7acb0ac..30006d97 100644 --- a/.doc/remediation/2026-09-23-coordination-db-daemon-implementation-undertaking-plan.md +++ b/.doc/remediation/2026-09-23-coordination-db-daemon-implementation-undertaking-plan.md @@ -126,6 +126,15 @@ flowchart LR | **W2-U5** | W2 | CURRENT 状态输出化 | `incremental`(`docs_project` 已有) | `scripts/agentctl.py:1308` `docs_project`;行模板约 `:1358-1362`;槽位保护 `:903-908`;`.doc/ops/CURRENT.md`;`.doc/ops/2026-09-21-agent-worktree-workflow.md:3` | **W1-U3 done**;**W2-U4** 建议先合入(投影调度) | `current-projection` | `scripts`, `.doc` | (1) 双任务并行投影不丢行;(2) 同行 CAS → `BASE_CHANGED`;(3) 槽位保护不回退;(4) 人工「焦点/受控约束」区块机器不写;(5) 修正 CURRENT `:5`/`:15` 与操作规范「Linux 本机」过时描述 | revert 投影代码+文档;保留人工段落 | | **W3-U6** | W3 | FEATURE-MATRIX 稳定 ID | `incremental` | `.doc/status/FEATURE-MATRIX.md` 完成度表约 `:52-78`(27 行);`docs apply` done 门禁 `:922-928` | **W2-U5 done** | `matrix-record-id` | `scripts`, `.doc` | (1) 无证据升 `done` 被拒;(2) 未知列/历史段落保留;(3) 整文 rewrite 不能夹带 done;(4) 任务 close ≠ 自动升 done;(5) `production_ready` 仍只由发布门禁判定 | revert;记录 ID 映射表保留在 Git 便于回滚对照 | +### 4.2.1 落地 tip 回填(2026-09-23) + +| wp_id | merged tip(local_dev) | 判定 | +|---|---|---| +| **W2-U7** | `981021b2` | done | +| **W2-U4** | `725e2e4b` | done | +| **W2-U5** | `c780a030` | done | +| **W3-U6** | feature/matrix-record-id-2026-09-23(base `713b7cbe`;合入前) | in_progress | + ### 4.3 判定列(开工前填) 每包 short-term 增加列:`判定` = `planned | in_progress | blocked | done | cancelled`。本承接计划合入时全部为 **planned**。 diff --git a/.doc/status/FEATURE-MATRIX.md b/.doc/status/FEATURE-MATRIX.md index 5895600e..61719aa7 100644 --- a/.doc/status/FEATURE-MATRIX.md +++ b/.doc/status/FEATURE-MATRIX.md @@ -47,35 +47,35 @@ ## 完成度矩阵 -| 模块 | 声明范围 | 状态 | 发布关系 | 证据 | 剩余工作 / 关闭条件 | mutex | -|------|----------|------|----------|------|---------------------|-------| -| Agent worktree 治理自动化 | 主目录保护、任务 worktree、机器认领、候选集成、dev 部署与安全清理 | partial | non_blocker | [方案](../remediation/2026-09-21-agent-workflow-governance-plan.md);[L1 验收](../test-reports/2026-09-21-agent-governance-test-report.md);[W1-B macOS](../ops/short-term/2026-09-22-agentctl-macos.md);[W4](../ops/short-term/2026-09-22-governance-automation.md);residual `modular-decouple-residual-2026-09-23` | L1 与 macOS `with/docs apply/validate/integrate` 已合入。W4 landed:durable queue + 完整 docs projection apply(行/整文 CAS)+ deploy/recover 真实收据闭环 + Darwin cwd 可见性测试。仍 deferred:PI 源码镜像 compose、跨机隔离、automation/w4 实现收敛。本行不升 done | `agent-workflow-governance` | -| 意图识别 L1 | 18 类 Intent、三分支消解、写/只读分流、双标签 `DOC_BUSY`、intent 纯依赖边界 | done | non_blocker | [intent-recognition](../system-design/intent-recognition/);[工作流作用域](../test-reports/2026-09-21-intent-workflow-scoping-test-report.md);[审计](../audit/2026-09-13-conversation-intent-runtime-state.md);[报告](../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md);[双标签](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/live.json);[U1](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)–[U3](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) | **边界 before**:含 U9–U12 叙事混入 → **after**:U9–U12 迁至「多意图扩面」行。关闭:纯依赖边界回归即重开 | `intent` | -| 多意图持久计划(U1–U8 基线) | app/intentflow 生命周期、HITL、默认 `legacy`、U1–U8 代码与安全基线 | partial | non_blocker(默认 legacy) | [设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[U1](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)–[U8](../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md);[Wave2 真 PI](../test-reports/2026-09-16-wave2-real-pi-evidence-test-report.md);[Track I1](../test-reports/2026-09-22-track-i1-query-owner-test-report.md) | **after Track I1**:生产组合根已去 Fake query owner,改真实 QueryOwner;receipt 含 auth scope digest;confirm 后走既有步骤内核 dispatcher。默认仍 `MULTI_INTENT_PLAN_TIER=legacy`。升 `auto_read/confirm` 需 Track I2(项目 allowlist + 频率门)。U9–U12 仍独立 dry-run | `intent-plan` | -| 多意图扩面(U9–U12) | U9 LLM 分段实验;U10 mutate;U11 docgov;U12 workflow/run-control | partial | deferred_enhancement | [设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[脚手架](../test-reports/2026-09-16-pu8-u9-u12-flags-test-report.md);[U9](../test-reports/2026-09-17-w4-u9-segment-test-report.md);[U10](../test-reports/2026-09-17-w4-u10-mutate-test-report.md);[U11](../test-reports/2026-09-17-w4-u11-docgov-test-report.md);[U12](../test-reports/2026-09-17-w4-u12-run-control-test-report.md);[2026-09-20 复核](../ops/research/2026-09-20-capability-enablement-impact-research.md) | U9 proposer 已实现和注入但未进入生产聊天分段调用;提议请求已带 reasoning profile。U10–U12 当前为 dry-run/validated-only adapter。历史直接调用/PI 测试继续有效,不代表 live 接线。逐域实现和验收,禁止以 `full` 一次放量 | `intent-plan` | -| 对话 / ctxmgr baseline | 多轮上下文、刷新/重登/重启恢复、授权同集正文与计数、U10 端口化停止扩面 | done | non_blocker | [multi-turn](../system-design/multi-turn-dialogue/);[刷新审计](../audit/2026-09-13-chat-history-refresh-disappears.md);[U10](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md);[门禁 B3](../test-reports/2026-09-16-chat-refresh-gate-test-report.md)(项目 6359) | **before**:语义摘要误标 D5 混入 → **after**:摘要迁「语义摘要 D3」;D7 数据治理独立。U10 停止扩面 | `chat` | -| 语义摘要(D3) | 授权后可见集合上的语义摘要;shadow → 可选替换 deterministic | partial | deferred_enhancement | [chat-agent-p6-backlog](../backlog/chat-agent-p6-backlog.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[pu6](../ops/long-term/2026-09-16-pu6-semantic-summary-contract.md);[脚手架](../test-reports/2026-09-16-pu6-semantic-summary-test-report.md);[W2 真 PI](../test-reports/2026-09-17-w2-semantic-summary-shadow-test-report.md);[Track S1](../ops/short-term/2026-09-22-track-s1-summary-consolidation.md) | **after Track S1**:durable `chat_summary_shadow_jobs` + 后台租约/watermark/provenance 已合入;served Narrative 保持确定性。shadow 默认 off;`SEMANTIC_SUMMARY_REPLACE` **未接线**。**2026-09-23 实测** DOCREV 路径 schema **63**。授权可见集 digest 已进 shadow 路径。本行不升 done | `chat` | -| 对话数据治理(D7) | 留存/删除口径、库·备份·日志控制、敏感字段加密边界 | deferred | deferred_enhancement(违规则升 blocker) | [计划](../remediation/2026-09-16-feature-matrix-production-readiness-plan.md) Scope Boundaries;[D7 ADR 草案](../adr/2026-09-17-d7-chat-data-retention.md);[W7 盘点](../audit/2026-09-17-d7-data-inventory.md);[红线证据](../test-reports/2026-09-22-redline-evidence-d7-test-report.md) | 只读盘点 + Track E ID-only 符合性已补。口径仍 `pending-compliance-signoff`;**禁止物理删除**。本行不升 done | `chat` | -| 智能体小队 | 角色-任务-工作区-黑板 | done | non_blocker | [agent-squad](../system-design/agent-squad/);[test 2026-09-07](../test-reports/2026-09-07-dynamic-squad-planning-test-report.md) | 非关键步骤降级(A5/A6)属 backlog | `squad` | -| 工作流治理 | 三正式工作流、设置页/DutyMode、动作级鉴权、真实 PI 三工作流 E2E、full/none 混合长链 | done | non_blocker | [三工作流整改](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[409/职责](../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md);[鉴权](../test-reports/2026-09-14-governance-action-level-authz-test-report.md);[PI E2E](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md);[Wave2 full/none](../test-reports/2026-09-16-wave2-real-pi-evidence-test-report.md) | full 跨用户审批 + none 免审批不阻塞已签。纯软件自举仍独立 planned | `workflow` | -| 研发设计控制(rdev) | 医疗第 4 工作流:13×60 manifest/模板、`squad.rdev_doc.v1` kind 编排、main-completed 硬 precheck、StageKey 动态化;不含前端/真 PI/键名空间化 | partial | deferred_enhancement | [设计](../system-design/project-workflow/07-研发工作流rdev接入-设计与实施计划.md);[收口](../ops/short-term/2026-09-22-rdev-closeout.md);[报告](../test-reports/2026-09-22-rdev-closeout-test-report.md);[P3 历史](../test-reports/2026-09-19-rdev-p3-real-pi-test-report.md) | **after 2026-09-22 收口**:`rd_proposal` 标题门禁 + 法规表首表截止 dry PASS;nightly 脚本已扩四工作流(FullChain×3+FullNone)。P3 真 PI 三样本重跑因缺 `env:dev` **blocked**(不以 stub 冒充)。剩余:获环境后重跑 P3。本行保持 partial | `workflow-def` / `rdev-templates` | -| 纯软件项目自举 | 软件项目创建、Bootstrap、Delivery、受控工程交接 | partial | deferred_enhancement(明确不挡首发) | [设计](../system-design/2026-09-14-software-project-bootstrap-workflow.md);[ADR](../adr/2026-09-16-software-project-bootstrap-keys.md);[L1 报告](../test-reports/2026-09-16-software-project-bootstrap-test-report.md);[W5a](../test-reports/2026-09-17-w5a-software-bootstrap-ui-pi-test-report.md);[红线证据](../test-reports/2026-09-22-redline-evidence-swboot-test-report.md) | **after W5a + 红线证据**:catalog 驱动创建、软件不挂医疗 key。**SWBOOT-10 仍 stub**(L1–L4 证据已补;L5/L6 待授权)。本行不升 done | `workflow-design` | -| IAM / 鉴权 | 项目级 API 鉴权 + RBAC;会话/阶段授权 | done | 加固 | [v3 full inventory](../audit/authorization-matrix-v3-full.md);[session 中断](../test-reports/2026-09-16-iam-route-inventory-test-report.md);[fail-closed](../test-reports/2026-09-16-wave1-iam-fail-closed-test-report.md);[410 策略](../audit/2026-09-16-bug11-410-retire-decision.md);[R13](../audit/2026-09-16-r13-data-safety-checklist.md) | 全路由 inventory + session 中断负例 + 410 冻结 + R13 基线已签 | `authz` | -| 文档治理 | 法定文档生命周期 + 租约 + 受控正文读取 | done | non_blocker | [docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md);[正文 UI](../test-reports/2026-09-14-controlled-content-ui-acceptance.md);[canonical hash](../remediation/2026-09-14-controlled-content-canonical-hash-remediation.md);[键统一](../test-reports/2026-09-21-workflow-doc-key-unification-test-report.md) | 项目 143 只读;不终止。`doc_proj*` 同一发布键不能再并存 | `docgov` | -| 文档版本 baseline | 账本、人工修订、确定性 diff+lineage、运行时 UI、负责人通知 | done | non_blocker | [管理](../test-reports/2026-09-13-document-revision-management-test-report.md);[Round20 UI](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[ADR](../adr/2026-09-13-document-version-boundary.md);[proposed/authoritative](../ops/short-term/2026-09-20-proposed-authoritative-reports.md) | **before**:完整 PI narrative 混入 → **after**:迁「PI change-report 叙事」。fallback 报告是本行内显式行为,不是缺口。lineage GET 已按 URL 项目和文档可见性裁剪。test_manager 血缘的下游/上游版本改读文档版本,不再写死 1。Agent 候选报告为 `proposed`,正式提交才写 authoritative 后继并挂到版本;拒绝、替代后旧报告不能再出建议。人工修订、导入和聊天卡仍未分开预估与正式报告,见 [T1](../ops/short-term/2026-09-20-impact-loop-t1.md)。项目追踪索引见下一行 | `docgov` | -| 阶段回溯与影响闭环 | 五表追踪索引、影响报告、L1 文档修订、L2 阶段再打开、待复核软标记、对话修订提案 | done | deferred_enhancement(不挡首发) | [设计](../system-design/2026-09-20-stage-backtrack-and-impact-loop-design.md);[Track T](../remediation/2026-09-20-capability-enablement-impact-plan.md);[对话化报告](../test-reports/2026-09-21-trace-panel-to-chat-test-report.md);[T 补强](../ops/short-term/2026-09-22-track-t-strengthen.md) | 已合入 dev。常驻「需求与影响」面板已退役。**2026-09-23 实测** DOCREV 路径 schema **63**;test=`rc-v1.1.0-beta.1` schema 61;main 本轮未晋升。阶段推进确认门禁仍在。不签 D7 对话 ADR | `trace-index` | -| PI change-report 叙事 | 只读消费 diff+lineage 的 PI 叙事;失败全量降级 fallback | partial | deferred_enhancement | [Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[pu7](../ops/long-term/2026-09-16-pu7-pi-narrative-contract.md);[W3 真 PI](../test-reports/2026-09-17-w3-pi-change-report-narrative-test-report.md);[红线负例](../test-reports/2026-09-22-redline-evidence-pi-narrative-test-report.md) | flag 默认 **off**(红线不放量)。fallback 全量负例单测已补。pi-agent reasoning 路径已带 `--no-tools`。不打开开关 | `docgov` | -| 前端工作台 | 三栏 + 块文档 + SSE;错误卡/`TaskRunCard` 竖向进度/busy;版本冲突信封;demo seed 默认关;终止 preview | done | non_blocker | [workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[双标签](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/screenshots/tab-b-busy.png);[demo](../test-reports/2026-09-16-demo-seed-pollution-test-report.md);[B4](../test-reports/2026-09-16-frontend-gate-b4-test-report.md)(项目 6363);[TaskRunCard](../test-reports/2026-09-21-taskrun-status-card-persistence-test-report.md) | **before**:空「缺口」却 partial → **after**:本行 done。其他 409 消费方信封复用另列 hardening backlog | `web` | -| PI Runner / 配置链 | pi-agent + MiniMax + typed-result-v1 | done | non_blocker | [piagent](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md);[container-env](../test-reports/2026-09-13-container-env-configuration-test-report.md);[typed-result](../test-reports/2026-09-15-pi-typed-result-v1-test-report.md) | 文档生成仍使用读写和搜索工具。`tool_profile=reasoning` argv 为 `--no-tools`。**2026-09-22 实测** pi-agent 已 bind-mount `pi-args.mjs` | `pi-agent` | -| 三环境运维 | dev/test/main + 共享 KB;对话/业务库隔离 | done | non_blocker | [PROJECT.md](../../PROJECT.md) §4;[晋升报告](../test-reports/2026-09-22-dev-gate-and-test-promotion-test-report.md);[DOCREV](../test-reports/2026-09-22-docrev-ui-rerun-test-report.md) | **2026-09-23 实测**:本地/共享 dev DOCREV 路径 schema **63**;test health schema **61**(`rc-v1.1.0-beta.1`);main 本轮未晋升 | `infra` | -| CI / E2E | PR CI、PG 集成、治理 PG、已签真实 PI 门禁;**nightly** schedule/`workflow_dispatch` + infra/product 分类 receipt | done | 加固(阻止**下一次**晋升,不自动否定已发布) | [BUG-08](../test-reports/2026-09-16-ci-governance-pg-bug08-test-report.md);[PI 三工作流](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md);[Wave2B](../test-reports/2026-09-16-wave2b-nightly-promotion-receipt-test-report.md);[Wave2C](../test-reports/2026-09-16-wave2c-same-image-digest-test-report.md);[W1 green](../test-reports/2026-09-17-w1-ci-e2e-green-nightly-test-report.md) + [receipt `6e2476f0…`](../assets/promotion-receipts/6e2476f0f2e408e111fe06ca7c31a38294a340b3.json) | **before**:partial(FullNone product_fail / secrets 文案过时)→ **after**:secrets 已配;duplicate goose 00048 已清;FullNone+U8 nightly `verdict=pass` | `ci` | -| Artifact 同 digest 晋升 | 候选 commit 一次构建、按 digest 晋升、promotion receipt | done | 加固 | [计划 PU5B](../remediation/2026-09-16-feature-matrix-production-readiness-plan.md);[Wave2B](../test-reports/2026-09-16-wave2b-nightly-promotion-receipt-test-report.md);[Wave2C](../test-reports/2026-09-16-wave2c-same-image-digest-test-report.md) | **关闭**:same-image pin(`candidate-images-*` + `PINNED_IMAGE_MODE` + promote `--require-digests`)。**声明**:单机 retag/digest pin;远程 registry 推送另立任务 | `infra` | -| 可靠事件核心 | PG dispatcher、notify/advance/projection live、生产闭包 hook 退出、Phase2 选择性解耦已合入 | done | non_blocker | [E0A–E2](../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md) 等;[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[shared live](../test-reports/2026-09-15-event-notify-shared-live-test-report.md);[phase2 closeout](../test-reports/2026-09-15-phase2-closeout-test-report.md) | **before**:与 FAV off 混成 partial → **after**:FAV 独立行。选择性后续解耦按收益触发 | `architecture-docs` / `events` | -| 模块开发规范 | 窄端口、领域事件、wire DTO 三种契约;故障隔离红线;新增模块/表/事件流程。不含批次 A–G 的代码整改 | done | non_blocker | [规范](../system-design/2026-09-20-module-development-standards.md);[审计](../audit/2026-09-20-module-coupling-audit.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md) | 文档入口已立。代码整改不在本行 | `module-decoupling-spec` | -| 模块解耦批次 A–G | server 端口装配、chat 解环、docgov 词汇、工作流单向依赖、巨型文件、前端 api client、21 条例外清零 | done | non_blocker | [分批计划](../remediation/2026-09-20-module-decoupling-batch-plan.md);[审计](../audit/2026-09-20-module-coupling-audit.md);[A](../ops/short-term/2026-09-22-server-assembly-cleanup.md);[B](../ops/short-term/2026-09-22-chat-app-decouple.md);[C](../ops/short-term/2026-09-22-docgov-vocabulary-convergence.md);[D](../ops/short-term/2026-09-22-workflow-def-unidirect.md);[E](../ops/short-term/2026-09-22-engine-split.md);[F](../ops/short-term/2026-09-22-web-api-client.md);[G1](../ops/short-term/2026-09-22-g1-exception-clearance.md);[G2/G3](../ops/short-term/2026-09-22-g2-g3-exception-clearance.md) | **after 2026-09-22**:A–F 与 E 已合入;G1/G2/G3 例外清零后 `arch-check --mode block` PASS 且 baseline import/sql_write/path/event **全 0**。关闭本伞行 | `module-decoupling-spec` | -| Final Artifact Vault(FAV) | 不可变终态制品库;`FAV_DEGRADED_READ=false` | partial | deferred_enhancement | [Track E 复盘](../ops/research/2026-09-15-track-e-retrospective.md);[U7 报告](../test-reports/2026-09-16-fav-u7-incremental-test-report.md);[W6 shadow](../test-reports/2026-09-17-w6-fav-subscriber-shadow-test-report.md);[红线证据](../test-reports/2026-09-22-redline-evidence-fav-test-report.md) | subscriber shadow 只计算 intended outcome。**live 未放量**;观察窗起点已登记。`FAV_DEGRADED_READ` 默认 false;禁止整支 merge | `events` | -| 系统管理台 | 全屏系统级管理视图(总览/KB/特性开关/系统设置/工作流/角色/用户/文档 8 分组);`/api/v1/admin/system/*`;`system_settings` 白名单可写;吸收下线 AdminSettingsModal;细粒度 `system:*` + 设置审计日志(goose 00065) | done | non_blocker | [short-term](../ops/short-term/2026-09-17-system-admin-console.md);[测试报告](../test-reports/2026-09-17-system-admin-console-test-report.md);residual `modular-decouple-residual-2026-09-23` | 剩余 deferred:Playwright 实跑、KB 运维动作、白名单项接消费方 | `web` + `sysadmin` | -| 个人工程中控台(已移出) | 原本地只读看板与后来的 Control Center 都不再属于本仓库 | removed | 进度管理改由独立项目承担 | [历史设计](../archive/design/2026-09-17-personal-engineering-control-center-plan.md);[历史报告](../test-reports/2026-09-17-engineering-dashboard-test-report.md) | 2026-09-19 删除 `cmd/control-center`、`internal/controlcenter`、`control-center/web`、`deploy/control-center`。不恢复 `engineering-dashboard` | — | +| record_id | 模块 | 声明范围 | 状态 | 发布关系 | 证据 | 剩余工作 / 关闭条件 | mutex | +|------|----------|------|----------|------|---------------------|-------|-------| +| gov-agent-worktree | Agent worktree 治理自动化 | 主目录保护、任务 worktree、机器认领、候选集成、dev 部署与安全清理 | partial | non_blocker | [方案](../remediation/2026-09-21-agent-workflow-governance-plan.md);[L1 验收](../test-reports/2026-09-21-agent-governance-test-report.md);[W1-B macOS](../ops/short-term/2026-09-22-agentctl-macos.md);[W4](../ops/short-term/2026-09-22-governance-automation.md);residual `modular-decouple-residual-2026-09-23` | L1 与 macOS `with/docs apply/validate/integrate` 已合入。W4 landed:durable queue + 完整 docs projection apply(行/整文 CAS)+ deploy/recover 真实收据闭环 + Darwin cwd 可见性测试。仍 deferred:PI 源码镜像 compose、跨机隔离、automation/w4 实现收敛。本行不升 done | `agent-workflow-governance` | +| intent-l1 | 意图识别 L1 | 18 类 Intent、三分支消解、写/只读分流、双标签 `DOC_BUSY`、intent 纯依赖边界 | done | non_blocker | [intent-recognition](../system-design/intent-recognition/);[工作流作用域](../test-reports/2026-09-21-intent-workflow-scoping-test-report.md);[审计](../audit/2026-09-13-conversation-intent-runtime-state.md);[报告](../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md);[双标签](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/live.json);[U1](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)–[U3](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) | **边界 before**:含 U9–U12 叙事混入 → **after**:U9–U12 迁至「多意图扩面」行。关闭:纯依赖边界回归即重开 | `intent` | +| intent-plan-u1u8 | 多意图持久计划(U1–U8 基线) | app/intentflow 生命周期、HITL、默认 `legacy`、U1–U8 代码与安全基线 | partial | non_blocker(默认 legacy) | [设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[U1](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)–[U8](../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md);[Wave2 真 PI](../test-reports/2026-09-16-wave2-real-pi-evidence-test-report.md);[Track I1](../test-reports/2026-09-22-track-i1-query-owner-test-report.md) | **after Track I1**:生产组合根已去 Fake query owner,改真实 QueryOwner;receipt 含 auth scope digest;confirm 后走既有步骤内核 dispatcher。默认仍 `MULTI_INTENT_PLAN_TIER=legacy`。升 `auto_read/confirm` 需 Track I2(项目 allowlist + 频率门)。U9–U12 仍独立 dry-run | `intent-plan` | +| intent-plan-u9u12 | 多意图扩面(U9–U12) | U9 LLM 分段实验;U10 mutate;U11 docgov;U12 workflow/run-control | partial | deferred_enhancement | [设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[脚手架](../test-reports/2026-09-16-pu8-u9-u12-flags-test-report.md);[U9](../test-reports/2026-09-17-w4-u9-segment-test-report.md);[U10](../test-reports/2026-09-17-w4-u10-mutate-test-report.md);[U11](../test-reports/2026-09-17-w4-u11-docgov-test-report.md);[U12](../test-reports/2026-09-17-w4-u12-run-control-test-report.md);[2026-09-20 复核](../ops/research/2026-09-20-capability-enablement-impact-research.md) | U9 proposer 已实现和注入但未进入生产聊天分段调用;提议请求已带 reasoning profile。U10–U12 当前为 dry-run/validated-only adapter。历史直接调用/PI 测试继续有效,不代表 live 接线。逐域实现和验收,禁止以 `full` 一次放量 | `intent-plan` | +| chat-ctxmgr | 对话 / ctxmgr baseline | 多轮上下文、刷新/重登/重启恢复、授权同集正文与计数、U10 端口化停止扩面 | done | non_blocker | [multi-turn](../system-design/multi-turn-dialogue/);[刷新审计](../audit/2026-09-13-chat-history-refresh-disappears.md);[U10](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md);[门禁 B3](../test-reports/2026-09-16-chat-refresh-gate-test-report.md)(项目 6359) | **before**:语义摘要误标 D5 混入 → **after**:摘要迁「语义摘要 D3」;D7 数据治理独立。U10 停止扩面 | `chat` | +| chat-semantic-d3 | 语义摘要(D3) | 授权后可见集合上的语义摘要;shadow → 可选替换 deterministic | partial | deferred_enhancement | [chat-agent-p6-backlog](../backlog/chat-agent-p6-backlog.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[pu6](../ops/long-term/2026-09-16-pu6-semantic-summary-contract.md);[脚手架](../test-reports/2026-09-16-pu6-semantic-summary-test-report.md);[W2 真 PI](../test-reports/2026-09-17-w2-semantic-summary-shadow-test-report.md);[Track S1](../ops/short-term/2026-09-22-track-s1-summary-consolidation.md) | **after Track S1**:durable `chat_summary_shadow_jobs` + 后台租约/watermark/provenance 已合入;served Narrative 保持确定性。shadow 默认 off;`SEMANTIC_SUMMARY_REPLACE` **未接线**。**2026-09-23 实测** DOCREV 路径 schema **63**。授权可见集 digest 已进 shadow 路径。本行不升 done | `chat` | +| chat-data-d7 | 对话数据治理(D7) | 留存/删除口径、库·备份·日志控制、敏感字段加密边界 | deferred | deferred_enhancement(违规则升 blocker) | [计划](../remediation/2026-09-16-feature-matrix-production-readiness-plan.md) Scope Boundaries;[D7 ADR 草案](../adr/2026-09-17-d7-chat-data-retention.md);[W7 盘点](../audit/2026-09-17-d7-data-inventory.md);[红线证据](../test-reports/2026-09-22-redline-evidence-d7-test-report.md) | 只读盘点 + Track E ID-only 符合性已补。口径仍 `pending-compliance-signoff`;**禁止物理删除**。本行不升 done | `chat` | +| squad | 智能体小队 | 角色-任务-工作区-黑板 | done | non_blocker | [agent-squad](../system-design/agent-squad/);[test 2026-09-07](../test-reports/2026-09-07-dynamic-squad-planning-test-report.md) | 非关键步骤降级(A5/A6)属 backlog | `squad` | +| workflow-gov | 工作流治理 | 三正式工作流、设置页/DutyMode、动作级鉴权、真实 PI 三工作流 E2E、full/none 混合长链 | done | non_blocker | [三工作流整改](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[409/职责](../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md);[鉴权](../test-reports/2026-09-14-governance-action-level-authz-test-report.md);[PI E2E](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md);[Wave2 full/none](../test-reports/2026-09-16-wave2-real-pi-evidence-test-report.md) | full 跨用户审批 + none 免审批不阻塞已签。纯软件自举仍独立 planned | `workflow` | +| workflow-rdev | 研发设计控制(rdev) | 医疗第 4 工作流:13×60 manifest/模板、`squad.rdev_doc.v1` kind 编排、main-completed 硬 precheck、StageKey 动态化;不含前端/真 PI/键名空间化 | partial | deferred_enhancement | [设计](../system-design/project-workflow/07-研发工作流rdev接入-设计与实施计划.md);[收口](../ops/short-term/2026-09-22-rdev-closeout.md);[报告](../test-reports/2026-09-22-rdev-closeout-test-report.md);[P3 历史](../test-reports/2026-09-19-rdev-p3-real-pi-test-report.md) | **after 2026-09-22 收口**:`rd_proposal` 标题门禁 + 法规表首表截止 dry PASS;nightly 脚本已扩四工作流(FullChain×3+FullNone)。P3 真 PI 三样本重跑因缺 `env:dev` **blocked**(不以 stub 冒充)。剩余:获环境后重跑 P3。本行保持 partial | `workflow-def` / `rdev-templates` | +| workflow-swboot | 纯软件项目自举 | 软件项目创建、Bootstrap、Delivery、受控工程交接 | partial | deferred_enhancement(明确不挡首发) | [设计](../system-design/2026-09-14-software-project-bootstrap-workflow.md);[ADR](../adr/2026-09-16-software-project-bootstrap-keys.md);[L1 报告](../test-reports/2026-09-16-software-project-bootstrap-test-report.md);[W5a](../test-reports/2026-09-17-w5a-software-bootstrap-ui-pi-test-report.md);[红线证据](../test-reports/2026-09-22-redline-evidence-swboot-test-report.md) | **after W5a + 红线证据**:catalog 驱动创建、软件不挂医疗 key。**SWBOOT-10 仍 stub**(L1–L4 证据已补;L5/L6 待授权)。本行不升 done | `workflow-design` | +| iam-authz | IAM / 鉴权 | 项目级 API 鉴权 + RBAC;会话/阶段授权 | done | 加固 | [v3 full inventory](../audit/authorization-matrix-v3-full.md);[session 中断](../test-reports/2026-09-16-iam-route-inventory-test-report.md);[fail-closed](../test-reports/2026-09-16-wave1-iam-fail-closed-test-report.md);[410 策略](../audit/2026-09-16-bug11-410-retire-decision.md);[R13](../audit/2026-09-16-r13-data-safety-checklist.md) | 全路由 inventory + session 中断负例 + 410 冻结 + R13 基线已签 | `authz` | +| docgov | 文档治理 | 法定文档生命周期 + 租约 + 受控正文读取 | done | non_blocker | [docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md);[正文 UI](../test-reports/2026-09-14-controlled-content-ui-acceptance.md);[canonical hash](../remediation/2026-09-14-controlled-content-canonical-hash-remediation.md);[键统一](../test-reports/2026-09-21-workflow-doc-key-unification-test-report.md) | 项目 143 只读;不终止。`doc_proj*` 同一发布键不能再并存 | `docgov` | +| docgov-revision | 文档版本 baseline | 账本、人工修订、确定性 diff+lineage、运行时 UI、负责人通知 | done | non_blocker | [管理](../test-reports/2026-09-13-document-revision-management-test-report.md);[Round20 UI](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[ADR](../adr/2026-09-13-document-version-boundary.md);[proposed/authoritative](../ops/short-term/2026-09-20-proposed-authoritative-reports.md) | **before**:完整 PI narrative 混入 → **after**:迁「PI change-report 叙事」。fallback 报告是本行内显式行为,不是缺口。lineage GET 已按 URL 项目和文档可见性裁剪。test_manager 血缘的下游/上游版本改读文档版本,不再写死 1。Agent 候选报告为 `proposed`,正式提交才写 authoritative 后继并挂到版本;拒绝、替代后旧报告不能再出建议。人工修订、导入和聊天卡仍未分开预估与正式报告,见 [T1](../ops/short-term/2026-09-20-impact-loop-t1.md)。项目追踪索引见下一行 | `docgov` | +| trace-impact | 阶段回溯与影响闭环 | 五表追踪索引、影响报告、L1 文档修订、L2 阶段再打开、待复核软标记、对话修订提案 | done | deferred_enhancement(不挡首发) | [设计](../system-design/2026-09-20-stage-backtrack-and-impact-loop-design.md);[Track T](../remediation/2026-09-20-capability-enablement-impact-plan.md);[对话化报告](../test-reports/2026-09-21-trace-panel-to-chat-test-report.md);[T 补强](../ops/short-term/2026-09-22-track-t-strengthen.md) | 已合入 dev。常驻「需求与影响」面板已退役。**2026-09-23 实测** DOCREV 路径 schema **63**;test=`rc-v1.1.0-beta.1` schema 61;main 本轮未晋升。阶段推进确认门禁仍在。不签 D7 对话 ADR | `trace-index` | +| docgov-pi-narrative | PI change-report 叙事 | 只读消费 diff+lineage 的 PI 叙事;失败全量降级 fallback | partial | deferred_enhancement | [Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[go/no-go GO](../ops/research/2026-09-16-wave3-pu6-pu8-go-no-go.md);[pu7](../ops/long-term/2026-09-16-pu7-pi-narrative-contract.md);[W3 真 PI](../test-reports/2026-09-17-w3-pi-change-report-narrative-test-report.md);[红线负例](../test-reports/2026-09-22-redline-evidence-pi-narrative-test-report.md) | flag 默认 **off**(红线不放量)。fallback 全量负例单测已补。pi-agent reasoning 路径已带 `--no-tools`。不打开开关 | `docgov` | +| web-workbench | 前端工作台 | 三栏 + 块文档 + SSE;错误卡/`TaskRunCard` 竖向进度/busy;版本冲突信封;demo seed 默认关;终止 preview | done | non_blocker | [workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[双标签](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/screenshots/tab-b-busy.png);[demo](../test-reports/2026-09-16-demo-seed-pollution-test-report.md);[B4](../test-reports/2026-09-16-frontend-gate-b4-test-report.md)(项目 6363);[TaskRunCard](../test-reports/2026-09-21-taskrun-status-card-persistence-test-report.md) | **before**:空「缺口」却 partial → **after**:本行 done。其他 409 消费方信封复用另列 hardening backlog | `web` | +| pi-runner | PI Runner / 配置链 | pi-agent + MiniMax + typed-result-v1 | done | non_blocker | [piagent](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md);[container-env](../test-reports/2026-09-13-container-env-configuration-test-report.md);[typed-result](../test-reports/2026-09-15-pi-typed-result-v1-test-report.md) | 文档生成仍使用读写和搜索工具。`tool_profile=reasoning` argv 为 `--no-tools`。**2026-09-22 实测** pi-agent 已 bind-mount `pi-args.mjs` | `pi-agent` | +| infra-envs | 三环境运维 | dev/test/main + 共享 KB;对话/业务库隔离 | done | non_blocker | [PROJECT.md](../../PROJECT.md) §4;[晋升报告](../test-reports/2026-09-22-dev-gate-and-test-promotion-test-report.md);[DOCREV](../test-reports/2026-09-22-docrev-ui-rerun-test-report.md) | **2026-09-23 实测**:本地/共享 dev DOCREV 路径 schema **63**;test health schema **61**(`rc-v1.1.0-beta.1`);main 本轮未晋升 | `infra` | +| ci-e2e | CI / E2E | PR CI、PG 集成、治理 PG、已签真实 PI 门禁;**nightly** schedule/`workflow_dispatch` + infra/product 分类 receipt | done | 加固(阻止**下一次**晋升,不自动否定已发布) | [BUG-08](../test-reports/2026-09-16-ci-governance-pg-bug08-test-report.md);[PI 三工作流](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md);[Wave2B](../test-reports/2026-09-16-wave2b-nightly-promotion-receipt-test-report.md);[Wave2C](../test-reports/2026-09-16-wave2c-same-image-digest-test-report.md);[W1 green](../test-reports/2026-09-17-w1-ci-e2e-green-nightly-test-report.md) + [receipt `6e2476f0…`](../assets/promotion-receipts/6e2476f0f2e408e111fe06ca7c31a38294a340b3.json) | **before**:partial(FullNone product_fail / secrets 文案过时)→ **after**:secrets 已配;duplicate goose 00048 已清;FullNone+U8 nightly `verdict=pass` | `ci` | +| infra-artifact-digest | Artifact 同 digest 晋升 | 候选 commit 一次构建、按 digest 晋升、promotion receipt | done | 加固 | [计划 PU5B](../remediation/2026-09-16-feature-matrix-production-readiness-plan.md);[Wave2B](../test-reports/2026-09-16-wave2b-nightly-promotion-receipt-test-report.md);[Wave2C](../test-reports/2026-09-16-wave2c-same-image-digest-test-report.md) | **关闭**:same-image pin(`candidate-images-*` + `PINNED_IMAGE_MODE` + promote `--require-digests`)。**声明**:单机 retag/digest pin;远程 registry 推送另立任务 | `infra` | +| events-core | 可靠事件核心 | PG dispatcher、notify/advance/projection live、生产闭包 hook 退出、Phase2 选择性解耦已合入 | done | non_blocker | [E0A–E2](../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md) 等;[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[shared live](../test-reports/2026-09-15-event-notify-shared-live-test-report.md);[phase2 closeout](../test-reports/2026-09-15-phase2-closeout-test-report.md) | **before**:与 FAV off 混成 partial → **after**:FAV 独立行。选择性后续解耦按收益触发 | `architecture-docs` / `events` | +| module-spec | 模块开发规范 | 窄端口、领域事件、wire DTO 三种契约;故障隔离红线;新增模块/表/事件流程。不含批次 A–G 的代码整改 | done | non_blocker | [规范](../system-design/2026-09-20-module-development-standards.md);[审计](../audit/2026-09-20-module-coupling-audit.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md) | 文档入口已立。代码整改不在本行 | `module-decoupling-spec` | +| module-batches-ag | 模块解耦批次 A–G | server 端口装配、chat 解环、docgov 词汇、工作流单向依赖、巨型文件、前端 api client、21 条例外清零 | done | non_blocker | [分批计划](../remediation/2026-09-20-module-decoupling-batch-plan.md);[审计](../audit/2026-09-20-module-coupling-audit.md);[A](../ops/short-term/2026-09-22-server-assembly-cleanup.md);[B](../ops/short-term/2026-09-22-chat-app-decouple.md);[C](../ops/short-term/2026-09-22-docgov-vocabulary-convergence.md);[D](../ops/short-term/2026-09-22-workflow-def-unidirect.md);[E](../ops/short-term/2026-09-22-engine-split.md);[F](../ops/short-term/2026-09-22-web-api-client.md);[G1](../ops/short-term/2026-09-22-g1-exception-clearance.md);[G2/G3](../ops/short-term/2026-09-22-g2-g3-exception-clearance.md) | **after 2026-09-22**:A–F 与 E 已合入;G1/G2/G3 例外清零后 `arch-check --mode block` PASS 且 baseline import/sql_write/path/event **全 0**。关闭本伞行 | `module-decoupling-spec` | +| events-fav | Final Artifact Vault(FAV) | 不可变终态制品库;`FAV_DEGRADED_READ=false` | partial | deferred_enhancement | [Track E 复盘](../ops/research/2026-09-15-track-e-retrospective.md);[U7 报告](../test-reports/2026-09-16-fav-u7-incremental-test-report.md);[W6 shadow](../test-reports/2026-09-17-w6-fav-subscriber-shadow-test-report.md);[红线证据](../test-reports/2026-09-22-redline-evidence-fav-test-report.md) | subscriber shadow 只计算 intended outcome。**live 未放量**;观察窗起点已登记。`FAV_DEGRADED_READ` 默认 false;禁止整支 merge | `events` | +| web-sysadmin | 系统管理台 | 全屏系统级管理视图(总览/KB/特性开关/系统设置/工作流/角色/用户/文档 8 分组);`/api/v1/admin/system/*`;`system_settings` 白名单可写;吸收下线 AdminSettingsModal;细粒度 `system:*` + 设置审计日志(goose 00065) | done | non_blocker | [short-term](../ops/short-term/2026-09-17-system-admin-console.md);[测试报告](../test-reports/2026-09-17-system-admin-console-test-report.md);residual `modular-decouple-residual-2026-09-23` | 剩余 deferred:Playwright 实跑、KB 运维动作、白名单项接消费方 | `web` + `sysadmin` | +| removed-control-center | 个人工程中控台(已移出) | 原本地只读看板与后来的 Control Center 都不再属于本仓库 | removed | 进度管理改由独立项目承担 | [历史设计](../archive/design/2026-09-17-personal-engineering-control-center-plan.md);[历史报告](../test-reports/2026-09-17-engineering-dashboard-test-report.md) | 2026-09-19 删除 `cmd/control-center`、`internal/controlcenter`、`control-center/web`、`deploy/control-center`。不恢复 `engineering-dashboard` | — | --- diff --git a/configs/agent-governance.json b/configs/agent-governance.json index 6d7a9264..b286f146 100644 --- a/configs/agent-governance.json +++ b/configs/agent-governance.json @@ -24,7 +24,7 @@ }, ".doc/status/FEATURE-MATRIX.md": { "evidence_for_done": true, - "header": "| 模块 |" + "header": "| record_id | 模块 |" } }, "reserved_record_ids": ["holder", "idle", "Cursor", "Codex", "-"], diff --git a/scripts/agentctl.py b/scripts/agentctl.py index f5ee593a..ee77e696 100755 --- a/scripts/agentctl.py +++ b/scripts/agentctl.py @@ -44,7 +44,7 @@ DEFAULT_POLICY = { }, '.doc/status/FEATURE-MATRIX.md': { 'evidence_for_done': True, - 'header': '| 模块 |', + 'header': '| record_id | 模块 |', }, }, 'reserved_record_ids': ['holder', 'idle', 'Cursor', 'Codex', '-'], @@ -1045,7 +1045,11 @@ def matrix_states(content): continue cells = table_cells(line) if status_index is None: - if cells[0].casefold() not in ('模块', 'module', 'feature'): + if not cells: + continue + first = cells[0].casefold() + # record_id/id first → stable key in cells[0]; legacy 模块/module/feature → key is module name. + if first not in ('record_id', 'id', '模块', 'module', 'feature'): continue labels = [c.strip('*').casefold() for c in cells] columns = [i for i,c in enumerate(labels) if c in ('状态','state','status')] @@ -1066,6 +1070,50 @@ def matrix_states(content): return states +def matrix_module_states(content): + """Map module display name → status for evidence gates across record_id migrations.""" + states, status_index, module_index, width = {}, None, None, None + for line in content.splitlines(): + if not line.lstrip(' ').startswith('|'): + if status_index is not None: + break + continue + cells = table_cells(line) + if status_index is None: + if not cells: + continue + first = cells[0].casefold() + if first not in ('record_id', 'id', '模块', 'module', 'feature'): + continue + labels = [c.strip('*').casefold() for c in cells] + columns = [i for i, c in enumerate(labels) if c in ('状态', 'state', 'status')] + if len(columns) != 1: + deny('INVALID_DOCUMENT', 'Matrix needs one explicit status column') + module_cols = [i for i, c in enumerate(labels) if c in ('模块', 'module', 'feature')] + if first in ('record_id', 'id'): + if len(module_cols) != 1: + deny('INVALID_DOCUMENT', 'Matrix with record_id needs one module column') + module_index = module_cols[0] + else: + module_index = 0 + status_index, width = columns[0], len(cells) + continue + if all(re.fullmatch(r':?-+:?', cell.replace(' ', '')) for cell in cells): + continue + if len(cells) != width: + deny('INVALID_DOCUMENT', 'Matrix records must match its columns') + module = cells[module_index] + if module in states: + deny('INVALID_DOCUMENT', 'Matrix module names must be unique') + value = cells[status_index] + if value not in ('done', 'partial', 'planned', 'deferred', 'blocked', 'removed'): + deny('INVALID_STATE', 'Matrix status must use an unformatted canonical state') + states[module] = value + if status_index is None: + deny('INVALID_DOCUMENT', 'Matrix table header is missing') + return states + + def docs_snapshot(repo, args): if args.file not in SHARED_DOCS: deny('PATH_OUT_OF_SCOPE', 'Only the two shared governance documents are managed') @@ -1130,10 +1178,12 @@ def docs_apply(repo, args): if slot(replacement) != slot(before[filename]): deny('PATH_OUT_OF_SCOPE', 'Document admin cannot overwrite integration slot ownership') # A layout update cannot bypass the feature-completion evidence rule. + # Compare by module display name so additive record_id migration does not + # look like newly promoted done rows (keys would otherwise diverge). if DOC_RULES.get(filename, {}).get('evidence_for_done') or filename.endswith('FEATURE-MATRIX.md'): - old_states = matrix_states(before[filename]) - new_states = matrix_states(replacement) - if any(value == 'done' and old_states.get(key) != 'done' for key,value in new_states.items()): + old_states = matrix_module_states(before[filename]) + new_states = matrix_module_states(replacement) + if any(value == 'done' and old_states.get(key) != 'done' for key, value in new_states.items()): deny('EVIDENCE_REQUIRED', 'Change capability completion using a reviewed row update') after[filename] = replacement continue @@ -1142,13 +1192,16 @@ def docs_apply(repo, args): cells = table_cells(replacement) if record_id not in cells[:2]: deny('INVALID_REQUEST', 'Replacement must preserve the record id') - if filename.endswith('FEATURE-MATRIX.md') and 'done' in cells and matrix_states(before[filename]).get(record_id) != 'done': - evidence = change.get('evidence', []) - if 'docs:approve' not in json.loads(task['capabilities']) or not isinstance(evidence, list) or not evidence or any(not isinstance(e, str) for e in evidence): - deny('EVIDENCE_REQUIRED', 'Capability completion requires approval capability and committed evidence') - for evidence_file in evidence: - safe_path(repo.current, evidence_file) - git(repo.current, 'cat-file', '-e', 'HEAD:' + relative(evidence_file)) + if filename.endswith('FEATURE-MATRIX.md'): + if cells[0] != record_id: + deny('INVALID_REQUEST', 'FEATURE-MATRIX replacement must keep record_id in the first column') + if 'done' in cells and matrix_states(before[filename]).get(record_id) != 'done': + evidence = change.get('evidence', []) + if 'docs:approve' not in json.loads(task['capabilities']) or not isinstance(evidence, list) or not evidence or any(not isinstance(e, str) for e in evidence): + deny('EVIDENCE_REQUIRED', 'Capability completion requires approval capability and committed evidence') + for evidence_file in evidence: + safe_path(repo.current, evidence_file) + git(repo.current, 'cat-file', '-e', 'HEAD:' + relative(evidence_file)) lines = after[filename].splitlines() live = doc_rows(after[filename], record_id) if live: @@ -1156,7 +1209,7 @@ def docs_apply(repo, args): else: header = DOC_RULES.get(filename, {}).get('header') if not header: - header = '| owner | task |' if filename.endswith('CURRENT.md') else '| 模块 |' + header = '| owner | task |' if filename.endswith('CURRENT.md') else '| record_id | 模块 |' positions = [i for i, line in enumerate(lines) if line.startswith(header)] if len(positions) != 1: deny('INVALID_DOCUMENT', 'Target table header is absent or ambiguous') @@ -1749,6 +1802,11 @@ def docs_project(repo, args): replacement = w4.build_projection_row( task_id=task['id'], owner=task['owner'], branch=task['branch'], worktree=worktree_cell, mutex=args.mutex or '-', status=status) + elif filename.endswith('FEATURE-MATRIX.md'): + # MATRIX statuses (done|partial|planned|…) differ from CURRENT projection vocab; + # callers must supply a full row including stable record_id via --replacement. + deny('INVALID_REQUEST', + 'FEATURE-MATRIX row projection requires --replacement with full row including record_id') else: deny('INVALID_REQUEST', 'Row projection for this file requires --replacement') change = w4.build_row_projection_change( diff --git a/scripts/tests/test_agentctl.py b/scripts/tests/test_agentctl.py index 50f0e49c..86cfa629 100644 --- a/scripts/tests/test_agentctl.py +++ b/scripts/tests/test_agentctl.py @@ -49,7 +49,8 @@ class AgentctlTests(unittest.TestCase): "# Coordination\n\n| Task | Owner | Branch | State |\n| --- | --- | --- | --- |\n" + "\n".join(self.current_rows.values()) + "\n", encoding="utf-8") (self.root / ".doc/status/FEATURE-MATRIX.md").write_text( - "# Features\n\n| Feature | State |\n| --- | --- |\n| core | planned |\n", encoding="utf-8") + "# Features\n\n| record_id | 模块 | 状态 |\n| --- | --- | --- |\n| core | core | planned |\n", + encoding="utf-8") self.git("add", ".") self.git("commit", "-m", "test fixture") @@ -373,7 +374,7 @@ class AgentctlTests(unittest.TestCase): before = {name: (task / name).read_bytes() for name in (current, features)} request = self.docs_request([ self.doc_change(current, "alpha", self.current_rows["alpha"], self.current_rows["alpha"].replace("active", "done")), - self.doc_change(features, "core", "| core | stale |", "| core | done |"), + self.doc_change(features, "core", "| core | core | stale |", "| core | core | done |"), ]) result = self.cli("docs", "apply", "--task", "alpha", "--request", request, cwd=task, check=False) self.assertNotEqual(result.returncode, 0) @@ -528,11 +529,159 @@ class AgentctlTests(unittest.TestCase): for indent in range(4): with self.subTest(indent=indent): request = self.docs_request([{"file":filename,"record_id":"@document","expected_sha256":snapshot["sha256"], - "replacement":original.replace("| core | planned |", " "*indent+"| core |done|")}], "compact-done-"+str(indent)) + "replacement":original.replace("| core | core | planned |", " "*indent+"| core | core |done|")}], "compact-done-"+str(indent)) result = self.cli("docs", "apply", "--task", "alpha", "--request", request, cwd=task, check=False) self.assertNotEqual(result.returncode, 0) self.assertEqual((task / filename).read_text(), original) + def test_matrix_done_without_evidence_refused(self): + task = self.initialized_task(capabilities=("docs:publish", "docs:approve", "docs:admin")) + filename = ".doc/status/FEATURE-MATRIX.md" + old = "| core | core | planned |" + # Row update to done without evidence list → EVIDENCE_REQUIRED + request = self.docs_request([ + self.doc_change(filename, "core", old, "| core | core | done |"), + ], "matrix-done-no-evidence") + denied = self.cli("docs", "apply", "--task", "alpha", "--request", request, cwd=task, check=False) + self.assertNotEqual(denied.returncode, 0) + self.assertIn("EVIDENCE_REQUIRED", denied.stderr) + self.assertIn("| core | core | planned |", (task / filename).read_text()) + # @document rewrite that bumps partial/planned→done without per-row evidence + original = (task / filename).read_text() + snapshot = json.loads(self.cli("docs", "snapshot", "--file", filename, "--record", "@document", cwd=task).stdout) + bumped = original.replace("| core | core | planned |", "| core | core | done |") + request = self.docs_request([{ + "file": filename, "record_id": "@document", + "expected_sha256": snapshot["sha256"], "replacement": bumped, + }], "matrix-doc-done-bypass") + denied = self.cli("docs", "apply", "--task", "alpha", "--request", request, cwd=task, check=False) + self.assertNotEqual(denied.returncode, 0) + self.assertIn("EVIDENCE_REQUIRED", denied.stderr) + self.assertEqual((task / filename).read_text(), original) + + def test_matrix_record_id_layout_migration_without_new_dones(self): + """Additive record_id column must not trip EVIDENCE_REQUIRED when statuses unchanged.""" + task = self.initialized_task(capabilities=("docs:publish", "docs:admin")) + filename = ".doc/status/FEATURE-MATRIX.md" + legacy = ( + "# Features\n\n" + "| 模块 | 状态 |\n" + "| --- | --- |\n" + "| core | planned |\n" + "| intent | done |\n" + ) + (task / filename).write_text(legacy, encoding="utf-8") + self.git("add", filename, cwd=task) + self.git("commit", "-m", "legacy matrix", cwd=task) + snapshot = json.loads(self.cli("docs", "snapshot", "--file", filename, "--record", "@document", cwd=task).stdout) + migrated = ( + "# Features\n\n" + "| record_id | 模块 | 状态 |\n" + "| --- | --- | --- |\n" + "| core | core | planned |\n" + "| intent-l1 | intent | done |\n" + ) + request = self.docs_request([{ + "file": filename, "record_id": "@document", + "expected_sha256": snapshot["sha256"], "replacement": migrated, + }], "matrix-layout-migrate") + result = self.cli("docs", "apply", "--task", "alpha", "--request", request, cwd=task) + self.assertEqual(result.returncode, 0, result.stderr) + text = (task / filename).read_text() + self.assertIn("| record_id | 模块 | 状态 |", text) + self.assertIn("| intent-l1 | intent | done |", text) + self.assertIn("| core | core | planned |", text) + + def test_matrix_unknown_columns_and_lineage_preserved(self): + task = self.initialized_task(capabilities=("docs:publish", "docs:admin")) + filename = ".doc/status/FEATURE-MATRIX.md" + body = ( + "# Features\n\n" + "| record_id | 模块 | 状态 | extra |\n" + "| --- | --- | --- | --- |\n" + "| core | core | planned | keep-me |\n\n" + "## Wave 0 lineage\n\n" + "trailing history must survive layout edits.\n" + ) + (task / filename).write_text(body, encoding="utf-8") + self.git("add", filename, cwd=task) + self.git("commit", "-m", "seed matrix lineage", cwd=task) + snapshot = json.loads(self.cli("docs", "snapshot", "--file", filename, "--record", "@document", cwd=task).stdout) + updated = body.replace("| core | core | planned | keep-me |", + "| core | core | planned | keep-me-too |") + request = self.docs_request([{ + "file": filename, "record_id": "@document", + "expected_sha256": snapshot["sha256"], "replacement": updated, + }], "matrix-preserve-wave0") + result = self.cli("docs", "apply", "--task", "alpha", "--request", request, cwd=task) + self.assertEqual(result.returncode, 0, result.stderr) + text = (task / filename).read_text() + self.assertIn("## Wave 0 lineage", text) + self.assertIn("trailing history must survive layout edits.", text) + self.assertIn("keep-me-too", text) + self.assertIn("| record_id | 模块 | 状态 | extra |", text) + + def test_task_close_does_not_auto_promote_matrix_done(self): + task = self.initialized_task(capabilities=("docs:publish",)) + filename = ".doc/status/FEATURE-MATRIX.md" + before = (task / filename).read_text() + self.assertIn("| core | core | planned |", before) + closed = json.loads(self.cli("task", "close", "--id", "alpha", "--status", "done").stdout) + self.assertEqual(closed["status"], "done") + after = (task / filename).read_text() + self.assertEqual(after, before) + self.assertIn("| core | core | planned |", after) + self.assertFalse((task / ".doc/remediation/gap-matrix.md").exists()) + + def test_matrix_duplicate_or_rename_record_id_rejected(self): + task = self.initialized_task(capabilities=("docs:publish", "docs:admin")) + filename = ".doc/status/FEATURE-MATRIX.md" + # Duplicate record_id in document → INVALID_DOCUMENT / AMBIGUOUS + dup = ( + "# Features\n\n" + "| record_id | 模块 | 状态 |\n" + "| --- | --- | --- |\n" + "| core | core | planned |\n" + "| core | other | partial |\n" + ) + (task / filename).write_text(dup, encoding="utf-8") + self.git("add", filename, cwd=task) + self.git("commit", "-m", "dup matrix", cwd=task) + snapshot = json.loads(self.cli("docs", "snapshot", "--file", filename, "--record", "@document", cwd=task).stdout) + request = self.docs_request([{ + "file": filename, "record_id": "@document", + "expected_sha256": snapshot["sha256"], "replacement": dup, + }], "matrix-dup-apply") + denied = self.cli("docs", "apply", "--task", "alpha", "--request", request, cwd=task, check=False) + self.assertNotEqual(denied.returncode, 0) + self.assertTrue( + "INVALID_DOCUMENT" in denied.stderr or "AMBIGUOUS_RECORD" in denied.stderr, + denied.stderr) + # Replacement missing / renaming record_id → INVALID_REQUEST + good = ( + "# Features\n\n" + "| record_id | 模块 | 状态 |\n" + "| --- | --- | --- |\n" + "| core | core | planned |\n" + ) + (task / filename).write_text(good, encoding="utf-8") + self.git("add", filename, cwd=task) + self.git("commit", "-m", "reset matrix", cwd=task) + old = "| core | core | planned |" + # Renaming record_id while editing under the old id + request = self.docs_request([ + self.doc_change(filename, "core", old, "| core-renamed | core | planned |"), + ], "matrix-rename-id") + denied = self.cli("docs", "apply", "--task", "alpha", "--request", request, cwd=task, check=False) + self.assertNotEqual(denied.returncode, 0) + self.assertIn("INVALID_REQUEST", denied.stderr) + request = self.docs_request([ + self.doc_change(filename, "core", old, "| enigmamodule | planned |"), + ], "matrix-missing-id") + denied = self.cli("docs", "apply", "--task", "alpha", "--request", request, cwd=task, check=False) + self.assertNotEqual(denied.returncode, 0) + self.assertIn("INVALID_REQUEST", denied.stderr) + def test_validated_linear_commit_cannot_bypass_candidate_entrypoint(self): task = self.initialized_task(scopes=("src",), capabilities=("git:dev",)) self.cli("hooks", "install")