Compare commits

..
Author SHA1 Message Date
weichenandCursor ed29cb5200 docs(ops): close Wave 0 status and ignore multi-GB UI dumps
Point CURRENT and FEATURE-MATRIX at the arch-check baseline, and keep local Playwright traces out of git.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:00:35 +00:00
weichenandCursor e9d57ea772 feat(arch): add contracts skeleton and warn-mode arch-check
Give later waves a measurable import/table/path baseline without changing business behavior or occupying the integration slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:00:32 +00:00
weichenandCursor 241bfccc1e docs(adr): accept modular monolith decoupling architecture
Record the contract-first, single-writer design so Wave 0 has an accepted boundary to implement against.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:00:29 +00:00
weichenandCursor f2a7fa94d2 docs(workflow): record frozen plan 409 and optional-duty governance docs
Keep the audit, remediation, and MVP rule review with the short-term tasks so later waves do not rediscover the 409 root cause.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:00:26 +00:00
weichenandCursor ea3eeadb77 chore(ops): remove Herdr agent roles and dispatch scripts
Drop live roster/policy and herdr-agent start/dispatch helpers so collaboration follows AGENTS worktree/mutex only; archive prior governance evidence.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 05:22:04 +00:00
757 changed files with 3976 additions and 48518 deletions
-1
View File
@@ -42,7 +42,6 @@
| 架构设计 | [system-design/README.md](system-design/README.md) |
| 测试报告 | [test-reports/](test-reports/) |
| 历史功能设计 | [archive/design/superpowers/](archive/design/superpowers/) |
| Herdr 角色、审批与备援 | [ops/2026-09-13-herdr-agent-roster.md](ops/2026-09-13-herdr-agent-roster.md) |
---
@@ -1,62 +1,29 @@
# ADR:以纵向绞杀方式实施模块化单体解耦
# ADR:模块化单体解耦——契约通信、单一写者、编排下沉
## 状态
提议(2026-09-14;架构与实施计划已修订,等待用户确认后进入首个实现里程碑)
已接受(2026-09-14;Wave 0 契约骨架与 arch-check warn 基线已落地,未占集成槽)
## 背景
`internal/server`、`internal/bizdev`、共享 `UserProjectContext`、工作区路径和多表写入形成隐式耦合。
历史受控正文 404/409、刷新后投影缺失和任务终态不完整说明,单纯搬包不会修复事实源、事务与恢复边界。
多轮审计与实测表明:一处修改波及多处的根因不是模块数量不足,而是——
`internal/server`(17k 行)同时是组合根、跨模块闭包事件总线、编排载体与文件系统/SSE 细节持有者;`internal/bizdev` 是第二组合根(依赖 16 个内部包);`UserProjectContext` 被 chat/coordinator 双向直改;`document_records` 有 5 个写者;工作区路径与 squad 文件 schema 是无版本化的隐性公共契约;`intent→bizdev` 反向依赖。
证据与完整诊断见 [../system-design/2026-09-14-module-decoupling-architecture.md](../system-design/2026-09-14-module-decoupling-architecture.md) §1。
## 决策
1. **保持模块化单体**:不拆微服务;进程内调用使用窄端口,跨进程可靠性只用于持久事件和 FAV。
2. **纵向绞杀**:先在现有包边界插入端口和适配器,迁完一条业务链并验证后再移动或重命名包;禁止“先全量搬包、以后再接口化”。
3. **契约分层**:外部 API DTO 归 `server/api`;持久 schema、公共事件和稳定共享词汇进入按领域划分的 contracts;一对一内部接口由消费者拥有。
4. **命令与事务同属一个应用用例**:一个业务命令只有一个事务 owner;跨表属主通过同一不透明事务作用域协作,业务状态、账本、当前指针、staging 和 outbox 原子提交。
5. **单一写者不等于单独事务**:表属主控制 SQL 和不变量;应用 UnitOfWork 控制跨属主提交边界。属主端口不得私自嵌套提交。
6. **并发正确性以数据库为准**:用户编辑使用乐观版本/ETag;状态转换使用行锁和条件更新;项目级不变量可使用事务级 advisory lock;进程内 mutex 只能优化,不能作为多副本正确性依据。
7. **锁顺序固定**:同一事务按 project/workflow instance → document record → document version/snapshot → task run → outbox/staging 的顺序取锁;事务内禁止 LLM、对象存储、网络调用和长文件 I/O。
8. **可靠事件采用 transactional outbox**:事件按至少一次投递设计,具有稳定 ID、schema version、环境/项目范围、聚合序号、因果链和幂等键;逐消费者记录 delivery、重试、租约和死信。
9. **工作区是可清理投影**:跨模块只传不可伪造 Workspace ID 和受限 artifact key;物理路径只在 workspace/squadrun 适配器内解析和校验。
10. **最终成果进入 FAV**:PostgreSQL 保存业务关系和授权,FAV 只保存已确认终态的精确 payload、manifest、回执和删除状态,workspace 不承担最终成果事实源。
11. **授权逐动作校验**:认证适配器构造不可由请求覆盖的 Principal;HTTP、CLI、后台订阅者和恢复流程都按 action/resource/current state fail closed。
12. **先完成文档可靠性试点**:只有受控正文刷新、重启、并发提交、投影缺失降级和授权负例通过后,才批准 chat、squad、编排层和传输层扩展。
13. **迁移采用 expand/migrate/contract**:允许新增 Goose migration;不得修改已发布迁移;回滚只保证回到最近的兼容阶段,不能任意独立 revert 早期依赖。
14. **协议改造独立立项**:统一错误信封和 PI Runner `result.json` 不作为核心模块解耦前置条件;它们使用独立兼容与 E2E 验收。
## 并发与失败语义
- 普通聚合状态转换默认 `READ COMMITTED` + 明确行锁/条件更新;涉及跨聚合唯一不变量时才使用 Serializable,并对 `40001`/`40P01` 重跑完整事务。
- outbox worker 使用小批次 `FOR UPDATE SKIP LOCKED` 认领,处理发生在事务外;完成、续租和失败回填使用 fencing token 防止过期 worker 覆盖新 owner。
- 每个写命令必须同时有 idempotency key、expected version 或两者;相同 key 不同 payload 返回 typed conflict。
- 锁等待、事务时长、重试次数、队列积压和死信必须可观测;超过预算时失败返回,不无限等待。
## 授权与恢复语义
- Principal 至少携带 actor、环境、认证来源和请求关联 ID;项目、会话、文档、阶段与 duty 从数据库权威关系重新解析。
- 持久事件中的 actor 只用于审计,不能替代订阅者对当前资源状态的授权检查。
- FAV 降级读取要求运行库授权图完整;授权图缺失时禁止面向用户返回内容。
- 恢复只允许进入 scratch identity;promotion 需要系统管理员与数据责任人确认,并通过各属主端口提交,禁止恢复 CLI 直写运行表。
1. **架构形态**:维持模块化单体(不做微服务拆分),新增 `internal/contracts` 作为跨模块接口/DTO/事件/共享枚举的唯一 SSOT;模块间仅允许「调 contracts 接口」与「发布/订阅 contracts 事件」两种通信。
2. **单一写者**:每张表、每类文件唯一属主(docgov 独占 `document_records`;chatlog 独占 chat_* 表;workspace 独占工作区路径);跨模块写走属主端口方法。
3. **编排下沉**:跨模块流程收敛到应用编排层(chatflow/stageflow/docflow,拆自 bizdev/coordinator/chat);HTTP handler 只做参数→服务→DTO 三行式。
4. **组合根唯一**:wiring 迁 `internal/app`;`server.NewServer` 只剩 HTTP 装配;SSE 帧协议下沉 `internal/stream/transport`。
5. **squadrun 契约**:系统备好工作区与 `InputBundle`,小队按 `OutputContract` 交货并写 `RunManifest`(SchemaVer=1);外部禁止直读/覆写工作区内部文件。
6. **机器门禁**:`scripts/arch-check.sh` + `module-boundaries.yaml`(import allowlist / 表属主 / 路径字面量属主),warn 两周后 block 进 CI 与集成槽位冒烟。
7. **兼容承诺**:HTTP URL 与响应结构在 Wave 1–5 不变;**零表结构迁移**;旧路径设一版兼容期后删除。
8. **实施顺序**:Wave 0 立规矩 → 1 止血 → 2 读路径 API 化 → 3 小队契约化 → 4 单写者 → 5 编排事件化(可拆 5a/5b)→ 6 传输收口;每 Wave 独立分支、独立回滚,遵守 AGENTS.md §6 mutex/槽位纪律,避开在途认领。
## 后果
- 首个实现里程碑的改动面小于原 Wave 1–6,但会先增加 UnitOfWork、事件投递和授权基础设施。
- “单表唯一写者”检查改为生产 SQL 写权限检查,并允许 migration、测试和经批准运维脚本存在表名。
- `feature/final-artifact-vault` 是候选依赖,不直接假定可合入;必须先按当前 dev 重放测试、迁移和权限审计。
- 包物理移动、错误信封、SSE 和 PI Runner 协议可延后,不阻塞文档一致性整改。
## 替代方案
- **一次性横向搬包**:拒绝。冲突面大,不能先证明用户故障减少。
- **仅增加 arch-check**:拒绝。门禁不能替代事务、锁和授权契约。
- **拆微服务**:拒绝。当前问题是模块边界和数据一致性,不需要引入分布式事务与跨服务部署成本。
- **继续把 workspace 作为恢复来源**:拒绝。工作区属于可清理计算现场,不能成为最终事实源。
## 相关文档
- [模块解耦架构](../system-design/2026-09-14-module-decoupling-architecture.md)
- [模块解耦整改与重构计划](../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- [方案复核](../audit/2026-09-14-module-decoupling-plan-review.md)
- [文档版本边界 ADR](./2026-09-13-document-version-boundary.md)
- 新增包:contracts / app / chatlog / contextasm / docquery / squadrun(squad 换壳);
- `internal/bizdev` 与 `internal/ctxmgr` 将被拆解退役(知识迁移到 use case 与两个子包);
- 所有后续新能力(含软件项目自举)必须基于新边界实现,禁止再挂 bizdev 门面;
- 任何契约(contracts 中已发布的 DTO/事件/文件 schema)变更须走 ADR。
@@ -1,30 +0,0 @@
---
title: "事件连续性采用 consumer checkpoint + 首事件 bootstrap"
status: accepted
created: 2026-09-15
updated: 2026-09-15
---
# ADR:事件连续性采用 consumer checkpoint + 首事件 bootstrap
## 状态
接受(E0A)。在独立 FAV 审计或明确的无缺口 event sequence 迁移完成前不得改为 gap blocking。
## 背景
`event_envelopes` 已有 `UNIQUE (aggregate_type, aggregate_id, aggregate_version)`。受控文档的首次持久事件常常从较高 `aggregate_version`(账本 version_no)开始,中间版本从未发事件。若把领域版本号当成无缺口事件序号并在缺号时等待,会永久阻塞 delivery。MemoryBus 的 `TestGapDoesNotSkipVersion` 只是 characterization,不得搬到 PostgreSQL dispatcher。
## 决策
1. Track E 选择 **consumer checkpoint + 首事件 bootstrap**。
2. 每个 `(consumer, aggregate_type, aggregate_id)` 记录已成功处理的 `event_id` 与可选 `aggregate_version`。该 aggregate 上的第一件 **safe** 事件即为 bootstrap,不要求 version=1。
3. 同一版本多个不同类型事件:当前唯一约束禁止。E0A 审计后保持该约束;需要同版本多事件时另立 additive 迁移,把序号改到独立 `event_seq`,不在本 ADR 启用。
4. **禁止** 在 dispatcher 启用 gap wait / `ErrGapWait` 阻塞,直到另有 ADR 选择独立无缺口 event sequence 且完成回填。
5. 未知 schema、project 0、错误 environment、未知 consumer 的记录进入 inventory,不得 live claim。
## 后果
- E0B checkpoint 表随 dispatcher migration 增加。
- Projection 以 `document_id + source_snapshot_id + digest` no-replace,不依赖连续 version。
- poison 事件 quarantine 后不静默跳号;其他 aggregate 继续。
@@ -2,7 +2,7 @@
title: "Herdr Agent 角色、备援与自动审批治理"
status: done
created: 2026-09-13
updated: 2026-09-13
updated: 2026-09-14
owner: Codex
branch: feature/herdr-agent-governance
worktree: .worktrees/feature-herdr-agent-governance
@@ -11,6 +11,8 @@ mutex: ops-governance
# Herdr Agent 角色、备援与自动审批治理
> **superseded 2026-09-14**:活文档与 `scripts/herdr-agent-*.sh` 已移除;本文件仅作历史证据。见 [2026-09-14-remove-herdr-agent-settings.md](./2026-09-14-remove-herdr-agent-settings.md)。
## 目标
建立可审计的 Herdr Agent 能力分工、额度保护、故障接管和免人工工具审批入口,并明确 Herdr PI 与产品容器 PI Agent Runner 不是同一执行体。
@@ -47,9 +49,10 @@ mutex: ops-governance
## 相关链接
- Agent roster: [../../ops/2026-09-13-herdr-agent-roster.md](../../ops/2026-09-13-herdr-agent-roster.md)
- Handoff: [../../ops/handoffs/2026-09-13-herdr-agent-governance.md](../../ops/handoffs/2026-09-13-herdr-agent-governance.md)
- Agent roster: [2026-09-13-herdr-agent-roster.md](./2026-09-13-herdr-agent-roster.md)
- Handoff: [handoffs/2026-09-13-herdr-agent-governance.md](./handoffs/2026-09-13-herdr-agent-governance.md)
- Test report: 本任务文“证据 / 备注”
- 移除设定任务: [./2026-09-14-remove-herdr-agent-settings.md](./2026-09-14-remove-herdr-agent-settings.md)
## 证据 / 备注
@@ -1,10 +1,12 @@
# Herdr Agent 角色、审批与备援 SSOT
**更新**: 2026-09-13
**owner**: `orchestrator_codex`
**status**: active
> **archived / superseded 2026-09-14**:不再作为活协作规范;脚本已删除。历史证据保留本文件。移除任务见 [./2026-09-14-remove-herdr-agent-settings.md](./2026-09-14-remove-herdr-agent-settings.md)。
本文只管理工程协作终端,不管理产品运行时智能体。通用分支、worktree、mutex、集成槽、密钥和破坏性操作规则仍以仓库根 [AGENTS.md](../../AGENTS.md) 为准。
**更新**: 2026-09-13(归档标注 2026-09-14)
**owner**: `orchestrator_codex`
**status**: archived
本文只管理工程协作终端,不管理产品运行时智能体。通用分支、worktree、mutex、集成槽、密钥和破坏性操作规则仍以仓库根 [AGENTS.md](../../../AGENTS.md) 为准。
## 1. 身份边界
@@ -1,61 +0,0 @@
---
title: "可靠事件与 FAV 集成 M2–M3"
status: cancelled
created: 2026-09-14
updated: 2026-09-15
owner: TBD
branch: refactor/durable-event-fav-integration
worktree: "-"
mutex: event-delivery
---
# 可靠事件与 FAV 集成 M2–M3
> 2026-09-15:本任务把 durable event 与未审计 FAV 绑成同一关闭条件,且步骤状态已与 U8/U9 后续交付漂移。任务停止使用;持久事件由 [Track E](../../ops/short-term/2026-09-15-durable-event-track-e.md) 接续,FAV subscriber 继续走独立审计,不把本条已勾选步骤视为生产 dispatcher 验收。
## 目标
完成 U5–U9,使投影、通知、RunManifest 和最终成果在多 worker、崩溃、重放和 workspace 清理后仍可恢复且不越权。
## 范围
- opaque workspace capability、lease 和 fencing。
- durable outbox、逐消费者 delivery/inbox、重试和 dead letter。
- 审计并集成 `feature/final-artifact-vault` 的适用实现。
- taskrun finalize、RunManifest 持久化、FAV coverage 和迁移 corpus。
## 非目标
- 不盲目整分支 cherry-pick FAV。
- 不启用跨授权图的 vault 读取。
- 不自动销毁 dev/main 数据。
- 不执行 U10–U12。
## 步骤
1. [x] 读取 M1 test report,确认继续 M2 的 go/no-go 已通过。
2. [x] 重新分配 Goose 序号并审计 U6/FAV schema 组合。
3. [x] 实现 U5–U6,多 app/worker 和 crash matrix 先通过。
4. [x] 逐文件审计 FAV 分支,按 U7 边界迁移合格实现。
5. [ ] 实现 U8,收敛 taskrun terminal finalize 与 RunManifest。
6. [ ] 实现 U9 的 checkpoint backfill、corpus、quarantine 和 cleanup gates。
7. [ ] 完成真实 PI、浏览器、workspace 清理、scratch recovery 和 rebuild 演练。
## 验收标准
- [ ] 多订阅者有独立 delivery,失败者不阻塞其他订阅者。
- [ ] worker crash/retry/replay 不造成重复可见副作用。
- [ ] workspace 清空后,verified 最终文档/回复仍可定位并校验。
- [ ] 授权图缺失、跨项目、tombstone、坏 digest 和 stale fencing 全部拒绝。
- [ ] clean/oldest/previous/hazard/import/reload/rollback/artifact recovery 八轨有独立证据。
- [ ] 任何数据销毁仍需完整备份、corpus、FAV coverage 和用户批准。
## 相关链接
- Checklist: [../checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Handoff: 实施时创建
- Test report: 实施后按 M2、M3 分开创建
- Plan: [../../remediation/2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
## 证据 / 备注
本任务依赖 M1,不得与 M1 同时修改 docgov/docrevision 的事务主链。
@@ -1,55 +0,0 @@
---
title: "模块解耦架构与重构计划修订"
status: done
created: 2026-09-14
updated: 2026-09-14
owner: Codex
branch: feature/module-decoupling-remediation
worktree: .worktrees/feature/module-decoupling-remediation
mutex: architecture-docs
---
# 模块解耦架构与重构计划修订
## 目标
把模块解耦方案修订为可以分段实施、验证和回滚的架构与重构计划,补齐事务、并发互斥、授权、可靠事件、FAV、数据迁移和真实页面验收。
## 范围
- 修订模块化单体架构设计与 ADR。
- 新增详细整改与重构计划。
- 建立首个文档可靠性纵向试点及后续里程碑任务。
- 更新 CURRENT、FEATURE-MATRIX 和相关索引。
## 非目标
- 本任务不修改业务代码、数据库迁移或部署配置。
- 本任务不合并 `feature/final-artifact-vault`,只定义其集成依赖和边界。
- 本任务不执行共享容器验证,也不占用集成槽位。
## 步骤
1. [x] 对照当前源码、已接受 ADR、FAV 分支和外部权威资料复核原方案。
2. [x] 修订架构设计与 ADR。
3. [x] 编写详细整改计划、里程碑任务和验收清单。
4. [x] 更新协作 SSOT 与索引并完成文档一致性检查。
## 验收标准
- [x] 计划明确事务所有权、锁顺序、事件投递语义、授权主体和恢复边界。
- [x] 首个独立交付边界直接覆盖受控文档刷新、重启、投影缺失和授权负例。
- [x] 每个后续里程碑有依赖、文件范围、并发风险、测试矩阵、停走门和回滚边界。
- [x] FAV、迁移语料库和完整备份的职责不重叠,工作区不再承担最终成果事实源。
## 相关链接
- Checklist: [../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Handoff: 不需要;实现阶段使用两个 planned short-term 接续
- Test report: 本任务仅产出计划,不生成业务验收报告
## 证据 / 备注
- 原方案位于主工作区未跟踪文件;本任务在独立 worktree 重建并修订,未覆盖原工作区。
- `feature/final-artifact-vault` 已有实现与测试证据,但尚未合入本任务基线,实施前必须重新审计分支差异。
- 文档校验:本地相对链接、R/KTD/U ID 唯一性、Mermaid fence 和 `git diff --check` 均通过。
@@ -0,0 +1,51 @@
---
title: "移除 Herdr 工作与角色设定"
status: done
created: 2026-09-14
updated: 2026-09-14
owner: Cursor-Auto
branch: feature/remove-herdr-agent-settings
worktree: "-"
mutex: agent-collab-docs
---
# 移除 Herdr 工作与角色设定
## 目标
从仓库活文档与脚本中移除 Herdr Agent 角色、审批、备援与派发设定,协作规范回到通用 AGENTS / worktree / mutex 流程。
## 范围
- 删除 `scripts/herdr-agent-start.sh`、`scripts/herdr-agent-dispatch.sh`
- 归档 roster / 相关 handoff
- 从 `AGENTS.md`、`PROJECT.md`、`.doc/README.md` 去掉 Herdr 专章与索引
## 非目标
- 不改写历史 audit / remediation / 已归档任务中的执行者名(如 `implementer_cursor`)作为证据
- 不卸载本机 Herdr 客户端
## 步骤
1. [x] 从 `dev` 开 `feature/remove-herdr-agent-settings` 并认领
2. [x] 移除活文档与脚本中的 Herdr 设定
3. [x] 归档 roster / handoff 并更新 CURRENT
4. [x] 提交
## 验收标准
- [x] 活文档与 `scripts/` 无 Herdr 角色/派发入口
- [x] 历史证据在 `archive/` 可追溯
## 相关链接
- Roster(已归档): [./2026-09-13-herdr-agent-roster.md](./2026-09-13-herdr-agent-roster.md)
- 既有治理归档: [./2026-09-13-herdr-agent-governance.md](./2026-09-13-herdr-agent-governance.md)
- Handoff(已归档): [./handoffs/2026-09-13-herdr-agent-governance.md](./handoffs/2026-09-13-herdr-agent-governance.md)
## 证据 / 备注
- 删除:`scripts/herdr-agent-start.sh`、`scripts/herdr-agent-dispatch.sh`
- 文档:去掉 `AGENTS.md` §6.6、`PROJECT.md` §10 Herdr 章与索引行、`.doc/README.md` roster 入口
- 归档:roster + handoff → `.doc/archive/ops/`
@@ -1,63 +0,0 @@
---
title: "M5/M6 组合根与传输门禁 U11–U12"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/app-composition-u11-u12
worktree: "-"
mutex: app
---
# M5/M6 组合根与传输门禁 U11–U12
## 目标
按整改计划四个子切片完成组合根、文档通知闭包迁出、stageflow 用例、UserProjectContext CAS;再收口 SSE 编码与已清零规则的 arch-check block。用户已明确授权继续 U11/U12(推翻 U10 报告的停止扩面)。
## 范围
- U11a:`internal/app` 唯一 composition root;幂等 Start/Stop
- U11b:文档 `OnOutbox` 通知迁到 `internal/app/docnotify`
- U11c:`internal/app/stageflow` 拥有 ExecuteTask / ExecuteStage
- U11d:`ContextUpdate` 版本 CAS,禁止跨模块字段级直改
- U12:SSE 中性 frame 编码;`import`/`event` 转 block;不改错误信封与 PI Runner 协议
## 非目标
- 不碰 `intent` 包行为(编码阶段 mutex 仍由 Codex 占用;合入后浏览器门另开 handoff)
- 不整支 merge `feature/final-artifact-vault`;不启用 `FAV_DEGRADED_READ`
- 不终止或改写项目 143
- 不删除未到期的 sql_write/path 例外(U3/U5 残留)
- 不在 worktree 内 `env-service`
## 步骤
1. [x] 认领 CURRENT + 本任务
2. [x] U11a composition root
3. [x] U11b docnotify
4. [x] U11c stageflow
5. [x] U11d ContextUpdate
6. [x] U12 SSE + arch-check block_kinds
7. [x] 短测 / 目标包 race / 报告
8. [x] 占槽 `--no-ff` 合入 `dev` + 主仓 `dev rebuild`
## 验收标准
- [x] 重复 Start 不重复注册 subscriber;Stop 后再 Start worker 仍在
- [x] server 生产代码不再赋值 `OnOutbox`
- [x] HTTP 与 CLI 走同一 stageflow 用例
- [x] ContextUpdate 并发 stale version 不丢更新赢家
- [x] `arch-check --mode block` 对已清零的 import/event 通过
- [x] 测试报告回链 U11/U12
- [x] 合入后 `/health` `/ready` schema 38、`pi-agent`、新镜像 digest
## 相关链接
- Checklist: [../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Plan: [../../remediation/2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- Test report: [../../test-reports/2026-09-15-app-composition-u11-u12-test-report.md](../../test-reports/2026-09-15-app-composition-u11-u12-test-report.md)
## 证据 / 备注
用户口头授权:「继续解耦到 U11、U12」。合入 `dev@bf59cce`。rebuild 镜像 `sha256:a8e3e940f01111c4298c67947ae9f4cd6105f13cf58134672f4a87daa19e27ab`。health/ready:`.doc/test-reports/assets/2026-09-15-app-composition-u11-u12/rebuild-health-ready.txt`。
@@ -1,45 +0,0 @@
---
title: "D4 bizdev locator 最终移除"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/bizdev-locator-removal
worktree: "-"
mutex: bizdev
---
# D4 bizdev locator 最终移除
## 目标
删除 bizdev 上 8 个 locator getter;组合根一次性 Snapshot 后由 Runtime/Server 持有端口。
## 范围
- `Pool` `DocGov` `DocRevision` `ContextManager` `CAS` `ProjectWorkflow` `FreeformDoc` `KB`
- Runtime / Server 字段
- archtest 禁止把 getter 加回去
- 调用方迁移
## 非目标
- 不删 SchemaVersion / DatabaseReady
- 不切事件 live
- 不实现 Track P
## 步骤
1. [x] Snapshot + Runtime 端口
2. [x] 迁移 server/cmd/tests
3. [x] 同批删除 8 getter
4. [x] 报告合入
## 验收标准
- [x] 生产无 8 个 getter
- [x] [S1 报告](../../test-reports/2026-09-15-bizdev-locator-removal-test-report.md)
## 相关链接
- Phase 2 D4
@@ -1,39 +0,0 @@
---
title: "D7b chat 编排剩余批次"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/chatflow-orchestration-boundary
worktree: "-"
mutex: chat
---
# D7b chat 编排剩余批次
## 目标
`internal/chat` 生产代码不再 import bizdev;任务请求走 stageflow 类型别名。
## 范围
- action_executor 去掉 Bizdev 字段
- 收紧 chat import allowlist
- 表征测试保留
## 非目标
- 不搬空测试 import
- 不把 taskrun 签名从 bizdev 别名拷成独立结构
- 不切事件 live
## 步骤
1. [x] action_executor 改 stageflow 类型
2. [x] 收紧 yaml
3. [x] 报告合入
## 验收标准
- [x] chat 生产无 bizdev import
- [x] [S4b 报告](../../test-reports/2026-09-15-chatflow-orchestration-boundary-test-report.md)
@@ -1,59 +0,0 @@
---
title: "U10 chatlog/contextasm 原地端口化"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/chatlog-contextasm-u10
worktree: "-"
mutex: chat
---
# U10 chatlog/contextasm 原地端口化
## 目标
在不物理拆包的前提下,为对话读取与 prompt 装配建立带 Principal 的消费者端口,使正文、分类、计数、导出、摘要和恢复使用同一授权可见集合。
## 范围
- `internal/app/chatflow` ChatLog / ContextAssembler 端口
- ctxmgr 表所有权不变;adapter 内做可见性过滤
- server 历史读取 handler 改走 ChatLog;忽略 query/body 中的 user_id 身份
- 会话 restore / 记忆召回只注入允许集合
- 不碰 `intent` mutex,不物理搬到 `chatlog`/`contextasm` 包
## 非目标
- U11–U12
- 整支 merge `feature/final-artifact-vault`
- 启用 `FAV_DEGRADED_READ`
- 纯搬包
## 步骤
1. [x] 核实 `chat` mutex:`fix/chat-history-refresh` 已是 `dev` 祖先;剩余真实 PI 刷新与 U10 同批收口
2. [x] 从最新 `dev` 开 `feature/chatlog-contextasm-u10` 并登记 CURRENT
3. [x] 定义 chatflow 端口与 ctxmgr adapter
4. [x] 迁移 window/day/stats/search/unread/export/digest/history/restore/memory
5. [x] 合同测试:同集计数、非 owner 403、restore/digest 不放大不可见消息
6. [x] 验收报告;最后一句 **停止扩面**
## 验收标准
- [x] 刷新前后同一授权集合的正文与分类计数一致(adapter 合同测试)
- [x] 跨用户负例 fail closed(guest 非 owner)
- [x] context assembly / digest 只使用允许集合
- [x] 真实 PI 闲聊刷新 E2E 证据(与对话刷新活验同批;编制任务链 save 400 未纳入停走)
- [x] 未物理拆包;DTO 转换为 0,拆包收益不成立
## 相关链接
- Checklist: [../checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Plan: [../../remediation/2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- Chat refresh: [../../test-reports/2026-09-13-chat-history-refresh-test-report.md](../../test-reports/2026-09-13-chat-history-refresh-test-report.md)
- Test report: [../../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md](../../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md)
## 证据 / 备注
U9 最后一句 **继续 U10** 只批准进入 M4。禁止 U11–U12。`intent` 认领仍 `in_progress`,本单元不改意图分类。活验项目 6252 / `sess-p6252-u10`;产物 `.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json`。未占槽 rebuild。
@@ -1,59 +0,0 @@
---
title: "M3 U9 存量回填、migration corpus 与数据生命周期"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/dataset-lifecycle-u9
worktree: "-"
mutex: dataset
---
# M3 U9 存量回填、migration corpus 与数据生命周期
## 目标
只保留可解释的演示/回归数据,并持续验证旧数据迁移、重载和受控恢复。backfill 可暂停续跑,异常进 quarantine;八条轨道可重复;销毁默认 fail closed。
## 范围
- dataset registry(pinned / demo / regression / migration_baseline / ephemeral / quarantine)
- checkpoint 分批 backfill:只枚举 snapshot、approved/commit event、completed chat turn
- SKIP LOCKED 多 worker;禁止扫描 workspace
- 销毁门禁:FAV coverage + 完整备份 restore + corpus + 精确 manifest + 双人批准 + quarantine 观察窗
- restore 拒绝共享 env DSN;只允许 scratch
- 八轨:clean / oldest-supported / previous / hazard / import / reload / rollback / artifact recovery
## 非目标
- U10–U12;不碰 `chat` / `intent` mutex
- 不整支 merge `feature/final-artifact-vault`;不启用 `FAV_DEGRADED_READ`
- 不修改历史 Goose;不销毁 `agent_system_dev/test/main`
- 不终止或改写项目 143;worktree 内禁止 `env-service`
## 步骤
1. [x] CURRENT 认领 `mutex=dataset`;从 `dev` 开 `feature/dataset-lifecycle-u9`
2. [x] Goose 00038 + `module-boundaries.yaml`
3. [x] `internal/artifactvault/backfill.go` + `internal/dataset` + `cmd/dataset`
4. [x] 硬化 `scripts/restore-system-db-drill.sh`
5. [x] 隔离库 + 八轨 + 目标包 `-race` + 占槽 rebuild
6. [x] 验收报告;最后一句 **继续 U10**
## 验收标准
- [x] backfill 中断、重复、并发新终态时分母/分子可复算且不重复 artifact
- [x] legacy-v0 / 旧 schema / 高 ID / projection fork / 缺 snapshot → quarantine 或升级
- [x] restore 拒绝共享 DSN、错误 storage identity、篡改 manifest、缺权限
- [x] coverage / backup / corpus 任一失败阻止 destroy
- [x] 批准 dataset 导入后关系、SHA、sequence 可复算
## 相关链接
- Checklist: `.doc/ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md`
- Plan: `.doc/remediation/2026-09-14-module-decoupling-refactor-plan.md` U9
- Test report: `.doc/test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md`
## 证据 / 备注
见验收报告。Goose 00038。dev schema 38。
@@ -1,46 +0,0 @@
---
title: "D6 doccontent canonical 边界"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/doccontent-canonical-boundary
worktree: "-"
mutex: docgov
---
# D6 doccontent canonical 边界
## 目标
Markdown canonicalization 与 SHA 抽到 `internal/doccontent`;生产 `docgov` 不再 import `docrevision`。
## 范围
- `internal/doccontent`
- `docgov/lease.go` 改走 doccontent
- `docrevision` 薄封装保持旧调用方
- golden + wrapper 对账
## 非目标
- 不改 hash 语义
- 不碰项目 143 数据
- 不删 `docrevision.CanonicalizeMarkdown` 导出(兼容)
## 步骤
1. [x] 分支与 CURRENT
2. [x] 提取模块与切断 docgov→docrevision
3. [x] golden / arch-check
4. [x] 报告并合入
## 验收标准
- [x] 生产 docgov 不 import docrevision
- [x] project143 hard-break golden 仍过
- [x] [S3 报告](../../test-reports/2026-09-15-doccontent-canonical-boundary-test-report.md)
## 相关链接
- Phase 2: [../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
@@ -1,53 +0,0 @@
---
title: "Track E 持久事件交付"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-e2-hook-guard
worktree: "-"
mutex: events
---
# Track E 持久事件交付
## 目标
按 E0A→E0B→E1A→E1B→E1C 完成 notify、workflow advance、projection 的 PG 持久交付,并用授权页面刷新/重启恢复证据关闭 `DOC-RELIABILITY-PILOT` 的事件部分。
## 范围
- E0A:生产入口/UoW、event contract、runtime registry、历史数据与 sequence 门。
- E0B:PG dispatcher、attempt audit、独立进程、并发与故障注入。
- E1A/B/C:三个消费者独立 shadow、switch、rollback 和真实恢复验收。
## 非目标
- FAV consumer 激活、bizdev/chat/intent 结构重构、HTTP 错误信封、PI typed result。
- 删除或覆盖历史事件;在 E0A 通过前启动 dispatcher。
## 步骤
1. [x] E0A 单独建 short-term/分支,dispatcher 保持 off。
2. [x] E0A 报告通过后再认领 E0B。
3. [x] 依次交付 E1A notify、E1B workflow advance、E1C projection;每步独立 go/no-go。
4. [x] E2 兼容守卫:live 时闭包停写;hook API 待 live 窗口后删除。
5. [x] 同步 test report、CURRENT、FEATURE-MATRIX、gap-matrix、[复盘](../research/2026-09-15-track-e-retrospective.md)。
## 验收标准
- [ ] 满足 [Phase 2 Track E Definition of Done](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md#track-e-definition-of-done)(共享 live 与删除 hook API 仍开放)。
- [x] 每个波次拥有独立 owner、mutex、分支、报告和回滚证据。
- [x] 未把计划、MemoryBus、stub 或日志冒充生产 PG/browser/restart 验收。
## 相关链接
- Checklist: 按每个波次建立
- Audit: [Phase 2 方案审阅](../../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- Remediation: [Phase 2 修订计划](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Test report: [E2](../../test-reports/2026-09-15-event-e2-hook-guard-test-report.md)
- 复盘: [./research/2026-09-15-track-e-retrospective.md](../research/2026-09-15-track-e-retrospective.md)
## 证据 / 备注
本条只建立执行入口,不代表已批准 E0A 或已认领 mutex。实施前必须按 CURRENT 检查冲突并从当时最新 dev 建分支。
@@ -1,49 +0,0 @@
---
title: "E0A 事件生产、契约与历史数据门"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-production-scope-contract
worktree: "-"
mutex: events
---
# E0A 事件生产、契约与历史数据门
## 目标
组合根注入唯一 `docflow.Commands`;candidate-ready、downstream-impact、approved 三条链在同一 UoW 写 envelope/delivery;缺 env/project fail closed;FAV 不写入;allowlist 与 runtime registry parity;历史 inventory 分类且不删数据;dispatcher 保持 off。
## 范围
- D3 生产入口与作用域
- D10 既有 event allowlist 补全与 registry parity
- D11 inventory、sequence ADR、repair/quarantine/expire、replay 骨架、service principal 表
## 非目标
- 不实现/启动 PG dispatcher
- 不激活 FAV,不写 staging/artifact/publication
- 不删除历史事件
- 不开始 Track S/P
## 步骤
1. [x] 从最新 `dev` 开 `fix/event-production-scope-contract` 并登记 CURRENT
2. [x] 唯一 Commands、三条链同 UoW、FAV 隔离
3. [x] allowlist + registry parity + 动态 FAV 注册失败
4. [x] inventory/repair/replay/principal additive schema 与用例
5. [x] 连续性模型 ADR;gap blocking 关闭
6. [x] 隔离库 PG 证据与 test-report
## 验收标准
- [x] 见 [E0A 测试报告](../../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md)
## 相关链接
- Remediation: [../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- Report: [../../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md](../../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md)
- ADR: [../../adr/2026-09-15-event-consumer-checkpoint.md](../../adr/2026-09-15-event-consumer-checkpoint.md)
@@ -1,43 +0,0 @@
---
title: "E0B PG dispatcher 基座"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/events-dispatcher-pg
worktree: "-"
mutex: events
---
# E0B PG dispatcher 基座
## 目标
原子 lease/attempt/heartbeat/fencing、独立 `cmd/events`、默认 mode=off、1/2/4 worker 与崩溃注入。
## 范围
- Goose 00040、ClaimLeases、cmd/events、compose events 服务
## 非目标
- 不把任何 consumer 切 live
- 不激活 FAV
- 不删除历史
## 步骤
1. [x] 从 E0A 后 `dev` 开 `feature/events-dispatcher-pg`
2. [x] additive schema + atomic claim
3. [x] worker/heartbeat/fencing/shadow scan
4. [x] cmd/events + compose
5. [x] 隔离库 PG + race + 报告
## 验收标准
- [x] [E0B 测试报告](../../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- Report: [../../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md](../../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md)
@@ -1,48 +0,0 @@
---
title: "E1A notify shadow 与切换"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-notify-cutover
worktree: "-"
mutex: events
---
# E1A notify shadow 与切换
## 目标
notify 消费者具备 shadow 覆盖门、live 唯一可见结果与显式 rollback;生产集群保持 off。
## 范围
- Goose 00041、`EmitVisibleDocumentEvent`、`docnotify.EventConsumer`、Handler 与 Ack 同事务
- cmd/events 注册 notify(mode=off 时不 claim)
## 非目标
- 不把共享环境 notify 切 live
- 不删除 OnOutbox 闭包
- 不激活 FAV / workflow advance / projection live
## 步骤
1. [x] 从 E0B 后 `dev` 开 `fix/event-notify-cutover`
2. [x] additive `source_event_id` 与可见结果唯一索引
3. [x] shadow dry-run + live 同事务 ack
4. [x] fixture N=30、quarantine、correlation、rollback
5. [x] 隔离库 PG + race + 报告
## 验收标准
- [x] [E1A 测试报告](../../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- Report: [../../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md](../../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md)
## 证据 / 备注
隔离库 `agent_rel_e1a` 测完已 DROP。共享 `event_consumer_modes.notify=off`。
@@ -1,44 +0,0 @@
---
title: "E1B workflow advance shadow 与切换"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-workflow-advance
worktree: "-"
mutex: events
---
# E1B workflow advance shadow 与切换
## 目标
workflow_advance 具备 shadow/live/rollback;并发或重放批准只产生一次阶段可推进可见结果。生产集群保持 off。
## 范围
- Goose 00042、`docadvance.EventConsumer`、`EmitVisibleStageReady`、MarkDocTaskApproved 走 fenced tx
- cmd/events 注册 workflow_advance
## 非目标
- 不把共享环境 workflow_advance 切 live
- 不删除 AddOnApprovedHook
- 不激活 FAV / projection live
## 步骤
1. [x] 从 E1A 后 `dev` 开 `fix/event-workflow-advance`
2. [x] additive source_event_id on stage_advance_requests
3. [x] consumer 重读文档并同事务 ack
4. [x] 隔离库并发/重放/quarantine/rollback
5. [x] 报告
## 验收标准
- [x] [E1B 测试报告](../../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- Report: [../../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md](../../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md)
@@ -1,41 +0,0 @@
---
title: "E1C projection no-replace"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-projection-cutover
worktree: "-"
mutex: events
---
# E1C projection no-replace
## 目标
projection 消费者幂等只前进;共享集群保持 off。
## 范围
- Goose 00043、ProjectHeadNoReplace、docproject.EventConsumer
## 非目标
- 不把共享 projection 切 live
- 不激活 FAV
- 不删除闭包
## 步骤
1. [x] 分支与 additive schema
2. [x] no-replace SQL + consumer
3. [x] 隔离库 + race + worker 重启
4. [x] 报告
## 验收标准
- [x] [E1C 测试报告](../../test-reports/2026-09-15-event-e1c-projection-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
@@ -1,48 +0,0 @@
---
title: "E2 闭包 live 停写与 Track E 复盘"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/event-e2-hook-guard
worktree: "-"
mutex: events
---
# E2 闭包 live 停写与 Track E 复盘
## 目标
在 dispatcher 仍默认 off 时保留 `OnOutbox` / `AddOnApprovedHook` 接线,使对应消费者切 `live` 后闭包立即停写,避免双写;并写 Track E 复盘。不关闭 `DOC-RELIABILITY-PILOT`。
## 范围
- `events.WriterLive`
- `docnotify.Subscriber.SkipWrite`
- Runtime / 遗留 HTTP hook 在 `workflow_advance` live 时 no-op
- 复盘与 E2 测试报告
## 非目标
- 不删除 hook API(须等 live 发布窗口)
- 不把共享 notify/advance/projection 切 live
- 不激活 FAV
- 不关闭 Track E 发布 blocker
## 步骤
1. [x] 从最新 `dev` 开 `fix/event-e2-hook-guard` 并登记 CURRENT
2. [x] WriterLive + 闭包守卫 + 单测
3. [x] 隔离库 mode 矩阵
4. [x] 复盘与报告
## 验收标准
- [x] live 时闭包不写;off/shadow 仍写
- [x] 生产仍保留 Bind / AddOnApprovedHook(mode=off 必需)
- [x] [E2 报告](../../test-reports/2026-09-15-event-e2-hook-guard-test-report.md)
## 相关链接
- Track E: [./2026-09-15-durable-event-track-e.md](./2026-09-15-durable-event-track-e.md)
- 复盘: [../research/2026-09-15-track-e-retrospective.md](../research/2026-09-15-track-e-retrospective.md)
@@ -1,54 +0,0 @@
---
title: "共享环境事件消费者 live 切换"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/event-shared-live-cutover
worktree: "-"
mutex: events
---
# 共享环境事件消费者 live 切换
## 目标
在共享 `agent-dev` 上按 notify → workflow_advance → projection 完成 shadow → drain → live → 回滚演练,再删除生产 hook 注册。
## 范围
- `scripts/event-consumer-mode.sh` + `cmd/eventmode`
- 共享 `agent_system_dev` inventory / quarantine
- 逐消费者 live 与授权页纵切(项目 6275;143 只读)
## 非目标
- FAV live
- test/main 环境
- 编辑 Phase 2 计划原文
- Track P(独立波次)
## 步骤
1. [x] L0 受控 SetMode 与 inventory
2. [x] L1 notify
3. [x] L2 workflow_advance
4. [x] L3 projection + 授权页
5. [x] L4 删除生产 hook 注册
## 验收标准
- [x] fav / test / main 切模式失败
- [x] 每消费者独立 live 报告
- [x] 生产代码无 `OnOutbox =` / `AddOnApprovedHook(`
## 相关链接
- Long-term: [.doc/archive/ops/2026-09-15-event-shared-live-cutover.md](../../archive/ops/2026-09-15-event-shared-live-cutover.md)
- Notify: [.doc/test-reports/2026-09-15-event-notify-shared-live-test-report.md](../../test-reports/2026-09-15-event-notify-shared-live-test-report.md)
- Advance: [.doc/test-reports/2026-09-15-event-workflow-advance-shared-live-test-report.md](../../test-reports/2026-09-15-event-workflow-advance-shared-live-test-report.md)
- Projection: [.doc/test-reports/2026-09-15-event-projection-shared-live-test-report.md](../../test-reports/2026-09-15-event-projection-shared-live-test-report.md)
## 证据 / 备注
已合入 `dev@39dc68d`。生产 hook 注册已删;方法本体保留一个窗口。
@@ -1,34 +0,0 @@
---
title: "共享环境事件消费者 live 切换"
status: done
created: 2026-09-15
updated: 2026-09-15
---
# 共享环境事件消费者 live 切换
## 动机
Track E 已在隔离库证明 notify / workflow_advance / projection 的 exactly-one visible outcome 与 E2 闭包守卫。共享集群仍为 `off`,HTTP 闭包仍是唯一真实写者。未 live 则不能删 hook API,也不能关闭 `DOC-RELIABILITY-PILOT`。
## 成功标准
- 按消费者独立:shadow coverage → drain → 原子 live;E2 守卫使对应闭包停写。
- 授权页刷新/重启正文与 head digest 一致;未授权不泄露。
- 回滚开关保留一个发布窗口后再删 `OnOutbox` / `AddOnApprovedHook`。
- FAV 保持 disabled;项目 143 只读。
## 依赖
- E0A–E2 已合入;隔离库报告已归档。
- 需要明确授权:动共享 `agent-dev` 消费者 mode。
## 暂不启动原因
已完成共享 live 与生产去注册。方法本体保留一个窗口。
## 相关链接
- [Track E 复盘](../research/2026-09-15-track-e-retrospective.md)
- [E2 报告](../../test-reports/2026-09-15-event-e2-hook-guard-test-report.md)
- [gap-matrix DOC-RELIABILITY-PILOT](../../remediation/gap-matrix.md)
@@ -1,39 +0,0 @@
---
title: "D7a intent 与 bizdev 解绑"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/intent-bizdev-boundary
worktree: "-"
mutex: intent
---
# D7a intent 与 bizdev 解绑
## 目标
intent 只依赖成熟度词汇叶子包,不再 import bizdev。
## 范围
- `internal/maturity`
- intent 生产与表征测试
- bizdev 类型别名保持兼容
## 非目标
- 不改识别规则
- 不迁 coordinator / chatflow(D5/D7b)
## 步骤
1. [x] 叶子包与别名
2. [x] intent 切断 bizdev
3. [x] 表征测试与 arch-check
4. [x] 报告
## 验收标准
- [x] intent 生产 import 无 bizdev
- [x] [S4a 报告](../../test-reports/2026-09-15-intent-bizdev-boundary-test-report.md)
@@ -1,50 +0,0 @@
---
title: "清点旁支并收口已合入本地分支"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: chore/leftover-branch-cleanup
worktree: "-"
mutex: ops
---
# 清点旁支并收口已合入本地分支
## 目标
删除 tip 已是 `dev` 祖先的本地旁支与对应 worktree;不整支合入会回归或触红线的 5 条未合并分支;主仓跑一次 short 冒烟。
## 范围
- 拆 7 个已合入 worktree
- `git branch -d` 已 `--merged` 旁支
- CURRENT 记录故意保留的 FAV / herdr-removal / diagnosis / data-root / `dev-old-linear`
- vet / short / arch-check / health+ready
## 非目标
- 不整支 merge `feature/final-artifact-vault`;不启用 `FAV_DEGRADED_READ`
- 不合入 `feature/remove-herdr-agent-settings`(会回归 U12 arch-check、删 Herdr 脚本)
- 不合入 `fix/project143-controlled-content-404-diagnosis`(会回退审计关闭结果)
- 不合入 `fix/dev-runtime-data-root-guard`、`dev-old-linear`
- 不 push;不删 `origin/*`;不从 worktree 起 docker;不碰项目 143
## 步骤
1. [x] 占 CURRENT 集成槽
2. [x] 拆已合入 worktree
3. [x] 删除已 merged 本地旁支
4. [x] 冒烟并写报告
5. [x] 槽位 idle + archive
## 验收标准
- [x] 已合入旁支 worktree 只剩 FAV 错名目录
- [x] `--merged dev` 旁支已删(31 条)
- [x] 5 条未合入分支仍在
- [x] 测试报告 + health/ready schema 38
## 相关链接
- Test report: [../../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md](../../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md)
@@ -1,57 +0,0 @@
---
title: "审阅并修订模块解耦 Phase 2 方案"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Codex
branch: docs/module-decoupling-ipc-assessment
worktree: "-"
mutex: architecture-docs
---
# 审阅并修订模块解耦 Phase 2 方案
## 目标
以当前代码、migration、ADR 和 Phase 1 计划为证据,修正调研与 Phase 2 方案,并补齐高并发、互斥、权限、历史数据、灰度和回滚设计;不实施业务代码。
## 范围
- 复核调研报告与原 Phase 2 方案的事实、依赖和完成边界。
- 将事件可靠性、结构解耦、HTTP/PI 协议拆成独立轨道。
- 补充 PG 状态机、fencing、幂等、顺序、连接预算、权限、replay、脱敏、迁移和 browser/restart 验收。
- 同步 audit、remediation、CURRENT、FEATURE-MATRIX 与 gap-matrix。
## 非目标
- 不实现 dispatcher、consumer、migration 或协议代码。
- 不合并、部署、重启容器、删除数据或审计/合入 FAV 分支。
- 不把文档完成写成系统能力完成。
## 步骤
1. [x] 完成仓库启动链和上位 ADR/Phase 1 证据复核。
2. [x] 完成一致性、可行性、范围、安全、产品与对抗视角审阅。
3. [x] 修正调研报告中的 PG、依赖方向、allowlist 与进程边界事实。
4. [x] 重写 Phase 2 为 Track E/S/P,补齐详细实施和停走门。
5. [x] 同步索引与状态 SSOT。
6. [x] 执行文档链接、diff、冲突标记和术语检查。
## 验收标准
- [x] 调研不再把 SELECT-only Claim、MemoryBus 测试或 allowlist 基线写成生产闭环。
- [x] Track E 可独立关闭,FAV/D8/D9 不阻塞。
- [x] 方案明确 at-least-once 与 exactly-one visible outcome、最终提交点 fencing、集群级切换和授权模型。
- [x] 历史脏数据只分类/隔离/修复,不授权删除。
- [x] 文档状态一致且没有实施或发布声明。
## 相关链接
- Audit: [方案审阅](../../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- Remediation: [Phase 2 修订计划](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Research: [IPC/RPC 现状评估](../../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)
- Test report: 不适用(文档审阅,无业务实现)
## 证据 / 备注
本任务沿用用户已创建的 `docs/module-decoupling-ipc-assessment` 分支。该分支名早于当前 `feature/*|fix/*` 规则;未改写或重命名用户分支。起点提交为 `a3392e3` 与 `5cef856`,本轮未获授权 commit/push。
@@ -1,47 +0,0 @@
---
title: "PI typed-result-v1 P1–P4"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/pi-typed-result
worktree: "-"
mutex: pi-agent
---
# PI typed-result-v1 P1–P4
## 目标
Runner additive 输出 `result_v1`;Go typed-first fail-closed;共享 dev 真实 PI 双轨对账;去掉 stderr/legacy 明文错误。
## 范围
- `configs/schemas/pi-run-result-v1.json`
- `deploy/pi-agent/result-v1.mjs` + runner 接线
- `internal/agent` parser / 负例 / `RUN_PI_E2E=1` 双轨
## 非目标
- 不把 member 正文搬进 `result_v1`(仍走 `patches[]`)
- 不改 HTTP 状态码;不启用 FAV;不写项目 143
## 步骤
1. [x] Schema + Runner additive
2. [x] Go typed-first + handshake
3. [x] 真实 PI 双轨
4. [x] 删 stderr/隐式 legacy;报告与合入
## 验收标准
- [x] typed-present-invalid 永不 fallback
- [x] handshake downgrade 负例 PASS
- [x] `RUN_PI_E2E=1` 成功/失败/取消/超时对账
- [x] test-report 归档
## 相关链接
- Test report: `.doc/test-reports/2026-09-15-pi-typed-result-v1-test-report.md`
- Remediation: `.doc/remediation/2026-09-15-pi-typed-result-v1-remediation.md`
- P0: `.doc/ops/research/2026-09-15-pi-typed-result-p0-matrix.md`
@@ -1,45 +0,0 @@
---
title: "晋升 dev → test 并部署测试环境"
status: in_progress
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/promote-dev-to-test-2026-09-15
worktree: "-"
mutex: infra
---
# 晋升 dev → test 并部署测试环境
## 目标
把已完成的 Phase 2 代码从本地 `dev` 合入 `test`,重建并冒烟测试环境,供人工实测。不实施多意图 HITL。
## 范围
- `test` 分支 `--no-ff` 合入当前 `dev`
- `./scripts/env-service.sh test rebuild`
- test 库 notify/workflow_advance/projection 切 live(L4 去 hook 后 off 会停写);FAV 保持 off
## 非目标
- 不实施多意图 HITL U1+
- 不合入 `main`、不启用 FAV
- 不写项目 143
## 步骤
1. [x] 确认 Phase 2 已在本地 `dev`
2. [ ] occupy 集成槽并合入 `test`
3. [ ] rebuild 测试服务
4. [ ] health/ready + schema 冒烟
## 验收标准
- [ ] `:8081` health/ready PASS
- [ ] events `:8089` health PASS
- [ ] FAV 仍 off
## 相关链接
- CURRENT: `.doc/ops/CURRENT.md`
@@ -1,40 +0,0 @@
---
title: "D5 stageflow 类型归属与 D7b chatflow 首批"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: fix/stageflow-type-ownership
worktree: "-"
mutex: stageflow
---
# D5 stageflow 类型归属与 D7b chatflow 首批
## 目标
coordinator 生产代码不再 import bizdev;task/stage 请求走 stageflow 类型;chatflow assembler 改用 maturity。
## 范围
- stageflow 类型别名与状态常量
- coordinator 构造改为 StageTaskRunner + ContextServices
- chatflow 去掉 bizdev import
## 非目标
- 不复制行为方法成 DTO(身份别名 + token golden)
- 不删除 bizdev 八个 getter(D4)
- 不搬空 chat 包
## 步骤
1. [x] 类型边界与 coordinator 解绑
2. [x] chatflow assembler
3. [x] 表征测试与 arch-check
4. [x] 报告
## 验收标准
- [x] coordinator 生产 import 无 bizdev
- [x] [S2/S4b 报告](../../test-reports/2026-09-15-stageflow-type-ownership-test-report.md)
@@ -1,60 +0,0 @@
---
title: "M3 U8 TaskRun 终态与 RunManifest"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/taskrun-runmanifest
worktree: "-"
mutex: taskrun
---
# M3 U8 TaskRun 终态与 RunManifest
## 目标
TaskRun 终态在同一 UoW 内 CAS 写入唯一合法状态,并持久化类型化 RunManifest;重复 finalize / cancel race / SSE 断线不得产生第二条助手消息或第二份 artifact;workspace 清理仅在 verified receipt 之后。
## 范围
- Goose 00037 `task_run_manifests` + `finalizing` 状态
- `internal/taskrun` RunManifest 规范字节 / SHA / members
- `taskrun.Commands.Finalize` 唯一 finalize 命令;server 变薄
- `ctxmgr.FinalizeAssistantTaskMessage` 仅此写路径加入 UoW
- workspace 清理门禁;`ReadArtifact` 替代 `Join(workDir, "output.md")`
- BackendRef 服务端 policy;隔离库并发测试;占槽 rebuild;U8 报告
## 非目标
- U9 backfill / corpus / 八轨 / 销毁
- M4–M6;整支 merge FAV;启用 `FAV_DEGRADED_READ`
- 终止或改写项目 143
- 动 `chat` / `intent` 刷新任务
- worktree 内 `env-service`
## 步骤
1. [x] CURRENT 认领 `mutex=taskrun`;从本地 `dev` 开 `feature/taskrun-runmanifest`
2. [x] Goose 00037 Up+Down;`module-boundaries.yaml` 表属主
3. [x] Finalize 同 UoW:CAS + 助手 turn + manifest + envelope/staging
4. [x] 清理门禁与 server 去路径、BackendRef
5. [x] 隔离库双 pool / race;占槽 rebuild;报告最后一句只能「继续 U9」或「停止扩面」
## 验收标准
- [x] 重复 finalize:同一 status、同一 manifest SHA、助手消息 1 条、envelope/staging 不加倍
- [x] finalize ∥ cancel:恰好一个合法终态
- [x] SSE `done` 不出现在 TX 失败路径;commit 前断线重试不第二 turn
- [x] 无 verified receipt 则 cleanup FAIL;有 receipt 则可清 workspace 且 staging 仍能取出原 SHA
- [x] 报告最后一句为「继续 U9」或「停止扩面」;U9 清单项保持未勾
## 相关链接
- Checklist: [2026-09-14-module-decoupling-refactor-acceptance.md](../checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Remediation: [2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- 权威停走门: [2026-09-14-document-reliability-m2-test-report.md](../../test-reports/2026-09-14-document-reliability-m2-test-report.md)(继续 M3)
- Test report: [2026-09-15-taskrun-runmanifest-u8-test-report.md](../../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md)
## 证据 / 备注
未签字前禁止 U9–U12。合入 + 容器测占集成槽,主仓 `./scripts/env-service.sh dev rebuild`。
@@ -1,31 +0,0 @@
---
title: "Track P 协议实施(信封与 typed-result)"
status: done
created: 2026-09-15
updated: 2026-09-15
---
# Track P 协议实施(信封与 typed-result)
## 动机
H0/P0 盘点后独立实施 HTTP 信封与 PI typed-result,不回退事件 live。
## 成功标准
已关闭:
- [HTTP 信封 H1–H3](../../test-reports/2026-09-15-http-error-envelope-h1-h3-test-report.md)
- [PI typed-result P1–P4](../../test-reports/2026-09-15-pi-typed-result-v1-test-report.md)
## 依赖
mutex `server`/`web`/`pi-agent` 已释放。
## 暂不启动原因
已完成。
## 相关链接
- [Phase 2 计划](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
@@ -8,6 +8,8 @@ status: closed
# 交接:Herdr Agent 治理分支待集成
> **superseded 2026-09-14**:Herdr 角色/脚本已从活文档移除;本交接仅作历史证据。见 [.././2026-09-14-remove-herdr-agent-settings.md](.././2026-09-14-remove-herdr-agent-settings.md)。
## 目标(下一位 Agent 应完成什么)
治理规范已完成并准备合入 `dev`;本文件保留为集成证据。
@@ -36,9 +38,9 @@ status: closed
| 路径 | 说明 |
|------|------|
| `.doc/ops/2026-09-13-herdr-agent-roster.md` | 角色与路由 SSOT |
| `scripts/herdr-agent-start.sh` | 免人工审批启动入口 |
| `scripts/herdr-agent-dispatch.sh` | 主备派发与防重复策略 |
| `.doc/archive/ops/2026-09-13-herdr-agent-roster.md` | 角色与路由 SSOT(已归档) |
| `scripts/herdr-agent-start.sh` | 免人工审批启动入口(已删除) |
| `scripts/herdr-agent-dispatch.sh` | 主备派发与防重复策略(已删除) |
| `AGENTS.md` / `PROJECT.md` | 强制入口与 PI 身份边界 |
## 如何验证
@@ -59,5 +61,5 @@ git diff --check
## 相关链接
- CURRENT: [CURRENT.md](../CURRENT.md)
- Task: [2026-09-13-herdr-agent-governance.md](../../archive/ops/2026-09-13-herdr-agent-governance.md)
- Task: [2026-09-13-herdr-agent-governance.md](./2026-09-13-herdr-agent-governance.md)
- Checklist: 任务文中的验收标准
@@ -1,47 +0,0 @@
---
title: "发布门禁闭环 → production_ready"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
branch: docs/production-ready-flip
worktree: "-"
mutex: ci
---
# 发布门禁闭环 → production_ready
## 目标
按 gap-matrix 发布门禁勾选 B1–B4,对齐环境 schema 后翻 `production_ready=yes`。
## 范围
- B1 CI TEST_DATABASE_URL + 治理 PG(已完成)
- B2 真实 PI 三工作流 E2E(已完成)
- B3 对话全链路恢复(已完成)
- B4 版本冲突/终止 preview(已完成)
- B5 SSOT 翻旗 + main schema 对齐(已完成)
## 非目标
- 多意图 U9–U12、软件项目自举、FAV、完整 PI change-report 叙事
## 步骤
1. [x] B1 BUG-08
2. [x] B2 PI E2E
3. [x] B3 chat refresh + restart
4. [x] B4 conflict + termination-preview + envelope unwrap
5. [x] B5 merge/smoke、main rebuild 迁库、翻旗
## 验收标准
- [x] gap 门禁四框可勾(含对话与前端)
- [x] FEATURE-MATRIX / gap / CURRENT `production_ready: yes`
- [x] main/dev/test health schema_version=47
## 相关链接
- Test reports: `2026-09-16-ci-governance-pg-bug08`、`pi-three-workflow-e2e`、`chat-refresh-gate`、`frontend-gate-b4`
- gap-matrix / FEATURE-MATRIX / CURRENT
@@ -76,7 +76,7 @@ severity: high
## 关联整改
- Remediation: [../remediation/2026-09-13-chat-history-refresh-remediation.md](../remediation/2026-09-13-chat-history-refresh-remediation.md)
- Short-term: [../archive/ops/2026-09-13-chat-history-refresh-remediation.md](../archive/ops/2026-09-13-chat-history-refresh-remediation.md)
- Short-term: [../ops/short-term/2026-09-13-chat-history-refresh-remediation.md](../ops/short-term/2026-09-13-chat-history-refresh-remediation.md)
- Gap matrix: [../remediation/gap-matrix.md](../remediation/gap-matrix.md)
## 证据
+21 -33
View File
@@ -1,22 +1,20 @@
---
title: "arch-check U1 可重放基线"
title: "arch-check Wave 0 基线"
status: done
created: 2026-09-14
updated: 2026-09-14
severity: medium
---
# arch-check U1 可重放基线
# arch-check Wave 0 基线
## 现象
Wave 0 的全仓 grep 会把 Goose、`*_test.go` 和路径字面量一视同仁,无法作为生产写者门禁。U1 用 `go list` + AST/正则拆成四类规则,并给每条既有债写明 owner、原因、截止里程碑和到期日。
模块边界此前只能靠人工约定。Wave 0 用当前 `go list` 生成 import allowlist,并用目标属主扫描表名与路径字面量,得到可重复的 warn 基线。
## 根因分析
- `document_records` 的生产写者不止 `docgov`:`docrevision.projectRootPointersTX` 与 `docduty` 职责槽位仍直接 `UPDATE`。
- `output.md` / `data/dev` / `workspaces/` 仍被 agent、bizdev、coordinator、docgov、docrevision、server、storage 用 `filepath.Join`、字符串字面量或间接常量构造。
- Goose 与测试夹具大量出现同样表名,不能算生产写者债。
`document_records`、`output.md`、`data/dev` 被多个包直接提及,与「单一写者 / 路径属主」目标不一致。这些不是本轮回归,而是 Wave 1+ 的收口对象。
## 严重度
@@ -26,39 +24,29 @@ Wave 0 的全仓 grep 会把 Goose、`*_test.go` 和路径字面量一视同仁
- ADR: [../adr/2026-09-14-modular-monolith-decoupling.md](../adr/2026-09-14-modular-monolith-decoupling.md)
- 设计: [../system-design/2026-09-14-module-decoupling-architecture.md](../system-design/2026-09-14-module-decoupling-architecture.md)
- 边界: [../system-design/module-boundaries.yaml](../system-design/module-boundaries.yaml)
- 任务: [../ops/short-term/2026-09-14-document-reliability-pilot.md](../ops/short-term/2026-09-14-document-reliability-pilot.md)
- 任务: [../ops/short-term/2026-09-14-module-decoupling-wave0.md](../ops/short-term/2026-09-14-module-decoupling-wave0.md)
## 证据
命令(2026-09-14,`refactor/document-reliability-pilot` worktree):
命令:`./scripts/arch-check.sh --mode warn`(2026-09-14,本工作区)
- import 相对基线 allowlist:**0** 条新边
- 目标属主扫描:**21** 条 warn(按包去重)
```
./scripts/arch-check.sh --mode warn
go test ./internal/archtest -count=1
WARN R5 table document_records mentioned in authz, workspace, docduty, server, bizdev, docrevision
WARN R5 table freeform_documents mentioned in docrevision
WARN R5 table task_runs mentioned in server, projectinstance, docgov
WARN R6 path output.md mentioned in coordinator, server, bizdev, docgov, docrevision, agent
WARN R6 path data/dev mentioned in coordinator, server, bizdev, storage
WARN R6 path workspaces/ mentioned in server
violations=21
arch-check warn: recorded 21 baseline findings
```
可重放计数(只含生产 Go;Goose/`*_test.go` 不计):
`--mode block` 会因这 21 条失败,故 **不得**在 warn 期满前把脚本挂进集成冒烟。
| 规则 | 计数 | 处理 |
|------|------|------|
| import | 0 | 相对 2026-09-14 production `go list` allowlist,无新边 |
| sql_write | 5 | 例外,U3/U8 到期 |
| path | 17 | 例外,U4/U5/U8 到期 |
| event | 0 | `OnOutbox` 生产者属主为 docrevision,server/notification 为消费者 |
## 后续
验证:
- `deploy/postgres/goose` 与 `*_test.go` 出现 `document_records` 不报生产写者违规。
- 迷你仓 `internal/server/rogue_write.go` 新增 `UPDATE document_records` 时 `go test ./internal/archtest` 失败并指出文件。
- `filepath.Join`、字符串拼接、间接常量构造 `output.md` 均可检出。
- 无到期日例外、过期例外立即 block。
- `baseline_counts` 锁定现有计数,只能下降。
`--mode block` 在例外清零前会失败,不得挂进集成冒烟。
## 开放问题
- U3 收口 `document_records` / `freeform_documents` 跨属主写。
- U4/U5 收口 handler 与投影路径构造。
- U8 收口 `task_runs` 终止写与 finalize `output.md`。
- Wave 1 起按属主清零上表,再把对应规则转 block
- 本轮不占集成槽、不 `env-service` rebuild
@@ -1,98 +0,0 @@
---
title: "模块解耦方案复核"
status: done
created: 2026-09-14
updated: 2026-09-14
scope: architecture, transactions, concurrency, authorization, events, artifact recovery
---
# 模块解耦方案复核
## 结论
模块化单体、单一写者、瘦传输层和应用编排层的方向成立,但原方案不能直接批准 Wave 1–6。
原方案把事务、事件、工作区和最终成果四条边界拆开设计,可能在包依赖减少后产生新的数据不一致、跨租户授权旁路和不可恢复投影。
整改应先打通一条真实文档纵向链路,再按证据决定是否扩展到 chat、squad、SSE 和 PI Runner。
## 已确认问题
### A1. 单一写者拆分会破坏跨表原子性
`internal/docrevision/pg_mutate.go` 当前在一个事务中写版本账本并投影 `document_records` 根指针。
原方案要求 docrevision 改调 docgov/freedoc 普通端口,却没有定义跨属主事务或命令所有权。
如果各端口各自提交,会出现版本账本、正文 head、治理状态和 outbox 部分成功。
### A2. 现有 outbox 不是可泛化的可靠事件总线
`internal/docrevision/service.go` 在版本事务完成后调用 `OnOutbox`,并忽略回调错误。
`outbox_events` 只有全局 `published_at`,没有逐消费者确认、租约、重试、死信和幂等收件箱。
拟议的 `Publish(ctx, event)` 也没有事务作用域,不能兑现“与业务同事务”。
### A3. 工作区仍被当成事实源
原 `WorkspaceRef` 暴露 `Root`、`OutputDir` 和 `ManifestPath`,`OutputContract` 继续接受裸路径。
这不能从类型上阻止路径拼接、跨工作区访问或链接逃逸。
docquery 若继续在运行时从 `output.md` 选择正文,会保留导致历史 404/409 的 split-brain 根因。
### A4. 最终成果保险库未进入模块边界
`feature/final-artifact-vault` 已设计并实现终态归档、只读降级和 scratch 恢复,但尚未合入当前 dev 基线。
原解耦方案没有为 artifactvault 分配端口、事件、授权和恢复边界,后续容易由 docquery 或 CLI 重建旁路。
### A5. contracts 可能成为新的高扇入万能包
原方案把内部接口、HTTP DTO、事件、错误码和共享枚举集中到一个包,并要求所有 DTO 版本化。
这会把语义耦合搬到 `contracts` 和 `app`,使普通内部调整承担不必要的 ADR 成本。
### A6. 并发控制只覆盖了进程内互斥
当前代码同时存在 `sync.Mutex`、行锁、乐观 ETag、唯一幂等键和 `pg_advisory_xact_lock`。
原方案没有规定哪些锁用于正确性、锁顺序、超时、重试边界和多副本行为。
进程内锁只能优化单实例竞争,不能作为跨实例正确性条件。
### A7. 授权主体和后台执行边界缺失
“在应用层入口统一授权”没有定义可信 Principal 的来源,也没有覆盖 CLI、事件订阅者、恢复工具和后台任务。
若端口继续接受调用方填写的 `UserID`、`ProjectID` 或裸 `DocRef`,可能形成 confused-deputy 或跨项目访问。
### A8. 横向 Wave 缺少最小可交付边界
原方案先物理搬包,再接口化,最后才处理单写者和事件语义。
这会重复修改高扇出代码,并在真正验证边界之前冻结大量无消费者契约。
错误信封和 PI Runner 协议与文档一致性解耦没有直接依赖,不应阻塞核心路线。
### A9. 迁移与回滚承诺不成立
可靠多消费者 outbox、FAV 集成和必要的状态字段需要增量 migration,因此“数据零迁移”不成立。
后续里程碑会依赖前序契约,不能任意独立 revert;只能按 expand/migrate/contract 阶段和兼容窗口回退。
### A10. 架构检查范围会产生误报
表名和路径字面量合法存在于 Goose migration、fixture、测试和运维脚本。
R5/R6 应检查生产运行时的越权写入和路径解析,不应以全仓 grep 的零出现作为完成条件。
## 外部规则核对
- PostgreSQL 行锁和事务级 advisory lock 会在事务结束时释放,适合短期业务互斥;session 级 advisory lock 不跟随回滚,不用于本方案的业务锁。[PostgreSQL explicit locking](https://www.postgresql.org/docs/17/explicit-locking.html)
- `SKIP LOCKED` 适合多消费者队列表,不适合作为普通一致性查询语义。[PostgreSQL SELECT](https://www.postgresql.org/docs/current/sql-select.html)
- Serializable 或 deadlock 重试必须重跑完整事务,包括决定 SQL 和参数的业务逻辑。[PostgreSQL serialization failure handling](https://www.postgresql.org/docs/16/mvcc-serialization-failure-handling.html)
- 授权必须默认拒绝,并在每次请求或后台动作上重新校验,不能信任客户端传入的身份和资源归属。[OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html)
## 整改结论
1. 暂停批准原 Wave 1–6,保留只读架构基线。
2. 先定义事务、锁、授权、事件和持久成果契约。
3. 首个交付只覆盖受控文档读取与终态提交纵向链。
4. FAV、迁移语料和完整备份作为三个互补层接入。
5. 通过真实页面刷新、重启、并发、权限和恢复停走门后,再批准其他模块拆分。
## 证据入口
- `internal/docrevision/pg_mutate.go`
- `internal/docrevision/service.go`
- `internal/workspace/resolver.go`
- `internal/docduty/revoke.go`
- `internal/taskrun/manager.go`
- `deploy/postgres/goose/00018_2026-09-12-outbox-notifications-stage-advance.sql`
- `.doc/adr/2026-09-13-document-version-boundary.md`
- `feature/final-artifact-vault` 分支中的 FAV ADR、整改方案与测试报告
@@ -1,56 +0,0 @@
---
title: "planning 项目残留 active_workflow_key 异态审计"
status: done
created: 2026-09-14
updated: 2026-09-14
severity: low
---
# planning 项目残留 active_workflow_key 异态审计
## 现象
dev 库存在 `lifecycle_status='planning' AND active_workflow_key <> ''` 行。评审时记为 81;本轮只读复测为 **83**(相对评审 +2)。这些行看起来像「已选工作流但未走设置激活」。
## 根因分析
关闭 `initial_workflow_key` 直通前,`CreateProject` 在键非空时会写 `lifecycle=active` + `ActiveWorkflowKey`。本异态是 **planning 却带 key**,更符合自动化测试夹具成对插入(`PROJ_MGR_*` / `TEST_PROJ_*`),而不是真实用户走创建旁路后的 active 项目。
本轮 **未** `UPDATE`/`DELETE`。
## 严重度
`low`
创建旁路已在 `fix/governance-action-level-authz` 关闭。存量 83 行全部无 live 实例、无创建人,不影响项目 143,也不阻塞 G1 鉴权矩阵。
## 关联整改
- Short-term: [2026-09-14-governance-action-level-authz](../archive/ops/2026-09-14-governance-action-level-authz.md)
- Research: [2026-09-14-mvp-governance-rules-review](../ops/research/2026-09-14-mvp-governance-rules-review.md)
## 证据
只读查询(`shuimu-context-pg-dev` / `agent_system_dev`,2026-09-14):
| 指标 | 数量 |
|------|------|
| `lifecycle=active` | 141 |
| `lifecycle=planning` | 209 |
| `planning AND active_workflow_key <> ''` | **83** |
分类(禁止改库,仅标注):
| 分类 | 数量 | 判定 |
|------|------|------|
| 测试夹具 | **83** | `code` 为 `PROJ_MGR_YYYYMMDDHHMMSS`(名「智能微创内窥镜」)或 `TEST_PROJ_*`(名「测试内窥镜系统」);`active_workflow_key=main`;`workflow_selection_version=1`;`creator_user_id` 空;`has_live_instance=false`;时间戳成对出现于 2026-09-12~09-14 |
| 历史直通(真实用户创建旁路) | **0** | 无非夹具命名、无创建人、无 live 实例的业务项目 |
| 不明 | **0** | — |
样本 id(完整 83 行均属上表夹具模式,不逐条展开):61–62、122–128、6015–6021、6160–6161、6192/6195。项目 **143 不在此集合**。
相对评审 81 的 +2:`6192` / `6195`,创建于 2026-09-14 07:26 UTC,仍是同一对夹具命名。
## 开放问题
- 是否在后续专项清理夹具行(需单独任务与备份,不在本治理鉴权波次)。
@@ -1,85 +0,0 @@
---
title: "前端 mock 交付物污染真实项目:幻影受控文档伪造终审已生效态与法定职责"
status: done
created: 2026-09-15
updated: 2026-09-15
severity: critical
---
# 前端 mock 交付物污染真实项目:幻影受控文档伪造终审已生效态与法定职责
## 现象
用户在 **test 环境**(127.0.0.1:8081)新建测试项目「测试项目」(test 库 `projects.id=1`,唯一项目),工作台立即显示 11 份「受控文档」,其中包括与该项目毫无关系的:
- 《4K超高清荧光内窥镜系统立项与可行性报告》
- 《微创外科内窥镜全球竞品技术与临床深度调研报告》
- 神经外科双频超声吸引(NeuroPulse)系列
- CUSA 超声手术吸引系统系列
这些文档:
1. 显示**伪造的生命周期状态**(`reviewing` / `approved`——`DeckDrawer.tsx` 将 `approved` 渲染为「**终审已生效**」),即用户所称「生效区」出现从未经过任何 docgov 生命周期流转的"已生效"文档;
2. 带有**伪造的法定职责人**(author 张工 / reviewer 李主管 / approver 王总监——均非真实用户);
3. 带有伪造版本号(V1.0)、伪造更新时间、伪造正文全文;
4. 在项目成员视角按真实受控文档参与 RBAC 可见性过滤与工作流槽位合并,**与真实服务端文档混排**。
而 test 库 `document_records` 为 **0 行**——服务端受控文档台账完全为空,这 11 份文档**全部来自前端硬编码 mock 数据**。
## 根因分析
### 1. mock 交付物硬编码绑定 projectId 1/2/3/5201/6001–6010
`web/src/App.tsx:267` `INITIAL_DELIVERABLES` 硬编码 7 份 mock 交付物 `projectId: 1`(doc-001~004、doc-shared-001、doc-private-001/002);`P2_INITIAL`(projectId 2)、`CUSA_INITIAL_DELIVERABLES`(projectId 3)、`NEUROPULSE`(5201)、`TEN_PROJECTS`(6001+)同理。`ALL_INITIAL_DELIVERABLES` 聚合后作为 `loadDeliverables()` 的默认值(App.tsx:621),并经 `saveDeliverables` **写入 localStorage 持久化**。
### 2. 项目过滤按数字 ID 匹配,新建项目与 mock 项目 ID 撞车
`App.tsx:1014`:`currentProjectDeliverables = deliverables.filter(doc => doc.projectId === currentProjectId)`。
- test 库为全新库,用户新建的第一个项目得到 `id=1` → 与 mock 的 `projectId: 1` **精确撞车**,7 份幻影文档全部"归属"该项目;
- 新建项目时 `createProjectTemplateDeliverables`(App.tsx:3844)再克隆 7 份模板骨架(`doc-p1-*`,`lifecycleState: 'template'`,合规)→ 7 mock + 4~7 模板/私有,构成用户看到的 11 份;
- **dev 库同样中招**:`agent_system_dev.projects` 存在真实项目 id 1–8(智能微创内窥镜/测试内窥镜系统等),id 1/2/3 的真实项目同样被 mock 文档污染。
### 3. mock 正文与 mock 用户/权限无环境门控,已进生产构建产物
- `mockDocuments.ts` 无任何 `import.meta.env` 门控;`App.tsx` 中 `MOCK_USERS`(含伪造 `projectPermissions: {doc-001: approver...}`)作为 `loadUsers()` 默认值与 `currentUser` 初始身份兜底(App.tsx:610/617);
- **构建产物已验证污染**:`web/dist/assets/index-DogUjae5.js` 中 grep 命中「4K超高清荧光」字符串——dev/test/main 三环境共用同一前端构建,main 生产环境同样受影响。
### 4. 既有防线只挡"正文请求",不挡"清单展示"
团队已知悉 legacy mock ID(`revisionToolbarMount.ts:24 isLegacyLocalMockDocId`:`doc-\d{3}` / `doc-shared-*` / `doc-private-*` / `doc-cusa-*`),并禁止它们发起 content/revision 请求(`controlledDocHydrate.ts:shouldLoadControlledContent` 排除)。但这只防住了「幻影文档冒充服务端正文」,**没有防住幻影文档出现在交付物清单、生命周期徽章(终审已生效)、职责栏与项目文档统计中**——用户看到的正是后者。
### 5. 服务端权威清单未做前端对账
`GET /api/v1/projects/{id}/documents`(`docgov/project_docs.go`,`WHERE project_id=$1 AND task_key<>''`,服务端已正确按项目隔离)返回空数组时,`mergeWorkflowDocumentsFromServer`(`deliverableSync.ts:41`)**直接 `return prev`,不删除本地多余项**——本地幻影文档无任何下架机制。
## 严重度
`critical`:
1. **治理完整性破坏**:空项目展示「终审已生效」受控文档 + 三级法定职责人,在医疗器械合规语境下(ISO 13485 / 21 CFR Part 11 电子记录可靠性)构成"记录失实";
2. **跨环境广泛影响**:dev 真实项目 id 1–8、test 新建项目、main 生产同构建产物全部受影响;
3. **权限视图失真**:伪造职责人/权限映射混入 RBAC 过滤链,用户对"谁可审批什么"产生错误认知;
4. 既有防线(isLegacyLocalMockDocId)证明团队已两次踩坑(本审计为同域第三类症状),说明 mock 数据保留策略系统性不足。
## 关联整改
- Remediation: [2026-09-15-mock-deliverables-pollution-remediation.md](../remediation/2026-09-15-mock-deliverables-pollution-remediation.md)
## 证据
- test 库(`shuimu-system-pg-test`,127.0.0.1:5434):`projects` 仅 id=1「测试项目」(通用医疗器械);`document_records` 0 行;全库 87 张业务表除 projects/users/auth_sessions/chat_sessions/project_workflows 外全部为空
- dev 库(`shuimu-context-pg-dev`,127.0.0.1:5433):真实项目 id 1–8(智能微创内窥镜 / 测试内窥镜系统)→ 与 mock projectId 1/2/3 撞车
- `web/src/App.tsx:267-498`(INITIAL_DELIVERABLES/P2/CUSA/ALL_INITIAL_DELIVERABLES)、`621`(loadDeliverables)、`1014`(projectId 过滤)、`3844`(新建克隆模板)
- `web/src/data/mockDocuments.ts:32-505`(mock 文档全文与伪造 lifecycleState/职责人)、`web/src/data/seeds/neuropulseSeed.json`(projectId 5201)、`tenProjectsSeed.json`(6001–6010)
- `web/dist/assets/index-DogUjae5.js`:grep 命中「4K超高清荧光」(生产构建含 mock 数据)
- `web/src/features/documentRevision/revisionToolbarMount.ts:24-32`(isLegacyLocalMockDocId 既有防线)
- `web/src/lib/deliverableSync.ts:41-45`(serverDocs 空时不回收本地项)
- `web/src/components/doc/DeckDrawer.tsx:87-103`(approved → 「终审已生效」渲染)
- `web/src/api/projectDocuments.ts:46-58`(服务端清单 API,服务端隔离正确)
## 开放问题
- mock 数据的保留意图(demo 演示模式?)需要在整改方案中决策:彻底移除 vs 环境门控(`import.meta.env.MODE` / 构建期注入 `VITE_ENABLE_DEMO_SEEDS`)
- localStorage 中已被 `saveDeliverables` 持久化的 mock 项,需要一次性迁移清理(对齐既有 `dropRecordKeys`/ControlledInvalidationPlan 机制)
- main 环境是否已有真实用户看过幻影文档(`document_access_audit` 为 0 行,无服务端读取痕迹,风险主要在前端展示层)
@@ -1,111 +0,0 @@
---
title: "模块解耦 Phase 2 方案审阅"
status: done
created: 2026-09-15
updated: 2026-09-15
severity: high
---
# 模块解耦 Phase 2 方案审阅
## 结论
模块化单体、消费者端口、组合根和持久事件的方向成立,但原 Phase 2 方案不能直接进入实施。它把事件可靠性、结构整理和两个外部协议绑成一个完成目标,并基于数项不成立的代码事实设计切换门。修订版已把 Track E(持久事件)、Track S(结构解耦)、Track P(外部协议)拆开,Track E 必须先完成生产者与历史数据门,再启动 dispatcher。
## 高优先级发现
### A1. PG delivery 尚未形成生产闭环
`internal/events/pg.go` 的 `ClaimIDs` 只做 SELECT + `FOR UPDATE SKIP LOCKED`,没有在同一事务写 lease owner/token/until;也没有 PG ack/fail/retry/dead-letter 的完整生产实现。`internal/events/dispatcher_test.go` 验证的是 MemoryBus。原方案把这些能力写成“已有”,会低估 D1 的 migration、状态机和故障测试范围。
整改:D1 增加 additive migration、原子 lease、heartbeat、fenced side-effect/ack、retry/dead/quarantine、不可变 attempt 表和独立 `cmd/events` 进程。
### A2. “恰好一次投递”不可由当前算法保证
副作用成功后、ack 前崩溃会导致重放。Fencing 若只拦 ack,也拦不住租约过期的旧 worker 提交副作用。
整改:契约改为 at-least-once delivery + exactly-one visible outcome。Token 进入 consumer command 和最终提交点;数据库副作用与 inbox/token 校验同事务,projection 使用 expected version、digest 和单调 marker。
### A3. 原 shadow 定义会双写,且按天零差异可空跑通过
旧方案同时写闭包和消费者结果,却又称“不产生可见变化”;两者矛盾。三天 dev 流量也可能没有低频文档事件或失败分支。
整改:闭包是 shadow 期间唯一真实写者。消费者只计算 normalized intended outcome 并写 reconciliation。停走门同时要求预登记样本、分支覆盖、最短时间和零未解释 diff;生产入口未证明出事件前不开始计时。
### A4. 文档事件源与作用域尚不可信
部分生产 HTTP 路径临时构造 `docflow.Commands`,没有稳定注入 EventSink/UoW。`Environment:"dev"`、`ProjectID:0` 和 FAV stage project 0 会使跨环境/项目 delivery 失真。
整改:E0A 先由组合根注入唯一命令对象;领域变化、envelope、delivery 同一 UoW;缺 project/env fail closed;旧数据先 inventory。
### A5. AggregateVersion 不能直接当无缺口事件序号
当前只在部分领域转换发事件。历史文档首次事件可能从较高版本开始;按缺号等待会永久阻塞。
整改:D11 在独立 event sequence 与 consumer checkpoint/bootstrap 中二选一,审计现有 aggregate/version 唯一约束并迁移。未决前禁止开启 gap blocking。
### A6. docgov/docrevision 不是双向 import
生产方向为 `docgov → docrevision`,用途集中在 canonical Markdown 与 SHA helper。原方案“提升无行为类型到 vocabulary”不能承载 canonicalization 行为。
整改:D6 改为提取内聚 `doccontent` 行为模块和 golden vectors;D6 可独立执行,不依赖 bizdev/stageflow。
### A7. event allowlist 已存在
`module-boundaries.yaml` 已有 `event_producers`/`event_consumers`。问题是映射稀疏,且运行时注册没有与静态清单做 parity 检查。
整改:D10 提升到 E0A,补 payload schema/version、enabled state 与 registry parity;FAV 标记 disabled。
### A8. FAV、HTTP、PI 不应阻塞核心
FAV 分支未完成独立审计。ADR 已把 HTTP 错误信封和 PI result protocol 定义为独立工作。把三者放入 Track E DoD 会延迟最有价值的刷新恢复闭环。
整改:Track E 只激活 notify、workflow advance、projection。FAV 只预留 disabled 契约;D8/D9 分别另建 remediation。
### A9. Replay、后台权限与日志脱敏不足
延迟事件不能沿用历史用户权限;当前 replay 校验不足以支持生产 apply。Raw payload/error 进入 dead-letter 或 reconciliation 会泄露正文、路径或凭证。
整改:每 consumer 独立 service principal,处理时重读资源和当前权限。Replay 采用 capability + 精确范围 + dry-run digest/apply exact digest + 审计;多项目/批量 apply 两人批准。日志只存 ID/digest/typed code/sanitized summary。
### A10. 滚动切换缺少集群级权威写者
删除新版本 hook 不会阻止旧实例继续执行。若 dispatcher 同时 live,滚动部署会双写。
整改:`off|shadow|live` 使用带 revision 的集群级状态;先部署兼容代码、drain 全部旧实例、记录 backlog 水位,再原子切换。回滚先暂停 claim并核对 receipt/backlog。
### A11. Locator 门禁原文过宽
全局禁止 `*pgxpool.Pool`/`pgx.Tx` 会拦截组合根注入与登记表属主的合法 UoW unwrap。
整改:只禁止领域/用例 API 暴露、返回、转发 pool/tx;明确允许 app/cmd 构造注入和登记属主 unwrap。
## 范围修订
| 轨道 | 内容 | 关闭条件 |
|---|---|---|
| Track E | D1/D2/D3/D10/D11 | PG + browser + restart + auth/replay 证据完成后独立关闭 |
| Track S | D4/D5/D6/D7a/D7b | 各单元独立 go/no-go 与报告 |
| Track P | HTTP error、PI typed result | 各自独立 remediation,不阻塞 Track E/S |
## 关联整改
- [修订后的 Phase 2 计划](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- [修订后的现状调研](../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)
## 审阅方法与证据
- 代码证据:`internal/events/pg.go`、`bus.go`、`dispatcher_test.go`、`replay.go`、`internal/app/docflow/commands.go`、`internal/docgov/lease.go`、`internal/bizdev/service.go`。
- Schema:`deploy/postgres/goose/00035_2026-09-14-durable-event-delivery.sql`。
- 边界:`.doc/system-design/module-boundaries.yaml`。
- 上位决策:模块化单体 ADR 与 Phase 1 U6。
- 审阅视角:一致性、可行性、范围、安全、产品价值、对抗失败预演;外部 reviewer 的有效结论仅用于交叉验证,不替代仓库证据。
## 开放问题
以下问题必须由 E0A 的代码/数据审计回答,不能在计划阶段猜测:
- projection consumer 的最终 owner 与 no-replace 提交接口。
- event sequence 或 checkpoint/bootstrap 的选择及迁移成本。
- 每类事件前 7 天基线流量、shadow 样本 N 和 worker 连接预算。
- 现存错误 scope/schema delivery 的数量和 repair/quarantine/expire 分类。
@@ -1,122 +0,0 @@
---
title: "多意图与 HITL 方案复核"
status: done
created: 2026-09-15
updated: 2026-09-15
severity: high
---
# 多意图与 HITL 方案复核
## 结论
提案方向合理,且可复用现有 IntentFrameV2、ActionRegistry、PendingExpectation、交互卡和可靠事件骨架。但初稿不能直接实施:它会让 LLM backend 进入 `internal/intent`、把跨模块执行继续堆入 coordinator,并以不足以抵御多实例竞态的 PlanID+StepID 代替状态机和动作幂等,存在解耦回退、越权和双执行风险。
已按审阅结果重写[系统设计](../system-design/2026-09-15-multi-intent-hitl-plan.md)与[任务总览](../ops/short-term/2026-09-15-multi-intent-hitl.md)。本次仅修改文档,没有实施业务代码。
## 已确认问题
### P1:原 LLM 接线破坏 intent 纯模块边界
初稿要求在 `internal/intent/segmenter.go` 经既有 `agent.Backend` 分段;当前边界只允许 `intent -> maturity`。照此实施必然新增 intent 到 agent/coordinator 的依赖。
**整改:** 规则分段留在 intent;可选 LLM 仅作为 `app/intentflow` 外围 adapter,返回不可信分段建议,每段重新走确定性识别、安全扫描和 ActionRegistry。任何阶段都禁止 intent import agent、PG、storage 或 coordinator。
### P1:计划持久化缺少权威状态机与并发协议
初稿两表只有宽泛 status/payload,PlanID+StepID 只是标识,不能防重复确认、确认/取消/过期竞态、两个 worker 同时执行,也不能处理业务成功而步骤 receipt 未落库的崩溃窗口。
**整改:** 增加 plan revision/digest、append-only decisions、expected revision、decision nonce、步骤 CAS、lease/fencing、动作级幂等 receipt 和恢复对账。PG 是唯一权威;UserProjectContext/消息只保存 plan 引用。
### P1:确认未与当前授权绑定
持久化 user/role 或用户曾经确认都不能证明执行时仍有权。原稿没有要求恢复、读取和每步执行重新检查当前项目成员、duty、资源生命周期与版本。
**整改:** 确认只记录意愿;所有读取/决策验证 user/session/project 四元作用域;每步由动作 owner 按当前 principal 和 expected resource version 重新授权。失败 fail closed,不以系统身份代执行。
### P1:执行器方案会让 coordinator 再次成为 service locator
初稿拟扩展 `coordinator/action_planner.go` 的分发表来执行写动作,会把 docgov/taskrun/workflow 等具体实现重新聚集到 coordinator,抵消已完成的 chatflow/stageflow/bizdev 解耦。
**整改:** 新增深模块 `internal/app/intentflow` 作为计划生命周期 owner,通过消费者拥有的窄端口调用动作属主;coordinator/chat 仅保留兼容入口,组合根唯一装配。
### P1:事件与 SSE 被混为一条通道
现有 Track E 只处理注册的 PG 事件,不会自动把任意 delivery 变成 SSE。若只发 SSE,刷新丢失;若只写 outbox,浏览器不会自动得到状态。
**整改:** 计划状态同步落库;outbox 只发布版本化状态事实并驱动消息/read model 投影;SSE 是提交后的提示。刷新总是 GET PlanView。事件先登记 YAML、StaticContracts 和 payload allowlist。
### P1:不确定分段会退回单意图执行
“置信下降/指代补全失败就合并回单意图”与“不确定必须澄清、未确认零副作用”矛盾,仍可能执行 TopIntent 并丢弃其余任务。
**整改:** 只有确定为完整单意图连动时才合并;低置信、指代失败或无法证明完整一律澄清,保留候选理解但不执行。
### P1:数据复制与步骤传递缺少信任边界
初稿可能把原文、槽位、结果复制到 JSONB、日志、事件、SSE,再把查询摘要直接注入 task brief,扩大敏感数据面和提示注入路径。
**整改:** 计划保存消息引用/digest/allowlist display snapshot;事件和日志仅传 scope、状态与安全摘要引用;步骤间使用带 provenance/type/digest/sensitivity 的 ResultReference。结果只能进入隔离材料区,不能修改 action、target、tool 或 capability。
### P1:灰度开关顺序错误
现有 MULTI_INTENT_ENABLED 默认 true;初稿到最后一阶段才新增 tier,会让中间合入的行为缺少默认关闭门。
**整改:** U1 先建立默认 legacy 的新 tier;U2 只 shadow;auto_read 先维持两个查询的当前上限;确认和每个动作 adapter 分档开放。回滚必须继续支持已有计划读取/取消/收口。
## 重要产品修订
- 无活动写计划时单意图生成行为保持不变;多意图 generate 的确认/tier/adapter 能力由 intentflow BatchActionPolicy 管理,静态风险仍引用 ActionRegistry;
- 计划卡默认显示一句摘要和主动作,详细风险/步骤折叠展开,降低认知负担;
- 自然语言“确认”只有在当前会话恰有一个活动可见计划时才绑定;多计划或混入新任务时澄清;
- 聚合澄清不承诺一次自由文本必然填满所有槽位;只接受可唯一映射值,槽位依赖/冲突继续追问;
- 部分确认默认是分批批准,未选项保留待确认;只有显式排除才取消,部分完成提供重试/继续/关闭;
- 单意图生成兼容承诺只适用于当前没有活动写计划;有活动计划时统一冲突视图,避免双任务;
- 多意图价值必须用采用率、确认放弃率和拆单回退率证明;价值不足时停止写动作扩面,但保留“不静默丢任务”的安全改进。
- 批量确认、tier 和 adapter 策略归 intentflow 的 BatchActionPolicy;ActionRegistry 只保留动作身份与静态风险,避免编排政策回灌 L1;
- 计划卡折叠态仍显示目标、最高风险、不可撤销副作用和非原子语义;技术元数据才可折叠;
## 并发与权限检查表
- 同 turn 同 digest 返回原计划;同 turn 异 digest 冲突;
- decision 带 expected revision、nonce 与 digest;
- plan/step CAS 与单调 fencing;
- fencing 和幂等占位必须进入动作属主事务,只锁计划行不足以阻止旧 worker 副作用;
- confirm/cancel/expiry/edit 只有一个胜者;
- 部分确认必须依赖闭包;
- 双标签、双实例、worker 接管最多一次副作用;
- 跨 user/project/session 不可读、不可确认且不泄露存在性;
- 确认后成员/职责/资源状态变化仍会拒绝执行;
- SSE 重复、乱序、缺失由 GET reconcile;
- CSRF/Origin 沿用服务端认证策略,nonce 不冒充 CSRF。
- active-plan discovery 是刷新必需入口,不能依赖消息投影中恰好保存 plan_id。
## 范围与任务修订
原 T1–T5 被重拆为核心 U1–U8、可选实验 U9 和属主扩面 U10–U12:契约门禁、纯规则 shadow、持久计划、事件投影、决策/授权、Web、只读执行、task generate 首版、LLM adapter、mutate/docgov/workflow-run 分项扩面。每个单元有独立依赖、文件范围、测试、停走门与真实 mutex。总览不长期占用 `intent`;每个 action 仍需独立 short-term。
## 评审覆盖
- 本地视角:coherence、feasibility、security、scope、product、design、adversarial;
- 独立 cross-model:Claude Opus 5/high 的 security、product、adversarial 与 whole-document sweep;
- cross-model 审的是初稿,其关于 LLM 输入、plan ACL、结果传递、幂等、产品价值和确认负担的有效意见已纳入修订;其余由当前代码与边界事实校正。
## 关联整改
- System design: [2026-09-15-multi-intent-hitl-plan.md](../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Short-term: [2026-09-15-multi-intent-hitl.md](../ops/short-term/2026-09-15-multi-intent-hitl.md)
## 证据
- `internal/intent/plan_builder.go`:首连接词、两段、写意图返回 nil;
- `internal/coordinator/action_planner.go`:pending confirm 仅文字提示;
- `internal/intent/registry.go`:task.run/adhoc 为 medium 且当前不全局 RequiresConfirm;
- `internal/intent/flags.go`:MULTI_INTENT_ENABLED 默认 true;
- `.doc/system-design/module-boundaries.yaml`:intent 只依赖 maturity,Track E/table owners 已登记;
- `internal/events/registry.go`:事件须静态注册;
- `internal/app/uow/uow.go`:不透明 TxScope;
- `web/src/App.tsx`:现有 card action 含前端本地业务状态路径。
## 开放问题
无阻塞性架构问题。各放量阈值必须在 U2 shadow 基线形成后预注册;这属于实施期量化,不授权跳过停走门。
@@ -1,44 +0,0 @@
---
title: Demo/测试数据污染系统性审计
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
---
# Demo / 测试数据污染系统性审计
## 前序
本审计在 [2026-09-15 mock 交付物污染真实项目](./2026-09-15-mock-deliverables-pollute-real-projects.md)(及对应 [整改](../remediation/2026-09-15-mock-deliverables-pollution-remediation.md))之上收敛为全栈系统性排查:前端门控、goose 演示项目/会话、stub API。
## 背景
空项目展示「终审已生效」受控文档 + 伪造三级职责人。初判怀疑 docgov 隔离失败;实锤为前端 mock/seed 与 DB goose 演示种子污染。
## 结论
| 面 | 判定 | 说明 |
|----|------|------|
| 服务端 `document_records` / project_docs | **正常** | 按 `project_id` 隔离;空项目台账为 0 |
| 前端 `ALL_INITIAL_DELIVERABLES` / mockDocuments | **critical** | 无门控进生产包;projectId 1/2/3 撞车 |
| 前端 DEFAULT_PROJECTS / sessions / MOCK_USERS | **critical/high** | NeuroPulse 5201、CUSA id=3、6001–6010 |
| `deliverableSync` 空清单 `return prev` | **critical** | 权威空列表不回收本地 mock |
| `isLegacyLocalMockDocId` 覆盖不全 | **critical** | 未覆盖 neuropulse / ten-projects |
| Goose `00011`/`00012` | **critical** | 全环境写入 6001–6010 + 聊天 |
| API `backend=stub` | **high** | main 仍可请求 stub |
| `BootstrapDevSeedUsers` | **OK** | 已有 env 门控 |
## 证据路径
- `web/src/App.tsx`(整改前 INITIAL_*)
- `web/src/data/mockDocuments.ts` / `neuropulseDemo.ts` / `tenProjectsDemo.ts`
- `web/src/lib/deliverableSync.ts`
- `deploy/postgres/goose/00011_*.sql` / `00012_*.sql`
- `internal/taskrun/backend.go`
- 产物扫描:`scripts/check-prod-bundle.sh`
## 整改回链
- [remediation](../remediation/2026-09-16-demo-seed-pollution-remediation.md)
- [test-report](../test-reports/2026-09-16-demo-seed-pollution-test-report.md)
+2 -28
View File
@@ -13,37 +13,11 @@
## 核心文档(按阅读顺序推荐)
### 多意图与 HITL 方案复核(2026-09-15)
**文件**: [2026-09-15-multi-intent-hitl-plan-review.md](./2026-09-15-multi-intent-hitl-plan-review.md)
**结论**: 多意图方向可行,但必须以 `app/intentflow` 深模块、PG 权威状态机、逐动作即时授权和分波 mutex 防止 intent/coordinator 再耦合;确认、卡片和 SSE 均不能替代授权或权威状态。
**设计/计划**: [多意图持久计划与 HITL](../system-design/2026-09-15-multi-intent-hitl-plan.md) · [核心 U1–U8 与扩面 U9–U12](../ops/short-term/2026-09-15-multi-intent-hitl.md)
### 模块解耦 Phase 2 方案复核(2026-09-15)
**文件**: [2026-09-15-module-decoupling-phase2-plan-review.md](./2026-09-15-module-decoupling-phase2-plan-review.md)
**结论**: PG delivery 尚未形成生产闭环;原计划把事件、结构和协议三轨绑成一次交付,并误判 docgov/docrevision 依赖方向。修订版先完成事件生产与历史数据门,再以 PG dispatcher、逐消费者 shadow 和真实刷新/重启恢复收口。
**整改**: [Phase 2 持久事件交付与后续解耦路线](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
### arch-check U1 可重放基线(2026-09-14)
### 模块边界 arch-check Wave 0 基线(2026-09-14)
**文件**: [2026-09-14-arch-check-baseline.md](./2026-09-14-arch-check-baseline.md)
**结论**: 四类规则(production import / SQL write / path / event)可重放。import=0,sql_write=5,path=17,event=0。Goose 与测试不计生产写者。新违规与过期例外立即 block。
### 模块解耦方案复核(2026-09-14)
**文件**: [2026-09-14-module-decoupling-plan-review.md](./2026-09-14-module-decoupling-plan-review.md)
**结论**: 模块化单体方向成立,但原横向 Wave 缺少跨属主事务、可靠事件、多副本互斥、逐动作授权和 FAV 边界;应先完成受控文档可靠性纵向试点,再按证据扩面。
**整改**: [模块解耦与文档可靠性重构计划](../remediation/2026-09-14-module-decoupling-refactor-plan.md)
**结论**: import 相对现状 allowlist 无新边;表/路径目标属主扫描 21 条 warn,作为 Wave 1+ 收口清单,不在本轮转 block。
### 项目 143 workflow-plan 409 与三权全有或全无(2026-09-14)
+19 -78
View File
@@ -1,44 +1,24 @@
# 当前焦点
**更新**: 2026-09-16
**production_ready**: yes(门禁 B1–B4 已签;dev/test/main `schema_version=47`。不把 fallback change report 写成完整 PI)
**更新**: 2026-09-14
**production_ready**: no(`CHAT-INTENT-STATE` 等无关 blocker 仍开放。文档账本运行时 UI Round20 **PASS**,不把 fallback change report 写成完整 PI,也不把本轮写成全仓可发布)
## 焦点
1. **MATRIX 深度测试 + 晋升 test**:`feature/matrix-deep-test-promote-test` → `rc-v1.0.0-beta.2`
2. **首发后 backlog**:多意图 U9–U12、软件项目自举、FAV、完整 PI change-report 叙事
3. **MULTI-INTENT HITL**:核心 U1–U8 已合入;U9–U12 不阻塞首版
1. **WORKFLOW-PLAN**: [冻结 409 与文档职责可选治理](../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)(Wave 1–4 已在 `fix/workflow-plan-409-frozen-and-optional-duties` 落地;Wave 5 占槽 e2e 进行中;后续治理原则见 [MVP 治理规则评审](../ops/research/2026-09-14-mvp-governance-rules-review.md))
2. **CHAT-INTENT**: [对话意图运行时状态](../audit/2026-09-13-conversation-intent-runtime-state.md)(`fix/conversation-intent-state`;与文档账本运行时无关)
3. **CHAT**: [对话历史刷新](../audit/2026-09-13-chat-history-refresh-disappears.md)(认领仍 `in_progress`;gap 行已 PASS,以代码/handoff 为准收敛)
## 并行认领
| owner | task | branch | worktree | mutex | status |
|-------|------|--------|----------|-------|--------|
| Cursor-Auto | 2026-09-16-matrix-deep-test-promote-test | feature/matrix-deep-test-promote-test | - | infra | in_progress |
| Cursor-Auto | 2026-09-16-production-ready-gates | docs/production-ready-flip | - | ci | done |
| Cursor-Auto | 2026-09-16-demo-seed-pollution | fix/demo-data-pollution-web | - | web | done |
| Cursor | 2026-09-16-multi-intent-u8-task-generate | feature/multi-intent-u8-task-generate | - | intent-plan | done |
| Cursor | 2026-09-16-multi-intent-u7-auto-read | feature/multi-intent-u7-auto-read | - | intent-plan | done |
| Cursor | 2026-09-16-multi-intent-u6-web-cards | feature/multi-intent-u6-web-cards | - | web | done |
| Cursor | 2026-09-16-multi-intent-u5-decision-api | feature/multi-intent-u5-decision-api | - | intent-plan | done |
| Cursor | 2026-09-16-multi-intent-u4-outbox-projection | feature/multi-intent-u4-outbox-projection | - | events | done |
| Cursor | 2026-09-15-multi-intent-u3-intentflow-pg | feature/multi-intent-u3-intentflow-pg | - | intent-plan | done |
| Cursor | 2026-09-15-multi-intent-u2-segmenter | feature/multi-intent-u2-segmenter | - | intent | done |
| Cursor | 2026-09-15-multi-intent-u1-contracts | feature/multi-intent-u1-contracts | - | architecture-docs | done |
| Cursor | app-composition-u11-u12 | feature/app-composition-u11-u12 | - | app | done |
| Cursor | chatlog-contextasm-u10 | feature/chatlog-contextasm-u10 | - | chat | done |
| Cursor | chat-history-refresh-remediation | fix/chat-history-refresh | - | chat | done |
| Cursor | dataset-lifecycle-u9 | feature/dataset-lifecycle-u9 | - | dataset | done |
| Cursor | taskrun-runmanifest-u8 | feature/taskrun-runmanifest | - | taskrun | done |
| Cursor | document-reliability-m1-live-and-m2 | refactor/document-reliability-pilot | - | workspace | done |
| Codex | module-decoupling-remediation-plan | feature/module-decoupling-remediation | - | architecture-docs | done |
| Codex | module-decoupling-phase2-plan-review | docs/module-decoupling-ipc-assessment | - | architecture-docs | done |
| Cursor | module-decoupling-phase2-docs | feature/module-decoupling-phase2-docs | - | architecture-docs | done |
| verifier_antigravity | controlled-content-ui-acceptance | fix/controlled-content-ui-acceptance | - | document-content-ui-acceptance | done |
| implementer_cursor | controlled-content-canonical-hash | fix/controlled-content-canonical-hash | - | docgov | done |
| verifier_antigravity | controlled-content-ui-acceptance | fix/controlled-content-ui-acceptance | .worktrees/fix-controlled-content-ui-acceptance | document-content-ui-acceptance | done |
| implementer_cursor | controlled-content-canonical-hash | fix/controlled-content-canonical-hash | .worktrees/fix-controlled-content-canonical-hash | docgov | done |
| Codex | project143-controlled-content-404-diagnosis | fix/project143-controlled-content-404-diagnosis | - | docgov-content-diagnosis | done |
| Codex | software-project-bootstrap-plan | feature/software-project-bootstrap-plan | - | workflow-design | done |
| Codex | conversation-intent-runtime-state | fix/conversation-intent-state | - | intent | done |
| Cursor | conversation-intent-runtime-state | docs/conversation-intent-dual-tab | - | intent | done |
| Cursor | chat-history-refresh-remediation | fix/chat-history-refresh | - | chat | in_progress |
| Codex | conversation-intent-runtime-state | fix/conversation-intent-state | .worktrees/fix-conversation-intent-state | intent | in_progress |
| Cursor | document-revision-wave1-6-implementation | feature/document-revision-management | - | docgov | done |
| Cursor-Auto | document-revision-runtime-ui03 | fix/document-revision-runtime-ui03 | - | docgov | done |
| Cursor-Auto | document-revision-sse-idempotency | fix/document-revision-sse-idempotency | - | docgov | done |
@@ -66,36 +46,21 @@
| Cursor-Auto | document-revision-evidence-count | fix/document-revision-evidence-count | - | document-revision-evidence-count | done |
| Cursor-Auto | document-revision-session-close | feature/document-revision-session-close | - | document-revision-session-close | done |
| Cursor-Auto | vite-frp-allowed-hosts | fix/vite-frp-allowed-hosts | - | web-devserver | done |
| implementer_cursor | workflow-plan-409-frozen-and-optional-duties | fix/workflow-plan-409-frozen-and-optional-duties | - | workflow | done |
| implementer_cursor | governance-action-level-authz | fix/governance-action-level-authz | - | workflow | done |
| Cursor | leftover-branch-cleanup | chore/leftover-branch-cleanup | - | ops | done |
| Cursor | event-e0a-production-scope-contract | fix/event-production-scope-contract | - | events | done |
| Cursor | event-e0b-dispatcher-pg | feature/events-dispatcher-pg | - | events | done |
| Cursor | event-e1a-notify-cutover | fix/event-notify-cutover | - | events | done |
| Cursor | event-e1b-workflow-advance | fix/event-workflow-advance | - | events | done |
| Cursor | event-e1c-projection-cutover | fix/event-projection-cutover | - | events | done |
| Cursor | event-e2-hook-guard | fix/event-e2-hook-guard | - | events | done |
| Cursor | doccontent-canonical-boundary | fix/doccontent-canonical-boundary | - | docgov | done |
| Cursor | intent-bizdev-boundary | fix/intent-bizdev-boundary | - | intent | done |
| Cursor | stageflow-type-ownership | fix/stageflow-type-ownership | - | stageflow | done |
| Cursor | bizdev-locator-removal | fix/bizdev-locator-removal | - | bizdev | done |
| Cursor | chatflow-orchestration-boundary | fix/chatflow-orchestration-boundary | - | chat | done |
| Cursor | phase2-closeout-inventories | feature/phase2-closeout-inventories | - | architecture-docs | done |
| Cursor | event-shared-live-cutover | feature/event-shared-live-cutover | - | events | done |
| Cursor | pi-typed-result | feature/pi-typed-result | - | pi-agent | done |
| Cursor | promote-dev-to-test-2026-09-15 | feature/promote-dev-to-test-2026-09-15 | - | infra | done |
| Cursor-Auto | remove-herdr-agent-settings | feature/remove-herdr-agent-settings | - | agent-collab-docs | done |
| implementer_cursor | workflow-plan-409-frozen-and-optional-duties | fix/workflow-plan-409-frozen-and-optional-duties | .worktrees/fix-workflow-plan-409-frozen-and-optional-duties | workflow | in_progress |
| Cline | governance-action-level-authz | fix/governance-action-level-authz | - | workflow | blocked |
| Cursor | module-decoupling-wave0 | feature/remove-herdr-agent-settings | - | arch | done |
> 新任务开始前登记。`branch` 必须为 `feature/<slug>` 或 `fix/<slug>`,**禁止** `dev` / `test` / `main`。同一 `mutex` 同时仅一个 `in_progress`。
> workflow-plan 409 与治理鉴权 G1–G5 已收口(见 [test-report](../test-reports/2026-09-14-governance-action-level-authz-test-report.md))。禁止终止或改写项目 143。
> `document-reliability-pilot` U11–U12 已合入 `dev@bf59cce` 并 rebuild。`CHAT-INTENT-STATE` 双标签 busy 已 PASS(项目 6275)。禁止 worktree 内 `env-service`。项目 143 只读,禁止终止。
> 2026-09-15 旁支清理:[报告](../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md)。已合入本地旁支 31 条已 `git branch -d`;7 个对应 worktree 已拆。extra worktree 仅余 `.worktrees/fix-dev-runtime-data-root-guard`(目录名是 guard,检出的是 `feature/final-artifact-vault`)。**故意不合入、不删**:`feature/final-artifact-vault`、`feature/remove-herdr-agent-settings`、`fix/project143-controlled-content-404-diagnosis`、`fix/dev-runtime-data-root-guard`、`dev-old-linear`。不删 `origin/*`。不整支 merge FAV;不启用 `FAV_DEGRADED_READ`。
> `workflow-plan-409-frozen-and-optional-duties` 已由 implementer_cursor 接管:worktree 已创建,Wave 1–4 提交落地,Wave 5 占集成槽位(e2e)进行中。
> `governance-action-level-authz` blocked 仅为等待同 mutex `workflow` 的 Wave 5 收敛;收敛后从最新 `dev` 创建 `fix/governance-action-level-authz` 并改 `in_progress`,不得在当前 `feature/remove-herdr-agent-settings` 工作区编码。
## 集成槽位
| holder | phase | since | scope | queue |
|--------|-------|-------|-------|-------|
| Cursor-Auto | merging | 2026-09-16T13:20Z | matrix deep test → promote rc-v1.0.0-beta.2 + test rebuild | - |
| implementer_cursor | e2e | 2026-09-14 | workflow-plan 409 frozen + optional duties | governance-action-level-authz |
**phase**: `idle` | `merging` | `smoke` | `e2e`
@@ -105,9 +70,9 @@
| 环境 | 端口 | schema | 状态 |
|------|------|--------|------|
| dev | 8080 | **47** | healthy(`pi-agent` typed-result-v1;events worker `:8088`;notify/advance/projection live、fav off;health+ready PASS;demo 6001–6010 retired) |
| test | 8081 | **47** | healthy(`rc-v1.0.0-beta.1`;pi-agent `:18866`;events `:8089`;notify/advance/projection live、fav off;health+ready PASS;schema 与 dev 对齐 47) |
| main | 8000 | **47** | healthy(app + events + runner + DB;与 dev/test 对齐) |
| dev | 8080 | **32** | healthy(产品代码部署为 `36e4bc3`;真实 UI 主链+restart PASS) |
| test | 8081 | 25→27* | healthy |
| main | 8000 | 25→27* | healthy(app + runner + DB) |
## SSOT
@@ -118,35 +83,11 @@
| 发布缺口 | [gap-matrix](../remediation/gap-matrix.md) |
| 测试报告 | [test-reports/](../test-reports/) |
| Agent 手册 | [AGENTS.md](../../AGENTS.md) |
| 意图双标签 busy 交接 | [./handoffs/2026-09-15-conversation-intent-dual-tab.md](./handoffs/2026-09-15-conversation-intent-dual-tab.md) |
| 受控正文 hash 漂移 W1–W6 | [../ops/handoffs/2026-09-14-controlled-content-canonical-hash.md](../ops/handoffs/2026-09-14-controlled-content-canonical-hash.md) |
| DOCREV ADR | [../adr/2026-09-13-document-version-boundary.md](../adr/2026-09-13-document-version-boundary.md) |
| DOCREV 管理测试 | [../test-reports/2026-09-13-document-revision-management-test-report.md](../test-reports/2026-09-13-document-revision-management-test-report.md) |
| DOCREV 运行时 UI Round20 | [../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) |
| 纯软件项目自举设计 | [../system-design/2026-09-14-software-project-bootstrap-workflow.md](../system-design/2026-09-14-software-project-bootstrap-workflow.md) |
| 模块化单体解耦架构 | [../system-design/2026-09-14-module-decoupling-architecture.md](../system-design/2026-09-14-module-decoupling-architecture.md) |
| 模块解耦整改计划 | [../remediation/2026-09-14-module-decoupling-refactor-plan.md](../remediation/2026-09-14-module-decoupling-refactor-plan.md) |
| Phase 2 方案审阅 | [../audit/2026-09-15-module-decoupling-phase2-plan-review.md](../audit/2026-09-15-module-decoupling-phase2-plan-review.md) |
| Phase 2 修订计划 | [../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md) |
| 多意图 HITL 复核方案 | [../system-design/2026-09-15-multi-intent-hitl-plan.md](../system-design/2026-09-15-multi-intent-hitl-plan.md) |
| 多意图 HITL U1 契约 | [../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md) |
| 多意图 HITL U2 分段 | [../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md](../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md) |
| 多意图 HITL U3 PG | [../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) |
| 多意图 HITL U4 投影 | [../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md](../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md) |
| 多意图 HITL U5 API | [../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md](../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md) |
| 多意图 HITL U6 Web | [../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md](../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md) |
| 多意图 HITL U8 generate | [../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md](../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md) |
| 多意图 HITL U7 只读 | [../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md](../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md) |
| 文档可靠性 M1 报告 | [../test-reports/2026-09-14-document-reliability-pilot-test-report.md](../test-reports/2026-09-14-document-reliability-pilot-test-report.md) |
| 文档可靠性 M1 活验 | [../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md](../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md) |
| 文档可靠性 M2 | [../test-reports/2026-09-14-document-reliability-m2-test-report.md](../test-reports/2026-09-14-document-reliability-m2-test-report.md) |
| 文档可靠性 M3 U8 | [../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md](../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md) |
| 文档可靠性 M3 U9 | [../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md](../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md) |
| 文档可靠性 M4 U10 | [../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md) |
| 文档可靠性 M5/M6 U11–U12 | [../test-reports/2026-09-15-app-composition-u11-u12-test-report.md](../test-reports/2026-09-15-app-composition-u11-u12-test-report.md) |
| Track E E2 闭包守卫 | [../test-reports/2026-09-15-event-e2-hook-guard-test-report.md](../test-reports/2026-09-15-event-e2-hook-guard-test-report.md) |
| Track E 复盘 | [./research/2026-09-15-track-e-retrospective.md](./research/2026-09-15-track-e-retrospective.md) |
| 旁支清点收口 | [../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md](../test-reports/2026-09-15-leftover-branch-cleanup-test-report.md) |
| SSE/幂等审计 | [../audit/2026-09-13-document-revision-sse-idempotency.md](../audit/2026-09-13-document-revision-sse-idempotency.md) |
| 质量门禁自污染审计 | [../audit/2026-09-13-document-revision-quality-gate-self-pollution.md](../audit/2026-09-13-document-revision-quality-gate-self-pollution.md) |
| 当前文档路由审计 | [../audit/2026-09-13-document-revision-active-doc-routing.md](../audit/2026-09-13-document-revision-active-doc-routing.md) |
@@ -1,9 +1,9 @@
---
title: "对话刷新恢复整改 Checklist"
status: done
status: in_progress
created: 2026-09-13
updated: 2026-09-15
related_task: "../2026-09-13-chat-history-refresh-remediation.md"
updated: 2026-09-13
related_task: "../short-term/2026-09-13-chat-history-refresh-remediation.md"
---
# 对话刷新恢复整改 Checklist
@@ -36,10 +36,10 @@ related_task: "../2026-09-13-chat-history-refresh-remediation.md"
## Wave 5 — 验收
- [x] `go test -short ./...` — 证据:本机执行输出
- [x] 真实 PI 刷新 E2E(需 dev 容器 + pi-agent)— 证据:`.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json`(项目 6252 闲聊刷新同集 + guest 403;编制任务链未通过)
- [ ] 真实 PI 刷新 E2E(需 dev 容器 + pi-agent)— 证据:待 test-report 补录
- [x] 测试报告归档 — 证据:`.doc/test-reports/2026-09-13-chat-history-refresh-test-report.md`
## 完成定义
- [x] 全部勾选且有证据链接
- [x] gap-matrix `CHAT-HISTORY-REFRESH` → PASS
- [ ] 全部勾选且有证据链接
- [ ] gap-matrix `CHAT-HISTORY-REFRESH` → PASS
@@ -1,74 +0,0 @@
---
title: "模块解耦重构验收清单"
status: in_progress
created: 2026-09-14
updated: 2026-09-15
owner: Cursor
---
# 模块解耦重构验收清单
## M0 架构与基线
- [x] contracts 分类、事务 owner、表属主、锁顺序、事件信封、Principal 和 FAV 边界均有唯一规范来源。
- [x] arch-check 分离 production import、SQL write、path 和 event registration;例外有 owner 与到期日。
- [x] 当前违规基线可重复生成,新违规立即阻断。
## M1 文档可靠性
- [x] 人工编辑、agent commit、approve/reject 的跨表写入同事务(U3;隔离库双会话编辑已测)。
- [x] fault injection 任一点失败均无部分提交(U2 隔离库)。
- [x] 同 ETag 并发写只有一个赢家(内存 + 双会话)。
- [x] 1、2、4 app replicas 结果一致。
- [x] GET 服务端零写入 + typed consistency(U4 单测)。refresh/reload 真页面 PASS([活验报告](../../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md))。
- [x] 项目 143 等价 hazard 与新项目真实页面刷新、重登、restart、rebuild PASS。
- [x] 服务端负例 fail closed;浏览器跨用户 401/404 PASS。
## M2 事件与 FAV
- [x] 业务终态、staging 和 outbox 同事务。
- [x] 每个 consumer 有独立 delivery/inbox/attempt/lease/dead-letter。
- [x] 1、2、4 dispatcher 无重复可见副作用和永久饥饿。
- [x] crash-before/after-side-effect/ack 全部可恢复。
- [x] stale fencing、跨项目事件、错误 producer、坏 digest 均拒绝。
- [x] FAV 中间结果、Prompt、工具轨迹和 secret 准入率为零。
- [x] DB 授权成功后才允许 degraded read;授权图缺失 fail closed。
- [x] tombstone/删除账本 union-deny PASS。
## M3 TaskRun、workspace 与数据生命周期
- [x] RunManifest 规范字节、SHA、成员和 storage identity 持久化。
- [x] 重复 finalize、SSE 断线和 cancel race 不重复消息或 artifact。
- [x] WorkspaceRef 无物理路径,路径遍历和链接逃逸负例 PASS。
- [x] 旧 lease writer 被 fencing token 拒绝。
- [x] workspace 清空后最终成果仍可定位和校验。
- [x] backfill 可暂停、续跑和重放;异常进入 quarantine。
- [x] 八条 migration/reload/recovery 轨道 PASS。
- [x] 数据销毁前完整备份、corpus、FAV coverage 和人工批准全部满足。
## M4–M6 选择性扩展
- [x] 每个子切片在原包边界先获得行为收益,再决定物理搬包。
- [x] chatlog/contextasm 保持授权可见集合和计数一致。
- [x] app 是唯一组合根,subscriber 重复启动不重复注册。
- [x] UserProjectContext 跨模块写路径走类型化 ContextUpdate + 版本 CAS(coordinator 作为 owner 仍可改 Project 字段)。
- [ ] server 无 SQL、路径拼接和业务闭包。(OnOutbox 已迁出;生产 SQL 无新增;path 例外 `workspaces/` / `output.md` 未到期,未删)
- [ ] 对应架构规则全部 block,过期例外和 flags 已删除。(`import`/`event` 已 block;sql_write/path 基线例外仍在)
## 证据分层
- [x] Unit/stub 证据。
- [x] PostgreSQL integration 证据(隔离库,非共享 env 库)。
- [x] race/concurrency 目标包证据(非全仓 race)。
- [x] fault injection 证据(U2)。
- [x] 真实 PI 证据。
- [x] 真实浏览器证据。
- [x] restart/rebuild 证据。
- [x] cross-user/project authorization negative 服务端证据。
- [x] scratch recovery 与完整 DB restore 证据。
## 关闭条件
- [x] test report 回链具体 U-ID、commit、环境 identity 和 fixture/dataset。([U11–U12 报告](../../test-reports/2026-09-15-app-composition-u11-u12-test-report.md);合入 `dev` 后补 rebuild 镜像)
- [x] CURRENT、FEATURE-MATRIX、gap-matrix 与任务状态一致。
- [x] 未实施后续仍为 planned/deferred,不用局部测试冒充全计划完成。
@@ -1,22 +0,0 @@
---
title: "多意图 HITL U1 契约冻结 checklist"
status: done
created: 2026-09-15
updated: 2026-09-15
related_task: "2026-09-15-multi-intent-u1-contracts"
---
# 多意图 HITL U1 契约冻结 checklist
## Wave 0
- [x] YAML `app/intentflow` allowlist + 三表 owner + unwrap_owners — 证据:`.doc/system-design/module-boundaries.yaml`
- [x] 三条 `intent.plan.*` YAML ↔ StaticContracts parity — 证据:`go test ./internal/events -run RegistryParity`
- [x] archtest 扫描 `intent.plan.*` — 证据:`go test ./internal/archtest`
- [x] intentflow 状态/错误码/Service/政策/legacy tier — 证据:`go test ./internal/app/intentflow`
- [x] CSRF/Bearer 结论落盘 — 证据:U1 short-term
- [x] `go test -short ./...` — 证据:[U1 报告](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -1,22 +0,0 @@
---
title: "多意图 HITL U2 规则分段 checklist"
status: done
created: 2026-09-15
updated: 2026-09-15
related_task: "2026-09-15-multi-intent-u2-segmenter"
---
# 多意图 HITL U2 规则分段 checklist
## Wave 1
- [x] characterization 锁定 legacy IntentPlan — 证据:`internal/intent/plan_builder_test.go`;[报告 §5.1](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md)
- [x] 分段器 golden(连接词/句号/序号/先再最后) — 证据:[proposal-verbose.txt](../../test-reports/assets/2026-09-15-multi-intent-u2-segmenter/proposal-verbose.txt)
- [x] 查询并总结不拆;写段进入提案;5 段拒绝;红线整体拒绝;指代澄清 — 证据:同上
- [x] digest 稳定;shadow 不改 TopIntent — 证据:`TestPlanProposal_DigestStable` / `TestPlanProposal_WriteNotDroppedAndLegacyUnchanged`
- [x] 反事实 auto_read 错误自动执行 = 0 — 证据:`plan-proposal eval denom=8 false_auto_execute=0`
- [x] `go test -short ./internal/intent ./internal/coordinator ./internal/app/intentflow` — 证据:[unit.txt](../../test-reports/assets/2026-09-15-multi-intent-u2-segmenter/unit.txt);[short.txt](../../test-reports/assets/2026-09-15-multi-intent-u2-segmenter/short.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -1,22 +0,0 @@
---
title: "多意图 HITL U3 intentflow PG checklist"
status: done
created: 2026-09-15
updated: 2026-09-15
related_task: "2026-09-15-multi-intent-u3-intentflow-pg"
---
# 多意图 HITL U3 intentflow PG checklist
## Wave 2
- [x] Goose 00044 三表 + unique/CAS/lease 列 — 证据:`deploy/postgres/goose/00044_2026-09-15-intent-plans.sql`;`TestGooseU3_00044_HasUpAndDown`
- [x] 创建幂等与同 turn 异 digest — 证据:[plans-verbose.txt](../../test-reports/assets/2026-09-15-multi-intent-u3-intentflow-pg/plans-verbose.txt)
- [x] 决策 nonce / revision CAS / 过期 — 证据:同上
- [x] 两 worker 无双 owner;租约接管;旧 fence 拒绝 — 证据:`TestTwoWorkersOneOwnerAndLeaseTakeover`
- [x] receipt 对账不盲跑;环境隔离;legacy HandleTurn 不落盘 — 证据:`TestReceiptWritebackFailureDoesNotRerun` / `TestHandleTurnLegacyDoesNotPersist`
- [x] Assemble 接线且 chat 不调用;arch-check 无新例外 — 证据:[short.txt](../../test-reports/assets/2026-09-15-multi-intent-u3-intentflow-pg/short.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -1,19 +0,0 @@
---
title: "多意图 HITL U4 outbox checklist"
status: done
created: 2026-09-16
updated: 2026-09-16
related_task: "2026-09-16-multi-intent-u4-outbox-projection"
---
# 多意图 HITL U4 outbox checklist
- [x] 同 UoW Append intent.plan.* — 证据:[emit-verbose.txt](../../test-reports/assets/2026-09-16-multi-intent-u4-outbox-projection/emit-verbose.txt)
- [x] golden payload 无敏感字段 — 证据:`testdata/intent-plan-awaiting-v1.json`
- [x] 重复/乱序/伪造 producer — 证据:`TestProjectionOnlyForwardAndForgedRejected`
- [x] 投影只前进;跨用户隔离 — 证据:同上
- [x] dispatcher 语义未改;arch-check 绿 — 证据:[short.txt](../../test-reports/assets/2026-09-16-multi-intent-u4-outbox-projection/short.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -1,20 +0,0 @@
---
title: "多意图 HITL U5 decision API checklist"
status: done
created: 2026-09-16
updated: 2026-09-16
related_task: "2026-09-16-multi-intent-u5-decision-api"
---
# 多意图 HITL U5 decision API checklist
- [x] 冻结 REST 路径挂到认证 mux — 证据:[http-verbose.txt](../../test-reports/assets/2026-09-16-multi-intent-u5-decision-api/http-verbose.txt)
- [x] Principal 不从 body 复制 — 证据:`TestIntentPlanHTTP_IgnoresBodyPrincipalAndSameReceipt`
- [x] 非成员/跨作用域/管理员负例 — 证据:`TestIntentPlanHTTP_ScopeNegatives` / `AdminDoesNotBypassMembership`
- [x] StepAuthorizer 在 confirm 与 execute 前调用 — 证据:[authorize-verbose.txt](../../test-reports/assets/2026-09-16-multi-intent-u5-decision-api/authorize-verbose.txt)
- [x] stale/nonce/edit/非法部分确认 — 证据:同上
- [x] arch-check / short 绿 — 证据:[short.txt](../../test-reports/assets/2026-09-16-multi-intent-u5-decision-api/short.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -1,19 +0,0 @@
---
title: "多意图 HITL U6 Web checklist"
status: done
created: 2026-09-16
updated: 2026-09-16
related_task: "2026-09-16-multi-intent-u6-web-cards"
---
# 多意图 HITL U6 Web checklist
- [x] PLAN_CONFIRM 类型与 PlanView 映射 — 证据:`web/src/engine/planCard.test.ts`
- [x] 决策走 REST,不改 AST — 证据:`planCardTouchesLocalAST` + App early-return
- [x] 409/过期/submitting 状态 — 证据:同上
- [x] App early-return — 证据:`web/src/App.tsx`
- [x] 单元测试绿;Playwright 门控 skip — 证据:[npm-test.txt](../../test-reports/assets/2026-09-16-multi-intent-u6-web-cards/npm-test.txt)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -1,14 +0,0 @@
---
title: "U7 auto_read checklist"
status: done
created: 2026-09-16
related_task: "2026-09-16-multi-intent-u7-auto-read"
---
# U7
- [x] legacy HandleTurn 不落盘
- [x] auto_read 查询创建并执行
- [x] 写话语不落盘
- [x] QueryGuard 拒绝 task.run
- [x] chat 调用 HandleTurn;arch 绿
@@ -1,23 +0,0 @@
---
title: "U8 task generate checklist"
status: done
created: 2026-09-16
updated: 2026-09-16
related_task: "2026-09-16-multi-intent-u8-task-generate"
---
# U8
- [x] confirm 话语落盘 awaiting,确认前不执行 — 证据:`TestHandleTurnConfirmPersistsAwaitingWithoutExecute`
- [x] 第二活动写计划冲突 — 证据:`TestHandleTurnConfirmRejectsSecondActiveWritePlan`
- [x] OwnerMux 路由 + nil Task fail closed — 证据:`TestOwnerMuxRoutesGenerateToTask` / `TestOwnerMuxNilTaskFailClosed`
- [x] 确认后 generate 一次、重放不双跑 — 证据:`TestConfirmThenMuxExecutesGenerateOnce`
- [x] adapter 幂等 / 拒查询 / 撤销 — 证据:`TestTaskRunAdapter*`
- [x] LiveTaskStarter 同键重放 — 证据:`TestLiveTaskStarterReplaysIdempotencyKey`
- [x] QueryGuard 仍拒 task.run;auto_read 写话语不落盘 — 证据:U7 回归 + `TestQueryGuardRejectsGenerate`
- [x] 真实 PI stop-gate — 证据:`TestTaskGenerateRealPIStopGate` SKIP
- [x] arch-check block 绿 — 证据:[报告](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md)
## 完成定义
- [x] 全部勾选且有证据链接
@@ -1,67 +0,0 @@
---
title: "意图 mutex 从 Codex 转 Cursor:仅剩浏览器双标签门"
created: 2026-09-15
from: Codex
to: Cursor
status: closed
---
# 交接:对话意图运行时状态 — 浏览器双标签门
## 目标(下一位 Agent 应完成什么)
在 U11–U12 已合入并 rebuild 的 `:8080` 上,用**新建项目**补齐真实 PI + 双标签 busy / 刷新恢复证据。通过则关 `CHAT-INTENT-STATE` 并 archive;失败则从最新 `dev` 新开 `fix/conversation-intent-dual-tab`,**不要**在已合入的 `fix/conversation-intent-state` 上追加。
## 已完成
- Wave 0–4 服务端/单测已在 `dev`(`fix/conversation-intent-state` 是祖先)。
- 前端 5s 租约轮询:`web/src/App.tsx`。
- `DOC_BUSY` 预检:`internal/server/task_run_handlers.go`(不创建第二 run,`error_info.actions=[]`)。
- UI busy 文案:`BlockRenderer` / `DeckDrawer`「编辑中」。
- 只读总结真实 PI(用例 H)已签;项目 143 诊断污染未删。
## 未完成
- 浏览器刷新恢复与双标签租约可见性(报告用例 E)。
- 整改 Wave 3–4 未勾项:运行中刷新、busy 自动解除、并发写不新增 run 的**活验证据**。
## 认领 / 槽位状态
| 项 | 值 |
|----|-----|
| mutex 已释放 | no(`intent` 转 Cursor `in_progress`) |
| 集成槽位 holder | idle(U11–U12 已释放;本门禁不占槽,除非要合入 UI 补丁) |
| branch | 编码已在 `dev`;活验文档用 `docs/conversation-intent-dual-tab` |
| worktree | `.worktrees/fix-conversation-intent-state` **禁止** `env-service` |
> 用户已要求关掉 CURRENT 两行 `in_progress`,授权 Cursor 接管剩余验收。不覆盖 Codex worktree 未合并代码。
## 关键文件
| 路径 | 说明 |
|------|------|
| `.doc/ops/short-term/2026-09-13-conversation-intent-runtime-state.md` | 任务文 |
| `.doc/test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md` | 用例 E 待补 |
| `.doc/remediation/2026-09-13-conversation-intent-runtime-state-remediation.md` | Wave 3–4 |
| `web/src/App.tsx` | 5s lease 轮询 |
| `internal/server/task_run_handlers.go` | DOC_BUSY 预检 |
## 如何验证
```bash
# 主仓已 rebuild 的 dev,禁止 worktree 内 env-service
curl -sf http://127.0.0.1:8080/ready
# 新建项目 + 隔离 session;禁止项目 143;禁止 sess-p143-u9 探针
```
## 风险 / Blocker
- 项目 143 只读:不终止、不改写、不打探针。
- 客户端在 lease 已投影后会本地拦截写请求(不发 POST);HTTP 409 须在轮询窗口内或走 API 第二通道取证。
- 诊断污染消息仍不擅自删除。
## 相关链接
- CURRENT: [CURRENT.md](../CURRENT.md)
- Task: [../short-term/2026-09-13-conversation-intent-runtime-state.md](../short-term/2026-09-13-conversation-intent-runtime-state.md)
- Test report: [../../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md](../../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md)
@@ -1,47 +0,0 @@
---
title: "选择性模块解耦 M4–M6"
status: planned
created: 2026-09-14
updated: 2026-09-14
owner: TBD
mutex: architecture
review_cycle: milestone
---
# 选择性模块解耦 M4–M6
## 目标
在文档可靠性、可靠事件和 FAV 已证明收益后,按 U10–U12 分别收敛 chatlog/contextasm、应用组合根、共享上下文和传输层。
## 为什么是长期任务
这些改动不直接修复当前受控正文事实源问题,且会触及仍在进行的 chat/intent 工作。
M1–M3 未通过前执行会扩大冲突面,并提前冻结未经真实消费者验证的契约。
## 触发条件
- M1–M3 的 test report 全部 PASS。
- 同类缺陷触达文件数和运行故障率表明继续解耦具有收益。
- `chat`、`intent`、`bizdev/coordinator`、`server/stream` mutex 按子切片释放。
- 每个子切片有独立 owner、回滚点和行为验收,不批准一个巨型 Wave。
## 候选子任务
1. U10 chatlog/contextasm 原地端口化。
2. U11a 唯一 app composition root。
3. U11b 按事件逐个替换闭包桥。
4. U11c 逐 use case 迁移 ExecuteTask/executeStageInternal。
5. U11d UserProjectContext snapshot/update 收权。
6. U12 server/SSE 边界和架构门禁收口。
## 不包含
- 错误信封统一。
- PI Runner result.json 协议。
- 微服务拆分。
## 相关链接
- [模块解耦整改与重构计划](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
- [模块化单体解耦架构](../../system-design/2026-09-14-module-decoupling-architecture.md)
@@ -1,55 +0,0 @@
---
title: "H0 HTTP/SSE 公开错误信封盘点"
created: 2026-09-15
status: done
confidence: high
---
# 调研:H0 HTTP/SSE 公开错误信封盘点
## 结论
`Server.Routes()` 现有 **122** 条公开路由。错误响应至少三种并存:纯文本 `http.Error`、`{"error","message"}` JSON、以及 SSE `error_info`(`user_message/code/class/request_id`)。前端设置页已按 `error` code 分支,聊天流走 `error_info`;大量文档/任务路由仍回传 `err.Error()`,H1 必须 additive 统一,不能先改状态码。
## 证据
| 项 | 路径/命令 | 结果 |
|----|-----------|------|
| 路由清单 | `internal/server/server.go` `Routes()` | 122 条 `mux.HandleFunc` |
| 纯文本/拼接 error | `handlers.go`、`task_run_handlers.go`、`asset_handlers.go`、`sse.go` | `http.Error(w, err.Error(), …)` 会泄露内部原因 |
| JSON `{error,message}` | `project_settings_handlers.go`、`project_members_handlers.go`、`auth_helpers.go`、`chatflow_http.go` | 已有 `ERR_*` / `PLAN_FROZEN` 等稳定 code |
| SSE | `internal/stream/types.go` `ErrorInfo`;`classify.go` 固定 `UserMessage` | 有 `request_id`;`error` 字符串与 `error_info.user_message` 并存 |
| 前端 code 分支 | `web/src/api/projectSettingsError.ts` | `PLAN_FROZEN` / `PLAN_REVISION_CONFLICT` / `ERR_CONCURRENT_SWITCH` |
| 前端文案匹配 | `web/src/App.tsx` `detail.includes('无权访问该项目')` | 未知 code 仍靠 substring |
## 兼容风险
| 家族 | 代表路由 | 现状 | H1 风险 |
|------|----------|------|---------|
| 纯文本 | `POST /api/v1/chat`、`POST /api/v1/tasks/runs` | `Content-Type` 非 JSON,正文即 message | 前端若按 JSON 解析会失败;须 additive 保留旧正文或双写 |
| JSON error+message | 设置/成员/鉴权 | `error` 当 code | 与目标 `code` 字段同义;H1 应同时输出 `code` 与 `error` |
| SSE error_info | `/api/v1/chat/stream`、task stream | 已有 code/class/request_id | 与 HTTP 信封字段名不完全对齐(`user_message` vs `message`) |
| 授权拒绝 | `ERR_UNAUTHENTICATED` / `ERR_FORBIDDEN` | 部分 JSON、部分纯文本 | 统一后仍须不泄露资源存在性 |
## 建议映射(领域 → 目标 wire code)
| 领域情况 | 目标 code | 备注 |
|----------|-----------|------|
| 未登录 | `AUTHZ` | 不区分用户是否存在 |
| 项目/文档无权 | `AUTHZ` | 与 404 策略保持现有授权选择 |
| 参数/校验 | `VALIDATION` | details 只允许公开字段名 |
| 版本/修订冲突 | `VERSION_CONFLICT` | 现 `PLAN_REVISION_CONFLICT` 映射 |
| 幂等/重复提交 | `IDEMPOTENCY_CONFLICT` | 任务 run 已有 idempotency |
| 规划冻结 | `VALIDATION` 或保留 `PLAN_FROZEN` | H3 前不得改状态码 |
| 内部错误 | `INTERNAL` | 仅 `request_id`;禁止 SQL/路径/凭证 |
## 开放问题
- H1 是否把 SSE `user_message` 与 HTTP `message` 做成别名双写,需实施时定,不阻塞立项。
- 状态码 breaking 必须另写 ADR(H3)。
## 建议动作
- H1:envelope registry + request ID 中间件;旧 `error` 字段 additive 保留。
- 负例:XSS、路径、SQL、token、prompt、跨租户 ID 不得进入 `message`/`details`。
- 实施见 [HTTP 信封整改](../../remediation/2026-09-15-http-error-envelope-remediation.md)。
@@ -1,149 +0,0 @@
---
title: "模块解耦与 IPC/RPC 交互现状评估(复核修订版)"
status: done
created: 2026-09-15
updated: 2026-09-15
author: Cline
confidence: high
---
# 调研:模块解耦与 IPC/RPC 交互现状评估
## 结论
1. 系统采用模块化单体,不应把所有模块调用改成 IPC/RPC。当前已运行的外部传输边界有两条:Web 与 server 的 HTTP/SSE、Go server 与 PI Agent Runner 的 HTTP。`cmd/events` 和 FAV worker 是计划中的独立进程,不是已运行事实。
2. 端口、组合根、事件信封、RunManifest、幂等键和 arch-check 提供了可执行的边界基础;`import=0/event=0` 只表示没有超出现有 allowlist/baseline 的新违规,不能证明语义解耦已经完成。
3. 首要可靠性缺口是事件“部分生产、没有生产级消费闭环”。`internal/events/pg.go` 尚无原子 lease、ack/fail、retry/dead-letter 的完整实现;现有 dispatcher 测试覆盖 MemoryBus,不是 PostgreSQL 运行证据。
4. 最大结构扩散源仍是 bizdev service locator。另有 `docgov → docrevision` 单向 canonical/hash 工具依赖、chat/coordinator 扇出和 `intent → bizdev` 依赖。此前“docgov↔docrevision 双向 import”的结论不成立。
5. HTTP 错误信封与 PI Runner typed result 是独立协议债,不应阻塞持久事件链关闭。FAV 分支也不应成为 notify/projection 交付的前置条件。
## 1. 通信边界
| 边界 | 机制 | 当前状态 |
|---|---|---|
| Web ↔ server | `/api/v1/*` HTTP + SSE | 已运行;错误信封仍未统一 |
| Go ↔ PI Agent Runner | HTTP + Bearer;health/run/cancel/search | 已运行;结果仍依赖 legacy stdout/result.json 路径 |
| 单体内模块 | 消费者端口 + `internal/app` 组合根 | 已运行;bizdev locator 和部分直依赖仍扩大改动面 |
| 领域事件 | PG envelope/delivery schema | 写侧部分存在;生产 dispatcher 未闭环 |
| `cmd/events` | 计划中的独立 worker | 尚未实现/部署 |
| FAV worker | 独立审计轨道 | 分支未整支合入;不得作为本轮验收前置 |
不建议把单体内端口改成 RPC。那会增加序列化、延迟、部分失败与运维成本,却不消除当前 locator、授权、幂等和事件消费缺口。
## 2. 已有契约与真实边界
### 已有且可校验
- `.doc/system-design/module-boundaries.yaml` 与 `internal/archtest` 管理 import、SQL write、path 和 event 规则。
- `events.Envelope` schema 1 包含 event/aggregate/correlation/causation/idempotency/digest/producer 等字段,并校验 digest 与敏感字段。
- `taskrun.RunManifest` schema 1 使用 canonical JSON 与 SHA-256。
- TaskRun 同 idempotency key 异 request digest 返回冲突;文档写使用 expected head/ETag。
- backend 选择由服务端 allowlist 控制,出站数据经过 secret stripping。
- `module-boundaries.yaml` 已有 `event_producers` 与 `event_consumers` 段。后续工作是补全并校验 runtime registry parity,不是新建段落。
### 尚未闭合
- `PGSink.Append`/`InsertEnvelope` 已存在,但 `ClaimIDs` 仍是 SELECT-only claim;没有生产级 lease 获取、heartbeat、fenced ack/fail、retry、dead-letter 和 immutable attempt audit 闭环。
- `event_deliveries` 每个 event/consumer 一行,只保存当前状态和累计 attempt;无法还原每次 lease/attempt 历史。
- `internal/events/replay.go` 只检查 dry-run 与 consumer/operator/reason 等基础字段,尚未形成带认证主体、env/project/event scope、plan digest 和 apply 审计的应用用例。
- `docflow` envelope 仍存在 `Environment:"dev"`、`ProjectID:0`,且 `Fav.StageAgentCommit(ctx, 0, ...)` 使用错误项目作用域。
- 部分 server 路径临时构造 `docflow.Commands`,没有稳定注入 EventSink/UoW;不能假设 candidate-ready、downstream-impact、approved 三条链已经产生可供 shadow 的事件。
- 闭包 hook 没有版本、重试、delivery 或 replay 记录。
## 3. 耦合点
### 3.1 bizdev service locator
`bizdev.Service` 暴露 `Pool()/CAS()/DocGov()/DocRevision()/ProjectWorkflow()/FreeformDoc()/KB()/ContextManager()`。调用方可以绕过端口取得数据库池和其他模块实现,令签名或构造变化向多包扩散。
整改应先加 no-new-callers 门禁,再逐调用方迁移,最后在一个 contract 提交删除 8 个 getter。门禁应禁止领域/用例 API 暴露或转发 pool/tx,同时允许 app/cmd 组合根向表属主构造器注入 pool,并允许登记属主从 opaque TxScope 解出 tx。
### 3.2 docgov 到 docrevision 的单向工具依赖
生产依赖方向是 `docgov → docrevision`。直接用途集中在 Markdown canonicalization 与 SHA helper;`docrevision` 不生产 import `docgov`。
目标不是“破双向环”,而是把 canonical Markdown + digest 提取为有行为、内聚、带 golden vectors 的共享模块,例如 `internal/doccontent`。它不应进入只放无行为值对象的 vocabulary。
### 3.3 chat、coordinator 与 intent
- coordinator 仍以 `bizdev.TaskRunRequest/Result` 为词汇。
- chat 编排跨多个模块,需按用例逐批迁入 chatflow。
- intent 与 bizdev 的解绑是较小且独立的迁移,不应和 chat 大迁移绑成一个分支。
### 3.4 闭包桥与未接线事件
当前批准后的推进与通知仍可通过 `docrevision.OnOutbox`、`docgov.AddOnApprovedHook` 及组合根闭包执行。闭包在提交后的进程内调用不能提供 durable delivery、重试、dead-letter、replay 或 attempt audit。
不能直接删除闭包。正确顺序是:
1. 证明生产入口在同一 UoW 写入领域变化、envelope 和目标 delivery。
2. 对历史事件做 dry-run inventory,隔离 scope/schema/sequence 异常。
3. 完成真实 PG dispatcher。
4. shadow 只计算 intended outcome,不执行业务副作用。
5. 以时间、样本和状态分支覆盖作为切换门。
6. 按 notify、workflow advance、projection 独立切换和回滚。
## 4. 并发、数据与权限风险
### 并发
- `FOR UPDATE SKIP LOCKED` 只有在 claim 事务同时更新 lease owner/token/until 并 RETURNING 时才完成所有权转移;当前 SELECT-only `ClaimIDs` 不够。
- Fencing 不能只保护 ack。token 必须进入 consumer command,并在数据库副作用或 projection marker 的最终提交点校验。heartbeat 失败应取消 handler。
- 同一 consumer/aggregate 最多一个 inflight;不同 aggregate 并行。领域版本可能稀疏,不能直接当无缺口事件序号。
- at-least-once delivery 通过 inbox/唯一键/CAS/no-replace 得到 exactly-one visible outcome;不能声称 delivery 本身 exactly once。
### 历史数据
旧记录可能含 project 0、错误 environment、未知 consumer、未知 payload schema 或稀疏 aggregate version。启用 live claim 前必须生成 manifest,并分类 safe/repair/quarantine/expire。任何修复保留 old/new digest、operator、reason、approval;本计划不删历史数据。
### 权限
后台 consumer 使用按 env/consumer/action 约束的 service principal。处理事件时按 ProjectID/DocID 重读资源归属、成员/duty、workflow config revision、活动 stage 和当前状态。事件 actor 只用于审计,不能把历史用户权限带到延迟执行时。
Replay 必须是应用用例:管理员 capability、精确范围、reason/approval、dry-run plan digest、apply exact digest 和不可变审计。多项目或批量 apply 需要操作者与批准人分离。
日志、dead-letter 和 reconciliation 只能保存 ID、digest、typed error code 与字段 allowlist 生成的摘要,不能保存原始 payload、正文、SQL error、绝对路径、token 或 prompt。
## 5. 优先级建议
### P0:Track E 持久事件交付
1. 修正 docflow 生产入口、env/project 作用域和 UoW 原子写。
2. 补全既有 event allowlist 与 runtime registry parity。
3. 审计历史事件、sequence/checkpoint 模型和现有唯一约束。
4. 实现 `cmd/events` 的 PG lease/heartbeat/fencing/attempt/dead-letter。
5. notify、workflow advance、projection 逐个 shadow、live、回滚。
6. 用真实 browser + PG + worker restart 证明刷新后正文恢复,无 projection-missing。
### P1:Track S 结构解耦
- D4:bizdev locator 调用方迁移与最终 getter 原子删除。
- D5:stageflow 自有 use-case 类型,coordinator 解绑 bizdev DTO。
- D6:提取 doccontent canonical 行为模块,移除单向工具依赖。
- D7a:intent 单独解绑 bizdev。
- D7b:chat 按用例迁入 chatflow。
这些单元分别 go/no-go,不作为事件可靠性 blocker 的关闭条件。
### P2:Track P 独立协议
- HTTP/SSE 错误信封另立 remediation;公开 details 必须按 code allowlist 并脱敏。
- PI Runner 任务命名为 typed-result-v1 rollout,不混称“协议 v2”。typed 字段存在但无效时 fail closed;只有字段缺失且握手声明旧 Runner 时才允许 legacy。
## 6. 证据索引
| 事实 | 证据 |
|---|---|
| 模块化单体决策 | `.doc/adr/2026-09-14-modular-monolith-decoupling.md` |
| PG delivery 当前实现 | `internal/events/pg.go`、`deploy/postgres/goose/00035_2026-09-14-durable-event-delivery.sql` |
| MemoryBus 测试边界 | `internal/events/dispatcher_test.go`、`internal/events/bus.go` |
| replay 当前校验 | `internal/events/replay.go` |
| 事件字段硬编码 | `internal/app/docflow/commands.go` |
| 闭包桥 | `internal/app/docnotify/subscriber.go`、`internal/docgov/engine.go`、`internal/app/app.go` |
| bizdev locator | `internal/bizdev/service.go:229-260` |
| 单向 canonical 依赖 | `internal/docgov/lease.go`、`internal/docrevision` canonical helper |
| allowlist 已存在 | `.doc/system-design/module-boundaries.yaml` |
## 建议动作
下一项只立 Track E 的 E0A:事件生产、契约与历史数据门。Dispatcher 必须保持 off,直到 PG 测试证明事件源和旧数据分类正确。完整执行计划见 [Phase 2 持久事件交付与后续解耦路线](../../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)。
@@ -1,54 +0,0 @@
---
title: "P0 PI Runner typed-result 兼容矩阵"
created: 2026-09-15
status: done
confidence: high
---
# 调研:P0 PI Runner typed-result 兼容矩阵
## 结论
当前 `/v1/run` 远程响应与本地 bridge stdout **都不是** `result_v1`。Go 只解析 `ok/fallback_reason/stderr/retryable/patches[]`;成功路径再 `MaterializeTargets`。仓库里没有 `configs/schemas/pi-run-result-v1.json`。typed 字段一旦出现但非法必须 fail closed;本盘点确认 legacy 窗口仍是默认路径。
## 证据
| 项 | 路径/命令 | 结果 |
|----|-----------|------|
| 远程调用 | `internal/agent/piagent.go` `executeRemote` | `POST {runnerURL}/v1/run`;Bearer via `ApplyRunnerAuth` |
| 远程解码 | 同上 `remoteResp` | `ok`, `fallback_reason`, `stderr`, `retryable`, `patches[].rel_path/content` |
| 本地 bridge | `PiAgentBackend.Execute` | stdin JSON payload;stdout **最后一行** JSON;失败把 `stderr` 拼进 `ErrorReason` |
| 产物 | `MaterializeTargets(workDir, req.Targets, incoming)` | 默认 target `output.md` |
| 既有 schema | `configs/schemas/` | 仅 `change-report-v1.json`,无 run-result |
| 取消/超时 | `CommandContext` + `http.Client{Timeout}` | 超时进 `ErrorReason`;无单调终态结构体 |
| Handshake | 无 | 未声明 typed capability,故今日全部算旧 Runner |
## 兼容矩阵
| Runner 形态 | 成功输出 | 失败输出 | Go 行为 | P1/P2 约束 |
|-------------|----------|----------|---------|------------|
| 远程 HTTP `/v1/run` | `ok=true` + patches | `ok=false` + fallback/stderr | 解码失败即失败;不读 `result_v1` | P1 additive 加 `result_v1`;P2 typed-present-invalid 禁止 fallback |
| 本地 bridge 二进制 | stdout 末行 `{ok}` | `ok=false` 或进程 err | 整段 stdout 进 `Logs` | Logs 不得含 prompt/token;P1 后 Logs 只留 digest |
| stub | 内存产物 | 分类失败 | 测试夹具 | 不作为真实 PI 证据 |
| 未知 major / 缺 schema | — | — | 今日不会发生 | P2 fail closed |
## 体积与路径风险
- patches `Content` 无 body/member 上限;P1 必须在分配前限制。
- `RelPath` 未在 adapter 层拒绝 `..` / 绝对路径(依赖 `MaterializeTargets`);P1 负例要覆盖 symlink escape。
- `ErrorReason` 拼接 `stderr`,可能带模型/路径;公开日志禁止原样落盘。
## 取消与竞争
- HTTP client timeout 与 context cancel 共用;无独立 cancel token 与 result 的 CAS。
- P3 真实 PI E2E 必须覆盖:成功、typed error、取消、超时、未知 schema。
## 开放问题
- 真实容器内 Runner 镜像版本与是否已能吐 `result_v1` 需 P1 时对一下 pi-agent 镜像,不阻塞立项。
## 建议动作
- P1:共享 JSON Schema `configs/schemas/pi-run-result-v1.json`;Runner additive 输出。
- P2:Go typed-first parser;handshake 声明旧 Runner 才允许 legacy。
- 实施见 [PI typed-result-v1](../../remediation/2026-09-15-pi-typed-result-v1-remediation.md)。
@@ -1,35 +0,0 @@
---
title: "Track E 持久事件交付复盘"
created: 2026-09-15
status: done
confidence: high
---
# 调研:Track E 持久事件交付复盘
## 结论
E0A–E1C 已在隔离库证明:领域变化、envelope、delivery 同 UoW;PG dispatcher 原子 lease/fencing;notify / workflow_advance / projection 各自 exactly-one visible outcome。共享集群消费者保持 **off**,HTTP 闭包仍是唯一真实写者。E2 已部署兼容守卫:消费者 `live` 时闭包停写,`off`/`shadow` 时闭包继续写。删除 `OnOutbox` / `AddOnApprovedHook` 必须等 live 发布窗口;当前删除会让 notify/advance 停写。`DOC-RELIABILITY-PILOT` 保持 OPEN。FAV 保持 disabled。
## 证据
| 项 | 路径/命令 | 结果 |
|----|-----------|------|
| E0A | [E0A 报告](../../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md) | PASS;dispatcher off;FAV 不写入 |
| E0B | [E0B 报告](../../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md) | PASS;1/2/4 worker;旧 token 失败 |
| E1A | [E1A 报告](../../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md) | 隔离库 unique notify PASS;共享 off |
| E1B | [E1B 报告](../../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md) | 隔离库 unique stage-ready PASS;共享 off |
| E1C | [E1C 报告](../../test-reports/2026-09-15-event-e1c-projection-test-report.md) | no-replace PASS;共享 off |
| E2 | [E2 报告](../../test-reports/2026-09-15-event-e2-hook-guard-test-report.md) | live 停写;off/shadow 仍写;API 保留 |
## 开放问题
- 共享环境尚未做 notify/advance/projection 的 live 切换与授权页刷新纵切,因此 Track E DoD 中「生产注册无 OnOutbox=」与「授权 UI 三类重启」未关闭。
- 历史 inventory 的 repair/quarantine 真实批量审批未在共享库演练。
- FAV 仍只预留 disabled 契约。
## 建议动作
- 下一窗口:按消费者独立 shadow coverage → drain → live,闭包因 E2 守卫自动停写;确认 backlog 与 receipt 后再删 hook API。
- Track S 从 D6(`internal/doccontent`)开始,不占用 events mutex。
- Track P 保持独立 remediation,不阻塞事件交付。
@@ -1,8 +1,8 @@
---
title: "修复对话刷新恢复与授权统计不一致"
status: done
status: in_progress
created: 2026-09-13
updated: 2026-09-15
updated: 2026-09-13
owner: Cursor
branch: fix/chat-history-refresh
worktree: ".worktrees/fix-chat-history-refresh"
@@ -37,7 +37,7 @@ mutex: chat
3. [x] 实现统一会话/消息授权查询及统计同集
4. [x] 实现历史 dry-run/backfill 与对账
5. [x] 完善前端恢复状态及用户隔离缓存
6. [x] 执行全量门禁、真实 PI 闲聊刷新 E2E 和双用户负例(编制任务激活链 save 400 未纳入本轮)
6. [ ] 执行全量门禁、真实 PI 刷新 E2E 和双用户负例(PG/单测已完成;PI 待 dev 容器)
## 验收标准
@@ -55,4 +55,3 @@ mutex: chat
- Audit: [../../audit/2026-09-13-chat-history-refresh-disappears.md](../../audit/2026-09-13-chat-history-refresh-disappears.md)
- Remediation: [../../remediation/2026-09-13-chat-history-refresh-remediation.md](../../remediation/2026-09-13-chat-history-refresh-remediation.md)
- Live: [../../test-reports/assets/2026-09-15-chat-history-refresh-live/live.json](../../test-reports/assets/2026-09-15-chat-history-refresh-live/live.json)(项目 6252,window=categories=2,guest 403)
@@ -1,11 +1,11 @@
---
title: "修复查询误触发写任务与任务状态刷新退化"
status: done
status: in_progress
created: 2026-09-13
updated: 2026-09-15
owner: Cursor
branch: docs/conversation-intent-dual-tab
worktree: "-"
updated: 2026-09-13
owner: Codex
branch: fix/conversation-intent-state
worktree: ".worktrees/fix-conversation-intent-state"
mutex: intent
---
@@ -34,26 +34,24 @@ mutex: intent
3. [x] 收紧写任务动作识别并修复 busy 错误分型
4. [x] 实现任务/租约状态刷新恢复与统一提示
5. [x] 实现命名文档的服务端鉴权只读总结(“总结”不止是不写入)
6. [x] 执行前端、Go、PG 与真实 PI 双标签页验收
6. [ ] 执行前端、Go、PG 与真实 PI 双标签页验收
- [x] Go、前端、构建、dev 重建与真实 PI 只读总结
- [x] 服务端 busy 预检不创建 run,并持久化无重试状态卡
- [x] 浏览器刷新恢复与双标签页 busy 可见性(项目 6275;禁止项目 143)
- [ ] 浏览器刷新恢复与双标签页 busy 可见性
## 验收标准
- [x] [整改方案](../../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md) 全部验收项有证据
- [x] `CHAT-INTENT-STATE` 由 FAIL 更新为 PASS
- [x] test-report 归档并回链
- [ ] [整改方案](../../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md) 全部验收项有证据
- [ ] `CHAT-INTENT-STATE` 由 FAIL 更新为 PASS
- [ ] test-report 归档并回链
## 相关链接
- Checklist: 本任务验收标准
- Handoff: [../../ops/handoffs/2026-09-15-conversation-intent-dual-tab.md](../../ops/handoffs/2026-09-15-conversation-intent-dual-tab.md)
- Handoff: 与 `fix/chat-history-refresh` 合并前复核 `App.tsx/chatWindow.ts`
- Test report: [../../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md](../../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md)
## 证据 / 备注
- Audit: [../../audit/2026-09-13-conversation-intent-runtime-state.md](../../audit/2026-09-13-conversation-intent-runtime-state.md)
- Remediation: [../../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md](../../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md)
- 双标签活验:项目 **6275** / `sess-p6275-u10` / `run_1789452602295343365`;产物 `.doc/test-reports/assets/2026-09-15-conversation-intent-dual-tab/`
- 未改写项目 143,未删除 `sess-p143-u9` 探针
@@ -1,54 +0,0 @@
---
title: "文档可靠性 M1 活验签字与条件 M2"
status: done
created: 2026-09-14
updated: 2026-09-14
owner: Cursor
branch: refactor/document-reliability-pilot
worktree: .worktrees/refactor-document-reliability-pilot
mutex: workspace
---
# 文档可靠性 M1 活验签字与条件 M2
## 目标
占集成槽把试点合入本地 `dev` 并 rebuild,补齐真实 PI / 浏览器 / 跨用户 / 多会话签字。仅当新报告最后一句为「继续 M2」时开工 U5–U7。
## 范围
- A1 占槽、合入、rebuild、health/ready
- A2 143 只读 + 新建项目页面 + fail-closed
- A3 真实 pi-agent 编制后刷新
- A4 隔离库双 pool / 4 会话
- A5 活验 go/no-go
- B 仅 go 后:U5–U7
## 非目标
- 不终止项目 143
- 未 go 不开 outbox/FAV
- 不拆 chat/squad
## 步骤
1. [x] 占集成槽并合入本地 dev rebuild
2. [x] 浏览器 + 跨用户
3. [x] 真实 PI
4. [x] 双 pool/4 会话
5. [x] 活验报告(最后一句:继续 M2)
6. [x] 条件 M2(U5–U7)
## 验收标准
- [x] health + ready 来自本分支镜像
- [x] 143/新项目刷新 404/409/projection-missing = 0 或报告停止扩面
- [x] 报告最后一句只能是继续 M2 或停止扩面
- [x] M2 报告最后一句只能是继续 M3 或停止扩面
## 相关链接
- Checklist: [../checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Prior report: [../../test-reports/2026-09-14-document-reliability-pilot-test-report.md](../../test-reports/2026-09-14-document-reliability-pilot-test-report.md)
- Live report: [../../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md](../../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md)
- M2 report: [../../test-reports/2026-09-14-document-reliability-m2-test-report.md](../../test-reports/2026-09-14-document-reliability-m2-test-report.md)
@@ -1,64 +0,0 @@
---
title: "文档可靠性纵向试点 M0–M1"
status: blocked
created: 2026-09-14
updated: 2026-09-14
owner: Cursor
branch: refactor/document-reliability-pilot
worktree: .worktrees/refactor-document-reliability-pilot
mutex: docgov
---
# 文档可靠性纵向试点 M0–M1
## 目标
在不横向搬包的前提下,完成 U1–U4,使受控文档在并发提交、页面刷新、重登、restart、rebuild 和 projection 缺失后仍从数据库账本返回唯一授权正文。
## 范围
- U1 架构基线与 production writer/path 门禁。
- U2 应用 UnitOfWork 和跨属主事务能力。
- U3 人工编辑、agent commit、批准/驳回事务化。
- U4 授权后的文档统一读模型。
- 项目 143 等价脱敏 hazard 与新项目真实 PI/UI 验收。
## 非目标
- 不启用 FAV degraded read。
- 不拆 chatlog/contextasm/squadrun 包。
- 不统一错误信封,不修改 PI Runner 协议。
- 不清理历史 dev 数据。
## 步骤
1. [x] 从最新 `dev`(`a8f9451`)创建实现分支,登记 CURRENT 并确认 `docgov` mutex 已释放。
2. [x] U1:四类规则 arch-check + archtest + 可重放基线(新违规 block)。
3. [x] 实现 U2,验证任意属主写入/commit 故障整体回滚。
4. [x] 实现 U3,删除提交后 outbox 正确性回调。
5. [x] 实现 U4,保证 GET 零写入和 projection 缺失不再伪装成 404。
6. [x] 隔离库 PG + 目标包 race 已跑;真实 PI / 浏览器 / rebuild **未**签字(未占槽)。
7. [x] 写 test report:结论 **停止扩面**。更新验收清单、FEATURE-MATRIX、CURRENT 和 gap-matrix。
## 验收标准
- [x] 同一 ETag 并发编辑只有一个合法赢家(内存 8 协程 + 隔离库双会话)。
- [x] 任一事务故障点不会留下部分提交(U2 隔离库)。
- [ ] 项目 143 等价 hazard 和新项目刷新/重启目标 404/409/projection missing 为 0(真实页面未测)。
- [x] 服务端匿名/未知文档/跨项目/错误责任人 fail closed;浏览器跨登录未测。
- [ ] 1、2、4 个 app 实例的最终状态一致(仅到双会话)。
- [x] M1 test report 结论:**停止扩面**。
## 相关链接
- Checklist: [../checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- Test report: [../../test-reports/2026-09-14-document-reliability-pilot-test-report.md](../../test-reports/2026-09-14-document-reliability-pilot-test-report.md)
- Plan: [../../remediation/2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
## M2+ 门(不开工)
U5 WorkspaceRef、U6 outbox、U7 按文件摘 FAV 需要独立审批,且仅当 M1 报告最后一句为「继续 M2」。当前是「停止扩面」,禁止实现 U5–U12。
## 证据 / 备注
隔离库与目标包 race 见 test-report assets。未占槽、未 rebuild。只有真实 PI/浏览器/rebuild 补测并把报告改为「继续 M2」后,才允许启动 durable event/FAV。
@@ -1,11 +1,11 @@
---
title: "治理鉴权升级:职责-动作严格对应 + 未激活拦截 + 关闭创建直通"
status: done
status: blocked
created: 2026-09-14
updated: 2026-09-14
owner: implementer_cursor
owner: Cline
branch: fix/governance-action-level-authz
worktree: ".worktrees/fix-governance-action-level-authz"
worktree: "-"
mutex: workflow
---
@@ -52,30 +52,29 @@ mutex: workflow
## 步骤
1. [x] 评审落盘 + 决策 A–D 收敛 + 本任务登记(Wave 5 已合入本地 `dev@19f6df5`,G0 已开工)
2. [x] G1 后端:`CheckDocTaskAccess` 动作-职责映射 + creator 例外移除(保留 none 生成触发)+ gov==nil 未激活拦截(202 契约保留);重写受影响单测
3. [x] G2 关闭 `initial_workflow_key` 直通 + 前后端字段废弃 + E2E legacy 用例更新
4. [x] G3 前端:chat 治理拦截自然语言提示、按钮级职责禁用、激活确认页冻结提示补强
5. [x] G4 dev 库 planning+with_wf 异态审计分类(只读报告,现测 83 条均为测试夹具)
6. [x] G5 集成验证 + 测试报告归档(新项目全链路:零治理创建→对话→配置→激活→职责动作负例)
1. [x] 评审落盘 + 决策 A–D 收敛 + 本任务登记(blocked 等待 Wave 5 收敛、mutex `workflow` 空闲)
2. [ ] G1 后端:`CheckDocTaskAccess` 动作-职责映射 + creator 例外移除(保留 none 生成触发)+ gov==nil 未激活拦截(202 契约保留);重写受影响单测
3. [ ] G2 关闭 `initial_workflow_key` 直通 + 前后端字段废弃 + E2E legacy 用例更新
4. [ ] G3 前端:chat 治理拦截自然语言提示、按钮级职责禁用、激活确认页冻结提示补强
5. [ ] G4 dev 库 81 个 planning+with_wf 异态审计分类(只读报告)
6. [ ] G5 集成验证 + 测试报告归档(新项目全链路:零治理创建→对话→配置→激活→职责动作负例)
## 验收标准
- [x] full 文档 API 负例:author 不可 review/approve;reviewer 不可 run/edit/submit;approver 不可 run/edit/review;creator 不可任一审批动作(view 除外)
- [x] none 文档:创建者可触发生成;submit/review/approve 全拒
- [x] 未激活项目编制类输入:消息正常显示、run 202 且 blocked、无小队/租约、chat 内明确治理提示文案(页面用「请编制用户初始需求收集表」命中任务 API)
- [x] `POST /projects` 带 `initial_workflow_key`:不再置 active,工作流目录仍自动挂载
- [x] `go vet ./...`、`go test -short ./...`、`cd web && npm test && npm run build` 全绿
- [x] 异态审计报告与测试报告归档并回链
- [ ] full 文档 API 负例:author 不可 review/approve;reviewer 不可 run/edit/submit;approver 不可 run/edit/review;creator 不可任一审批动作(view 除外)
- [ ] none 文档:创建者可触发生成;submit/review/approve 全拒
- [ ] 未激活项目 chat 输入「帮我生成立项文档」:消息正常显示、run 202 且 blocked、无小队/租约、chat 内明确治理提示文案
- [ ] `POST /projects` 带 `initial_workflow_key`:不再置 active,工作流目录仍自动挂载
- [ ] `go vet ./...`、`go test -short ./...`、`cd web && npm test && npm run build` 全绿
- [ ] 异态审计报告与测试报告归档并回链
## 相关链接
- Research(评审与决策记录): [2026-09-14-mvp-governance-rules-review.md](../../ops/research/2026-09-14-mvp-governance-rules-review.md)
- Research(评审与决策记录): [2026-09-14-mvp-governance-rules-review.md](../research/2026-09-14-mvp-governance-rules-review.md)
- 前序 Remediation(已实施 Wave 1–4): [2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md](../../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md)
- 202 契约来源: [2026-09-13-workflow-access-chat-members-ui01-02.md](../../audit/2026-09-13-workflow-access-chat-members-ui01-02.md)
## 证据 / 备注
- Wave 5 已合入本地 `dev@19f6df5`;本任务 worktree 已从该 `dev` 创建,mutex `workflow` 进入 `in_progress`。
- G4 只读复测:141 active / 209 planning;**83** 个 planning 带非空 `active_workflow_key`,全部为 `PROJ_MGR_*`/`TEST_PROJ_*` 夹具。见 [audit](../../audit/2026-09-14-planning-with-workflow-key-anomaly.md)。
- G5 验收:[2026-09-14-governance-action-level-authz-test-report.md](../../test-reports/2026-09-14-governance-action-level-authz-test-report.md)。
- Wave 5 占槽现状(2026-09-14 实测):`implementer_cursor` phase=e2e,worktree 存在未提交 e2e 产物;本任务排在集成槽位 queue。
- dev 库:133 active / 204 planning;81 个 planning 项目带非空 `active_workflow_key`(待 G4 审计分类)。
@@ -0,0 +1,54 @@
---
title: "模块解耦 Wave 0:契约包骨架 + 架构门禁基线"
status: done
created: 2026-09-14
updated: 2026-09-14
owner: Cursor
branch: feature/remove-herdr-agent-settings
worktree: "-"
mutex: arch
---
# 模块解耦 Wave 0:契约包骨架 + 架构门禁基线
> 总方案:[../../system-design/2026-09-14-module-decoupling-architecture.md](../../system-design/2026-09-14-module-decoupling-architecture.md)
> ADR:[../../adr/2026-09-14-modular-monolith-decoupling.md](../../adr/2026-09-14-modular-monolith-decoupling.md)
## 目标
建立 `internal/contracts` 骨架与 `scripts/arch-check.sh` 依赖门禁(warn 基线),使模块边界从此可度量、可执行,为 Wave 1–6 提供验收对照。
## 范围
- `internal/contracts/`:vocabulary.go(MaturityStage 等共享枚举占位)、errors.go(错误码表)、events.go(首批事件类型定义,纯定义零实现)
- `scripts/arch-check.sh` + `.doc/system-design/module-boundaries.yaml`(以现状生成 allowlist,不收紧)
- 基线违规报告存 `.doc/audit/2026-09-14-arch-check-baseline.md`
## 非目标
- 不改任何业务行为、不迁移任何包(属 Wave 1+)
- 不收紧任何依赖规则(block 转换在两周 warn 期后)
## 步骤
1. [x] 用户确认 ADR → 状态转「已接受」
2. [x] 建 contracts 骨架(纯定义,`go test ./internal/contracts` 绿)
3. [x] 写 arch-check.sh(import allowlist / 表属主 / 路径字面量三类检查,支持 --mode warn|block)
4. [x] 运行 warn 模式,基线报告落 `.doc/audit/`
5. [ ] 合 `dev` 占槽冒烟(本轮不占槽;集成槽仍由 workflow-plan Wave 5 持有)
## 验收标准
- [x] `./scripts/arch-check.sh --mode warn` 可运行并产出基线报告
- [x] `go vet ./... && go test -short ./...` 全绿(2026-09-14 本工作区;`internal/server` 9.823s)
- [x] ADR 状态「已接受」;本文件 status → done
## 相关链接
- Checklist: -
- Handoff: -
- Test report: -
## 证据 / 备注
- 依赖图实测(2026-09-14):server 25 内部包 / 17,007 行;bizdev 16 包;详见总方案 §1.1
@@ -1,6 +1,6 @@
---
title: "workflow-plan 409 冻结态守卫 + 文档职责可选治理"
status: done
status: in_progress
created: 2026-09-14
updated: 2026-09-14
owner: implementer_cursor
@@ -37,30 +37,29 @@ mutex: workflow
1. [x] 定位项目 143 的 409 `PLAN_FROZEN` 根因并落盘 audit。
2. [x] 完成方案审核:补齐定义优先、零治理拦截、成员有效性、权限、快照清理和真实 UI 边界。
2b. [x] 用户批准最终方案,开工登记(Wave 0)
3. [x] Wave 1:typed API error + frozen 独立只读视图 + sticky/可访问错误 + 两标签竞态恢复。
4. [x] Wave 2:DutyMode、强制/可选任务策略、partial/成员/零治理校验、服务端规范化。
5. [x] Wave 3:门禁、readiness、阶段/文档访问、运行时和预览统计统一。
6. [x] Wave 4:前端逐文档“纳入人工审批”开关及 full/none/partial 交互测试。
7. [x] Wave 5:合 dev、rebuild、真实浏览器设置页矩阵;项目 143 只读回归;归档 test report。真实 PI 生成/审批长链路未跑,见报告。
3. [ ] Wave 1:typed API error + frozen 独立只读视图 + sticky/可访问错误 + 两标签竞态恢复。
4. [ ] Wave 2:DutyMode、强制/可选任务策略、partial/成员/零治理校验、服务端规范化。
5. [ ] Wave 3:门禁、readiness、阶段/文档访问、运行时和预览统计统一。
6. [ ] Wave 4:前端逐文档“纳入人工审批”开关及 full/none/partial 交互测试。
7. [ ] Wave 5:合 dev、rebuild、真实浏览器新项目全链路;项目 143 只读回归;归档 test report。
## 验收标准
- [x] active 项目设置无编辑控件,页面显示冻结原因、工作流/阶段/职责快照和受控终止影响入口。
- [x] 允许裁剪的非必需文档 full/none 均合法;partial 精确拒绝。
- [x] 必需/阻断/不可裁剪文档全空被服务端拒绝(单测 + 定义优先)。
- [x] 保存和激活均拒绝非 active project member;预览后成员退出也 fail closed(单测)。
- [x] 所有文档 none 时可走预览拒绝「至少一份纳入人工审批」(页面 C)。
- [ ] none 文档仍生成和入账本、项目成员只读可见、创建者可生成/编辑,但无 review/approve 且不阻塞阶段(**本轮未跑真实 PI,单测已覆盖门禁/权限**)。
- [x] disabled/none 的冻结快照、plan hash 和 assignment rows 不残留旧职责(Wave 3 单测)。
- [x] 两标签陈旧保存的 409 在当前视口可见、草稿保留并转 frozen。
- [x] 设置页真实 UI 用例有截图证据并回链;生成/审批长链路另立项。
- [ ] active 项目设置无编辑控件,页面显示冻结原因、工作流/阶段/职责快照和受控终止影响入口。
- [ ] 允许裁剪的非必需文档 full/none 均合法;partial 精确拒绝。
- [ ] 必需/阻断/不可裁剪文档全空被服务端拒绝。
- [ ] 保存和激活均拒绝非 active project member;预览后成员退出也 fail closed。
- [ ] 所有文档 none 时可保存草稿但不能激活。
- [ ] none 文档仍生成和入账本、项目成员只读可见、创建者可生成/编辑,但无 review/approve 且不阻塞阶段。
- [ ] disabled/none 的冻结快照、plan hash 和 assignment rows 不残留旧职责。
- [ ] 两标签陈旧保存的 409 在当前视口可见、草稿保留并转 frozen。
- [ ] 工程门禁与整改方案中的真实 UI 用例全部有证据;报告回链。
## 相关链接
- Audit: [2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
- Remediation: [2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md](../../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md)
- Test report: [2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md](../../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md)
- Test report: (Wave 5 归档至 `.doc/test-reports/`)
## 证据 / 备注
@@ -68,4 +67,4 @@ mutex: workflow
- 当前 `parseError` 已读取后端 message;前端改造重点是 typed error、冻结态切换和视口内呈现。
- 当前职责校验只检查正数/互异,数据库只外键到 users;项目成员有效性必须补服务端校验。
- 当前终止实现会取消运行任务、关闭实例并退回 planning;关闭实例访问 fail closed,因此项目 143 不能作为终止测试对象。
- 方案已迁移至基于最新 dev 的 `fix/workflow-plan-409-frozen-and-optional-duties` 独立 worktree;用户已批准实施。
- 开始编码前必须先把本任务从当前误置的 `feature/remove-herdr-agent-settings` 工作区迁移至声明的 `fix/workflow-plan-409-frozen-and-optional-duties` 分支/worktree,禁止污染无关分支。
@@ -1,105 +0,0 @@
---
title: "多意图持久计划与 HITL(核心 U1–U8,扩面 U9–U12)"
status: done
created: 2026-09-15
updated: 2026-09-16
owner: Cursor
branch: "-"
worktree: "-"
mutex: "-"
---
# 多意图持久计划与 HITL(核心 U1–U8,扩面 U9–U12)
## 目标
不回退现有模块解耦、单意图行为和权限边界,交付可持久、可恢复、可并发裁决的 2–4 步计划;所有批量生成/写入/控制确认前零副作用,执行前逐动作重新授权。
## 权威文档
- [详细设计与计划](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- [复核审计](../../audit/2026-09-15-multi-intent-hitl-plan-review.md)
- [模块边界 SSOT](../../system-design/module-boundaries.yaml)
## 强制约束
- `internal/intent` 继续只依赖 `maturity`;新生命周期归 `internal/app/intentflow`;
- 确认不是授权;每步由动作 owner 按当前主体、状态和版本重新鉴权;
- PG plan state 权威,卡片/SSE 仅投影;
- 每步一个业务事务,不做跨模块长事务;
- 中间结果不进 FAV;
- 新行为从 legacy/shadow 开始,回滚不丢已有计划。
## 波次
| 波次 | 单元 | 交付 | 依赖 | 主 mutex | go/no-go |
|------|------|------|------|----------|----------|
| W0 | U1 | 模块/API/状态/事件契约 | 无 | `intent`,`events` | arch/event/table owner 全绿 |
| W1 | U2 | 纯规则提案 shadow | U1 | `intent` | 不改路由,安全错误为 0 |
| W2 | U3 | intentflow + PG/CAS/lease | U1,U2 | `intent-plan` | 两 worker 无双 owner/执行 |
| W2 | U4 | outbox + 投影 | U3 | `events` | projection diff=0 |
| W3 | U5 | decision API + 授权端口 | U3 | `intent-plan`,`server/authz` | 权限负例全绿 |
| W3 | U6 | Web 卡片/刷新/a11y | U4,U5 | `web` | 双标签/reload 无假成功 |
| W4 | U7 | 低风险只读执行 | U4-U6 | `intent-plan`,`chat` | legacy 无回归 |
| W4 | U8 | task generate adapter | U7 | `taskrun`,`intent-plan` | 首版 real PI 闭环 |
| W5 | U9 | 可选 LLM adapter 实验 | U2,U7 | `intent-plan`,`pi-agent` | 不阻塞首版;达阈值才启用 |
| W5+ | U10 | low mutate 逐 action 扩面 | U8 | 实际 owner | 单 action 签署 |
| W5+ | U11 | docgov 逐 action 扩面 | U8 | `docgov`,`intent-plan` | 单 action 签署 |
| W5+ | U12 | workflow/run-control 分项扩面 | U8 | `workflow`/`taskrun` | 分项签署 |
> 本文件仅是总览,不长期占用一个 mutex。实施时每个 U-ID 新建独立 short-term、分支和认领;U10–U12 还必须按 action 拆分。核心首版为 U1–U8,U9 与后续 owner 扩面不阻塞首版关闭。
## 步骤
1. [x] U1 冻结边界、状态机、批量策略、错误码、事件和默认 legacy tier([独立任务](./2026-09-15-multi-intent-u1-contracts.md);[报告](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md));
2. [x] U2 characterization-first 建 golden/hard-negative 与 shadow 基线([独立任务](./2026-09-15-multi-intent-u2-segmenter.md);[报告](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md));
3. [x] U3 建 intentflow owner、PG schema、CAS/lease/fencing/retention([独立任务](./2026-09-15-multi-intent-u3-intentflow-pg.md);[报告](../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md));
4. [x] U4 接 Track E outbox/dispatcher,只投影状态事实([独立任务](./2026-09-16-multi-intent-u4-outbox-projection.md);[报告](../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md));
5. [x] U5 建统一 decision command 与动作 owner 授权端口([独立任务](./2026-09-16-multi-intent-u5-decision-api.md);[报告](../../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md));
6. [x] U6 取消计划动作的前端本地成功路径,以 PlanView 恢复([独立任务](./2026-09-16-multi-intent-u6-web-cards.md);[报告](../../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md));
7. [x] U7 只开放独立低风险查询([独立任务](./2026-09-16-multi-intent-u7-auto-read.md);[报告](../../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md));
8. [x] U8 只接 task generate,完成首版闭环(真实 PI 环境缺失记 stop-gate)([独立任务](./2026-09-16-multi-intent-u8-task-generate.md);[报告](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md));
9. [ ] U9 作为独立可选实验接语义分段;
10. [ ] U10–U12 分别按 mutate/docgov/workflow/run-control owner 扩面。
## 验收标准
- [ ] 含写/生成/控制时,确认前相关表、任务、文档和工作流零变化;
- [ ] 两标签确认/取消只产生一个决策和至多一次动作;
- [ ] 服务/worker 重启后 PG 恢复,成功步骤不重跑;
- [ ] 确认后权限或资源版本变化时 fail closed;
- [ ] 跨用户/项目/会话读取和决策被隐藏;
- [ ] 按钮与自然语言确认得到同一服务端 receipt;
- [ ] intent 边界、单一写者、UoW、事件静态契约和组合根无回退;
- [ ] 无活动计划时单意图生成保持;有活动计划时不创建第二任务;多意图生成需确认;
- [ ] 部分确认可稍后处理未选项,只有显式排除才取消;部分完成可重试、继续或关闭;
- [ ] 双标签/刷新/重开/SSE 重连真实页面通过;
- [ ] 适用的真实 PI E2E 通过,stub 不冒充验收。
## 非目标
- >4 步、并行 DAG、多活动写计划自动合并;
- 跨步骤 ACID/自动补偿;
- coordinator/chat 全量重构;
- FAV 启用或中间产物归档;
- 改变单意图生成策略。
## 交付纪律
- 每单元记录精确边界影响、适用测试、go/no-go、回滚、branch/commit/merge/push 状态;
- 每单元独立 test report、CURRENT 认领/集成槽和 FEATURE-MATRIX 回链;
- 安全、越权、双执行或刷新差异任一出现,停止当前 tier;dispatcher 故障只停投影;LLM 故障进入澄清。
## 相关链接
- Checklist: [U1](../checklists/2026-09-15-multi-intent-u1-contracts.md);[U2](../checklists/2026-09-15-multi-intent-u2-segmenter.md);[U3](../checklists/2026-09-15-multi-intent-u3-intentflow-pg.md);[U8](../checklists/2026-09-16-multi-intent-u8-task-generate.md)
- Handoff: 每个 U-ID 独立建立
- Test report: [U1](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md);[U2](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md);[U3](../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md);[U4](../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md);[U5](../../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md);[U6](../../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md);[U7](../../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md);[U8](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md)
## 证据 / 备注
- 当前 `plan_builder.go` 最多两段且写意图返回 nil;`action_planner.go` 的确认仍是文字提示。
- 当前 `module-boundaries.yaml` 中 intent 仅依赖 maturity;Track E live,FAV off。
- U1 已冻结 intentflow 契约、事件与 BatchActionPolicy,默认 `MULTI_INTENT_PLAN_TIER=legacy`。
- U2 已落地规则分段与 shadow `PlanProposal`;生产 TopIntent / IntentPlan 不变;反事实 `false_auto_execute=0`。
- U8 已落地 confirm 落盘与 `task.run` adapter;默认 legacy 不落盘。U9–U12 不阻塞核心首版。共享环境 schema 45 待晋升窗口。
@@ -1,76 +0,0 @@
---
title: "多意图 HITL U1:契约冻结"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/multi-intent-u1-contracts
worktree: "-"
mutex: architecture-docs
---
# 多意图 HITL U1:契约冻结
## 目标
冻结 `app/intentflow` 边界、状态机、BatchActionPolicy、错误码、事件契约与默认 `legacy` tier;不改识别路由、不建表、不接 HTTP。
## 范围
- `module-boundaries.yaml`:`app/intentflow` allowlist、三表 owner、`unwrap_owners`、三条 `intent.plan.*` 事件
- `events.StaticContracts` 与 YAML 对等;archtest 扫描 `intent.plan.*`
- `internal/app/intentflow` 骨架:状态、错误码、Service 端口、政策、tier 开关
- CSRF/认证结论:现有 Bearer + CORS 对 U5 足够,不是 blocker
## 非目标
- 不修改 `internal/intent` 业务类型或 `MULTI_INTENT_ENABLED`
- 不建 Goose 表、不接线 `app.Assemble`、不改 chat/coordinator/Web
- 不 Append 事件、不实施 U2–U12
## REST(U5 再挂路由)
- `GET /api/v1/intent-plans/active`
- `GET /api/v1/intent-plans/{plan_id}`
- `POST /api/v1/intent-plans/{plan_id}/decisions`
- body:`expected_revision`、`decision_nonce`、`decision_digest`、`kind`、步骤选择
## CSRF / 认证(U5 前置结论,非 blocker)
现有认证是 `Authorization: Bearer` 或 `X-Session-Token` 请求头(`internal/server/auth_handlers.go`),无 cookie 会话,无独立 CSRF 中间件;另有 Origin allowlist CORS。
- 自定义头不会被浏览器跨站表单自动带上,现有模式对 U5 足够
- `decision_nonce` / 幂等键只防重放与并发,**不替代** CSRF 或身份认证
- U5 必须 `requireAuthenticatedUser` + 四元作用域(environment/project/session/user)
- **禁止**为计划 API 改成 cookie 自动提交
- 若未来改 cookie 认证,另立 auth 任务,不得在 intent-plan 端点发明弱 CSRF
## 步骤
1. [x] 从最新 `dev` 检出 `feature/multi-intent-u1-contracts` 并认领 CURRENT
2. [x] 登记边界 YAML、事件契约、archtest regex
3. [x] 落地 intentflow 骨架与 BatchActionPolicy
4. [x] arch/parity/short 测试与 U1 报告
## 验收标准
- [x] `intent -> maturity` 保持;server/chat 不直写计划表
- [x] YAML ↔ StaticContracts parity 绿
- [x] 未知 action/policy key fail closed;ActionRegistry 无 batch/tier 字段
- [x] 默认 `MULTI_INTENT_PLAN_TIER=legacy`
- [x] 单意图生成策略不变(本单元无运行时改动)
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Checklist: [../checklists/2026-09-15-multi-intent-u1-contracts.md](../checklists/2026-09-15-multi-intent-u1-contracts.md)
- Test report: [../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)
## 证据 / 备注
- 事件登记窗口同时占用 `events` mutex;U1 不改 intent 代码。
- 生产者含 `events`:StaticContracts 字面量落在 `internal/events/registry.go`,与现有 document.* 先例一致。
- CSRF:Bearer / `X-Session-Token` + CORS allowlist,U5 非 blocker。
- 冒烟:`go vet ./...`、`go test -short ./...`、`./scripts/arch-check.sh --mode block` PASS。U1 无 schema/容器变更,集成槽位保持 idle。
- 提交:`bdccb4d` docs(ops);`aefb1e4` feat(events);`9364da4` feat(intentflow);随后 docs(status)。
@@ -1,63 +0,0 @@
---
title: "多意图 HITL U2:规则分段与 shadow 提案"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/multi-intent-u2-segmenter
worktree: "-"
mutex: intent
---
# 多意图 HITL U2:规则分段与 shadow 提案
## 目标
在不改变生产路由(TopIntent / 现有 IntentPlan)的前提下,用纯规则分段器生成 2–4 步 `PlanProposal` 与 shadow 指标;写段不再在提案层被静默丢弃。
## 范围
- `internal/intent/segmenter.go`:连接词/句号/分号/换行/序号/先再最后,上限 4
- `PlanProposal` L1 值对象:span、证据、缺槽、依赖建议、稳定 digest
- Recognize 附加提案与 shadow;**不**改 coordinator 执行路径
- golden / hard-negative / 反事实(若处于 auto_read 会如何)
## 非目标
- 不建 PG、不接 HTTP、不改 Web
- 不把 HITL/tier 回灌 ActionRegistry
- 不启用 LLM 分段(U9)
- 不把 shadow 提案当作生产 IntentPlan
## 步骤
1. [x] 认领 CURRENT,characterization 锁定现有 IntentPlan
2. [x] 分段器 + PlanProposal + digest
3. [x] 接入 Recognize(leaf 识别防递归)
4. [x] golden/hard-negative/反事实与报告
## 验收标准
- [x] 「查风险,然后查法规」现有 IntentPlan 仍为 2 步 query
- [x] 「查法规然后生成报价单」生产 IntentPlan 仍为 nil(路由不变),提案含写段且 ComboHint=needs_confirm
- [x] 「查询并总结」不拆
- [x] 指代失败 → needs_clarify
- [x] 红线混入 → rejected
- [x] 5 段 → rejected_batch_size
- [x] 同输入 digest 稳定
- [x] 反事实错误自动执行 = 0
- [x] `intent -> maturity` 保持
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Checklist: [../checklists/2026-09-15-multi-intent-u2-segmenter.md](../checklists/2026-09-15-multi-intent-u2-segmenter.md)
- Test report: [../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md)
## 证据 / 备注
- L1 不 import intentflow;`ComboHint` 只是结构提示,不是授权。
- 单段复用 primary frame,避免二次 Recognize。
- 冒烟:`go vet ./...`、`go test -short ./...`、`./scripts/arch-check.sh --mode block` PASS。U2 无 schema/容器变更。
- 提交:`4751348` docs(ops) 认领;`9005766` test(intent) characterization;`932ba87` feat(intent) 分段器与 shadow 提案。
@@ -1,68 +0,0 @@
---
title: "多意图 HITL U3:intentflow PG/CAS/lease"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
branch: feature/multi-intent-u3-intentflow-pg
worktree: "-"
mutex: intent-plan
---
# 多意图 HITL U3:intentflow PG/CAS/lease
## 目标
建立持久计划/步骤/决策与并发协议(CAS revision、decision nonce、lease/fencing、创建幂等、retention);不接真实写动作,不改 chat/coordinator 生产路由。
## 范围
- Goose `00044`:`intent_plans` / `intent_plan_steps` / `intent_plan_decisions`
- `app/intentflow` owner repository + UoW;owner 可 unwrap pgx
- 创建幂等 `(environment, session_id, client_turn_id)`;同 turn 异 digest 冲突
- 决策 CAS + nonce 同/异 digest;确认/取消/过期竞态
- 步骤 lease + 单调 fencing;两 worker 只一个 owner
- 业务成功但 receipt 写回失败时按幂等键对账,不盲跑
- 环境隔离;关闭计划 retention 由 owner 删除
- `app.Assemble` 装配 `*intentflow.Plans`,chat 仍不调用
## 非目标
- 不接 HTTP(U5)、不 Append 事件(U4)、不接真实 action adapter(U7/U8)
- 不把 HITL/tier 回灌 ActionRegistry
- 不改 `internal/intent` 生产 TopIntent / IntentPlan
- 不 rebuild 共享 `:8080`(schema 44 仅隔离库/后续晋升窗口应用)
## 步骤
1. [x] 认领 CURRENT(mutex `intent-plan`)
2. [x] Goose 00044 + migrate gate
3. [x] Store/Engine:Create/Decide/Claim/Receipt/Expire/Purge
4. [x] 内存并发 + 可选 PG 测试;Assemble 接线
5. [x] 报告并合回本地 dev
## 验收标准
- [x] 双创建同 digest 返回同一 plan;异 digest 冲突
- [x] nonce 同 digest 返回 receipt;异 digest 冲突
- [x] 确认/取消/过期只一个 CAS 胜出
- [x] 两 worker 抢 eligible 步骤无双 owner
- [x] 租约过期可接管;旧 fencing token 被动作属主拒绝
- [x] 重启后 succeeded 不重跑;receipt 写回失败按幂等键恢复
- [x] 跨 environment 隐藏
- [x] 默认 legacy 时 HandleTurn 不落盘
- [x] `go test -short ./internal/app/intentflow ./internal/app ./internal/archtest ./internal/db` 绿
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Checklist: [../checklists/2026-09-15-multi-intent-u3-intentflow-pg.md](../checklists/2026-09-15-multi-intent-u3-intentflow-pg.md)
- Test report: [../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md](../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md)
## 证据 / 备注
- HandleTurn 在默认 legacy 下不落盘;CreatePlan 是 U3 测试与后续 U7 入口。
- 动作属主端口仅 FakeActionOwner;真实 adapter 从 U7/U8 按 key 接入。
- PG 活验需隔离 `TEST_DATABASE_URL`;本机 short 门禁跳过。共享 `:8080` 仍 schema 43。
- 提交:`a75aa45` docs(ops) 认领;`7dfd6d6` feat(db);`da0b3d8` feat(intentflow);`1385002` feat(app)。
@@ -1,51 +0,0 @@
---
title: Demo/测试数据污染全面整改
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
branch: fix/demo-data-pollution-web
worktree: "-"
mutex: web
---
# Demo / 测试数据污染全面整改
## 目标
消除前端 mock/seed 与 DB 演示项目对真实项目清单的污染;生产包无演示文案;main 拒 stub。
## 范围
- Wave 0–5 代码 + Wave 6 文档(本分支合并实现)
## 非目标
- 删除合法 `*.test.ts` fixture
- 改写工作流模板骨架
## 步骤
1. [x] Wave 0 止血
2. [x] Wave 1 门控
3. [x] Wave 2 localStorage 迁移
4. [x] Wave 3 UI 语义
5. [x] Wave 4 DB retire
6. [x] Wave 5 stub gate
7. [x] Wave 6 文档
## 验收标准
- [x] `check-prod-bundle.sh` PASS
- [x] deliverableSync / demoSeedIds / ResolveBackend 单测 PASS
- [x] `cd web && npm test` 全绿(审核 P0)
- [x] 00046/00047 retire + ListChatSessions 过滤(审核 P1)
- [x] 合入后共享环境 migrate + 人工空项目/会话抽检(dev schema 47;项目 6357 docs=0;列表无 6001–6010 / sess-wangjing)
## 相关链接
- Audit: [.doc/audit/2026-09-16-demo-seed-pollution-systemic.md](../audit/2026-09-16-demo-seed-pollution-systemic.md)
- 前序 Audit: [.doc/audit/2026-09-15-mock-deliverables-pollute-real-projects.md](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md)
- Remediation: [.doc/remediation/2026-09-16-demo-seed-pollution-remediation.md](../remediation/2026-09-16-demo-seed-pollution-remediation.md)
- Test report: [.doc/test-reports/2026-09-16-demo-seed-pollution-test-report.md](../test-reports/2026-09-16-demo-seed-pollution-test-report.md)
- 挑拣:`a91a031` `SEED_DEMO_USERS=false`(自 `fix/clean-test-env-baseline`)
@@ -1,49 +0,0 @@
---
title: "FEATURE-MATRIX 深度测试 + 晋升部署 test"
status: in_progress
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
branch: feature/matrix-deep-test-promote-test
worktree: "-"
mutex: infra
---
# FEATURE-MATRIX 深度测试 + 晋升部署 test
## 目标
按 FEATURE-MATRIX 对已实现模块做分层深度回归,通过后将本地 `dev` 晋升到 `test`(`rc-v1.0.0-beta.2`)并 rebuild/冒烟 `:8081`。
## 范围
- Wave 1:vet/short/arch/npm/bundle + 模块定向 + 隔离治理 PG
- Wave 2:dev `:8080` live API 抽检
- Wave 3:真实 PI 抽样(失败再升格三链)
- Wave 4:`dev` → `test` + rebuild + smoke
- Wave 5:测试报告 + SSOT
## 非目标
- 不实现纯软件项目自举
- 不默认 28min 三工作流 PI;不合 `main`;不改项目 143;不启用 FAV
## 步骤
1. [ ] 认领占槽
2. [ ] 自动化深度回归
3. [ ] live `:8080` 抽检
4. [ ] PI 抽样
5. [ ] 晋升 test 并冒烟
6. [ ] 报告与归档
## 验收标准
- [ ] 矩阵已实现行均有 PASS 证据
- [ ] `:8081` health/ready schema=47;`test-env-smoke.sh` PASS
- [ ] tag `rc-v1.0.0-beta.2`;报告归档
## 相关链接
- Plan: matrix_deep_test_promote
- FEATURE-MATRIX / CURRENT / gap-matrix
@@ -1,51 +0,0 @@
---
title: "多意图 HITL U4:outbox 与计划投影"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u4-outbox-projection
worktree: "-"
mutex: events
---
# 多意图 HITL U4:outbox 与计划投影
## 目标
权威计划在同一 UoW 写入 outbox;投影只应用状态事实;消息/SSE 丢失时 GET PlanView 仍能恢复。不改 dispatcher claim/lease/retry 语义。
## 范围
- Create/Decide/Receipt 同事务 Append `intent.plan.*`
- 最小 payload + golden;伪造 producer 拒绝
- projection consumer 幂等、只前进 revision;跨用户不可见
- ctxmgr 只经 CardProjector 端口(接口在 intentflow,实现可 no-op)
- 复用 Track E LiveConsumers
## 非目标
- 不改通用 dispatcher
- 不挂 HTTP(U5)、不改 Web(U6)、不执行动作(U7)
## 步骤
1. [x] 认领 CURRENT(mutex `events`)
2. [x] emit + golden + 投影只前进
3. [x] cmd/events 接入 multiplex;goose shadow
4. [x] 报告并合回本地 dev
## 验收标准
- [x] 创建计划产生 awaiting_input;payload 无 prompt/slots
- [x] 重复 event_id 不双写投影
- [x] 乱序低 revision 不覆盖高 revision
- [x] 伪造 producer 拒绝
- [x] GET PlanView 不依赖投影成功
- [x] arch-check / short 绿
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- Checklist: [../checklists/2026-09-16-multi-intent-u4-outbox-projection.md](../checklists/2026-09-16-multi-intent-u4-outbox-projection.md)
- Test report: [../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md](../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md)
@@ -1,54 +0,0 @@
---
title: "多意图 HITL U5:决策 API 与授权端口"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u5-decision-api
worktree: "-"
mutex: intent-plan
---
# 多意图 HITL U5:决策 API 与授权端口
## 目标
按钮与自然语言走同一 `DecidePlan` 命令;GET 发现活动计划不依赖投影;执行前由动作属主重新授权。确认不是授权。
## 范围
- 冻结路径:`GET /api/v1/intent-plans/active`、`GET /api/v1/intent-plans/{plan_id}`、`POST /api/v1/intent-plans/{plan_id}/decisions`
- Principal 只从认证会话 + query 的 project/session 组装,忽略 body 中的 user/project/session
- 四元作用域;非成员 403;跨 session/user 隐藏为 404
- 系统管理员不得绕过项目成员检查
- `StepAuthorizer` 端口 + Fake/dry-run;确认与执行前鉴权
- expected revision、nonce、依赖闭包、edit 升 revision
## 非目标
- 不接真实业务属主 adapter(U7/U8)
- 不改 Web(U6)、不改默认 legacy HandleTurn
- 不 rebuild 共享 `:8080`
## 步骤
1. [x] 认领 CURRENT(mutex `intent-plan`)
2. [x] 授权端口与 confirm/execute 即时鉴权
3. [x] HTTP handlers + 权限负例
4. [x] 报告并合回本地 dev
## 验收标准
- [ ] 投影缺失仍能 GET active
- [ ] 未登录 401;非成员 403;跨项目/会话/用户隐藏
- [ ] stale revision 409;重复 nonce 同 digest 同 receipt
- [ ] 非法部分确认拒绝;edit 使旧 revision 失效
- [ ] 确认前零副作用;权限撤销/资源版本 fail closed
- [ ] 无系统身份绕过
- [ ] `go test -short` 绿
## 相关链接
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
- Checklist: [../checklists/2026-09-16-multi-intent-u5-decision-api.md](../checklists/2026-09-16-multi-intent-u5-decision-api.md)
@@ -1,47 +0,0 @@
---
title: "多意图 HITL U6:Web 卡片、刷新与可访问性"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u6-web-cards
worktree: "-"
mutex: web
---
# 多意图 HITL U6:Web 卡片、刷新与可访问性
## 目标
UI 只呈现 PlanView;计划动作不走本地 AST/资源修改;刷新与双标签以 GET reconcile。
## 范围
- `PLAN_CONFIRM` 卡片类型
- intent-plans API client
- submitting/outdated/expired/conflict;409 看最新版
- App 计划动作 early-return,禁止本地成功路径
- Playwright 门控(无 `RUN_UI_ACCEPTANCE` 则 skip)
## 非目标
- 不接 auto_read 执行(U7)
- 不 rebuild 共享环境
## 步骤
1. [x] 认领 CURRENT
2. [x] 卡片/API/reconcile 与无 AST 路径
3. [x] 单元测试 + 门控 Playwright
4. [x] 报告并合回
## 验收标准
- [ ] 计划确认不修改 DocumentAST
- [ ] GET 可修复缺失投影
- [ ] 409 标 outdated 并带最新 PlanView
- [ ] 默认 Playwright skip
## 相关链接
- Checklist: [../checklists/2026-09-16-multi-intent-u6-web-cards.md](../checklists/2026-09-16-multi-intent-u6-web-cards.md)
@@ -1,14 +0,0 @@
---
title: "多意图 HITL U7:低风险只读执行"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u7-auto-read
worktree: "-"
mutex: intent-plan
---
# 多意图 HITL U7:低风险只读执行
HandleTurn 在 auto_read 下执行独立查询;默认 legacy 不变。QueryGuard 拒绝 generate。
@@ -1,54 +0,0 @@
---
title: "多意图 HITL U8:task generate adapter"
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor
branch: feature/multi-intent-u8-task-generate
worktree: "-"
mutex: intent-plan
---
# 多意图 HITL U8:task generate adapter
## 目标
`confirm` tier 下查询+生成落盘 awaiting;确认后仅开放 `task.run` / `task.run.adhoc`,稳定幂等键,不改单意图 taskrun HTTP。
## 范围
- HandleTurn:`ComboNeedsConfirm` 且 tier≥confirm 时 WritePlan 落盘,不自动执行
- `OwnerMux` 把 generate 路由到 Task,其余走 QueryGuard
- `TaskRunAdapter` + `LiveTaskStarter`(无 `PI_AGENT_RUNNER_URL` 只占位不启 PI)
- Assemble 接线;默认 `MULTI_INTENT_PLAN_TIER=legacy` 不变
## 非目标
- U9 LLM 分段、U10–U12 owner 扩面
- 不 rebuild 共享环境、不改项目 143
- 真实 PI 闭环若环境缺失记 stop-gate,不冒充验收
## 步骤
1. [x] 从 `dev` 开 `feature/multi-intent-u8-task-generate`
2. [x] confirm 落盘 + mux + adapter
3. [x] 单测与 arch-check
4. [x] 报告并合回
## 验收标准
- [x] 多意图生成确认前零执行
- [x] 活动写计划冲突
- [x] 确认后 mux 执行 generate,重放 starts=1
- [x] QueryGuard 仍拒绝 generate;权限撤销 fail closed
- [x] 真实 PI 无 URL 时 skip(stop-gate)
## 相关链接
- Checklist: [../checklists/2026-09-16-multi-intent-u8-task-generate.md](../checklists/2026-09-16-multi-intent-u8-task-generate.md)
- Test report: [../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md)
- Parent: [./2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
## 证据 / 备注
默认 legacy HandleTurn 仍不落盘。真实 PI 见报告 stop-gate。
@@ -61,5 +61,5 @@ updated: 2026-09-13
## 相关链接
- Audit: [../audit/2026-09-13-chat-history-refresh-disappears.md](../audit/2026-09-13-chat-history-refresh-disappears.md)
- Short-term: [../archive/ops/2026-09-13-chat-history-refresh-remediation.md](../archive/ops/2026-09-13-chat-history-refresh-remediation.md)
- Short-term: [../ops/short-term/2026-09-13-chat-history-refresh-remediation.md](../ops/short-term/2026-09-13-chat-history-refresh-remediation.md)
- gap-matrix 行: `CHAT-HISTORY-REFRESH`
@@ -1,8 +1,8 @@
---
title: "对话意图、可恢复任务状态与文档占用可见性整改"
status: done
status: in_progress
created: 2026-09-13
updated: 2026-09-15
updated: 2026-09-13
---
# 对话意图、可恢复任务状态与文档占用可见性整改
@@ -30,10 +30,11 @@ updated: 2026-09-15
## 验收标准
- [x] “开始编写用户初始需求表”只创建一个 run;运行中再次写请求不创建失败 run。
- [x] 任务失败后刷新,错误码、诊断摘要及允许动作与刷新前一致。
- [x] 运行中刷新,聊天占位、阶段进度、文档 busy 标识和输入保护均恢复。
- [x] 租约释放/任务终态后 UI 自动解除 busy,无需用户手动刷新。
- [x] “总结一下用户初始需求表”返回已有文档摘要,不创建 `task_runs`。
- [ ] “开始编写用户初始需求表”只创建一个 run;运行中再次写请求不创建失败 run。
- [ ] 任务失败后刷新,错误码、诊断摘要及允许动作与刷新前一致。
- [ ] 运行中刷新,聊天占位、阶段进度、文档 busy 标识和输入保护均恢复。
- [ ] 租约释放/任务终态后 UI 自动解除 busy,无需用户手动刷新。
- [x] 测试使用专用项目/会话并在 teardown 清理;禁止 `debug/test` 探针进入非 fixture 会话。
## 相关链接
@@ -1,677 +0,0 @@
---
title: "模块解耦与文档可靠性重构计划"
status: planned
created: 2026-09-14
updated: 2026-09-14
type: refactor
owner: TBD
deepened: 2026-09-14
---
# 模块解耦与文档可靠性重构计划
## Goal Capsule
- **Objective:** 项目文档、任务最终产物和最终智能体回复在并发写入、页面刷新、服务重启、工作区清理和受控恢复后仍能按权限定位到唯一、可校验的内容。
- **Means:** 采用模块化单体、纵向绞杀、应用 UnitOfWork、数据库互斥、transactional outbox、opaque workspace capability 和 FAV。
- **Authority:** 本计划受 [模块化单体解耦 ADR](../adr/2026-09-14-modular-monolith-decoupling.md)、[文档版本边界 ADR](../adr/2026-09-13-document-version-boundary.md) 和 [工作流运行时权威 ADR](../adr/2026-09-12-workflow-runtime-authority.md) 约束。
- **Stop condition:** 任一里程碑出现数据不变量无法在单事务维持、授权只能通过放宽实现、旧数据无法安全迁移,或真实页面故障率没有下降时,停止扩面并回到设计评审。
- **Execution profile:** 高风险、跨模块、迁移和授权敏感;characterization-first,逐纵向切片发布。
- **Delivery:** 每个里程碑独立 short-term、独立分支和独立验收报告;本计划本身不授权合并、部署或删数据。
---
## Product Contract
### Summary
重构先解决文档事实源、事务与恢复链,再扩展其他模块。
架构改造必须用用户可见的刷新、重启、并发和授权结果证明价值,不能只用包数量或代码行数证明完成。
### Problem Frame
系统当前同时依赖 PostgreSQL 账本、`document_records` 指针、workspace `output.md` 和若干内存状态。
这些状态在提交、刷新和重启时没有统一事务与恢复协议,导致历史上出现正文 404/409、projection missing、缓存竞争和任务完成后文档仍为空。
原解耦方案提出 contracts、单一写者和事件总线,但没有解释单一写者如何维持现有跨表原子性,也没有为多个 event subscriber、跨实例互斥和 FAV 恢复定义可执行协议。
### Requirements
**事实源与持久成果**
- R1. PostgreSQL immutable ledger 是文档版本与业务关系的权威,workspace 只作为可重建投影。
- R2. FAV 只归档服务端确认的终态文档、终态助手回复、类型化 RunManifest 和必要附件,中间结果准入率为零。
- R3. 数据库授权图完整但正文不可用时,系统可按 feature flag 从已验证 FAV 只读降级;授权图不完整时必须拒绝。
- R4. GET、刷新和重载不得隐式修复数据库、覆盖 head 或创建归档。
**事务与并发**
- R5. 一个业务命令只有一个事务 owner;业务状态、账本、当前指针及该里程碑已启用的 staging/outbox 必须原子提交。
- R6. 单一写者只约束 SQL 和不变量所有权,不允许各属主各自提交导致跨表半完成。
- R7. 多副本正确性必须依赖数据库行锁、事务级 advisory lock、唯一约束、expected version 和 fencing token;进程内 mutex 不能成为唯一正确性条件。
- R8. 所有写命令必须具有 idempotency key、expected version 或两者;相同 key 不同 payload 必须返回冲突。
- R9. 事务不得包含 LLM、PI Runner、对象存储、HTTP/SSE 或长文件 I/O。
**事件与恢复**
- R10. 持久事件采用至少一次投递、逐消费者 delivery、幂等 inbox、租约、fencing token、重试和死信。
- R11. 同一聚合事件按 aggregate version 有序,不同聚合允许并发;失败消费者不阻塞其他消费者。
- R12. 旧 workspace、旧数据库和 FAV 回填必须可断点续跑、可重复、可审计,异常进入 quarantine。
- R13. 恢复只进入 scratch identity,promotion 需要系统管理员和数据责任人确认,并通过属主端口提交。
**授权与隔离**
- R14. HTTP、CLI、worker、event subscriber 和恢复工具必须使用服务端构造的 Principal,并按 action/resource/current state 逐动作授权。
- R15. 客户端或事件 payload 中的 user、project、role、duty、backend 和路径不能作为授权事实。
- R16. WorkspaceRef 只能暴露不可伪造 ID、scope 和 fencing token;物理路径不得跨模块传播。
- R17. 路径解析必须拒绝绝对路径、`..`、跨项目 ID、symlink/hardlink 逃逸和 storage identity 不匹配。
- R18. 事件、日志、metrics、manifest 和 result 文件不得包含 secret、认证材料、Prompt 或不必要正文。
**交付与验证**
- R19. 首个独立交付边界是受控文档可靠性纵向试点,未通过停走门前不启动横向包搬移。
- R20. 每个里程碑必须分别提供 unit、PostgreSQL、并发/故障注入、真实 PI、真实浏览器、restart/rebuild 和跨用户负例证据;不适用项必须说明原因。
- R21. 迁移采用 expand/migrate/contract,允许新的 Goose migration,禁止修改已发布 migration。
- R22. 数据清理必须同时满足完整备份恢复、migration corpus、FAV coverage、精确删除 manifest 和用户批准,不得因“已有最终成果”跳过其他门禁。
### Success Criteria
- 项目 143 等价脱敏 hazard 和新建项目两条链路在刷新、重登、restart 与 rebuild 后正文成功率为 100%,目标 404/409/projection missing 为 0。
- 同一文档并发写只有一个合法赢家;失败请求不产生孤儿 snapshot、错 head、重复消息、重复通知或重复 artifact。
- 每个应发布终态都存在 publish request;已验证 artifact 可在 workspace 删除后按稳定逻辑 ID 定位并校验 SHA。
- 匿名、非成员、跨用户、跨项目、错误 duty、错误 stage、篡改事件和授权依赖失败全部 fail closed。
- 1、2、4 个应用实例和 dispatcher 下,状态与副作用结果一致;性能阈值由基线报告确认后固化,不能通过降低一致性达标。
- 旧 schema corpus、legacy-v0 workspace 和 previous-release corpus 均可升级、重载和回滚到最近兼容点。
### Scope Boundaries
**本计划包含**
- 文档、taskrun、workspace、artifactvault、可靠事件和授权基础设施。
- chatlog/contextasm、squadrun、app 组合根和 UserProjectContext 的后续选择性扩展。
- 数据生命周期、迁移 corpus、回填、quarantine 和 scratch 恢复的集成门禁。
**Deferred to Follow-Up Work**
- HTTP 错误信封统一。
- PI Runner stdout/result.json 协议替换。
- 全量 SSE transport 重写。
- 微服务拆分和跨服务消息基础设施。
- main 数据自动清理和未来 tenant 实体。
---
## Planning Contract
### Key Technical Decisions
- KTD1. **纵向绞杀优先。** 先在原包边界增加窄端口和适配器,迁完消费者并通过行为验收后再物理移动包。
- KTD2. **事务 owner 与表属主分离。** 应用用例拥有事务,领域模块拥有 SQL;同一 `pgx.Tx` 通过不透明 TxScope 绑定 repository。
- KTD3. **显式锁策略。** 普通状态转换使用 `READ COMMITTED`、行锁和条件更新;项目级不变量使用事务级 advisory lock;Serializable 只用于经过证明的复杂不变量。[PostgreSQL explicit locking](https://www.postgresql.org/docs/17/explicit-locking.html)
- KTD4. **固定锁顺序。** project/workflow instance → document root → version/snapshot/turn → task run → staging/outbox/delivery。
- KTD5. **事务外副作用。** 网络、LLM、对象存储、通知和投影由提交后的持久事件驱动。
- KTD6. **至少一次事件。** outbox 不承诺 exactly-once;event ID、consumer inbox 和业务唯一约束共同提供幂等结果。
- KTD7. **opaque workspace capability。** 跨模块不传物理路径,所有读写使用 scope-bound ID、artifact key 和 fencing token。
- KTD8. **三层权威。** PostgreSQL 管业务关系与授权,workspace 管临时现场,FAV 管已验证终态 payload/manifest/receipt/tombstone。
- KTD9. **授权逐动作重算。** Principal 来自受信适配器;状态改变在取得资源锁后重读当前授权事实,subscriber 的 actor 快照只用于审计。[OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html)
- KTD10. **依赖感知回滚。** 每个里程碑只保证回到最近兼容点;进入 contract 阶段后须按逆依赖顺序回滚。
- KTD11. **按证据收紧门禁。** arch-check 先记录基线,每条规则在对应纵向切片清零后转 block,不按日历统一切换。
- KTD12. **FAV 分支先审后用。** `feature/final-artifact-vault` 的现有实现作为候选,不直接视为 dev 已有能力;集成前重放迁移、测试、安全和并发审计。
### High-Level Technical Design
#### Component topology
```mermaid
flowchart TB
Transport[HTTP SSE CLI] --> UseCases[application use cases]
Jobs[workers and recovery] --> UseCases
UseCases --> Policy[authorization policy]
UseCases --> Unit[UnitOfWork]
Unit --> DG[docgov owner]
Unit --> DR[docrevision owner]
Unit --> TR[taskrun owner]
Unit --> OB[outbox and staging]
UseCases --> WSC[workspace capability]
OB --> Dispatch[delivery dispatcher]
Dispatch --> Projection[projection subscriber]
Dispatch --> AV[artifactvault subscriber]
Dispatch --> Notify[notification subscriber]
```
#### Write sequence
```mermaid
sequenceDiagram
participant C as Caller
participant A as App use case
participant P as Policy
participant DB as PostgreSQL
participant O as Outbox worker
participant V as FAV
C->>A: command + idempotency + expected version
A->>P: authorize principal/action/resource
P-->>A: allow or deny
A->>DB: begin and acquire locks in canonical order
A->>DB: ledger + root + staging + outbox
DB-->>A: commit
A-->>C: committed result
O->>DB: claim delivery
O->>V: publish immutable artifact
V-->>O: verified receipt
O->>DB: idempotent ack
```
#### Event delivery lifecycle
```mermaid
stateDiagram-v2
[*] --> pending
pending --> leased
leased --> delivered
leased --> retryable_failed
leased --> dead_letter
retryable_failed --> leased
leased --> pending: lease expired
delivered --> [*]
```
#### Migration lifecycle
```mermaid
flowchart TB
Expand[Expand schema and compatible readers] --> Shadow[Shadow validation]
Shadow --> Backfill[Checkpointed backfill]
Backfill --> Switch[Switch writer]
Switch --> Observe[Observe and restart test]
Observe --> Contract{Go or rollback?}
Contract -->|go| Remove[Remove old path]
Contract -->|rollback| Previous[Return to prior compatible point]
```
### Concurrency and Lock Matrix
| Resource/operation | Correctness primitive | Conflict result | Retry policy | Forbidden while held |
|---|---|---|---|---|
| Project duty/heal/revoke | transaction advisory lock keyed by project | wait then typed timeout | whole idempotent tx for deadlock only | network, LLM, filesystem copy |
| Workflow stage advance | instance row lock + expected config revision | stale-state conflict | caller refresh; no blind retry | external execution |
| Controlled document edit | document row + open version row + ETag | version conflict with current head metadata | user/client rebases | projection and notification |
| Agent candidate commit | candidate/document/version locks + idempotency key | stale candidate or idempotency conflict | exact same request may replay | PI/LLM call |
| TaskRun claim/finalize | unique idempotency + conditional status/version update | existing run or state conflict | same digest returns prior result | message/SSE side effect |
| Workspace write | DB lease + fencing token + atomic file commit | stale lease/token | reacquire then re-resolve state | arbitrary path access |
| Outbox delivery | row lease + `SKIP LOCKED` + fencing token | another worker owns item | retry at next schedule | subscriber work inside claim tx |
| FAV publish | artifact idempotency unique key + no-replace object write | existing verified artifact or digest conflict | same digest resumes | reading mutable workspace |
### Authorization Matrix
| Surface | Principal source | Resource facts | Required checks | Failure behavior |
|---|---|---|---|---|
| HTTP/SSE | authenticated session/middleware | DB project/session/document/workflow | membership, owner, duty, stage, action | 401/403/typed conflict; no data |
| CLI ops | service identity + operator session | explicit environment/dataset/resource manifest | capability, exact scope, dry-run where destructive | fail closed and audit |
| Event subscriber | registered service identity; event actor for audit only | DB current aggregate + event scope/digest | producer allowlist, project/resource match, current policy | dead letter/quarantine |
| FAV degraded read | current authenticated Principal | DB relation + vault manifest/tombstone | normal read permission first, then integrity | no fallback if auth graph incomplete |
| Recovery promotion | recovery credential + admin + data steward approval | scratch identity + signed plan + conflict map | two-party approval, no unresolved conflicts | refuse promotion |
| Agent backend | app-resolved BackendRef | project policy + InputBundle sensitivity | backend allowlist, least data, secret injection boundary | reject before dispatch |
### Delivery dependency graph
```mermaid
flowchart TB
M0[M0 baseline and contract correction] --> M1[M1 document reliability pilot]
M1 --> M2[M2 durable events and FAV integration]
M2 --> M3[M3 taskrun and workspace finalization]
M3 --> M4[M4 selective domain decoupling]
M4 --> M5[M5 app composition and context ownership]
M5 --> M6[M6 transport boundary cleanup]
M2 --> D[Data corpus and lifecycle rollout]
D --> M3
```
### Assumptions
- 当前 dev 基线为 schema 33;任何实现分支必须在创建 migration 时重新查询最新序号。
- `feature/final-artifact-vault` 尚未合 dev,现有代码与测试只能作为候选实现和证据来源。
- 当前无独立 tenant 实体,权限范围沿用 environment + project membership/admin;未来 tenant 模型另立 ADR。
- 性能容量目标需要在 M1 压测后固化;本计划先固定正确性和观测项,不伪造吞吐数字。
---
## Phased Delivery
| 里程碑 | 交付边界 | 预计范围 | 进入条件 | 退出/停走门 |
|---|---|---|---|---|
| M0 | 基线与契约纠偏 | 文档/门禁/characterization | 在途 mutex 不冲突 | 事务/锁/授权/事件/FAV 契约评审通过 |
| M1 | 文档可靠性纵向试点 | docflow/docgov/docrevision/docquery | M0 完成,独占 docgov | 刷新、重启、并发、权限和故障注入全 PASS |
| M2 | 持久事件与 FAV | outbox/delivery/artifactvault | M1 数据边界稳定 | 多 worker、重放、归档、降级读取和 tombstone PASS |
| M3 | taskrun/workspace 终态 | taskrun/squadrun/workspace | M2 verified receipt 可用 | 清 workspace 后最终产物仍可定位,重复 finalize 无副作用 |
| M4 | 选择性领域端口化 | chatlog/contextasm/squadrun | M1–M3 复盘证明收益 | 每个子切片独立回归;无纯搬包 |
| M5 | 组合根与上下文收权 | app/chatflow/stageflow/UserProjectContext | M4 稳定 | 每个 use case 单 owner;闭包按事件逐个替换 |
| M6 | 传输收口 | server/SSE | M5 完成 | server 无 SQL/编排/路径;R1–R7 对应规则全 block |
M0–M1 是首个批准范围。
M2–M6 需要在前一里程碑验收报告后重新 go/no-go,不构成一次性整体授权。
---
## Implementation Units
### Unit Index
| ID | 标题 | 主要文件 | 依赖 |
|---|---|---|---|
| U1 | 固化架构基线和门禁 | `scripts/arch-check.sh`, `.doc/system-design/module-boundaries.yaml` | 无 |
| U2 | 建立应用 UnitOfWork | `internal/app/uow`, owner repositories | U1 |
| U3 | 文档命令原子化 | docgov/docrevision/docflow | U2 |
| U4 | 文档授权读模型 | docquery/server/authz | U1, U3 |
| U5 | Workspace capability | workspace/squadrun | U1 |
| U6 | Durable event delivery | outbox/dispatcher/inbox | U2 |
| U7 | FAV 集成与降级读取 | artifactvault/docflow/docquery | U3, U4, U6 |
| U8 | TaskRun/RunManifest 终态 | taskrun/squadrun/workspace | U5, U6, U7 |
| U9 | 数据回填与迁移 corpus | dataset/FAV tooling | U6–U8 |
| U10 | chatlog/contextasm 端口化 | ctxmgr/chat/contextasm | M1–M3 go/no-go |
| U11 | 组合根和 use case 收权 | app/server/bizdev/coordinator | U10 |
| U12 | 传输边界与最终门禁 | server/stream/CI | U11 |
### U1. 固化架构基线和可执行门禁
- **Goal:** 建立不会把现有违规合法化、也不会误报 migration/fixture 的边界基线。
- **Requirements:** R19–R21;KTD1、KTD11。
- **Dependencies:** 无;必须避开 `intent`、`chat` 等在途 mutex,当前只占 `arch`。
- **Files:** `scripts/arch-check.sh`、`.doc/system-design/module-boundaries.yaml`、`internal/archtest/arch_test.go`、`internal/archtest/arch_test_test.go`、`.doc/audit/<date>-arch-check-baseline.md`。
- **Approach:**
1. 分离 production import、production SQL write、path construction、event producer/consumer 四类规则。
2. 表名扫描只识别 production Go 中的写语句;Goose、测试、fixture 和受控运维脚本进入显式类别,不以全仓零出现为目标。
3. 为每项既有违规记录 owner、原因、截止里程碑和到期日;新违规立即 block。
4. 只为已完成纵向切片的规则切换 block,不能以“两周后统一 block”代替清零。
- **Execution note:** 先对当前依赖和 SQL 写者生成可重复 characterization 报告,再改门禁。
- **Patterns to follow:** `go list` 依赖图、现有 AGENTS mutex、Goose 不可改写规则。
- **Test scenarios:**
- 合法的 Goose/fixture 表名不触发生产写者违规。
- 非属主 production 包新增 `UPDATE document_records` 时测试失败并定位文件。
- 路径通过字符串拼接、`filepath.Join` 和间接常量构造时均被检测。
- 无过期日例外、过期例外、新增越权 event producer 均阻断。
- **Verification:** 基线报告可重放;新增违规阻断;现有违规数只能下降。
### U2. 建立应用 UnitOfWork 和事务能力
- **Goal:** 在单一写者边界内维持跨表业务不变量。
- **Requirements:** R5–R9;KTD2–KTD5。
- **Dependencies:** U1。
- **Files:** `internal/app/uow/uow.go`、`internal/app/uow/pg_uow.go`、`internal/app/uow/pg_uow_test.go`、`internal/docgov/repository.go`、`internal/docrevision/repository.go`、`internal/taskrun/repository.go`、`internal/freedoc/repository.go`。
- **Approach:**
1. UnitOfWork 开启、提交和回滚唯一 `pgx.Tx`,向每个属主提供绑定该 transaction 的窄 repository capability。
2. TxScope 不暴露通用 `Exec` 给应用层;只有属主 repository 能执行自己的 SQL。
3. 禁止 repository 在已有 TxScope 内嵌套 transaction 或提前 commit。
4. 实现统一的完整事务重试 wrapper,只重试明确的 serialization/deadlock 错误,并保持 idempotency context。
5. 为锁超时、事务时长、重试和 rollback reason 加结构化指标,不记录业务正文。
- **Test scenarios:**
- 第二个属主写入失败时第一个属主写入回滚。
- outbox/staging 写入失败时业务状态和账本均回滚。
- commit 失败时不会返回成功或执行提交后副作用。
- `40001`/`40P01` 重跑完整事务并最终只产生一个业务结果。
- version conflict、permission denied、payload digest conflict 不进入自动重试。
- 尝试跨属主执行任意 SQL 无法通过类型边界或架构测试。
- **Verification:** fault injection 覆盖 begin、每个 owner write、outbox、commit;无部分提交。
### U3. 文档提交纵向事务化
- **Goal:** 将人工编辑、agent commit、批准/驳回和根指针投影收敛到文档用例事务。
- **Requirements:** R1、R5–R9、R19;KTD2–KTD5。
- **Dependencies:** U2;实施时独占 `docgov` mutex。
- **Files:** `internal/app/docflow/commands.go`、`internal/app/docflow/commands_pg_test.go`、`internal/docgov/engine.go`、`internal/docgov/lease.go`、`internal/docrevision/pg_mutate.go`、`internal/docrevision/service.go`、`internal/docrevision/document_commit_concurrency_pg_test.go`、`internal/server/document_revision_handlers.go`。
- **Approach:**
1. 为每个文档命令明确 aggregate、expected head、idempotency key 和授权 action。
2. 版本账本与 `document_records` 指针先在同一 UoW 写入;M1 保留现有通知兼容适配,但任何核心正确性不得依赖提交后的 `OnOutbox` 回调。
3. 按 KTD4 锁定 document root 与 open version;状态转换采用条件更新。
4. 提交返回 ledger/root 已持久化结果;workspace projection 和通知由提交后事件处理。
5. 保留现有 ETag 语义,统一 agent、人工与批准路径的冲突分类。
- **Execution note:** 先补当前行为的 PG characterization,再移动写入所有权;不得先删除旧事务路径。
- **Patterns to follow:** `internal/docrevision/pg_mutate.go` 当前同事务投影、`internal/docgov/lease.go` expected SHA、现有 document revision idempotency tests。
- **Test scenarios:**
- 同一 ETag 两个用户并发编辑,只有一个成功,另一个得到当前 head。
- 人工编辑与 agent commit 并发,账本 event_no 连续且 head 指向赢家。
- approve 与 reject 并发,只允许一个合法终态。
- candidate commit 在 root/version/outbox 任一故障点整体回滚。
- 相同 idempotency key 和相同 digest 返回原结果;不同 digest 返回冲突。
- 锁超时返回 typed retryable busy,不泄露 SQL 或路径。
- 两个 app 实例执行同一请求,结果与单实例一致。
- **Verification:** 文档四类命令的跨表不变量由 PostgreSQL 测试证明;`OnOutbox` 不再承担正确性。
### U4. 建立授权后的文档统一读模型
- **Goal:** 正文读取不再依赖 handler 拼路径或把一致性错误伪装成 404。
- **Requirements:** R1、R3、R4、R14、R15、R19;KTD1、KTD8、KTD9。
- **Dependencies:** U1、U3;实施时按 CURRENT 排队使用 `docgov` 和 `authz` mutex。
- **Files:** `internal/app/docflow/query.go`、`internal/app/docflow/query_test.go`、`internal/docquery/service.go`、`internal/docquery/service_pg_test.go`、`internal/server/project_doc_handlers.go`、`internal/server/document_revision_authz_test.go`、`web/src/api/projectDocuments.ts`、`web/src/lib/controlledDocHydrate.ts`、`web/e2e/controlled-document-reload.spec.ts`。
- **Approach:**
1. Principal 由认证适配器构造,DocRef 不携带可覆盖 Principal 的 user/role/duty。
2. 先解析数据库 resource→project、workflow、stage 和 duty,再读取 ledger/current pointer。
3. workspace projection 只作为校验缓存;缺失时不阻止读取数据库 immutable content。
4. ledger/root、projection 和 FAV 的差异映射为 typed consistency state,不再统一变成 404。
5. FAV 降级在 U7 接入前保持关闭;接口先保留明确 extension point。
6. 列表和版本查询强制分页,BatchGet 首期上限 100;批量授权按 Principal/project 分组并使用有界并发。
- **Test scenarios:**
- 正常 projection、projection 缺失、projection hash 漂移、ledger 缺失分别返回正确结果或 typed error。
- GET、刷新、重登不产生数据库写入、workspace 文件或归档事件。
- 匿名、非成员、跨用户会话、跨项目、错误 stage/duty 均拒绝且不泄露文档存在性。
- 授权依赖超时/错误时 fail closed。
- BatchGet 的 100/101 边界、重复引用、跨项目混合引用和限流拒绝不泄露资源存在性。
- 项目 143 等价 hazard 和新项目在页面刷新、restart、rebuild 后正文一致。
- **Verification:** 控制台和服务器目标 404/409/projection missing 为零;所有来源分支有服务端与浏览器证据。
### U5. Workspace capability、lease 与文件提交
- **Goal:** 从类型和运行时同时禁止跨模块裸路径与跨租户工作区访问。
- **Requirements:** R1、R7、R9、R16–R18;KTD7。
- **Dependencies:** U1。
- **Files:** `internal/workspace/types.go`、`internal/workspace/resolver.go`、`internal/workspace/capability.go`、`internal/workspace/capability_test.go`、`internal/workspace/lease_pg_test.go`、`internal/squad/workspace_adapter.go`、`internal/bizdev/service.go`、`internal/server/project_doc_handlers.go`。
- **Approach:**
1. WorkspaceRef 删除 Root/OutputDir/ManifestPath,只保留 scope-bound ID、schema version 和 fencing token。
2. workspace service 提供限定 artifact key 的 read、atomic writer、commit projection 和 inspect 能力。
3. ID 与 lease 绑定 environment、project、run 和 storage identity;所有写入校验 fencing token。
4. 使用 realpath/descriptor-based 检查,拒绝 `..`、绝对路径、symlink/hardlink 和根外 rename。
5. legacy-v0 workspace 只读;首次受控 Resume 校验后原子升级 v1,并保留兼容备份一个发布周期。
- **Test scenarios:**
- `..`、绝对路径、编码后的分隔符、空 key、跨 project Workspace ID 全部拒绝。
- symlink 和 hardlink 在校验后替换的 TOCTOU 场景仍不能逃逸。
- 旧 lease writer 在新 lease 签发后因 fencing token 过期而失败。
- 两个 app 实例并发提交同一 projection,reader 只看到完整 marker。
- v0 读取、升级失败回滚、未知 major 版本拒绝。
- **Verification:** production 包中 workspace 物理路径只存在于 workspace/squadrun adapter;多实例测试不依赖 `sync.Mutex`。
### U6. Durable outbox、逐消费者 delivery 与 replay
- **Goal:** 让后台投影、通知和 FAV 发布在崩溃与水平扩容下可恢复。
- **Requirements:** R5、R9–R11、R14、R18、R21;KTD5、KTD6。
- **Dependencies:** U2;需要新的 additive Goose migration。
- **Files:** `deploy/postgres/goose/000xx_*durable_event_delivery.sql`、`internal/events/envelope.go`、`internal/events/outbox.go`、`internal/events/dispatcher.go`、`internal/events/inbox.go`、`internal/events/dispatcher_pg_test.go`、`internal/events/replay.go`、`cmd/events/main.go`。
- **Approach:**
1. 保留业务 outbox record,新增 event envelope、每消费者 delivery/inbox、attempt、lease、next_attempt_at 和 dead-letter 数据。
2. `FOR UPDATE SKIP LOCKED` 只用于小批次 claim;worker 在 claim transaction 外执行 subscriber。
3. ack/fail 使用 delivery version/fencing token,过期 worker 不能覆盖新 lease owner。
4. 同 aggregate 依据 aggregate version 串行,不同 aggregate 并行;缺号进入等待或 quarantine。
5. retry policy 区分 transient、permanent、authorization/integrity failures;后两者默认 dead letter/quarantine。
6. replay CLI 先 dry-run,必须限定 consumer/event/project/time/id 范围并记录 operator、reason 和计划 hash。
7. 逐个迁移并删除 `OnOutbox` 与闭包桥;切换前 shadow 对账,切换后旧回调不再注册。
- **Test scenarios:**
- 两个和四个 worker 并发 claim,没有同一 lease 的双 owner。
- worker 在副作用前、后、ack 前崩溃,重启后最终只有一个可见业务结果。
- 一个 subscriber 永久失败不阻塞其他 subscriber。
- lease 过期后旧 worker ack 被 fencing token 拒绝。
- 相同 event 重放被 inbox 去重;相同 aggregate 乱序事件不越过缺失版本。
- 伪造 producer、跨项目 scope、payload digest 不符进入 quarantine。
- dead-letter replay 未授权、无 dry-run 或范围过宽时拒绝。
- **Verification:** 删除旧单一 `published_at` 语义前完成双读对账;pending age、attempt、lease steal、dead letter 可观测。
### U7. FAV 分支审计、终态发布与授权降级读取
- **Goal:** 将最终成果与 workspace 清理解耦,同时不形成第三套业务真相源。
- **Requirements:** R1–R4、R10–R15、R18、R21、R22;KTD8、KTD9、KTD12。
- **Dependencies:** U3、U4、U6;先审计 `feature/final-artifact-vault` 相对当前 dev 的完整差异。
- **Files:** `internal/artifactvault/`、`deploy/postgres/goose/000xx_*final_artifact*.sql`、`internal/app/docflow/artifact.go`、`internal/docquery/service.go`、`internal/server/vault.go`、`cmd/artifact-vault/`、`internal/artifactvault/*_test.go`。
- **Approach:**
1. 重用通过审计的 FAV eligibility、staging、publisher、manifest、tombstone 和 scratch recovery;不直接 cherry-pick 未复核的组合根/handler 改动。
2. 重新分配最新 Goose 序号,并验证 migration 与 U6 delivery schema 的组合和 Down 边界。
3. 文档终态 transaction 冻结精确 payload/SHA 或 immutable blob ref 并写 publish request;publisher 不重读 workspace 或可变消息行。
4. docquery 只在正常数据库授权成功后使用 FAV;manifest 只做 scope/integrity 交叉校验,不能授予权限。
5. union-deny:运行删除账本或 vault tombstone 任一侧声明删除即拒绝读取/恢复。
- **Execution note:** 现有 FAV 分支包含业务代码和 migration,必须先 rebase/merge audit,再按本计划拆分原子提交。
- **Test scenarios:**
- committed/sealed/approved 文档按准入表归档;ready/rejected/stale/quality_failed 和 workspace 草稿为零。
- publish 重复、对象已存在、每个 fsync/rename/marker 崩溃点都可恢复。
- workspace 删除后,授权用户可读 verified payload;未授权用户看不到 artifact 存在性。
- DB 授权关系缺失、manifest scope 不符、坏 SHA、tombstone、vault 不可用均 fail closed 或返回明确 degraded error。
- GET 零数据库写入、零 workspace 写入、零隐式恢复。
- 跨项目相同 SHA 不共享删除或密钥边界。
- **Verification:** FAV test report 与当前 dev 重放通过;`FAV_DEGRADED_READ` 默认关闭,直到 M2 全部负例通过。
### U8. TaskRun、RunManifest 与 workspace 清理门禁
- **Goal:** 任务终态和最终产物在重复 finalize、SSE 断线和 workspace 清理后保持一致。
- **Requirements:** R1、R2、R5–R12、R16–R18、R22;KTD5–KTD8。
- **Dependencies:** U5、U6、U7。
- **Files:** `internal/taskrun/manager.go`、`internal/taskrun/store.go`、`internal/taskrun/finalize.go`、`internal/taskrun/finalize_pg_test.go`、`internal/squad/manifest.go`、`internal/app/stageflow/execute.go`、`internal/server/task_finalize.go`、`internal/server/task_run_idempotent_sse_test.go`。
- **Approach:**
1. RunManifest 核心字段类型化并持久化规范字节、SHA、workspace/storage identity 和成员列表。
2. taskrun terminal finalize transaction 写状态、assistant terminal turn、manifest、artifact staging 和 outbox。
3. SSE done 只投影已提交状态;客户端断线与重试复用 task run idempotency key。
4. workspace 清理只依赖已冻结 staging 和 policy;需长期保留的最终成果还必须取得 verified receipt。
5. backend 由服务端 BackendRef policy 解析,InputBundle 携带数据分类和最小权限范围。
- **Test scenarios:**
- 同一 finalize 重复调用返回同结果,不重复消息、事件、manifest 或 artifact。
- finalize 与 cancel 并发只有一个合法终态。
- SSE 在 commit 前后断线并重试,历史中只有一个 assistant turn。
- workspace 在 finalize 后立即清理,publisher 仍从 staging 归档原 SHA。
- manifest digest、storage identity、artifact member 不一致阻止 verified/cleanup。
- 未授权 backend、敏感 InputBundle、凭证回显和 result 残留全部拒绝或清理。
- **Verification:** “完成但没有 durable manifest/publish request”和“已显示完成但正文仍模板”两类状态不可产生。
### U9. 存量回填、migration corpus 与数据生命周期
- **Goal:** 只保留可解释的演示/回归数据,并持续验证旧数据迁移、重载和受控恢复。
- **Requirements:** R2、R12、R13、R21、R22;KTD8、KTD10。
- **Dependencies:** U6–U8。
- **Files:** `cmd/dataset/`、`internal/dataset/`、`internal/artifactvault/backfill.go`、`scripts/backup-system-db.sh`、`scripts/restore-system-db-drill.sh`、`.doc/test-fixtures/`、`.doc/test-reports/`。
- **Approach:**
1. 建立 dataset registry,分类 pinned、demo、regression、migration baseline、ephemeral 和 quarantine。
2. backfill 只枚举 immutable document snapshot、approved/commit event 和 completed chat turn,禁止扫描 workspace。
3. 大表按稳定主键 checkpoint 分批处理;多个 worker 使用 `SKIP LOCKED` 或互斥 shard,限速避免挤占在线连接池。
4. 每个 batch 记录 source schema/commit/storage identity、范围、成功、quarantine 和重试水位。
5. dev 先蓝绿建立新数据根,导入 6–10 个批准 dataset;旧库/状态根只读 quarantine 7–14 天后,需用户再次批准才销毁。
6. 每个 release 验证 clean、oldest-supported、previous、hazard、import、reload、rollback 和 artifact recovery 八条轨道。
- **Test scenarios:**
- backfill 中断、重复和并发新终态时分母/分子可复算且不重复 artifact。
- legacy-v0 workspace、旧 schema、高 ID、projection missing/fork、缺 snapshot 分别升级或 quarantine。
- restore 强制 scratch,拒绝 dev/test/main DSN、错误 storage identity、篡改 manifest 和缺权限凭证。
- FAV coverage、完整备份 restore 或 migration corpus 任一失败都阻止 destroy。
- dev 选择性导入后项目关系、文件 SHA、sequence、授权和 reload 一致。
- **Verification:** 数据清理有精确 manifest、可恢复位置、观察窗口和批准记录;不修改历史 Goose。
### U10. chatlog/contextasm 原地端口化
- **Goal:** 在不重复付费搬包的前提下分离对话记录和 prompt 上下文装配。
- **Requirements:** R7、R14、R15、R19、R20;KTD1、KTD9。
- **Dependencies:** M1–M3 go/no-go;必须等待当前 `chat` mutex 释放。
- **Files:** `internal/ctxmgr/`、`internal/chat/`、`internal/app/chatflow/`、`internal/ctxmgr/chat_auth_pg_test.go`、`internal/server/chat_history_auth_test.go`。
- **Approach:**
1. 先定义 chatflow 所需的消费者侧 ChatLog 和 ContextAssembler ports。
2. 在现有 ctxmgr 内提供 adapters,迁移调用者并保持表所有权不变。
3. 统计接口 fan-in、DTO 转换和同类改动触达文件数;收益成立后再物理拆为 chatlog/contextasm。
4. 所有读取携带 Principal/action,不接受请求体 user/project 作为权限事实。
- **Test scenarios:**
- 刷新前后同一授权消息集合的正文、分类和计数一致。
- 跨用户、跨项目、已退出成员和服务端后台导出负例。
- context assembly 只读取允许集合,摘要/缓存不放大不可见消息。
- 原地 adapter 与最终拆包实现的 contract tests 等价。
- **Verification:** 同类对话变更触达面相对基线下降;拆包前已获得独立行为收益。
### U11. 组合根迁移、事件替换和共享上下文收权
- **Goal:** 让每个跨模块业务流程具有唯一应用用例 owner,而不是集中在 server/bizdev 闭包和共享指针。
- **Requirements:** R5、R7、R9–R11、R14、R15、R19、R20;KTD1、KTD5、KTD6、KTD9。
- **Dependencies:** U10;按四个独立子切片执行,不建立一个巨型 Wave。
- **Files:** `internal/app/app.go`、`internal/app/chatflow/`、`internal/app/stageflow/`、`internal/app/docflow/`、`internal/server/server.go`、`internal/bizdev/service.go`、`internal/coordinator/`、对应 contract/integration tests。
- **Approach:**
1. U11a 只把构造和生命周期迁到唯一 app composition root。
2. U11b 一次只替换一种闭包事件;每种事件单独迁移、对账和回滚。
3. U11c 逐个迁移 ExecuteTask/executeStageInternal 用例,不同时修改无关领域。
4. U11d 将 UserProjectContext 改为只读 snapshot + 类型化 ContextUpdate,单一 use case 应用增量。
- **Test scenarios:**
- app start/stop/restart 不丢 worker,重复启动不创建重复 subscriber。
- 每个闭包新旧路径 shadow 结果一致,切换后旧路径无调用。
- ContextUpdate 并发应用使用版本检查,不发生字段级 lost update。
- server、CLI 和 worker 调用同一 use case 得到一致授权和事务结果。
- **Verification:** 每个子切片独立发布、独立回滚;server 不再保存业务闭包,UserProjectContext 不被多方直接修改。
### U12. 传输边界收口和最终架构门禁
- **Goal:** 在领域行为稳定后缩减 server/stream 耦合并全面启用已清零规则。
- **Requirements:** R14、R18–R21;KTD1、KTD11。
- **Dependencies:** U11。
- **Files:** `internal/server/`、`internal/stream/transport/`、`scripts/arch-check.sh`、`.doc/system-design/module-boundaries.yaml`、CI 配置、`web/e2e/`。
- **Approach:**
1. server handler 只保留参数、Principal、use case 调用和 wire serialization。
2. SSE transport 只编码中性 progress/event frame,不拥有业务状态或重试决策。
3. 对已清零的 import、SQL writer、path、producer/consumer 规则逐项转 block。
4. 错误信封和 PI Runner 协议保持独立 follow-up,不进入本单元。
- **Test scenarios:**
- HTTP、SSE 断线重连和 CLI 对同一业务状态观察一致。
- server 新增领域实现 import、SQL 或路径拼接时 CI 失败。
- SSE 慢客户端、断开和重复连接不阻塞业务 transaction 或 dispatcher。
- 全套授权、重启和多实例回归保持通过。
- **Verification:** R1–R7 的修订版规则全 block;server 行数只作观察指标,不作替代行为验收。
---
## Verification Contract
### Evidence layers
| 层级 | 必须证明 | 不得替代 |
|---|---|---|
| Unit | 状态机、错误分类、schema、路径和 policy | PostgreSQL 原子性 |
| PostgreSQL integration | 事务回滚、锁、幂等、migration、并发 | 浏览器用户体验 |
| Fault injection | 每个 commit/delivery/publish 崩溃窗口 | 真实进程 restart |
| Concurrency/load | 多 app/worker、热点与非热点资源、积压和公平性 | 正确性断言 |
| Real PI | 真实 agent 生成、manifest、finalize、归档 | stub 或固定假输出 |
| Browser | 页面创建/打开/编辑/刷新/重登、错误与 degraded 状态 | API 直接调用 |
| Restart/rebuild | app、worker、workspace root、存储 identity 重载 | health 单点检查 |
| Authorization negative | 匿名/跨用户/跨项目/阶段/duty/后台/recovery | 前端隐藏按钮 |
| Recovery | 完整 DB restore、migration corpus、FAV scratch 恢复 | 仅列出 dump 内容 |
### Repository gates
- `go vet ./...`
- `go test -short ./...`
- 目标模块 PostgreSQL 集成和 race 测试;若全包 race 存在已知 TempDir flake,报告必须分离目标模块结果和基建债。
- `scripts/arch-check.sh` 对当前里程碑已收紧规则为 block,对未迁移规则输出基线差异。
- `web` 单元测试与 production build。
- dev 容器必须 rebuild 后检查 `/health` 与 `/ready`,不能用 restart 证明新代码已部署。
- 真实 PI、真实浏览器、post-restart 和多用户负例按独立证据分栏。
### Concurrency test matrix
| 维度 | 场景 | 必须断言 |
|---|---|---|
| App replicas | 1/2/4 | 结果和不变量一致,进程内 mutex 关闭仍正确 |
| Dispatcher replicas | 1/2/4 | 无双 owner ack,无重复可见副作用,无永久饥饿 |
| Resource shape | 同一文档热点/不同文档并行 | 热点正确冲突,非热点不被全局锁串行化 |
| Failure point | before commit/after commit/before ack/after side effect | 无丢事件,重复交付幂等 |
| Lock behavior | timeout/deadlock/serialization | 分类和完整事务重试正确,无无限等待 |
| Lease behavior | expiry/renew/steal/stale fencing | 旧 owner 无法覆盖新 owner |
| Load | steady/burst/backlog recovery | 记录 p50/p95/p99、锁等待、连接池、oldest event age |
### Authorization test matrix
每个状态改变和读取接口至少覆盖:匿名、已登录非成员、错误项目成员、会话非 owner、错误 duty、错误 stage、过期 lease、跨环境 ID、服务身份越权、授权依赖失败和系统管理员合法路径。
FAV 额外覆盖 manifest project 不符、tombstone、删除账本不一致和授权图缺失。
状态改变必须覆盖授权检查后的成员撤销、duty 变化、stage 推进和 lease 失效,证明用例在取得资源锁后重新验证当前事实。
### Migration and rollback matrix
| 阶段 | Forward proof | Rollback proof |
|---|---|---|
| Expand | 新 schema 与旧代码兼容 | migration Down 或旧代码继续运行 |
| Shadow | 新旧读取差异为零或有解释的 quarantine | 关闭 flag 回旧路径 |
| Backfill | checkpoint、幂等、并发新写一致 | 停止 worker,不撤销已安全扩展列 |
| Switch | 新 writer 唯一、旧 writer 只读 | flag 回最近兼容 writer |
| Observe | restart/rebuild/浏览器/PI/指标稳定 | 切回旧 reader/writer 与只读 quarantine 数据 |
| Contract | 引用扫描和用户批准 | contract 后只能逆序部署兼容版本,不能单 commit revert |
---
## Risk Analysis and Mitigation
| 风险 | 触发信号 | 缓解和停止条件 |
|---|---|---|
| contracts 成为新万能包 | fan-in、共享 DTO、ADR 数持续上升 | 消费者侧端口;按域拆公共契约;超过阈值回评边界 |
| 跨属主事务过大 | 锁等待、事务 p99、deadlock 上升 | 缩小原子集合;事务外副作用;固定锁序;停止扩面 |
| advisory lock 形成全局瓶颈 | 非热点资源也排队 | 只对项目级不变量使用;key 分区;检查 `pg_locks` |
| outbox backlog 放大 | oldest age/attempt/dead letter 超阈值 | 独立 worker 连接预算、批次和退避;按 aggregate 并行 |
| poison event 无限重试 | 同 event 高频失败 | typed permanent failure、dead letter、受控 replay |
| FAV 成为授权旁路 | DB 关系缺失仍返回内容 | 正常授权先行、union-deny、默认关闭 degraded read |
| 工作区链接逃逸 | realpath/scope mismatch | opaque ID、descriptor 检查、fencing、负例测试 |
| 回填压垮在线库 | lock wait/replication lag/连接池饱和 | checkpoint、小批次、限速、独立连接预算、可暂停 |
| 双读长期不收口 | exception 数和差异长期不降 | 明确 owner、到期日和 go/no-go;禁止无限兼容 |
| 物理搬包造成大冲突 | import churn 大于行为收益 | 原地端口化;行为稳定后再移动;按 mutex 排队 |
| FAV 分支漂移 | migration 冲突、dev API 已变化 | rebase audit,不整分支盲合;按单元摘取并重测 |
| 数据清理误删 | coverage/backup/corpus 任一未知 | 默认不删;蓝绿迁移;quarantine 观察;用户二次批准 |
---
## Operational and Rollout Notes
### Feature flags
- 新 docquery reader、单写路径、dispatcher consumer、FAV degraded read 和 legacy workspace reader 分别使用独立 flag。
- flag 只选择已兼容路径,不能跳过授权、完整性或终态准入。
- 每个 flag 有 owner、默认值、环境范围、启用前置和删除里程碑。
### Resource budgets
- app transaction、dispatcher、backfill 和 FAV publisher 使用分离的连接池或明确配额,避免后台积压耗尽在线请求连接。
- worker batch、lease、heartbeat、retry 和 concurrency 由配置管理;M1/M2 基线报告确定初值和告警阈值。
- 对同 aggregate 设置最大在途数 1;跨 aggregate 并行度按数据库与 vault 指标调节。
以下是首轮试点的安全起始值,不是产品 SLO;压测报告必须记录调整依据:
| 参数 | 起始值 | 调整约束 |
|---|---|---|
| 写事务 lock wait | 最多 2 秒且不超过请求剩余 deadline | 不允许无限等待;热点冲突优先返回 typed busy |
| serialization/deadlock retry | 最多 3 次,指数退避并带 jitter | 只重跑完整幂等事务 |
| dispatcher claim batch | 50 | claim transaction 只认领,不执行 subscriber |
| delivery lease/heartbeat | 30 秒 / 10 秒 | heartbeat 失败后旧 worker 不得 ack |
| delivery attempts | 12 次后 dead letter | permanent/auth/integrity failure 不做 12 次盲重试 |
| retry backoff ceiling | 15 分钟 | oldest age 仍受告警和人工处置约束 |
| backfill batch | 每批 200 个 aggregate | 按 lock wait、replication lag 和在线池占用自动降速 |
| backfill workers | dev 初始 1,验证后最多 4 | 每个 shard/checkpoint 不重叠 |
### Observability
- Dashboard:transaction/lock、document consistency、outbox delivery、workspace lease、FAV publication、authorization deny、backfill/quarantine。
- Alert:oldest event age、dead letter、storage identity mismatch、projection mismatch、FAV coverage gap、恢复/删除拒绝。
- Trace 使用 correlation/causation ID 串联 HTTP/use case/transaction/event/subscriber,但不得携带正文或 secret。
### Documentation lifecycle
- 每个里程碑开始前新建 short-term 和 CURRENT claim。
- 每个里程碑结束生成 test report,回链本计划 U-ID 和验收清单。
- 完成项移入 archive;未解决问题进入 audit/remediation,不通过口头说明关闭。
---
## Sources and Research
- [模块解耦方案复核](../audit/2026-09-14-module-decoupling-plan-review.md)记录当前源码中的事务、outbox、workspace 和授权缺口。
- `internal/docrevision/pg_mutate.go` 是现有账本与根指针同事务模式,U2–U3 不得降低其原子性。
- `internal/docduty/revoke.go` 已使用事务级 project advisory lock,是 KTD3 的本地先例。
- `internal/taskrun/manager.go`、`internal/taskrun/store.go` 已有进程内幂等锁与数据库唯一键,U8 需要把正确性完全落到跨实例可用的数据库协议。
- `feature/final-artifact-vault` 已实现候选 FAV 能力;U7 必须按当前 dev 重新审计,而不是把分支状态当成当前发布事实。
- [PostgreSQL `SKIP LOCKED`](https://www.postgresql.org/docs/current/sql-select.html)只用于队列式 claim,不用于普通一致性读取。
- [PostgreSQL serialization failure handling](https://www.postgresql.org/docs/16/mvcc-serialization-failure-handling.html)要求 serialization/deadlock 重试覆盖完整事务逻辑。
- [OWASP Business Logic Security](https://cheatsheetseries.owasp.org/cheatsheets/Business_Logic_Security_Cheat_Sheet.html)支持服务端重新推导身份、所有权和安全相关状态。
---
## Definition of Done
- [ ] U1–U9 完成并通过 M0–M3 的逐里程碑 go/no-go;U10–U12 只在收益复盘批准后执行。
- [ ] 文档提交不存在跨表半完成,所有提交后副作用来自持久事件。
- [ ] 多实例、多 worker、崩溃和 lease 过期场景保持相同业务结果。
- [ ] workspace 不再是正文或最终 manifest 的唯一事实源,裸路径不跨模块传播。
- [ ] FAV 只含终态成果,中间结果准入率为零,授权缺失时不可降级读取。
- [ ] 项目 143 等价 hazard 与新项目完成真实 PI、页面刷新、重登、restart/rebuild 和跨用户负例。
- [ ] clean/oldest/previous/hazard/import/reload/rollback/artifact recovery 八条迁移轨通过。
- [ ] arch-check 规则按纵向切片清零后全部 block,例外有 owner 和到期日。
- [ ] CURRENT、FEATURE-MATRIX、gap-matrix、ADR、系统设计、test report 和 checklist 状态一致。
- [ ] 放弃方案、临时代码、双写旁路、过期 flags 和无消费者契约已移除,不留在最终 diff。
## Related Links
- Audit: [模块解耦方案复核](../audit/2026-09-14-module-decoupling-plan-review.md)
- Architecture: [模块化单体解耦架构](../system-design/2026-09-14-module-decoupling-architecture.md)
- ADR: [模块化单体解耦](../adr/2026-09-14-modular-monolith-decoupling.md)
- Planning task: [本次计划修订任务](../archive/ops/2026-09-14-module-decoupling-remediation-plan.md)
- Acceptance: [重构验收清单](../ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
- FAV dependency: `feature/final-artifact-vault` 中的 `.doc/remediation/2026-09-14-final-artifact-vault-remediation.md`
- Data lifecycle dependency: `feature/final-artifact-vault` 中的 `.doc/remediation/2026-09-14-runtime-data-lifecycle-and-migration-corpus-remediation.md`
@@ -1,58 +0,0 @@
---
title: "HTTP 与 SSE 公开错误信封整改"
status: planned
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
---
# HTTP 与 SSE 公开错误信封整改
## 背景
Phase 2 复核确认错误信封涉及全部 HTTP 路由、SSE transport 和前端解析,属于独立 wire-contract 改造,不应阻塞持久事件交付。审阅见 [模块解耦 Phase 2 方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)。
## 目标
所有公开 HTTP/SSE 错误使用版本化、可脱敏、可测试的信封;客户端按 typed code 分支,不解析任意后端文案。迁移保持 additive,breaking 状态码变化必须另写 ADR。
## 契约
- 基础字段:`code`、固定安全 `message`、`request_id`、可选 `details`。
- 每个 code 单独维护 `details` 公开字段 allowlist;默认空。
- 禁止输出 raw error、SQL、堆栈、绝对路径、凭证、prompt、正文和跨租户资源 ID。
- 授权失败保持资源存在性不泄露;404/403 选择由现有授权策略决定。
- `VERSION_CONFLICT`、`IDEMPOTENCY_CONFLICT`、`VALIDATION`、`AUTHZ` 先建立领域错误到 wire code 的唯一映射。
- SSE error frame 与 HTTP 使用同一 code registry 和脱敏器,保留 transport 所需 event metadata。
## 分波次计划
| 波次 | 内容 | 验收 |
|---|---|---|
| H0 | 盘点路由、现有状态码、前端文本匹配和 SSE error frame | 路由矩阵与兼容风险签字 |
| H1 | 新增 envelope/code registry/request ID/details allowlist,旧字段 additive 保留 | schema/golden/negative tests |
| H2 | 前端逐 code 迁移,未知 code 显示安全通用错误 | 浏览器覆盖冲突、鉴权、校验、未知 code |
| H3 | 删除文本匹配和旧字段;若改变状态码先 ADR | 全路由 contract test;回滚窗口关闭 |
## 权限与安全验收
- 未授权用户无法从 code/message/details 区分资源存在性、owner 或项目成员。
- 任何 internal error 都只返回 request ID;完整诊断仅在受控服务端日志,且经过字段脱敏。
- 结构化 validation details 只包含公开字段名和稳定错误码,不回显原始输入。
- 日志按 request ID 关联,不把响应脱敏前对象序列化。
## 验收标准
- [ ] HTTP 与 SSE schema/golden 入 CI,所有公开端点有矩阵。
- [ ] 前端不再按 message substring 分支。
- [ ] XSS、路径/SQL/token/prompt/跨租户 ID 泄露负例通过。
- [ ] additive、switch、contract、rollback 各有 test report。
- [ ] 未改变的状态码保持兼容;breaking 变更有 ADR 与同步发布计划。
## 相关链接
- Audit: [Phase 2 方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- 上位路线: [Phase 2 修订计划](./2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Short-term: 实施前另建;H0 盘点见 [research](../ops/research/2026-09-15-http-error-envelope-h0-inventory.md)
- 实施 backlog: [long-term Track P](../ops/long-term/2026-09-15-track-p-protocol-implementation.md)
- gap-matrix 行: 当前为工程债,不单独作为 Track E 发布 blocker
@@ -1,47 +0,0 @@
---
title: "mock 交付物污染真实项目整改方案(demo 数据环境门控 + 服务端清单对账回收)"
status: planned
created: 2026-09-15
updated: 2026-09-15
---
# mock 交付物污染真实项目整改方案(demo 数据环境门控 + 服务端清单对账回收)
## 背景
[Audit 2026-09-15](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md):前端硬编码 mock 交付物(projectId 1/2/3/5201/6001+)与真实项目数字 ID 撞车,空项目展示「终审已生效」幻影受控文档与伪造法定职责人;mock 数据无环境门控且已进入生产构建产物;服务端权威清单为空时前端不回收本地多余项。
## 目标
1. 任何真实(服务端注册)项目的工作台**只显示**服务端 `document_records` + 该项目新建模板克隆项,永不出现 mock 幻影文档;
2. mock/demo 数据仅在显式开启的 demo 构建中生效(构建期注入,默认关闭);
3. 生产构建产物中不含 mock 文档正文与 mock 用户权限;
4. localStorage 已持久化的 mock 项在升级后一次性回收;
5. 前端对服务端清单做**双向对账**:服务端为权威,本地多余受控项下架(复用 ControlledInvalidationPlan/dropRecordKeys 机制)。
## 分波次计划
| 波次 | 内容 | 验收 |
|------|------|------|
| Wave 0 止血(低风险) | 1) `mergeWorkflowDocumentsFromServer` 增加对账回收:`category=workflow` 且 `isLegacyLocalMockDocId(docId)` 的本地项,在服务端清单返回(含空数组)时一律 drop(走 `dropRecordKeys` + 受控失效计划既有管道);2) 新建项目克隆模板的 docId 命名空间(`doc-p{projectId}-*`)与 mock 命名空间隔离校验测试 | test 环境新建项目后清单只剩 `doc-p1-*` 模板项;单测覆盖空清单回收 |
| Wave 1 demo 门控 | 1) 所有 demo 种子(mockDocuments/neuropulse/tenProjects/MOCK_USERS/MOCK 权限)收口到 `web/src/data/seeds/` 单一入口,导出统一 `DEMO_SEEDS`;2) 入口处 `if (!import.meta.env.VITE_ENABLE_DEMO_SEEDS) return EMPTY`(构建期常量,生产默认 false);3) `npm run build` 产物 grep 验证不含「4K超高清荧光」等特征串(`VITE_ENABLE_DEMO_SEEDS= npm run build`);4) demo 构建单独脚本 `build:demo` | 产物 grep 断言进 CI/前端测试;demo 模式显式 opt-in |
| Wave 2 存量清理 | 1) `loadDeliverables` 加载时一次性迁移:剔除命中 `isLegacyLocalMockDocId` 的持久化项(版本化 storage key bump);2) `loadUsers`/`loadProjects` 同理剔除 mock 用户/mock 项目(保留真实同步数据);3) 迁移写入 `storage.ts` 版本号,幂等可重放 | 升级后 localStorage 无 mock 残留;重复刷新幂等 |
| Wave 3 UI 语义防线 | 1) `DeckDrawer`/`DocGovActionBar` 对非服务端注册文档(无 ledger 事实)禁用生命周期徽章/治理按钮,显示「本地示例(不入账本)」占位标签;2) `visibleDeliverables` 统计口径排除 mock ID(防污染项目文档计数) | 空项目不再出现「终审已生效」徽章;组件测试 |
| Wave 4 验收与归档 | 1) test 环境真实新建项目全链路(新建→清单→刷新→重启容器)回归;2) dev 环境 id 1–3 项目抽检;3) `go vet` / `go test -short` / `cd web && npm test && npm run build` 全绿;4) test-report 归档 + gap-matrix 行 | 报告归档 `.doc/test-reports/`;gap-matrix 更新 |
## 验收标准
- [ ] test 新建项目:交付物清单 0 幻影文档,仅 `doc-p{id}-*` 模板项(lifecycleState=template)
- [ ] dev 项目 id 1/2/3:无 doc-001/doc-cusa-* 等幻影项
- [ ] 生产构建产物 grep 无 mock 特征串;demo 构建仅显式开启时含种子
- [ ] localStorage 升级迁移后无 mock 残留且幂等
- [ ] 服务端清单对账:服务端删除/为空时本地对应受控项下架
- [ ] 幻影文档(若 demo 模式保留)不带「终审已生效」徽章与治理操作
## 相关链接
- Audit: [../audit/2026-09-15-mock-deliverables-pollute-real-projects.md](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md)
- Short-term: [../ops/short-term/2026-09-16-clean-test-env-baseline.md](../ops/short-term/2026-09-16-clean-test-env-baseline.md)
- Test Report: [../test-reports/2026-09-16-clean-test-env-baseline-test-report.md](../test-reports/2026-09-16-clean-test-env-baseline-test-report.md)
- gap-matrix 行: 待补(发布 blocker:治理记录失实 / 跨环境影响)
- 既有同域防线: `web/src/features/documentRevision/revisionToolbarMount.ts`(isLegacyLocalMockDocId)、`web/src/lib/controlledDocHydrate.ts`(shouldLoadControlledContent)、`web/src/lib/deliverableSync.ts`(mergeWorkflowDocumentsFromServer)
@@ -1,342 +0,0 @@
---
title: "模块解耦 Phase 2:持久事件交付与后续解耦路线"
status: planned
created: 2026-09-15
updated: 2026-09-15
type: refactor
owner: TBD
---
# 模块解耦 Phase 2:持久事件交付与后续解耦路线
## 决策摘要
Phase 2 的核心交付只包含持久事件链:修正事件生产、补齐 PostgreSQL 投递实现、用无副作用 shadow 对账替换闭包桥,并以授权用户刷新/重启后的正文恢复作为停走门。
结构解耦(D4–D7)是独立轨道;HTTP 错误信封与 PI Runner typed result 各自单独立项。三条轨道分别验收,不能互相阻塞关闭。
本计划不拆微服务,不引入外部消息基础设施,不合入 FAV 分支,不删除历史数据,也不授权实施、合并或部署。
## 背景与纠偏
- 上位约束:[模块化单体解耦 ADR](../adr/2026-09-14-modular-monolith-decoupling.md)、[架构设计](../system-design/2026-09-14-module-decoupling-architecture.md)、[Phase 1 计划](./2026-09-14-module-decoupling-refactor-plan.md)。
- 复核结论:[Phase 2 方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)。
- 现状调研:[IPC/RPC 现状评估](../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)。
- `internal/events/pg.go` 目前只有信封写入与 SELECT 型 `ClaimIDs`,没有原子 lease、ack/fail、重试、dead-letter 的生产闭环。`internal/events/dispatcher_test.go` 只证明 `MemoryBus` 语义,不能作为 PG 运行证据。
- `docgov` 仅单向依赖 `docrevision` 的 Markdown canonical/hash 工具,不存在生产双向 import 环。
- `module-boundaries.yaml` 已有 `event_producers`/`event_consumers`;缺口是映射不完整、运行时注册未与静态清单校验。
- `docflow.Commands` 在部分生产 HTTP 路径临时构造,事件 sink 未稳定注入;其 envelope 仍写入 `Environment:"dev"`、`ProjectID:0`。未先修生产入口就开始 shadow,会得到虚假的零差异。
## 目标与边界
### Track E:持久事件交付(本计划核心)
目标:让 notify 与 projection 副作用在重复投递、进程崩溃、租约过期和重启后达到“至少一次投递、恰好一个可见结果”,并能从数据库追查每次 attempt。
包含 D1、D2、D3、D10、D11。Track E 完成后即可单独关闭,不等待结构或协议轨道。
### Track S:结构解耦(后续独立 go/no-go)
目标:移除 bizdev locator,收敛 stageflow/chat/intent 依赖,并消除 `docgov → docrevision` 的剩余工具依赖。包含 D4、D5、D6、D7a、D7b。
Track S 只有在 Track E 复盘后重新认领 mutex 才能开始;每个单元独立关闭。
### Track P:外部协议(另立 remediation)
- P1:HTTP/SSE 错误信封。
- P2:PI Runner typed-result-v1 rollout。
D8、D9 在本文件保留设计约束和立项入口,不属于 Track E/S 的 Definition of Done。独立方案见 [HTTP/SSE 错误信封](./2026-09-15-http-error-envelope-remediation.md) 与 [PI typed-result-v1](./2026-09-15-pi-typed-result-v1-remediation.md)。
### 明确排除
- U4/U5 的 path/sql_write 例外清零及其既有 owner。
- `feature/final-artifact-vault` 的审计、合入、subscriber 激活与真实副作用验收。本计划只预留 FAV event schema 和 disabled allowlist 条目。
- 全量 IPC/RPC、服务拆分、分布式事务协调器。
- 破坏性历史清理。旧事件只允许分类、隔离、修复或明确过期;任何删除另走审批计划。
## 需求与可追踪性
| ID | 要求 | 交付单元 | 核心验收 |
|---|---|---|---|
| E1 | PG delivery 状态机可生产运行 | D1 | 真实 PG 多 worker、崩溃点、fencing 测试 |
| E2 | 至少一次投递、一个可见结果 | D1/D2 | 副作用幂等键/事务 receipt;重复投递无重复可见结果 |
| E3 | 每次 attempt 可审计 | D1 | 不可变 attempt 表,日志不代替数据库审计 |
| E4 | 事件作用域真实且授权闭合 | D3/D11 | env/project/service principal/资源复核全部 fail closed |
| E5 | 闭包桥安全下线 | D2 | shadow 覆盖门通过;逐消费者切换;一窗口后删 API |
| E6 | 静态契约与运行注册一致 | D10 | allowlist 已有段补全;构建时 registry parity 门禁 |
| E7 | 历史脏数据不会误消费 | D11 | dry-run 清单;repair/quarantine/expire 决策可审计 |
| E8 | 用户刷新恢复 | D2 | 授权 UI 刷新/重启正文一致,无 projection-missing |
| S1 | bizdev 不再充当 locator | D4 | 8 个 getter 最终同批删除;无新调用方 |
| S2 | 用例类型归属清楚 | D5 | coordinator 不依赖 bizdev DTO |
| S3 | 剩余工具依赖消除 | D6 | docgov/docrevision 互不 import;canonical golden 一致 |
| S4 | intent/chat 可独立迁移 | D7a/D7b | 两条独立分支、mutex、验收与回滚 |
## 关键技术决策
1. **语义不写“exactly once delivery”。** Dispatcher 提供 at-least-once delivery。消费者用唯一键、事务 inbox/receipt、CAS 或 no-replace 提交保证 exactly-one visible outcome。
2. **shadow 不执行业务副作用。** 旧闭包仍是唯一真实写路径;shadow 只计算规范化 intended outcome,并写对账记录。禁止“闭包与消费者双写后比较”。
3. **独立 worker 进程。** 事件消费落在 `cmd/events`,与 HTTP 进程分开扩缩容;`internal/app` 不重复启动 dispatcher。该选择沿用 Phase 1 U6,避免两种拓扑并存。
4. **先证明事件源,再开始计时。** 三条文档链必须在同一 UoW 写入领域变化、envelope 和目标 delivery。PG 测试证明生产入口确实产生事件后,shadow 窗口才有效。
5. **每个消费者独立灰度。** 状态为 `off|shadow|live`,按 environment + consumer 配置。notify、workflow advance、projection 分开切换;FAV 保持 off。
6. **静态 allowlist 与运行 registry 同源。** `module-boundaries.yaml` 现有映射补全后生成或校验只读 registry manifest;生产禁止未登记的动态注册。
7. **历史事件先盘点。** 作用域为 0、环境错误、未知 consumer、序列不连续或 payload schema 未知的旧记录不得自动 live 消费。
8. **结构与协议不绑核心关闭。** Track E、S、P 分别有状态、停走门、测试报告和回滚点。
## 目标拓扑
```mermaid
flowchart LR
HTTP[server/use case] -->|domain change + envelope + deliveries / one UoW| PG[(PostgreSQL)]
WK[cmd/events] -->|atomic lease| PG
WK --> N[notify]
WK --> A[workflow advance]
WK --> P[projection]
N -->|idempotency key| PG
A -->|transactional inbox| PG
P -->|expected head + digest| WS[workspace projection]
F[FAV contract] -. disabled .-> WK
```
## 数据模型与并发协议
### Delivery 状态机
```text
pending -> leased -> acked
|-> pending transient failure / lease expiry
|-> dead max attempts or explicit permanent failure
|-> quarantine scope, schema, integrity or ordering violation
```
- Claim 必须在一个短事务内 `WITH candidates AS (SELECT ... FOR UPDATE SKIP LOCKED LIMIT ...) UPDATE ... FROM candidates ... RETURNING`,同时写 `lease_owner`、递增 `fencing_token`、`lease_until`、`attempt`。现有 SELECT-only `ClaimIDs` 不满足此条件。
- Handler 在 claim 事务外执行。Fencing token 必须随 consumer command 传到最终副作用提交点;数据库副作用在同一事务校验 token,projection marker 使用 expected version + 单调 token。Ack/fail 也必须匹配 `event_id + consumer + lease_owner + fencing_token`。旧 token 的副作用和 ack/fail 都必须失败。
- 长任务按受保护的 token 续租;heartbeat 失败立即取消 handler。停机先停止 claim,再等待 inflight 或安全释放租约。
- 同一 consumer + aggregate 同时最多一个 inflight;不同 aggregate 可并行。不能把领域版本号直接假设为无缺口事件序号。
- D11 必须在以下两种模型中选一并写 ADR/迁移:独立无缺口 event sequence;或 consumer checkpoint + 首事件 bootstrap。未决前禁止启用 gap 阻塞。
### 副作用原子性
| 消费者 | 可见结果契约 | 崩溃窗口处理 |
|---|---|---|
| notify | `event_id + recipient + notification_kind` 唯一键 | 通知写入与 inbox 同一 PG 事务;重放命中唯一键即视为成功 |
| workflow advance | `event_id + transition` 唯一 receipt;重新读取当前状态和权限 | 领域转换、outbox、inbox 同一 UoW;状态已前进时按 receipt 判定 |
| projection | `document_id + source_snapshot_id + digest` no-replace;expected head | 文件先写临时对象并 fsync,再原子提交 marker;重放核对 digest |
| FAV | 本计划不激活 | 由 FAV 审计定义 source-event/digest no-replace 契约 |
副作用完成后、delivery ack 前必须注入崩溃。恢复后可重复调用 handler,但最终只有一个可见结果。
### 审计表
Additive migration 新增不可变 `event_delivery_attempts`,至少记录:event、consumer、attempt、lease owner、fencing token、started/finished、outcome、typed error code、correlation ID。`event_deliveries` 只保存当前游标和状态。
attempt、dead-letter、shadow reconciliation 只存 ID、digest、typed code 和字段 allowlist 生成的摘要。禁止保存原始 payload、SQL error、绝对路径、token、prompt 或正文。
## 权限模型
| 动作 | 主体 | 必须校验 | 禁止 |
|---|---|---|---|
| 普通消费 | 每个 consumer 独立 service principal | environment、project、consumer、action;副作用前重读资源归属和当前状态 | 继承原用户会话、跨项目查询、共享万能 principal |
| shadow | ops service principal | 只写 reconciliation;不持有业务写权限 | 调用真实通知/推进/投影写端口 |
| replay dry-run | 具备事件运维 capability 的管理员 | env/project/consumer/event 范围、reason、approval ref | 无范围全库扫描、原始 payload 回显 |
| replay apply | 同一操作者能力 + 未过期 plan digest | apply 参数必须与 dry-run digest 完全相同 | 现场改范围;绕过资源当前授权 |
| 多项目/批量 replay | 两人批准 | operator 与 approver 分离;不可变审计 | 单人直接执行 |
worker 数据库角色只授予其拥有表和调用端口所需权限。Replay 是应用用例,不提供裸 SQL 运维入口。授权失败、资源已转移、project 不存在或 env 不匹配一律 quarantine,不重试为 transient。
## 分波计划
### E0A:生产者、契约与旧数据门(D3、D10、D11)
进入条件:认领 `events/app/arch` mutex;dispatcher 保持 off。
交付:
1. 组合根构造唯一 `docflow.Commands`,向 server 注入 UoW、PGSink、environment与 project resolver;禁止 HTTP handler 临时漏注入。
2. candidate-ready、downstream-impact、approved 三条链在领域提交同一 UoW 内写 envelope 和目标 delivery。
3. 修正 `Environment/ProjectID`,缺值 fail closed;先清点历史 `0/dev` 记录。
4. 补全现有 event allowlist,校验生产者、消费者、payload schema、运行 registry parity。
5. 生成历史事件 dry-run manifest,逐条分类为 safe、repair、quarantine、expire;不删数据。
6. 决定连续性模型,审计 `(aggregate_type, aggregate_id, aggregate_version)` 唯一约束是否允许同一版本多个事件;必要时 additive migration。
退出门:真实 PG 测试证明每条生产链产生正确 envelope/delivery;历史清单有审批结论;未登记事件和动态 consumer 构建失败。
### E0B:PG dispatcher 基座(D1)
进入条件:E0A 全部通过;旧数据不会进入 live claim。
交付:
1. 完成原子 lease、heartbeat、fenced ack/fail、backoff、dead/quarantine 和 attempt audit。
2. 新建 `cmd/events`;每个环境单独容器、配置和 DB 连接预算。HTTP Runtime 不启动 worker。
3. 增加 readiness(DB、registry、schema)、liveness、queue age、oldest pending、claim/ack/fail/fenced、attempt latency、dead/quarantine 指标。
4. 默认从 Phase 1 基线起步:batch 50、lease 30s、heartbeat 10s、max attempts 12、backoff ceiling 15m;压测报告才能调整。
5. 以 1/2/4 worker 验证无双 lease、跨 aggregate 并行、同 aggregate 串行、连接池有界和公平性。
退出门:PG 集成与 race 测试通过;在副作用后/ack 前、续租前后、停机 drain 等崩溃点均可恢复;资源预算和 p50/p95/p99 基线归档。
### E1A:notify shadow 与切换(D2-notify)
1. 旧闭包产生 canonical outcome;shadow handler 产生 intended outcome。两者经同一规范化器比较收件人、类型、去重键、payload digest。
2. E0A 根据经作用域校验和审批的前 7 天有效事件基线为每个 event type 预登记最小样本 N,N 不低于 30;低流量分支补确定性 replay fixture。窗口不少于 3 个完整日,并覆盖成功、授权拒绝、重复和 permanent failure。
3. 任一未解释 diff、越权、原始 payload 泄露或样本不足均重置窗口。
4. `off|shadow|live` 是带 revision 的集群级受控状态,不是单实例环境变量。先部署同时理解新旧模式的兼容代码,drain 并确认旧实例全部退出,再原子切换权威写者。
5. 先把 notify 置 live;闭包 notify 路径置 off。保留显式回滚开关一个发布窗口。
退出门:重复投递只有一个通知;重启不丢;correlation ID 可查 producer→attempt→receipt;回滚演练通过。
### E1B:workflow advance shadow 与切换(D2-advance)
批准事务必须发布 typed approved event。Consumer 在副作用前重读 document/project/workflow 状态和 service principal 权限。按 E1A 同样的 coverage gate 切换,随后移除批准 hook 注册。
退出门:并发批准只推进一次;陈旧或跨项目事件 quarantine;阶段推进产生的下游事件保持 causation/correlation;回滚演练通过。
### E1C:projection 恢复纵切(D2-projection)
在副作用前、副作用后/ack 前、lease 过期后三个位置终止 worker并重启。授权用户通过真实页面刷新和重新打开文档,正文必须与数据库 head/snapshot digest 一致,不出现 `projection missing`,不产生重复版本。未授权用户仍得到非泄露式拒绝。
退出门:真实 PG + browser + worker restart 报告通过;按 correlation ID 能还原完整链路。FAV 仍为 off。
### E2:核心收口
- 删除 `OnOutbox =`、`AddOnApprovedHook(` 等生产注册点。
- 保留 API 一个发布窗口后,再独立 contract 提交删除字段/方法本体。
- Track E 的 release blocker 关闭;Track S/P 保持各自状态,不拖延此关闭。
## 实施单元明细
### D1:PG dispatcher 与 attempt audit
主要文件:`deploy/postgres/goose/<next>_event_dispatcher.sql`、`internal/events/pg.go`、`internal/events/dispatcher.go`、`cmd/events/main.go`、环境 compose/config。
必须交付 E0B 的状态机、进程拓扑、连接预算、指标和真实 PG 故障注入。MemoryBus 测试只作快速 characterization,不计生产验收。
### D2:闭包迁移
主要文件:`internal/docrevision/service.go`、`internal/docgov/engine.go`、`internal/app/app.go`、`internal/app/docnotify`、projection owner。
拆成 notify、workflow advance、projection 三个 short-term。Shadow 只写 reconciliation;每个消费者都有独立 `off|shadow|live`、停走门和回滚演练。最后一个 live 窗口结束后才能删除 hook API。
### D3:事件生产与作用域
主要文件:`internal/app/docflow/commands.go`、server 注入点、`internal/taskrun/finalize.go`。
修复生产入口漏注入和硬编码。事件构造必须从已授权服务端上下文与持久记录取得 environment/project;客户端字段不可信。FAV staging 调用不属于 Track E;FAV disabled 时,生产链不得写 staging、artifact 或 publication 记录。`Fav.StageAgentCommit(ctx, 0, ...)` 的真实 project scope 修复随独立 FAV 审计实施。
### D10:事件契约与 registry parity
主要文件:`.doc/system-design/module-boundaries.yaml`、`internal/archtest`、registry manifest 生成/校验代码。
不是“新增 allowlist 段”,而是补全已有段并把 payload schema/version、合法 producer、合法 consumer、enabled state 一并校验。运行 registry 必须是静态清单的子集;FAV 条目标记 disabled。
### D11:历史数据与序列安全
主要文件:additive migration、只读 inventory/replay use case、审计报告。
交付历史清单、序列模型、约束审计、repair/quarantine/expire 规则。修复必须保留 old/new digest、operator、reason、approval;禁止原地无审计改值。
### D4:bizdev locator 最终移除
先加 no-new-callers 门禁,再分批把调用方迁移到消费者端口。准备工作可分批;8 个 getter 的最终删除必须在一个 contract 提交完成。规则只禁止领域/用例 API 暴露、返回或转发 pool/tx;允许 app/cmd 组合根向表属主构造器注入 pool,也允许登记属主从 opaque TxScope 解出 tx。
### D5:stageflow 类型归属
`stageflow` 定义 use-case request/result,并在 app 边界适配 bizdev 领域类型。行为方法不能机械复制成 DTO。用 mapping golden 和 characterization 锁定语义;coordinator 最终不 import bizdev。
### D6:移除单向 canonical 工具依赖
当前不是循环。把 Markdown canonicalization 与 SHA 作为一个内聚的共享行为模块(建议 `internal/doccontent`)提取,提供 golden vectors。禁止把带行为的 canonicalizer 塞入 vocabulary。完成后 docgov/docrevision 互不 import。
D6 不依赖 D4/D5,只受 docgov/docrevision mutex 与 U4/U5 排期约束。
### D7a:intent 与 bizdev 解绑
为 intent 注入最小只读消费者端口;单独分支、characterization、mutex 和验收。不得等待 chat 迁移。
### D7b:chat 编排迁入 chatflow
逐用例迁移,保留 handler characterization。只有 D4 提供所需端口后才开始;禁止“一次搬空包”。每批收紧一条 import 规则并可独立回滚。
### D8:HTTP/SSE 错误信封立项约束
另建 remediation。公开 wire 至少为 `code/message/request_id/details?`;`message` 使用固定安全文案,`details` 按 code 维护公开字段 allowlist。不得回传 raw error、SQL、路径、凭证、prompt、正文或跨租户 ID。授权拒绝保持资源存在性不泄露。全路由、SSE 与前端迁移各有 golden/negative test。
### D9:PI typed-result-v1 rollout 立项约束
另建 remediation,不称“协议 v2”。只有 typed 字段完全缺失且握手明确声明旧 Runner 时才允许 legacy;typed 字段存在但 schema/digest/path/run_id/size 校验失败必须 fail closed,禁止降级。真实 PI E2E 覆盖取消、超时、未知 schema、超限输出、secret/prompt 注入与 downgrade attack。
## 迁移、部署与回滚
| 阶段 | 部署顺序 | 可回滚动作 | 禁止 |
|---|---|---|---|
| expand | additive migration → producer 修复 → registry | worker 保持 off;回滚应用不删表 | 旧数据直接 live claim |
| shadow | worker shadow → reconciliation | consumer 置 off;保留记录 | 执行业务副作用;清空 diff |
| switch | 部署兼容代码 → drain 旧实例 → 记录 backlog 水位 → 原子切换单 consumer live/闭包 off | 暂停 claim,核对已执行 receipt 与 backlog,再 live off + 对应闭包 on;只在兼容窗口内 | 滚动部署时同时开启两条真实写路径 |
| contract | 一发布窗口后删 hook API | 通过新提交恢复,不回滚 schema | 删除 delivery/attempt 历史 |
回滚期间禁止同时 replay。恢复 live 前必须重新做 backlog dry-run,并确认旧 lease 已失效。Migration 只 additive;任何表/列删除另立计划。
## 分支、mutex 与交付件
| 单元 | mutex | 分支示例 | 独立报告 |
|---|---|---|---|
| D3/D10/D11 | events + app + arch | `fix/event-production-scope-contract` | E0A |
| D1 | events + deploy | `feature/events-dispatcher-pg` | E0B |
| D2-notify | events + docnotify | `fix/event-notify-cutover` | E1A |
| D2-advance | events + workflow | `fix/event-workflow-cutover` | E1B |
| D2-projection | events + docgov | `fix/event-projection-recovery` | E1C |
| D4 | bizdev | `fix/bizdev-locator-removal` | S1 |
| D5 | stageflow + coordinator | `fix/stageflow-type-ownership` | S2 |
| D6 | docgov + docrevision | `fix/doccontent-canonical-boundary` | S3 |
| D7a | intent | `fix/intent-bizdev-boundary` | S4a |
| D7b | chat + chatflow | `fix/chatflow-orchestration-boundary` | S4b |
每行先建 short-term 并登记 CURRENT。合入 dev 与共享容器验证必须占集成槽位。
## 验收与停走门
### Track E Definition of Done
- [ ] E1–E8 均有证据链接;E0A/E0B/E1A/E1B/E1C 各有独立 test report。
- [ ] PG 状态机、attempt audit、1/2/4 worker、race、崩溃点、fencing、顺序、背压和连接预算通过。
- [ ] notify/workflow/projection 分别完成 shadow coverage、切换和回滚演练;FAV 保持 disabled。
- [ ] 生产注册代码无 `OnOutbox =`、无 `AddOnApprovedHook(`;不存在 HTTP 与 worker 双重接线。
- [ ] 授权 UI 在三类 worker 重启点刷新/重开正文一致;未授权与跨项目负例通过。
- [ ] replay dry-run/apply digest、service principal、字段脱敏、双人批量审批负例通过。
- [ ] arch-check block、`go test -race` 目标包、`go test -short ./...`、PG 集成、browser/restart 全绿。
- [ ] CURRENT、FEATURE-MATRIX、gap-matrix 只关闭事件可靠性 blocker,不把 Track S/P 写成已完成。
### Track S 单元 DoD
D4–D7b 各自满足需求表中的 S1–S4、独立测试报告和 arch rule 收紧即可关闭;无需等待其他结构单元。
### Track P 立项门
D8、D9 各有独立 remediation、owner、范围、兼容矩阵、negative tests 和真实验收计划。本 Phase 2 不要求其实现完成。
## 风险与控制
| 风险 | 控制 |
|---|---|
| shadow 因无事件源虚假通过 | E0A 先证明每条生产入口写 envelope/delivery,之后才开始计时 |
| 领域版本缺号永久阻塞 | D11 明确 event sequence 或 checkpoint/bootstrap,不把 version 当连续事件号 |
| 副作用成功但 ack 丢失 | 每消费者幂等契约;真实崩溃注入;fenced ack |
| 重试覆盖历史 | immutable attempts;delivery 只存当前状态 |
| 脏旧事件跨环境/项目执行 | inventory + quarantine;资源当前授权复核;service principal 最小权限 |
| worker 抢光连接 | 独立 pool 预算、inflight 上限、queue/backpressure 指标、压测后调参 |
| poison event 阻塞 aggregate | quarantine 需显式审批;不静默跳号;其他 aggregate 继续 |
| shadow/replay 泄密 | schema 字段 allowlist、digest 摘要、无 raw payload/error |
| FAV 拖住核心 | 只预留 disabled 契约;激活归独立 FAV 计划 |
| 结构改造扩大爆炸半径 | no-new-callers 先行;小批迁移;最终 getter 原子删除 |
## 相关链接
- [方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- [现状调研](../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)
- [Phase 1 计划](./2026-09-14-module-decoupling-refactor-plan.md)
- [模块化单体 ADR](../adr/2026-09-14-modular-monolith-decoupling.md)
- [模块边界清单](../system-design/module-boundaries.yaml)
- [Track E 任务入口](../ops/short-term/2026-09-15-durable-event-track-e.md)
- [HTTP/SSE 错误信封独立方案](./2026-09-15-http-error-envelope-remediation.md)
- [PI typed-result-v1 独立方案](./2026-09-15-pi-typed-result-v1-remediation.md)
- [发布缺口 SSOT](./gap-matrix.md)
@@ -1,60 +0,0 @@
---
title: "PI Runner typed-result-v1 迁移方案"
status: done
created: 2026-09-15
updated: 2026-09-15
owner: Cursor
---
# PI Runner typed-result-v1 迁移方案
## 背景
PI Runner 已有 HTTP/Bearer 传输边界,但结果仍兼容 stdout/result.json。该工作是 Runner、taskrun、agent adapter 和真实 PI E2E 的独立协议迁移,不应称“协议 v2”,也不阻塞持久事件交付。
## 目标
`/v1/run` 返回带 schema version、run identity、member 清单、digest 和 typed outcome 的 `result_v1`。服务端严格校验后持久化;legacy 只在明确的旧 Runner 能力握手下保留一个发布窗口。
## 契约与降级规则
- JSON Schema:`configs/schemas/pi-run-result-v1.json`,canonical JSON 与 digest 规则固定。
- 结果至少包含 `schema_version`、`run_id`、`members[]`、typed success/error、retryable、content digest;member kind 使用 allowlist。
- Runner capability/handshake 明确声明是否支持 typed result,并与响应绑定。
- typed 字段完全缺失且握手声明旧 Runner 时,才允许 legacy。
- typed 字段存在但 schema、digest、run ID、member path、size 或 secret 检查失败时 fail closed,禁止 fallback。
- 文件路径必须落在本次 run 的受控输出根;拒绝绝对路径、`..`、symlink escape 和超限成员。
- error 分类和 retryable 由 allowlist 决定,不接受模型任意字符串控制重试。
## 分波次计划
| 波次 | 内容 | 验收 |
|---|---|---|
| P0 | 盘点 legacy 输出、最大体积、取消/超时语义和真实 Runner 版本 | compatibility matrix 与 schema review |
| P1 | Runner additive 输出 `result_v1`,旧字段保留 | Runner schema/golden、大小/路径/secret 负例 |
| P2 | Go parser typed-first 严格校验,按握手决定 legacy | downgrade、未知 major、digest/run mismatch fail closed |
| P3 | dev 真实 PI 双轨对账一个发布窗口 | `RUN_PI_E2E=1`;取消、超时、成功、失败均一致 |
| P4 | 删除 legacy parser/字段 | contract test 与前滚/回滚说明归档 |
## 高并发与安全
- `run_id`、request id、project/environment 和 backend identity 全链关联;禁止一个 run 接受另一个 run 的结果。
- Parser 在分配大对象前执行 body/member 数量与尺寸上限;压缩输入限制解压比。
- cancel 与 result 竞争使用单调终态:只允许一个 terminal outcome,晚到结果审计后丢弃。
- Runner 输出视为不可信输入;字段、路径、MIME、编码和文本均需验证。不得把 prompt、token 或完整模型 stderr 放入结果或公开日志。
## 验收标准
- [x] Schema/golden 在 Runner 与 Go 两侧共享并入 CI。
- [x] typed-present-invalid 永不 fallback;handshake downgrade attack 负例通过。
- [x] 并发 run/result 串线、cancel/result 竞争、超限与 path escape 负例通过。
- [x] 真实 PI E2E 覆盖成功、typed error、取消、超时与未知 schema。
- [x] legacy 删除前完成一个发布窗口对账和回滚演练。
## 相关链接
- Audit: [Phase 2 方案审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md)
- 上位路线: [Phase 2 修订计划](./2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md)
- Short-term: 实施前另建;P0 矩阵见 [research](../ops/research/2026-09-15-pi-typed-result-p0-matrix.md)
- 实施 backlog: [long-term Track P](../ops/long-term/2026-09-15-track-p-protocol-implementation.md)
- gap-matrix 行: 当前为工程债,不单独作为 Track E 发布 blocker
@@ -1,55 +0,0 @@
---
title: Demo/测试数据污染整改方案
status: done
created: 2026-09-16
updated: 2026-09-16
owner: Cursor-Auto
branch: fix/demo-data-pollution-web
mutex: web
---
# Demo / 测试数据污染整改方案
## 目标
生产构建默认无演示文案;权威服务端空清单回收本地 mock;DB 演示项目不进列表;main 拒绝 stub。
## 波次与状态
| Wave | 内容 | 状态 |
|------|------|------|
| 0 | `isDemoSeedDocId` + `mergeWorkflowDocumentsFromServer` 空清单 drop | done |
| 1 | `VITE_ENABLE_DEMO_SEEDS` + `@demo-seeds` alias + `check-prod-bundle.sh` | done |
| 2 | `purgeDemoSeedsFromLocalStorage` 幂等迁移 | done |
| 3 | DeckDrawer「本地示例」徽章;职责人默认值清空 | done |
| 4 | goose `00046` retire projects + `00047` retire sessions + list/`ListChatSessions` 过滤 | done |
| 5 | `ResolveBackendInEnv` main/prod 拒 stub | done |
| 6 | 审计/整改/报告/gap-matrix | done |
## 关键实现
- 判定:[`web/src/data/demoSeedIds.ts`](../../web/src/data/demoSeedIds.ts)
- 门控:[`web/vite.config.ts`](../../web/vite.config.ts) alias `@demo-seeds` → enabled/disabled
- 同步:[`web/src/lib/deliverableSync.ts`](../../web/src/lib/deliverableSync.ts)
- DB:[`deploy/postgres/goose/00046_2026-09-16-retire-demo-ten-projects.sql`](../../deploy/postgres/goose/00046_2026-09-16-retire-demo-ten-projects.sql)
- Stub:[`internal/taskrun/backend.go`](../../internal/taskrun/backend.go)
## 验收标准
- [x] 默认 `npm run build` 后 `check-prod-bundle.sh` PASS
- [x] 空 server 清单 drop demo-seed 单测 PASS
- [x] `ResolveBackendInEnv(..., "main")` 拒 stub 单测 PASS
- [x] 共享环境 migrate `00046`/`00047` 后列表无 6001–6010(dev schema 47)
- [x] 新建空项目 UI/API 交付物无伪造 approved(项目 6357 documents=0)
## 启用 Demo(仅本地/评审)
```bash
VITE_ENABLE_DEMO_SEEDS=true npm run dev
```
## Follow-up(P2,不挡合入)
- stub 旁路:`resolveTaskBackend` 双重失败返回 `""` 时 squad 回落 `cfg.AgentBackend`;建议 main/prod 启动 fail-fast 校验 `AGENT_BACKEND≠stub`
- `purgeDemoSeedsFromLocalStorage` 对 projectId 1/2/3 无 serverIds 守卫,可能清掉 test 环境真实本地会话缓存;长期改为按 `sess-neuropulse-*` / `sess-wangjing-*` 前缀或注释权衡
- 姊妹分支 `fix/clean-test-env-baseline` 重叠前端清理已放弃;已挑拣 `a91a031`(`SEED_DEMO_USERS=false`)与 2026-09-15 审计回链
-4
View File
@@ -3,10 +3,6 @@
| 文档 | 说明 |
|------|------|
| [gap-matrix.md](./gap-matrix.md) | 发布缺口 SSOT |
| [2026-09-14-module-decoupling-refactor-plan.md](./2026-09-14-module-decoupling-refactor-plan.md) | 纵向绞杀、UnitOfWork、高并发互斥、可靠事件、逐动作授权、FAV、迁移与恢复的详细重构计划 |
| [2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md](./2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md) | Phase 2 修订版:Track E 持久事件交付先行;Track S 结构解耦独立 go/no-go;HTTP 与 PI 协议另立 remediation([审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md);[调研](../ops/research/2026-09-15-module-decoupling-ipc-assessment.md)) |
| [2026-09-15-http-error-envelope-remediation.md](./2026-09-15-http-error-envelope-remediation.md) | HTTP/SSE typed error envelope、公开 details allowlist、前端 additive 迁移与安全负例 |
| [2026-09-15-pi-typed-result-v1-remediation.md](./2026-09-15-pi-typed-result-v1-remediation.md) | PI Runner typed-result-v1 schema、严格降级、并发终态与真实 PI 双轨验收 |
| [2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md](./2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md) | 项目设置 409 冻结态守卫 + 非必需文档三权全有或全无 + 成员/门禁/权限一致性 |
| [2026-09-14-controlled-content-canonical-hash-remediation.md](./2026-09-14-controlled-content-canonical-hash-remediation.md) | 项目 143 正文 canonical/raw 哈希漂移、错误语义与重复 hydration 整改 |
| [2026-09-13-document-revision-reviewer-duty-sync.md](./2026-09-13-document-revision-reviewer-duty-sync.md) | UI-01 已分配 B=reviewer,受控文档 reviewer_id 硬编码 2,矩阵降为 viewer |
+14 -19
View File
@@ -1,10 +1,10 @@
# 整改缺口复核矩阵(SSOT)
**更新**: 2026-09-16
**更新**: 2026-09-14
**分支**: dev
**production_ready**: yes(发布门禁 B1–B4 已签;dev/test/main schema=47。U9–U12 / 软件自举 / FAV / 完整 PI change-report 叙事不挡首发)
**production_ready**: no(`CHAT-INTENT-STATE` 等无关 blocker、CI 真实 PI 三工作流 E2E / 前端人工抽检未完成;文档账本运行时 UI Round20 已 PASS,不把 fallback 报告当成完整 PI)
**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md)
**Agent 手册**: [AGENTS.md](../../AGENTS.md) · [PROJECT.md](../../PROJECT.md)
**Agent 手册**: [AGENTS.md](../AGENTS.md) · [PROJECT.md](../PROJECT.md)
> Codex 2026-09-12 再审计项与本轮回环证据见下表「Codex 再审计」区段。
@@ -21,7 +21,7 @@
| BUG-05 | 拒绝逻辑分散 | PASS | `document_access.go` + `stage_access_helpers.go` | 已完成 |
| BUG-06 | token 明文/重放 | PASS | `activation_token_test.go` | 已完成 |
| BUG-07 | 完成后下一流程 | PASS | 同 BUG-01 | 已完成 |
| BUG-08 | 测试库隔离 | PASS | `db/testdb.go` Require/Skip;CI `TEST_DATABASE_URL` + governance PG 步骤;[report](../test-reports/2026-09-16-ci-governance-pg-bug08-test-report.md) | 已完成 |
| BUG-08 | 测试库隔离 | PARTIAL | `db/testdb.go` Require/Skip | CI 设 `TEST_DATABASE_URL` |
| BUG-09 | 版本冲突自动重试 | PASS | `StageAdvanceBanner` reload | 已完成 |
| BUG-10 | 无审计视图 | PASS | settings + UI | 已完成 |
| BUG-11 | 旧 API 未下线 | PARTIAL | 治理开启时 410 | 保持 + 文档标注 |
@@ -41,9 +41,6 @@
| DB-USERS-SEQ | 种子 users_id_seq 冷启动冲突 | PASS | `00025_...-sync-seed-sequences.sql`;dev/test setval |
| DATA-LIFECYCLE-DEV | completed 实例对应 active 项目 | PASS | dev dry-run 47 → fix SQL → 0 |
| DATA-TEST-WF | test 污染 active 工作流定义 | PASS | `retire-nonofficial-workflow-definitions.sql`;test UPDATE 5 |
| DEMO-DB-SEED | goose 00011/00012 演示项目污染列表 | **PASS** | `00046` retire projects + `00047` retire chat_sessions;`ListProjects*` / `ListChatSessions` 过滤 `demo_retired`;dev migrate schema **47**;抽检项目列表无 6001–6010、user1/2/3 无 `sess-wangjing*`、新建项目 6357 documents=0 | [audit](../audit/2026-09-16-demo-seed-pollution-systemic.md);前序 [2026-09-15](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md);[report](../test-reports/2026-09-16-demo-seed-pollution-test-report.md) |
| DEMO-STUB-API | main/prod 仍可请求 stub Agent | **PASS** | `ResolveBackendInEnv`;`TestResolveBackendInEnv_RejectsStubInMain` |
| DEMO-WEB-SEEDS | 前端 mock/seed 进生产包并撞 projectId | **PASS** | `@demo-seeds` 默认关闭;`check-prod-bundle.sh` PASS;[report](../test-reports/2026-09-16-demo-seed-pollution-test-report.md) |
| TEST-ADVISOR-BRIEF | 多意图 AdvisorBrief 丢失 | PASS | `action_planner.go` enrich;`action_planner_test.go` |
| TEST-V05-ARTIFACTS | V0.5 断言 3 vs 5 | PASS | `types_test.go` / `full_link_e2e_test.go` → 5 |
| TEST-CHAT-MEMORY | 语义记忆 sleep 竞态 | PASS | `session_test.go` deadline 轮询 |
@@ -60,10 +57,10 @@
| ID | 描述 | 状态 | 证据 | 计划动作 |
|---|---|---|---|---|
| WORKFLOW-PLAN-FROZEN-OPTIONAL-DUTIES | active 项目仍展示可编辑职责表单,409 提示在长表单视口外;现有规划又不支持非必需文档“三权全空”,且后端缺少职责人在任成员复核 | **PASS(设置页)** | [audit](../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md);[test-report](../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md)。项目 143 只读 frozen、A full+none 激活、B partial 不发 PUT、C 零治理拒绝、双标签转 frozen、成员无配置入口、刷新后 143 仍 frozen | 真实 PI 生成 full/none 并走审批/阶段不阻塞未纳入本轮页面矩阵,不作为本 gap 关闭的替代证据,另立项 |
| WORKFLOW-PLAN-FROZEN-OPTIONAL-DUTIES | active 项目仍展示可编辑职责表单,409 提示在长表单视口外;现有规划又不支持非必需文档“三权全空”,且后端缺少职责人在任成员复核 | **FAIL** | [audit](../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)。项目 143 返回 `PLAN_FROZEN` 属正确后端行为;缺陷位于冻结态 UX,新增能力还涉及定义优先、零治理拦截、门禁和权限一致性 | [remediation](./2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md);用户批准后从最新 dev 建 fix worktree,按 Wave 1–5 实施并以真实页面验收 |
| DOC-CONTENT-CANONICAL-HASH-DRIFT | 旧受控文档 bootstrap 裁剪 Markdown 双空格硬换行并将 canonical SHA 写入账本/DocGov,但未同步文件;正文读取把完整性冲突误报 404,lease/list sync 又放大并制造刷新后加载死锁 | **PASS(真实 UI)** | [audit](../audit/2026-09-14-project143-controlled-content-404.md);[UI report](../test-reports/2026-09-14-controlled-content-ui-acceptance.md)。代码已合 dev、schema 32、项目 143 定向 `migration_repair`;项目 143 `clean-run3` 与新项目 `full-chain-final` 主链及 restart 全部纯页面 PASS,目标 404=0 | [remediation](./2026-09-14-controlled-content-canonical-hash-remediation.md)。隔离 `TestReconcile_LegacyRepair_PG` 未执行,按用户“本轮只允许页面测试”的边界保留为工程测试债,不作为本轮 UI PASS 的替代证据 |
| CHAT-HISTORY-REFRESH | 工作流激活后刷新,对话正文被阶段过滤器清空,但分类数量与锚点仍按全量返回 | **PASS** | [test-report](../test-reports/2026-09-13-chat-history-refresh-test-report.md);活验 [live.json](../test-reports/assets/2026-09-15-chat-history-refresh-live/live.json)(项目 6252,window=categories=2,guest 403);代码:`message_scope.go`、`chat_history_auth.go`、goose 00026/00027 | 闲聊刷新已补。发布门禁「激活后文档任务 + 重登/重启」仍开放,不回退本 gap |
| CHAT-INTENT-STATE | 真实会话被诊断探针污染;只读查询误启动文档写任务;错误动作与编辑状态刷新后丢失 | **PASS** | [audit](../audit/2026-09-13-conversation-intent-runtime-state.md);[test-report](../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md);双标签活验项目 **6275** / `sess-p6275-u10`(`live.json` + Docker 截图)。**不**删除 `sess-p143-u9` 历史探针 | [remediation](./2026-09-13-conversation-intent-runtime-state-remediation.md)。Wave 3–4 浏览器门已签;诊断污染消息仍不擅自删除 |
| CHAT-HISTORY-REFRESH | 工作流激活后刷新,对话正文被阶段过滤器清空,但分类数量与锚点仍按全量返回 | **PASS** | [test-report](../test-reports/2026-09-13-chat-history-refresh-test-report.md);代码:`message_scope.go`、`chat_history_auth.go`、goose 00026/00027 | 真实 PI 刷新 E2E 待 dev 容器补录(自动化/PG 已 PASS) |
| CHAT-INTENT-STATE | 真实会话被诊断探针污染;只读查询误启动文档写任务;错误动作与编辑状态刷新后丢失 | **FAIL** | [audit](../audit/2026-09-13-conversation-intent-runtime-state.md);dev `sess-p143-u9` / task run / lease 现场 | [remediation](./2026-09-13-conversation-intent-runtime-state-remediation.md) |
| ENV-RESTART-SOURCE | `docker compose restart` 只重启旧镜像,健康检查无法证明合入代码已部署 | **PASS** | `env-service.sh rebuild` + 真实摘要重测 | 集成冒烟统一使用 `dev rebuild` |
| DOCREV-RUNTIME-404 | revision-state 404;账本内存丢失;块保存/overlay 无效;agent 假报告 | **PASS** | [Round20 报告](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[audit](../audit/2026-09-13-document-revision-runtime-404.md) | 运行时 UI 已闭环。change report 仍为 fallback,不冒充 PI。历史失败目录不删 |
| DOCREV-PG-ID-REMAP | 首次生成 PG 已写 snapshot/candidate,commit 因内存误删 baseline 而 not found | **PASS** | [audit](../audit/2026-09-13-document-revision-pg-id-remap.md);Round19 归档 `schema31-round19-ui03-advisor-briefing-docrevision-not-found`(candidate id=175 / output snapshot 250,禁止写成 candidate 250);Round20 UI-03 V2/r0 | 已合入 `dev@b258ab8`;不忽略 ErrNotFound;不删证据 |
@@ -72,8 +69,6 @@
| DOCREV-QUALITY-SELF-POLLUTE | 自检表引用禁词致 score=40 quality_failed;auto_repair 未启用;UI 映射 completed | **PASS** | [audit](../audit/2026-09-13-document-revision-quality-gate-self-pollution.md);Round20 UI-03 完成 | 不删证据;不删禁词 |
| DOCREV-ACTIVE-DOC-ROUTING | UI-05「当前受控文档」被法规关键词改路由到 `feasibility_reg`,intake 无 pending | **PASS** | [audit](../audit/2026-09-13-document-revision-active-doc-routing.md);Round20 UI-05 pending 停在 intake V2 | **不改弱 E2E**;不删证据 |
| DOCREV-QUALITY-STATUS-FP | 行动计划表状态列「待续」被门禁当敷衍,两轮 repair 后 quality_failed 80 | **PASS** | [audit](../audit/2026-09-13-document-revision-quality-status-false-positive.md);Round20 UI-03 | **不删禁词、不放宽正文**;不删证据 |
| GOVERNANCE-ACTION-AUTHZ | 文档动作按职责鉴权;未激活 202-blocked;关闭创建直通 | **PASS** | [test-report](../test-reports/2026-09-14-governance-action-level-authz-test-report.md);[audit 异态](../audit/2026-09-14-planning-with-workflow-key-anomaly.md) | 不改 83 条 planning+key 夹具;none 长 PI 审批链另开 |
| DOC-RELIABILITY-PILOT | 受控文档写路径与 PG 事件交付尚未形成生产闭环;闭包副作用在崩溃/重启后不可重试审计,错误 scope 或 projection 缺失仍可能导致刷新失败 | **PASS** | [初审](../audit/2026-09-14-module-decoupling-plan-review.md);[Phase 1](./2026-09-14-module-decoupling-refactor-plan.md);[Phase 2 复核](../audit/2026-09-15-module-decoupling-phase2-plan-review.md);[Phase 2 修订](./2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md);[U11–U12 报告](../test-reports/2026-09-15-app-composition-u11-u12-test-report.md);[E1A](../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md);[E1B](../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md);[E1C](../test-reports/2026-09-15-event-e1c-projection-test-report.md);[E2](../test-reports/2026-09-15-event-e2-hook-guard-test-report.md);[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[notify live](../test-reports/2026-09-15-event-notify-shared-live-test-report.md);[advance live](../test-reports/2026-09-15-event-workflow-advance-shared-live-test-report.md);[projection live](../test-reports/2026-09-15-event-projection-shared-live-test-report.md) | 共享 notify/workflow_advance/projection 已 live;生产不再注册 `OnOutbox=` / `AddOnApprovedHook(`。FAV 仍 off。HTTP/PI 实施不纳入本行。项目 143 只读 |
---
@@ -82,13 +77,13 @@
```
☑ go vet ./... 全绿
☑ go test -short ./... 全绿
☑ TEST_DATABASE_URL 下治理 PG 集成全绿(CI)
☑ 真实 PI Agent 三工作流治理 E2E 实录([test-report](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md))
☑ 对话刷新恢复:激活前聊天 + 激活后文档任务 + 刷新/重登/重启可恢复,双用户负例通过([test-report](../test-reports/2026-09-16-chat-refresh-gate-test-report.md);项目 6359)
□ TEST_DATABASE_URL 下治理 PG 集成全绿(CI)
□ 真实 PI Agent 三工作流治理 E2E 实录(本轮 stub/short 已绿,PI 待 CI token)
□ 对话刷新恢复:激活前聊天 + 激活后文档任务 + 刷新/重登/重启可恢复,双用户负例通过
☑ lifecycle fix SQL 已在 dev 执行
☑ test/dev health schema_version=47
☑ main 环境部署冒烟(本地 8000;schema 对齐见 CURRENT)
☑ 前端:版本冲突刷新、终止 preview 人工抽检([test-report](../test-reports/2026-09-16-frontend-gate-b4-test-report.md);项目 6363)
☑ test/dev health schema_version=25
☑ main 环境部署冒烟(本地 8000 health/ready schema 25)
□ 前端:版本冲突刷新、终止 preview 人工抽检
```
**结论**: 发布门禁四框已签。文档账本运行时 UI Round20 **PASS**;`CHAT-INTENT-STATE` 双标签 busy **PASS**;`DEMO-DB-SEED` **PASS**;BUG-08 **PASS**。`-race` TempDir flake 与 U9–U12 / 软件自举 / FAV / 完整 PI change-report 叙事不挡首发。不得把 fallback change report 写成完整 PI 叙事。
**结论**: 文档账本运行时真实 UI Round20 **PASS**(见 [test-report](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md))。**发布 blocker 仍包括 `CHAT-INTENT-STATE`、CI 真实 PI 三工作流 E2E 与前端人工抽检**;`-race` 全包并行 TempDir flake 为测试基建残留。不得把 fallback change report 写成完整 PI 叙事。
+9 -10
View File
@@ -1,7 +1,7 @@
# 模块与功能完成度(SSOT)
**更新**: 2026-09-16
**production_ready**: yes
**更新**: 2026-09-14
**production_ready**: no
**发布缺口**: [../remediation/gap-matrix.md](../remediation/gap-matrix.md)
**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md)
@@ -15,20 +15,19 @@
| 模块 | 能力 | 状态 | 证据 | 缺口/后续 | mutex |
|------|------|------|------|-----------|-------|
| 意图识别 L1 | 18 类 Intent + 三分支消解 | partial | [system-design/intent-recognition](../system-design/intent-recognition/);[现场专项审计](../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);[多意图复核方案](../system-design/2026-09-15-multi-intent-hitl-plan.md);[U1 契约](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md);[U2 分段](../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md);[U3 PG](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) | 明确写动作与只读总结已分流;双标签 `DOC_BUSY` 已签(项目 6275)。多意图核心 U1–U8 已完成;U9–U12 不阻塞首版。intent 纯依赖边界不得回退 | `intent` |
| 多意图持久计划 | app/intentflow 生命周期与 HITL 契约 | partial | [设计](../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) | U1–U8 核心首版已完成。U9–U12 不阻塞。默认 tier=legacy。真实 PI generate 待 runner URL。共享环境 schema 45 待晋升 | `intent-plan` |
| 对话 / ctxmgr | 多轮上下文、记忆、摘要 | partial | [system-design/multi-turn-dialogue](../system-design/multi-turn-dialogue/);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md);[U10 端口化](../archive/ops/2026-09-15-chatlog-contextasm-u10.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) | `CHAT-HISTORY-REFRESH` 与发布门禁「激活后文档任务 + 重登/重启」已签(项目 6359)。U10 原地端口 **停止扩面**。语义摘要(D5 backlog) | `chat` |
| 意图识别 L1 | 18 类 Intent + 三分支消解 | partial | [system-design/intent-recognition](../system-design/intent-recognition/);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md) | 明确写动作与只读总结已分流;完整 hard-negative/eval 集仍待补齐 | `intent` |
| 对话 / ctxmgr | 多轮上下文、记忆、摘要 | partial | [system-design/multi-turn-dialogue](../system-design/multi-turn-dialogue/);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md) | `CHAT-HISTORY-REFRESH`:作用域写入、同集授权统计、历史回填;语义摘要(D5 backlog) | `chat` |
| 智能体小队 | 角色-任务-工作区-黑板 | done | [system-design/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` |
| 工作流治理 | 三正式工作流 + 阶段门禁 | partial | [remediation/three-workflows](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[test 2026-09-12](../test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md);[冻结态/职责可选整改](../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md);[Wave 5 页面矩阵](../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) | 设置页/DutyMode + 动作级鉴权已落地;真实 PI 三工作流 E2E 已签。后续:none 文档真实 PI 审批长链路;模块可仍 partial | `workflow` |
| 工作流治理 | 三正式工作流 + 阶段门禁 | partial | [remediation/three-workflows](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[test 2026-09-12](../test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md);[冻结态/职责可选审计](../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md) | 三正式工作流与冻结后端已完成;active 设置页冻结 UX、非必需文档职责可选及成员/门禁/权限一致性待按 Wave 1–5 实施 | `workflow` |
| 纯软件项目自举 | 软件项目创建、Bootstrap 基线、Delivery 迭代与受控工程交接 | planned | [详细设计](../system-design/2026-09-14-software-project-bootstrap-workflow.md);[现状调研](../ops/research/2026-09-14-software-project-bootstrap-current-state.md);[验收计划](../ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md) | 当前仅完成方案;目录/模板/执行器/创建向导/真实 PI UI 均未实施。受控代码执行单列后续 Epic | `workflow-design` |
| IAM / 鉴权 | 项目级 API 鉴权 + RBAC | partial | [audit/authorization](../audit/authorization-matrix-v2.md);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md) | 历史读取端点补统一会话 owner + 阶段授权;旧 API 410 标注(BUG-11 partial) | `authz` |
| 文档治理 | 法定文档生命周期 + 租约 + 受控正文读取 | done | [test docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md);[项目 143 正文 404 审计](../audit/2026-09-14-project143-controlled-content-404.md);[受控正文真实 UI 验收报告](../test-reports/2026-09-14-controlled-content-ui-acceptance.md);[UI-06 缓存竞争审计](../audit/2026-09-14-document-revision-refresh-cache-race.md);[整改](../remediation/2026-09-14-controlled-content-canonical-hash-remediation.md) | 生命周期/租约保留。W1–W6 + 审查修补 + UI hydrate 资格 + 晚到 list sync 修复均已合入 dev。项目 143 纯 UI 回归(clean-run3)与新项目全链路(main + post-restart)已全量真实页面验证通过(PASS) | `docgov` |
| 文档版本与修改认知 | 智能体版本边界、人工修订标记、任意版本比较、变更报告与负责人通知 | partial | [管理测试](../test-reports/2026-09-13-document-revision-management-test-report.md);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[运行时审计](../audit/2026-09-13-document-revision-runtime-404.md);[ADR](../adr/2026-09-13-document-version-boundary.md) | **运行时 UI PASS**(6159 / V3/r2)。仍 `partial`:change report=`fallback`(真实 diff+lineage,非完整 PI 叙事)。系统级 `CHAT-INTENT` 见 gap-matrix | `docgov` |
| 前端工作台 | 三栏 + 块文档 + SSE | partial | [test workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md);[双标签截图](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/screenshots/tab-b-busy.png);[demo seed 污染整改](../test-reports/2026-09-16-demo-seed-pollution-test-report.md);[门禁 B4](../test-reports/2026-09-16-frontend-gate-b4-test-report.md) | 错误卡片/任务进度/文档 busy 刷新恢复已有项目 6275 证据。Demo seeds 默认关闭。版本冲突信封解包 + 终止 preview 抽检已签(项目 6363) | `web` |
| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 + typed-result-v1 | done | [test 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-v1](../test-reports/2026-09-15-pi-typed-result-v1-test-report.md) | — | `pi-agent` |
| 前端工作台 | 三栏 + 块文档 + SSE | partial | [test workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md) | 错误卡片/任务进度/文档 busy 状态刷新恢复与人工抽检待完成 | `web` |
| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 | done | [test 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) | — | `pi-agent` |
| 三环境运维 | dev/test/main + 共享 KB | done | [PROJECT.md](../../PROJECT.md) §4;四环境 healthy | — | `infra` |
| CI / E2E | PG 集成 + 真实 PI E2E | partial | [gap-matrix BUG-08](../remediation/gap-matrix.md);[test pg-ci](../test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md);[治理 PG 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);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) | BUG-08 PASS;真实 PI 三工作流 E2E 与前端/对话门禁已签。`-race` TempDir flake 为基建残留;夜间 CI `RUN_PI_E2E=1` 建议 | `ci` |
| 模块解耦与可靠事件 | 文档可靠性纵向试点、PG 持久事件交付与选择性模块化 | partial | [架构](../system-design/2026-09-14-module-decoupling-architecture.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md);[Phase 1](../remediation/2026-09-14-module-decoupling-refactor-plan.md);[Phase 2 审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md);[Phase 2 修订计划](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md);[E0A](../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md);[E0B](../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md);[E1A](../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md);[E1B](../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md);[E1C](../test-reports/2026-09-15-event-e1c-projection-test-report.md);[E2](../test-reports/2026-09-15-event-e2-hook-guard-test-report.md);[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[D6](../test-reports/2026-09-15-doccontent-canonical-boundary-test-report.md);[D7a](../test-reports/2026-09-15-intent-bizdev-boundary-test-report.md);[D5](../test-reports/2026-09-15-stageflow-type-ownership-test-report.md);[D4](../test-reports/2026-09-15-bizdev-locator-removal-test-report.md);[D7b](../test-reports/2026-09-15-chatflow-orchestration-boundary-test-report.md);[H0](../ops/research/2026-09-15-http-error-envelope-h0-inventory.md);[P0](../ops/research/2026-09-15-pi-typed-result-p0-matrix.md);[收口](../test-reports/2026-09-15-phase2-closeout-test-report.md);[notify live](../test-reports/2026-09-15-event-notify-shared-live-test-report.md);[advance live](../test-reports/2026-09-15-event-workflow-advance-shared-live-test-report.md);[projection live](../test-reports/2026-09-15-event-projection-shared-live-test-report.md);[HTTP 信封](../test-reports/2026-09-15-http-error-envelope-h1-h3-test-report.md);[PI typed-result](../test-reports/2026-09-15-pi-typed-result-v1-test-report.md) | E0A–E2 与共享 live 已过;生产无 hook 注册。D4–D7b 已合入。FAV off。Track P H1–H3 / P1–P4 已实施 | `architecture-docs` |
| CI / E2E | PG 集成 + 真实 PI E2E | partial | [gap-matrix BUG-08](../remediation/gap-matrix.md);[test pg-ci](../test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) | CI `TEST_DATABASE_URL` 隔离库仍缺;文档运行时真实 UI 已按 UI_PHASE 分文件且 post-restart 断言最终 A1 正文。`-race` 全包并行 TempDir flake 为基建残留 | `ci` |
| 模块化单体解耦 | `internal/contracts` + arch-check 门禁 | partial | [ADR](../adr/2026-09-14-modular-monolith-decoupling.md);[设计](../system-design/2026-09-14-module-decoupling-architecture.md);[Wave 0 基线](../audit/2026-09-14-arch-check-baseline.md) | Wave 0 仅骨架与 warn 基线(21 条属主/路径债)。不改业务、不占集成槽。Wave 1 起独立分支收口 | `arch` |
---
@@ -1,422 +1,427 @@
# 模块化单体解耦架构
# 模块解耦架构设计与实施方案(模块化单体 + 契约通信)
> 状态:**设计已修订,首个文档可靠性试点待实施**
>
> 决策:[模块化单体解耦 ADR](../adr/2026-09-14-modular-monolith-decoupling.md)
>
> 实施:[模块解耦整改与重构计划](../remediation/2026-09-14-module-decoupling-refactor-plan.md)
> 日期:2026-09-14
> 状态:**Wave 0 已落地(契约骨架 + arch-check warn 基线);Wave 1+ 待独立分支**
> 关联 ADR:[../adr/2026-09-14-modular-monolith-decoupling.md](../adr/2026-09-14-modular-monolith-decoupling.md)
> 任务条目:[../ops/short-term/2026-09-14-module-decoupling-wave0.md](../ops/short-term/2026-09-14-module-decoupling-wave0.md)
## 1. 目标与边界
---
本设计把 Agent-System 收敛为模块化单体,使项目文档在刷新、服务重启、并发修改和工作区清理后仍能从稳定逻辑标识定位到正确正文。
模块边界必须同时约束依赖、事务、并发、授权、文件和最终成果;只减少 Go import 或移动目录不算解耦完成。
## 0. 一句话
### 1.1 目标
把「server+bizdev 双组合根、隐形闭包桥、共享上帝上下文、多写者表、隐式路径契约」的现状,重构为**模块化单体**:各功能模块只通过 `internal/contracts` 中约定好的接口与 DTO 通信(含显式输入/输出/事件),编排逻辑下沉到应用层,传输与装配收敛到边界,最终用 CI 架构检查强制执行边界。
1. 每个业务命令有唯一应用用例、事务 owner 和幂等语义。
2. 每张运行表和每类文件有唯一写入属主,但跨表不变量仍能在同一事务提交。
3. HTTP、SSE、CLI、worker 和恢复工具经过同一授权决策,不信任调用方填写的身份或资源归属。
4. workspace 只保存计算现场和可重建投影;最终文档、最终回复和 manifest 进入 FAV。
5. 事件在崩溃、重复投递、多订阅者和水平扩容下可追踪、可重试、可隔离。
6. 首个纵向试点直接消除受控正文刷新/重启后 404、409 和 projection missing 类故障。
---
### 1.2 非目标
## 1. 现状诊断(证据汇总)
- 不拆微服务,不引入分布式事务协调器。
- 不在本轮统一全部 HTTP 错误响应。
- 不在本轮替换 PI Runner stdout/result 协议。
- 不把所有历史数据永久保留,也不把生产数据复制为测试 fixture。
- 不允许 FAV 绕过数据库授权或自动重建活动工作流、lease、pending task。
### 1.1 依赖图现状(go list 实测,2026-09-14)
```
server (17,007 行, 导入全部 25 个内部包) ← 唯一组合根 + 事件总线 + 编排
├─> chat (10 包) ──> coordinator (9 包) ──> bizdev (16 包) ──> squad/kb/docgov/...
│ │ │ │
│ │ └─> projectinstance ─> projectworkflow ─> auth
│ └─> intent ──> bizdev(反向依赖,仅因 MaturityStage 枚举未下沉)
└─> taskrun ──> bizdev + projectworkflow + ctxmgr + stream
```
突出问题不是「有依赖」,而是依赖的**方式**:
| # | 耦合热点 | 证据 | 后果 |
|---|---------|------|------|
| H1 | **server 是四合一**:组合根 + 跨模块事件总线 + 领域门卫 + 文件系统/SSE 细节持有者 | `server/server.go:52-177`(NewServer 装配 10+ 服务并织入运行时闭包);`server.go:32-49`(Server 16 个字段散点访问) | 任何模块的构造签名变化必改 NewServer + 字段表 + Routes |
| H2 | **bizdev 是第二组合根 + 万能门面** | `bizdev/service.go:53-190` 装配 10+ 下游;依赖 16 个内部包 | 新能力默认挂到 bizdev,职责无限膨胀 |
| H3 | **上帝上下文 `UserProjectContext`**:22 字段横跨 intent/ctxmgr/squad/bizdev 四包类型,chat 与 coordinator **双向直改** | 定义 `coordinator/context.go:78-114`;coordinator 内 `userCtx.` 出现 175 次;chat `session.go:386-410` 做字段级合并补丁 | 任何一方加字段,三方连锁改;「若为空则回填」逻辑是多方写同一结构的直接症状 |
| H4 | **工作区路径是最大隐性契约**:创建(squad.WorkspaceEngine)、命名、持久化(docgov/taskrun 各存一份)、校验(workspace.Resolver)、绕过(bizdev/coordinator 直拼)五权分立;另有 3 处硬编码 `data/dev` | `bizdev/service.go:1259-1282` 跨包覆写 squad 的 `workspace.json`/`blackboard.json`;`server/project_doc_handlers.go:16-19` 用 `DataDir/../..` 倒推仓库根;`coordinator/router.go:281-284` 注释承认容器路径映射隐式约定 | 改工作区布局会静默破坏 5 个包 |
| H5 | **squad 的文件 schema 与 DTO 是事实公共 API 但无版本化** | `bizdev/types.go:14-15,40,56-59` 大量 `type X = squad.X` 别名直透 HTTP;`coordinator/router.go:246-247` 直调 `LoadOrCreateLedger/LoadTrace`;`coordinator/engine.go:757-784` 直读写 `blackboard.json` | squad 内部文件格式任何改动静默破坏 3 个下游 |
| H6 | **共享表多写者**:`document_records` 被 docgov/docduty/docrevision/workspace/cmd 五方 UPDATE;`freeform_documents` 被 docrevision 反向写 | `docduty/store.go` 4 处、`docrevision/pg_store.go:235/432`、`workspace/resolver.go` 1 处 | 哈希/状态一致性靠约定而非单一写者 |
| H7 | **编排写在 handler / 跨 6+ 模块的巨型函数** | `chat/session.go:238 sendMessageInternal`(跨 9 模块);`bizdev/service.go:295 ExecuteTask`(鉴权+检索+编排+治理+持久化+流式六合一);`bizdev/service.go:1074 executeStageInternal`;`coordinator/engine.go:690/1020` | 修一处动全身,测试只能走全链路 |
| H8 | **server 内闭包桥替代显式事件流**:docrevision outbox 桥、审批钩子、reminder 轮询、taskrun executor/finalizer、ctxmgr approved-hook 全在 NewServer 用闭包缝合 | `server/server.go:114-175`;`workflow_approval_hook.go:14`;`notification_reminder_loop.go` | 模块间没有 import 关系却强耦合,且全部以 server 为中转 hub |
| H9 | **反向/错位依赖**:intent→bizdev(MaturityStage 未下沉);ctxmgr→docgov(case_indexing 接受 docgov 实体);领域层依赖 UI 事件格式(squad→stream);同名撞车(squad.ContextManager vs internal/ctxmgr) | `intent` 包 import bizdev;`ctxmgr/case_indexing.go:20` | 分层倒置,概念混淆 |
| H10 | **传输协议与基础设施细节内嵌 server**:SSE 帧手写、SPA 路径探测、`output.md` 哈希、`repoRoot()` 倒推;错误响应双轨(纯文本 vs JSON) | `server/sse.go:65-72,315-441`;`task_finalize.go:127-138`;`handlers.go:826/853` vs `project_doc_handlers.go:78` | 前端需双轨解析;脚本(`scripts/backfill_task_run_projection.go:44`)必须构造完整 Server 才能回填数据 |
| H11 | **PI Runner 协议 schema 三处手写**(Go / runner.mjs / pi-bridge index.mjs),无共享 IDL;CLI 通道靠「stdout 最后一行 JSON」脆弱约定 | `agent/piagent.go:141-149`;`deploy/pi-agent/runner.mjs:388`;`tools/pi-bridge/index.mjs` | 字段漂移只能靠集成测试兜底 |
### 1.2 正面样板(保持并推广)
并非全盘皆坏,以下边界是**本仓最好的实践**,目标架构将它们确立为全局标准:
- **chat_* 表族 0 越界**:全仓所有对话记录访问都经 `ctxmgr`(grep 实测 0 绕过)——这就是「对话记录模块」该有的样子;
- **kb 事实上是纯检索包**:仅 2 个调用方,接口 `Hub` 只有 Search/LookupCite/Stats/Close;唯一的越界(`MaterializeSnapshot` 写盘)是死代码,可删;
- **PI Runner 的 `Backend` 接口**(`agent/backend.go:28-31`)切换点单一、Bearer 认证明确;
- **docrevision 事件 outbox 同事务提交**——事件总线的雏形已在,只差泛化;
- **replyexport 纯函数**、**fsutil 原子写**——无状态基础设施包的正确形态。
---
## 2. 目标架构
```mermaid
flowchart TB
Client[Web or CLI] --> Adapter[server adapters]
Worker[Background workers] --> App[application use cases]
Adapter --> App
App --> Authz[authorization policy]
App --> UoW[UnitOfWork]
App --> ReadModels[read use cases]
UoW --> Owners[domain table owners]
Owners --> PG[(PostgreSQL)]
UoW --> Outbox[(outbox and staging)]
Outbox --> Dispatcher[event dispatcher]
Dispatcher --> Subscribers[idempotent subscribers]
Subscribers --> Vault[artifactvault]
App --> Workspace[workspace capability service]
Workspace --> Scratch[(scratch workspace)]
ReadModels --> PG
ReadModels --> Vault
### 2.1 六条设计原则
1. **契约优先(Contract-first)**:模块间只允许两种通信——①调用 `internal/contracts` 中定义的接口(显式输入结构 + 显式输出结构);②发布/订阅 `contracts/events` 中的类型化事件。禁止直接 import 对方内部类型、禁止读对方文件、禁止写对方表。
2. **单一写者(Single Writer)**:每张 PG 表、每类文件/目录恰好一个属主模块;其他模块只能通过属主的接口读写。
3. **编排下沉(Orchestration down)**:跨模块流程属于应用层(use case),不允许出现在 HTTP handler、也不允许埋在某个领域模块里(bizdev 现状)。
4. **模块自带边界(Self-contained)**:每个模块的输入由调用方(系统)准备齐全(含工作区、材料、上下文),输出只落到约定位置/返回值;模块不「顺便」帮别人做事(如 kb 不写文件、squad 不发 SSE)。
5. **传输与装配收敛到边缘**:HTTP/SSE/CLI 只是适配器;组合根唯一(`cmd/server` → `internal/app`)。
6. **可执行的门禁**:边界必须能被机器检查(包依赖 allowlist 进 CI),否则会再次腐化。
### 2.2 目标分层图
```
┌─────────────────────────────────────────────────────────────────┐
│ cmd/server + internal/app 唯一组合根(wiring、生命周期) │
├─────────────────────────────────────────────────────────────────┤
│ internal/server(瘦传输层) HTTP 路由 + SSE 帧 + 错误信封 │
│ 只做:参数解析 → 调应用服务 → DTO 序列化;禁止编排/SQL/拼路径 │
├─────────────────────────────────────────────────────────────────┤
│ 应用编排层(L1/L2 拆自 chat/coordinator/bizdev) │
│ chatflow 一轮对话的 use case(识别→协调→动作→落账) │
│ stageflow 阶段推进 / 任务执行的 use case │
│ docflow 文档生命周期 use case │
│ 它们 import contracts(接口) + 订阅/发布事件;不 import 对方实现 │
├─────────────────────────────────────────────────────────────────┤
│ internal/contracts ★ 新增:接口 + DTO + 事件 + 共享枚举(纯定义) │
├─────────────────────────────────────────────────────────────────┤
│ 领域能力模块(互不 import,只依赖 contracts + 自有 infra) │
│ squadrun 智能体小队执行器(沙箱内运行,产出 manifest) │
│ kb 法规/知识检索(纯查,无解释无写盘) │
│ chatlog 对话记录存储与查询(chat_* 表唯一属主) │
│ contextasm 上下文装配(记忆/摘要/检索召回,供编排层组装 prompt) │
│ docgov 文档生命周期治理(document_records 唯一属主) │
│ docrevision 版本账本(snapshots/versions/...) │
│ docquery 文档列表与正文读取(统一读模型,含自由文档) │
│ intent 意图识别(纯函数,零业务依赖) │
│ taskrun 任务运行生命周期(含两阶段占位完整协议) │
│ workflow* 工作流/实例治理 │
│ workspace 工作区路径唯一所有者(版本化 manifest) │
│ notification / replyexport / quote / template / agent(PI) │
├─────────────────────────────────────────────────────────────────┤
│ 基础设施:db / storage(CAS) / fsutil / stream(事件+传输) │
└─────────────────────────────────────────────────────────────────┘
```
### 2.1 分层职责
### 2.3 依赖规则(arch-check 强制项)
| 层 | 职责 | 禁止 |
|---|---|---|
| `internal/server` | 参数解析、认证信息转 Principal、调用应用用例、序列化 HTTP/SSE | SQL、事务、路径拼接、跨模块编排、后台重试 |
| `internal/app/*flow` | 用例编排、授权、UnitOfWork、命令幂等、事件发布 | 领域 SQL、物理路径、传输格式 |
| 消费者侧 ports | 表达一个用例需要的最小能力 | 聚合所有模块方法的万能接口 |
| 领域模块 | 业务不变量、表/文件写入所有权、事务绑定 repository | import 其他领域实现、开启不受控嵌套事务 |
| read model | 授权后的跨模块只读聚合 | 业务状态变更、修复式 GET 写入 |
| 基础设施 | PostgreSQL、CAS、FAV、workspace、事件 dispatcher | 推断业务终态或自行授予权限 |
| 规则 | 检查方式 |
|------|---------|
| R1 `contracts` 不 import 任何业务包 | allowlist:contracts 的内部 import 仅限空 |
| R2 领域模块之间禁止互相 import(跨模块只走 contracts) | 模块→模块 import 检查 |
| R3 领域模块禁止 import `server` / 应用编排层 | 方向检查 |
| R4 `server` 禁止 import 领域模块**实现**(只 import contracts + app 层服务接口) | allowlist |
| R5 每张表名只允许出现在属主包(grep SQL 字符串) | 表属主清单检查 |
| R6 工作区路径字面量(`workspaces/`、`output.md`、`data/dev` 等拼接)只允许出现在 `workspace`/`squadrun` | 字符串扫描 |
| R7 领域模块禁止 import `stream` 的传输层(只允许中性的进度事件接口) | allowlist |
### 2.2 契约分类
实施载体:`scripts/arch-check.sh`(基于 `go list -deps` + grep 的表属主/路径字面量检查),先以 **warn** 跑两周建立基线,再转 **block** 进 CI 与集成槽位冒烟。
`internal/contracts` 不再作为所有 DTO 的公共仓库。
### 2.4 模块边界总表
| 契约 | 所有位置 | 版本规则 |
|---|---|---|
| HTTP/SSE wire DTO | `internal/server/api`、`internal/stream/transport` | 对外兼容,breaking change 走 ADR |
| 一对一调用端口 | 消费者 use case 包内 | 随用例演化,不带 JSON tag,不自动走 ADR |
| 公共领域事件 | `internal/contracts/events/<domain>` | 有 schema version;生产者和多个消费者共同评审 |
| 持久文件/manifest schema | 所属模块,如 `artifactvault`、`workspace` | major/minor 兼容;未知 major fail closed |
| 稳定共享词汇 | `internal/contracts/vocabulary` | 仅无行为枚举和值对象;禁止依赖业务实现 |
| 错误分类 | 领域错误留领域包;wire 映射留 server | 不把数据库/路径/第三方原始错误暴露给客户端 |
| 模块(目标包) | 现状来源 | 唯一职责 | 允许依赖 | 明确禁止 |
|---|---|---|---|---|
| `contracts` | 新增 | 接口/DTO/事件/共享枚举定义 | 无 | 任何实现、IO |
| `squadrun` | `squad`(重组) | 在给定沙箱内编排角色-步骤,产出契约化交付物与 manifest | contracts, agent, template, quote, fsutil | 访问 DB;发 SSE;感知 docgov/chat/业务字段语义;写沙箱与 OutputDir 之外 |
| `kb` | `kb` | 法规/资产/能力三域检索 + 引用定位 | contracts, db | 解释、成文、写盘、缓存工作区 |
| `chatlog` | `ctxmgr` 拆分 | chat_* 表族读写、会话/消息/轮次/摘要/未读查询 | contracts, db, replyexport(策略) | 上下文装配、prompt 相关逻辑 |
| `contextasm` | `ctxmgr` 拆分 | 记忆/摘要/召回/上下文组装(供编排层) | contracts, chatlog(接口), kb(接口) | 直接被 HTTP 暴露 |
| `docgov` | `docgov` | 状态机、角色权限、租约、`document_records` 唯一写者 | contracts, db, fsutil | 被他人 UPDATE 属主表 |
| `docrevision` | `docrevision` | 版本/快照/变更事件账本、outbox | contracts, db, fsutil | 直写 `document_records`/`freeform_documents`(改走 docgov/freedoc 接口) |
| `docquery` | 新增(聚合读) | 文档列表/正文/版本的统一只读模型 | contracts, docgov/docrevision/freedoc 的读接口 | 写操作 |
| `intent` | `intent` | 消息→意图分类(纯规则) | contracts | import bizdev/任何业务模块 |
| `taskrun` | `taskrun` | 任务运行记录、两阶段占位、finalize 投影的完整协议 | contracts, db, stream(事件) | 在 server 里补协议缺口的现状 |
| `workspace` | `workspace`(强化) | 工作区路径解析/创建/manifest 版本化 | contracts, fsutil | 他人拼路径 |
| `notification` | `notification` | 通知投递 + outbox 轮询(事件订阅者) | contracts, db | 被闭包桥接 |
| `agent` | `agent` | PI Runner 双通道调用(协议单一 schema 源) | contracts | — |
| `chatflow`/`stageflow`/`docflow` | `chat`+`coordinator`+`bizdev` 拆解 | 跨模块 use case 编排、`UserProjectContext` 唯一属主 | contracts + 各模块接口 | 被 server/其他领域模块 import 实现细节 |
| `server` | `server`(瘦身) | HTTP/SSE 适配、错误信封、SPA | contracts, app 层服务接口 | 编排、SQL、拼路径、领域闭包 |
| `app` | 新增 | wiring、事件总线注册、生命周期 | 所有模块构造函数 | 被 server 反向 import |
接口默认由消费者拥有,应用组合根只注入实现。
只有三个以上消费者确实共享相同语义时,才提升为公共端口。
---
## 3. 模块边界
## 3. 核心接口契约设计
| 模块 | 唯一职责与写入所有权 | 可依赖 | 禁止 |
|---|---|---|---|
| `app/docflow` | 文档读取、提交、批准、投影和归档用例;相关事务 owner | 消费端口、authz、uow | SQL、物理路径 |
| `app/stageflow` | 阶段推进和任务执行用例 | 消费端口、authz、uow | bizdev 门面、HTTP DTO |
| `app/chatflow` | 一轮对话识别、协调、消息落账和任务触发 | 消费端口、authz、uow | 直接写共享上下文字段 |
| `docgov` | 文档治理状态、角色、lease、`document_records` 写者 | 自有 repository、稳定词汇 | 直调 docrevision 实现、读 workspace 文件 |
| `docrevision` | immutable snapshot/version/revision/event/report 账本写者 | 自有 repository | 直接写 `document_records`、`freeform_documents` |
| `freedoc` | 自由文档根表和发布状态写者 | 自有 repository | 被 docrevision 反向更新 |
| `docquery` | 授权后文档列表、正文、版本聚合读取 | 只读端口、artifact read fallback | 任何写入、目录扫描、授权推断 |
| `chatlog` | `chat_*` 表族读写和会话/消息/turn 查询 | 自有 repository | prompt 装配、外部导出策略 |
| `contextasm` | 记忆、摘要、召回和 prompt 上下文组装 | 消费者侧 ChatLog/KB read ports | HTTP、SQL 越界写入 |
| `intent` | 纯规则意图分类 | vocabulary | bizdev、server、IO |
| `taskrun` | task run 状态机、claim/finalize、幂等写者 | 自有 repository | server 补协议、workspace 路径 |
| `squadrun` | 在受限 workspace capability 内执行角色与步骤 | agent/template/quote 消费端口 | DB、SSE、业务授权、任意路径 |
| `workspace` | Workspace ID 签发、物理路径解析、projection 生命周期 | fsutil、storage identity | 业务终态、最终归档 |
| `artifactvault` | 终态 payload/manifest/receipt/tombstone 权威 | 独立存储、registry | 活动业务关系、运行授权、workspace 扫描 |
| `notification` | 通知偏好、投递和状态 | 事件消费、repository | 业务状态推进 |
| `app` | 唯一组合根、worker 生命周期、事件订阅注册 | 所有构造函数 | 被 server 反向装配 |
> 以下签名是**设计稿**(Go 伪代码),落地时放 `internal/contracts/`(按域分文件)。所有 DTO 带 json tag,一旦对外发布即视为版本化契约,变更需走 ADR。
模块“可依赖”只表示通过端口调用,不表示允许 import 对方实现包。
### 3.1 squadrun —— 智能体小队执行器(对应用户示例 1)
## 4. 事务与单一写者
**核心思想**:系统(编排层)负责「备料 + 备工作区 + 定产出契约」,小队只管「在沙箱里干活 + 按契约交货」。小队不再感知业务字段语义、DB、SSE。
### 4.1 两种所有权
```go
// contracts/squadrun.go
type SquadRunner interface {
Plan(ctx context.Context, spec RunSpec) (*RunPlan, error) // 只规划不执行
Run(ctx context.Context, spec RunSpec, r ProgressReporter) (*RunManifest, error)
Inspect(ctx context.Context, ws WorkspaceRef) (*RunState, error) // 取代外部直读 blackboard.json
Resume(ctx context.Context, ws WorkspaceRef, m RunModification, r ProgressReporter) (*RunManifest, error)
}
- **表属主**决定 SQL、约束和单表不变量。
- **事务 owner**决定一个业务命令需要哪些属主共同提交。
type RunSpec struct {
RunID string // 系统生成并已在 taskrun 落账
Workspace WorkspaceRef // 系统已创建好的沙箱(见 3.6)
Goal string // 任务目标
Inputs InputBundle // 全部输入(小队不做材料提取/检索/上下文装配)
Output OutputContract // 产出契约
Budget Budget
Backend string // pi-agent | cursor-cli | stub
}
两者不能合并为“每个模块各开一个事务”。
应用用例开启 `UnitOfWork`,取得绑定同一 `pgx.Tx` 的 repository capabilities;领域服务只能使用这些 capabilities,不能 commit、rollback 或启动嵌套事务。
// 系统准备的一切输入
type InputBundle struct {
Materials []FileInput // 已提取文本的材料(CAS 引用 + 文本)
Knowledge []KnowledgeHit // kb 检索结果(含 CiteKey)
PriorDocs []DocInput // 前序文档(已过阶段权限过滤)
Context []FileInput // user/project/memory 分级上下文
Facts map[string]string // 结构化业务参数(ProjectName/DeviceType… 的泛化)
}
### 4.2 文档提交原子集合
// 产出契约:完成后只把这些写到 OutputDir,并生成 manifest
type OutputContract struct {
OutputDir string
Artifacts []ArtifactSpec // {Name, Filename, Format, Required}
ManifestName string // 缺省 run-manifest.json
}
一次受控文档提交必须原子包含:
1. 校验 Principal、项目成员、duty、lease 和 expected head。
2. 锁定 `document_records` 与当前 open version。
3. 写 immutable content blob/snapshot/revision/change event。
4. 更新版本 head 与 `document_records` 当前指针/哈希。
5. 冻结应归档 payload 或不可变 blob 引用。
6. 写领域事件和 FAV publish request。
7. 提交后再进行 workspace 投影、通知和外部存储发布。
任一步失败,步骤 2–6 全部回滚。
投影或发布失败不会回滚业务提交,而是进入可重试队列并在 UI 暴露 degraded 状态。
### 4.3 事务隔离选择
| 场景 | 机制 | 原因 |
|---|---|---|
| 单文档编辑/批准/提交 | `READ COMMITTED` + `SELECT ... FOR UPDATE` + expected head | 竞争范围明确,冲突可向用户解释 |
| 同幂等键并发创建 | 唯一约束 + payload digest 校验 | 数据库决定唯一赢家 |
| 跨表项目级 duty/heal | `pg_advisory_xact_lock(project_id)` + 固定行锁顺序 | 复用现有项目级互斥,事务结束自动释放 |
| 复杂跨聚合唯一不变量 | `SERIALIZABLE`,完整事务有限重试 | 仅在显式证明需要时使用 |
| outbox 多 worker claim | `FOR UPDATE SKIP LOCKED` + lease/fencing token | 提高队列吞吐,不作为普通读取语义 |
### 4.4 锁顺序
所有跨属主事务按下列顺序获得锁:
1. project 或 workflow instance 事务级 advisory/row lock;
2. document/freeform/chat aggregate root;
3. version/snapshot/turn;
4. task run;
5. staging/outbox/delivery。
禁止在持锁期间调用 LLM、PI Runner、对象存储、HTTP、SSE 或执行大文件复制。
需要外部工作时采用 prepare → 外部执行 → compare-and-commit;commit 阶段重新验证 expected version。
### 4.5 超时与重试
- 每个写事务设置独立 context deadline 和数据库 `lock_timeout`;初始预算由配置管理,不在 handler 硬编码。
- `40001` 与 `40P01` 只允许重跑完整幂等事务,采用带抖动退避和有限次数。
- expected-version 冲突、权限拒绝、唯一键 payload 不同不是瞬时错误,不自动重试。
- 事务重试期间不得重复发送消息、SSE、通知或对象存储写入;这些副作用只能由提交后的 outbox 驱动。
## 5. 并发协议
### 5.1 文档并发
客户端读取正文时获得 `ETag = head_snapshot_id:head_revision_no`。
PATCH、agent commit、approve 和 projection repair 都必须携带 expected head 或稳定 idempotency key。
旧 ETag 返回 typed `VERSION_CONFLICT`,响应包含当前 head 元数据但不泄露无权正文。
### 5.2 TaskRun 并发
`Claim(idempotency_key, request_digest)` 通过唯一约束保证只创建一个 run。
相同 key、相同 digest 返回既有 run;相同 key、不同 digest 返回 `IDEMPOTENCY_CONFLICT`。
状态迁移使用 `WHERE status = expected AND version = expected_version`,影响行数为零即重新读取并分类冲突。
幂等键按 environment、project、actor、action 和客户端 key 作用域化,并与规范化 request digest 绑定。
幂等记录的保留期不得短于客户端重试窗口、事件重放窗口和对应业务记录的审计期。
### 5.3 Workspace 并发
Workspace ID 由服务端签发并绑定 environment、project、run、storage identity 和生命周期。
同一 workspace 同时只有一个写 lease;续租返回 fencing token,所有写操作校验 token。
本地 `sync.Mutex` 可减少同进程竞争,但跨副本 lease 和 token 才是正确性依据。
文件写入采用同目录临时文件、校验、原子 rename 和目录同步;reader 只读取完整 projection marker。
### 5.4 FAV 并发
逻辑 artifact 的幂等键由终态事件、资源、payload SHA 和 policy version 决定。
对象写入使用 content-addressed key 和 no-replace 语义;blob、manifest 全部校验完成后最后写 commit marker。
重复 publisher 可共享已有 blob,但只有一个 registry 状态迁移为 verified。
### 5.5 查询与背压
docquery 的列表和版本历史必须分页,BatchGet 首期硬上限 100 个引用;超过上限返回 typed validation error,不自动拆成无界并发查询。
批量读取先按 Principal 和 project scope 分组授权,再使用有界并发和数据库 statement deadline。
API 对 actor/project/action 维度限流,后台 backfill 和 dispatcher 使用独立连接预算,不能耗尽在线读写连接池。
SSE 慢客户端只影响传输缓冲;不能持有业务 transaction、数据库锁或阻止事件持久化。
## 6. 可靠事件
### 6.1 事件信封
每个持久事件至少包含:
```text
event_id
event_name
schema_version
environment
project_id
aggregate_type / aggregate_id / aggregate_version
actor_ref
correlation_id / causation_id
idempotency_key
payload_digest
occurred_at
// 唯一对外输出事实源:下游只读 manifest,不再扫目录猜文件
type RunManifest struct {
RunID string
Status string // succeeded | failed | partial
Artifacts []ArtifactResult // {Name, RelPath, SHA256, Bytes}
Steps []StepResult // {Key, Role, Status, DurationMS, RetryCount}
Gaps []string // 质量门禁未覆盖项(黑板 gaps 的投影)
Evidence map[string]string
SchemaVer int // 文件契约版本化(H5 的解药)
}
```
事件不携带 secret、认证 token、Prompt、正文或任意文件路径。
大 payload 先冻结到不可变 staging,事件只保存引用和 digest。
**配套迁移决定**:
- bizdev 的 `type X = squad.X` 别名(`bizdev/types.go:14-15,40,56-59`)全部解绑,bizdev/server 改用 contracts DTO;
- bizdev 停止覆写 squad 状态文件(`bizdev/service.go:1259-1282` 改调 `Resume`/`Inspect`);
- coordinator 停止直读 `blackboard.json`、直调 `LoadOrCreateLedger/LoadTrace`(`coordinator/router.go:246-258`、`engine.go:757-784`),改走 `Inspect`;
- squad 不再 import `stream`:`StepNotify` 回调改为 `contracts.ProgressReporter` 接口,SSE 转换由应用层完成。
### 6.2 投递模型
### 3.2 kb —— 法规知识库(对应用户示例 2)
```mermaid
sequenceDiagram
participant UC as Use case transaction
participant DB as PostgreSQL
participant W as Dispatcher worker
participant S as Subscriber
UC->>DB: business state + staging + outbox
DB-->>UC: commit
W->>DB: claim delivery with SKIP LOCKED
W->>S: deliver event and fencing token
S->>DB: idempotent side effect and inbox receipt in one transaction
S-->>W: success or typed failure
W->>DB: ack, retry schedule, or dead letter
现状已接近目标,只需**收紧**:
```go
// contracts/kb.go
type KnowledgeBase interface {
Search(ctx context.Context, q SearchQuery) (*SearchResult, error)
LookupCite(ctx context.Context, citeKey string) (*CiteRef, bool, error)
Stats(ctx context.Context) (*KBStats, error)
}
type SearchQuery struct { Text string; Domain []string; TopK int } // 只承载检索语义
type KnowledgeHit struct { CiteKey, Title, Section, Snippet string; Score float64 }
```
- 每个订阅者有独立 delivery 状态,不能共享单一 `published_at`。
- 投递语义为至少一次;消费者以 event ID/inbox 唯一约束幂等。
- 同一 aggregate 按 aggregate version 有序;不同 aggregate 可并行。
- claim 按 `next_attempt_at, event_id` 排序并采用 aging,防止热点失败事件令旧事件永久饥饿。
- 数据库 subscriber 的业务副作用与 inbox receipt 必须同事务;外部副作用使用业务幂等键并在回执落库前允许安全重放。
- transient failure 指数退避;永久失败进入 dead letter,不能阻塞其他订阅者。
- worker 认领带 lease、attempt 和 fencing token;过期 worker 无权提交 ack。
- replay 必须指定事件范围、目标消费者、操作者和原因,并写审计记录。
- delivery/outbox 的清理只能在所有必需消费者完成、重放窗口结束且恢复 checkpoint 已覆盖后执行;审计类事件按独立保留策略处理。
**决定**:① 删除死代码 `kb.MaterializeSnapshot`(写盘行为,全仓无调用);② 「解释/成文」永远留在编排层(现状 coordinator 拼 Markdown 的**位置**正确,但拼装代码应移到应用层 chatflow);③ bizdev façade 退役后由编排层直接持有该接口。
## 7. Workspace、账本与 FAV
### 3.3 chatlog —— 对话记录(对应用户示例 3)
### 7.1 三层权威
把 `ctxmgr` 拆成 `chatlog`(存储/查询,chat_* 表唯一属主——现状 0 越界,只需换壳)与 `contextasm`(上下文装配,见 3.6)。
| 层 | 权威内容 | 清理规则 |
```go
// contracts/chatlog.go
type ChatLog interface {
// 全部以「项目ID + 用户ID」等显式参数进出,返回带 json tag 的 DTO
ListSessions(ctx context.Context, f SessionFilter) ([]SessionSummary, error)
ListMessages(ctx context.Context, f MessageFilter) ([]MessageRecord, error) // 窗口/日期轴/分页
GetTurn(ctx context.Context, ref TurnRef) (*TurnRecord, error)
SearchMessages(ctx context.Context, f SearchFilter) ([]MessageRecord, error)
// + ListDigests / MarkRead / Import / Recategorize / Export(沿用现有能力面)
RecordMessage(ctx context.Context, w MessageWrite) (MessageID, error) // 仅编排层使用
}
type SessionFilter struct { ProjectID, UserID string; Status string; Page, PageSize int }
```
**迁移要点**:现有 20+ 条 `/api/v1/chat/*` 路由 **URL 不变**,handler 换成「解析参数 → 调 chatlog → DTO 序列化」三行式;DTO 用 golden 文件做契约测试(`web/src/api/chatSessions.ts` 等前端类型即 golden 的镜像);`export_policy` 判定保留 replyexport 纯函数。
### 3.4 docquery —— 文档列表与读取(对应用户示例 4)
```go
// contracts/docquery.go
type DocQuery interface {
ListDocuments(ctx context.Context, f DocFilter) ([]DocSummary, error)
// DocFilter{ProjectID, UserID, Category, Status, WorkflowID, Page...}
GetDocument(ctx context.Context, ref DocRef) (*DocContent, error)
// DocRef{DocID 或 {ProjectID, DutyKey}; Version/Revision 可选,缺省 head}
BatchGetDocuments(ctx context.Context, refs []DocRef) ([]DocContent, error)
}
type DocSummary struct { DocID, Title, Category, Status, Version, Owner string; UpdatedAt time.Time; HasPendingRevision bool }
type DocContent struct { Summary DocSummary; BodyMarkdown, ContentSHA256 string; Blocks []Block }
```
**要点**:① 受控文档(docgov/docrevision)与自由文档(freedoc)统一进一个读模型,前端不再两套 API 语义;② 授权在应用层入口统一(消灭「阶段权限过滤散在 handler」`server/handlers.go:928-930`);③ 正文来源(受控正文/工作区 output.md/CAS blob)由 docquery 内部决定——现状**路径知识 4 处重复**(docgov/project_docs.go:144、docrevision/projection.go:66、server/project_doc_handlers.go:15、bizdev/service.go:160-190)收敛为 1 处。
### 3.5 docgov / docrevision —— 治理与账本
- docgov 保持状态机/租约/角色权限,新增**端口方法**承接外部写需求:`BindWorkspace(ctx, docID, wsRef)`、`UpdateGovernanceFields(ctx, docID, patch)`——docduty/docrevision/cmd 对 `document_records` 的直写全部改走这些方法(解 H6);
- docrevision 只拥有账本表;对 `document_records` 2 处、`freeform_documents` 2 处 UPDATE(`pg_store.go:235/255/424/432`)改调 docgov/freedoc 接口;
- 正文单写路径:受控正文唯一写者 = docgov(内部委托 docrevision 账本);squad 工作区文件只经 `RunManifest` → 应用层 docflow 投影,结束「三个写者写同一个 output.md」。
### 3.6 intent / taskrun / workspace / contextasm / 事件总线
- **intent**:`MaturityStage` 等共享枚举下沉 `contracts/vocabulary.go`,删除 intent→bizdev import(解 H9);Recognizer 保持纯函数。
- **taskrun**:把散在 server 的两阶段占位协议(`task_run_handlers.go` 占位创建→执行→finalize 投影 + `task_finalize.go:127-138` 哈希 output.md)整体搬进 taskrun 包,server 只调 `taskrun.Execute(ctx, TaskRequest, ExecutorPort)`;ops 回填脚本改依赖 taskrun 服务而非 `server.NewServer`。
- **workspace**:`Resolver` 升级为唯一路径所有者:`Create(ctx, CreateSpec) (WorkspaceRef, error)` / `Resolve(id) (WorkspaceRef, error)`;产出 `WorkspaceRef{ID, Root, OutputDir, ManifestPath}` 这种**句柄**而非裸字符串路径,从类型上杜绝各包自拼路径(解 H4);3 处硬编码 `data/dev` 一并清除。
- **contextasm**:承接 ctxmgr 中「为 prompt 服务」的部分(三层记忆、滑动窗口、摘要、召回、改写缓存 C1~C5);`contextasm` 依赖 chatlog/kb 的**接口**而非实现。
- **事件总线**:泛化 docrevision 已有的 outbox 模式为 `contracts/events`:
```go
type Event interface{ EventName() string; OccurredAt() time.Time }
// 首批事件(均有隐式对应物,只是从闭包改为显式类型):
// DocumentApproved / DocumentRejected / DocumentLeaseChanged
// RunFinalized{RunID, WorkspaceID, Manifest} / StageAdvanced / StageGateDenied
// MessageRecorded / NotificationRequested
type EventBus interface {
Publish(ctx context.Context, ev Event) error // 与业务同事务写 outbox_events
Subscribe(name string, h EventHandler) // app 层注册
}
```
server.go:114-175 的 outbox 桥、`workflow_approval_hook`、reminder 轮询、ctxmgr approved-hook 全部改写为事件订阅者(解 H8)。
### 3.7 PI Runner 协议单一来源
新增 `configs/schemas/pi-runner.run.schema.json`(JSON Schema),Go 侧(`agent/piagent.go`)与 JS 侧(`deploy/pi-agent/runner.mjs`、`tools/pi-bridge/index.mjs`)由 schema 生成/校验;CI 加 schema 一致性测试;废弃「stdout 最后一行 JSON」约定,改为桥在 workDir 写 `result.json`。
---
## 4. 横切规范
### 4.1 包依赖门禁
`scripts/arch-check.sh`(新增):读取 `.doc/system-design/module-boundaries.yaml`(模块→允许 import 清单 + 表属主清单 + 路径字面量属主清单),执行三类检查:
1. `go list -f '{{join .Imports "\n"}}' ./internal/...` 比对 allowlist(规则 R1–R4、R7);
2. grep 表名字符串比对属主(R5);
3. grep 路径字面量(`workspaces/`、`output.md`、`data/dev`、`DataDir/../..`)比对属主(R6)。
先 `--mode warn` 输出基线报告(`.doc/audit/` 存档),两周后转 block 并纳入集成槽位冒烟与 CI。
### 4.2 统一错误信封
所有 API 错误统一 JSON:`{"error": "<CODE>", "message": "...", "detail": {...}}`;错误码表进 contracts。消灭 `http.Error` 纯文本与 JSON 双轨(`server/handlers.go:826/853` vs `project_doc_handlers.go:78`),前端单轨解析。
### 4.3 文件契约版本化
squad 工作区文件(workspace.json/blackboard.json/run-manifest.json)与 workspace manifest 全部带 `schema_ver` 字段;读取方遇到未知版本必须显式报错而非静默误读。`RunManifest.SchemaVer` 起步即 v1。
### 4.4 架构测试(防回腐化)
- `arch_test.go`(放 contracts 包):断言「server 不 import 领域实现包」「领域包互不 import」——CI 常跑;
- DTO golden 测试:chatlog/docquery 的响应结构序列化快照,前端类型与之对齐,防字段漂移。
---
## 5. 分阶段实施计划(Wave 0–6)
> 纪律:每个 Wave 独立 `feature/*` 分支 + 独立可回滚;遵守 AGENTS.md §6(mutex、集成槽位);合 dev 前 `go vet ./... && go test -short ./... && arch-check && env-service.sh dev rebuild && curl /health`。排期需避开 CURRENT 中 `in_progress` 的认领(chat-history-refresh、conversation-intent-state、workflow-plan Wave 5)所持 mutex。
### Wave 0:立规矩(0.5–1 天,低风险,mutex: arch)
- 建 `internal/contracts` 骨架(先放共享枚举 vocabulary.go、错误码表、事件类型定义,纯定义零实现);
- 写 `scripts/arch-check.sh` + `module-boundaries.yaml`(以现状为基线生成 allowlist,**先不收紧**);
- 产出基线违规报告存 `.doc/audit/`,作为后续各 Wave 的验收对照。
- **验收**:arch-check warn 模式可运行并产出基线;`go vet/test` 全绿;本 ADR 状态转「已接受」。
### Wave 1:止血清障(2–4 天,mutex: 多个小项,逐项独立提交)
1. 删死代码:`kb.MaterializeSnapshot`、ctxmgr 的 CAS 空壳依赖(`ctxmgr/manager.go:19` 注入未用);
2. 解反向依赖:`MaturityStage` 下沉 contracts,删除 intent→bizdev import;
3. 拆类型别名:bizdev 的 `type X = squad.X` 全部替换为独立 DTO(先复制字段,行为不变);
4. 清路径 hack:`server/project_doc_handlers.go:16-19` 的 `repoRoot()` 倒推、3 处硬编码 `data/dev`,统一改走 workspace.Resolver;
5. 统一错误信封(仅 server 层,路由 URL 不动)。
- **验收**:arch-check 中上述各项违规清零;前端 `npm test && npm run build` 通过(错误信封变更需前端配合单轨解析)。
### Wave 2:读路径 API 化——chatlog + docquery(1–2 周,mutex: chat → docgov)
- ctxmgr 拆分:chat_* 表访问与查询方法整体搬 `internal/chatlog`,prompt 装配留 `internal/contextasm`(先物理分包、行为不变,再做接口化);
- 新增 `internal/docquery` 聚合读模型,server 的文档/对话 handler 全部改为三行式;
- DTO golden 契约测试 + 前端类型对齐。
- **验收**:URL 不变前提下前端功能回归全通过;`chat_messages` 等表名在 chatlog 之外 0 出现(arch-check R5 首条 block 生效)。
### Wave 3:小队执行器契约化(1–2 周,mutex: squad)
- squad 重组为 squadrun 门面:实现 `SquadRunner` 四方法 + `RunManifest`(SchemaVer=1);`StepNotify` 改 `contracts.ProgressReporter`;
- bizdev 停止覆写 squad 状态文件、coordinator 停止直读 blackboard/ledger,全部改 `Inspect`/`Resume`;
- 编排层(此时仍可暂居 bizdev 内部的 `stageflow` 雏形)负责:创建工作区(workspace 模块)→ 备 InputBundle(材料/知识/前序文档/上下文)→ 定 OutputContract → 调 `Run` → 读 manifest 投影 docgov/taskrun。
- **验收**:`internal/squad`(squadrun)不再 import stream;`blackboard.json`/`LoadOrCreateLedger` 在 squad 包外 0 引用;真实 PI 全链路冒烟(AGENTS.md §8 铁律)。
### Wave 4:单写者与协议内聚(1 周,mutex: docgov → taskrun)
- docgov 增端口方法;docduty/docrevision/workspace/cmd 的 `document_records`/`freeform_documents` 直写改走端口;
- taskrun 吸收两阶段占位协议与 finalize 投影;`scripts/backfill_task_run_projection.go` 改依赖 taskrun 服务;
- 正文单写路径收敛(output.md 三写者 → manifest 投影唯一路径,旧路径保留一版兼容期后删除)。
- **验收**:R5 表属主检查全绿;ops 回填脚本不再 import server。
### Wave 5:编排与事件化(1–2 周,mutex: bizdev/coordinator —— 全程最大的一步,需独占排期)
- 新增 `internal/app`:wiring 从 NewServer 迁入;事件总线落地,5 个闭包桥全部改订阅者;
- bizdev 拆解:组合根职责交 app;`ExecuteTask`/`executeStageInternal` 按职责拆为 stageflow 的 use case(鉴权→备料→执行→投影→落账 分函数);
- `UserProjectContext` 所有权收归编排层:coordinator 返回 `ContextUpdate` 增量而非直改共享结构;chat 不再字段级合并。
- **验收**:server 不再出现业务闭包;`sendMessageInternal` 缩减为纯编排调用序列;arch-check R4 生效。
### Wave 6:传输与组合根收口(1 周,mutex: server/stream)
- SSE 帧协议下沉 `internal/stream/transport`;server 只剩路由+参数+序列化(目标:17k 行 → 约 6–8k);
- PI Runner JSON Schema 单一来源 + 双端校验 + `result.json` 替代 stdout 约定;
- arch-check 全面转 block 进 CI 与冒烟。
- **验收**:R1–R7 全绿;PI E2E(RUN_PI_E2E=1)通过;FEATURE-MATRIX 更新为解耦后模块结构。
---
## 6. 迁移与兼容策略
- **URL 兼容**:所有既有 HTTP 路由路径与响应结构在 Wave 1–5 期间保持不变(错误信封除外,属前端单轨化配合项);前端只在 Wave 2 换「同 URL 同结构」的内部实现。
- **数据零迁移**:本方案**不改任何表结构**,只改「谁来写」(写者路径收权)与「谁来读」(读模型聚合);Goose 序号不受影响。
- **双写/双读兼容期**:Wave 3 的 manifest 投影与 Wave 4 的正文单写路径,均设一版兼容期(旧路径只读、新路径写),冒烟一个发布周期后删旧路径。
- **回滚单位**:每个 Wave 一个 merge,可独立 revert;Wave 内小项(如 Wave 1 的 5 项)各自原子提交。
## 7. 验收与度量(怎么证明「解耦成功」)
| 指标 | 基线(2026-09-14 实测) | 目标 |
|---|---|---|
| PostgreSQL | 项目、权限、workflow、task、文档关系、版本账本、当前指针 | 依完整备份/PITR 和环境生命周期处理 |
| workspace/state | 执行现场、临时材料、可重建 projection | 终态冻结和归档门禁通过后按 TTL 清理 |
| FAV | 已归档 payload、manifest、receipt、tombstone | 按 retention/legal hold/delete ledger 处理 |
| server 导入内部包数 / 行数 | 25 个 / 17,007 | ≤ 10(contracts+app+少量) / 约 6–8k |
| bizdev 导入内部包数 | 16 | 拆解后各 use-case ≤ 5 |
| 领域包互相 import | 多处(含 intent→bizdev、ctxmgr→docgov) | 0(arch-check R2 block) |
| `document_records` 写者 | 5 方 | 1(docgov) |
| 工作区路径拼接点 | 4+ 处重复、3 处硬编码 | 仅 workspace 模块 |
| SSE 帧代码位置 | server/sse.go 手写 | internal/stream/transport |
| ops 脚本依赖 | 必须构造完整 Server | 直接调领域服务 |
| 「改一处波及几处」 | 以近 5 次跨模块 bug(见 .doc/audit/ 索引)触达文件数为基线抽样 | 同类改动触达文件数减半以上 |
### 7.2 Workspace capability
## 8. 风险与对策
跨模块 DTO 只包含:
```text
workspace_id
project_scope
run_id
lease_fencing_token
schema_version
```
调用方使用 `ReadArtifact(key)`、`OpenAtomicWriter(key)`、`CommitProjection(key, digest)` 等受限端口。
artifact key 必须是受控相对标识,禁止绝对路径、`..`、空段、跨作用域 ID、symlink 和 hardlink 逃逸。
### 7.3 RunManifest
RunManifest 的规范字节、SHA、workspace ID、storage identity 和输出成员在 taskrun finalize 时持久化。
`Evidence map[string]string` 和 `Gaps []string` 不作为核心协议;核心字段类型化,扩展只能进入带 namespace 和 schema 的 extensions。
workspace 内 manifest 是可重建副本,不是唯一事实源。
### 7.4 FAV 接入
artifactvault 只接收服务端确认的终态文档、终态助手回复和必要附件。
流式 chunk、候选、Prompt、工具轨迹、修复过程、临时报告和 workspace 草稿准入率必须为零。
发布从终态事务的 staging/outbox 驱动,禁止目录扫描。
docquery 的读取优先级为:
1. 校验 Principal 和数据库 resource→project 授权图;
2. 读取数据库 immutable ledger/current pointer;
3. 检查并校验 workspace projection,仅作为缓存;
4. 正文缺失但授权图完整时,可按 feature flag 从 FAV 只读降级;
5. 权限图缺失、vault tombstone、SHA 冲突或来源不一致时 fail closed。
GET 不得修复数据库或覆盖 head。
修复和恢复是独立命令,并产生审计记录。
## 8. 授权架构
### 8.1 Principal
Principal 由 HTTP session、服务身份或恢复凭证适配器构造,至少包含 actor ID、actor type、environment、认证来源、request/correlation ID 和明确 capabilities。
`UserID`、`ProjectID`、role 和 duty 不能直接从业务请求体覆盖 Principal。
### 8.2 决策模型
授权决策输入为 `Principal + Action + Resource + CurrentState`。
| 动作类别 | 强制条件 |
| 风险 | 对策 |
|---|---|
| 文档读取 | 项目成员/管理员 + 分类可见性 + stage/duty 范围 |
| 文档编辑/提交 | 写权限 + 当前 duty + 合法状态 + 有效 lease + expected head |
| 批准/驳回 | 对应 action-level duty + 冻结实例配置 + 当前状态 |
| TaskRun 执行/恢复 | 项目权限 + 合法 workflow/stage + 服务端解析的 backend capability |
| FAV 降级读取 | 正常读取授权已成功 + artifact scope/hash/删除状态一致 |
| replay/backfill | 运维 capability + 精确范围 + dry-run + 审计 |
| scratch recovery promotion | 系统管理员 + 数据责任人确认 + scratch identity + 冲突计划无未决项 |
| 与在途认领冲突(chat/intent/workflow 三个 in_progress) | Wave 排期避开其 mutex;Wave 1 的小项与三者无交集可先行 |
| Wave 5 改动面大(bizdev/coordinator/chat 同时动) | 拆成 5a(事件总线+wiring 迁移)与 5b(bizdev 拆解+上下文收权)两批;每批独立冒烟 |
| 大规模搬包引发行为漂移 | 各 Wave 以「物理搬移、行为不变」为第一步,接口化第二步;golden 契约测试 + 既有 54 个 server 测试文件兜底 |
| 前端配合项(错误信封单轨) | Wave 1 与前端同步排期;`web/e2e` Playwright 回归纳入该 Wave 验收 |
| arch-check 误报/规则争议 | 规则文件走 PR 评审;warn 期两周允许豁免清单(带到期日) |
应用用例可以在事务前做快速拒绝,但状态改变必须在取得资源锁后重新读取授权相关事实并再次判定,防止成员、duty、stage 或 lease 在检查后变化。
授权服务不可用或关系不完整时默认拒绝。
事件携带的 actor 只用于审计;订阅者产生持久或外部副作用前重新读取当前权威状态。
## 9. 与现有工作的衔接
### 8.3 后端与数据最小化
- 本方案不替代进行中的专项整改(chat-history-refresh、conversation-intent-state、workflow-plan Wave 5 等),它们按原计划收敛后再启动对应 mutex 的 Wave;
- `软件项目自举`(planned)应**基于本方案后的新边界**实施(squadrun 契约正好覆盖其执行器需求),避免在旧耦合上叠新功能;
- 各 Wave 合 dev 后按 AGENTS.md 同步更新 FEATURE-MATRIX、gap-matrix(若引入发布 blocker)与本文件状态。
调用方不能提交任意 `Backend string`。
应用层按环境、项目策略和输入敏感级别解析 `BackendRef`,agent 适配器再注入受管凭证。
凭证不得进入 DTO、日志、事件、manifest、result 文件或 FAV。
InputBundle 只包含完成任务必需的材料,并标记来源、分类、允许用途和生命周期。
---
## 9. 架构门禁
**附:现状→目标包名映射速查**
### 9.1 静态规则
| 规则 | 检查对象 | 例外 |
| 现状 | 目标 | 动作 |
|---|---|---|
| 领域实现互不 import | Go production packages | 消费端口和稳定 vocabulary |
| server 不 import repository/领域实现 | server production packages | app facade、wire DTO |
| 表写入唯一属主 | production SQL 的 INSERT/UPDATE/DELETE/MERGE | Goose、测试 fixture、批准的修复工具 |
| 工作区物理路径唯一属主 | production path construction/open/write | workspace/squadrun adapter |
| 事件发布者 allowlist | event name → producer package | 无运行时动态注册旁路 |
| 订阅者 allowlist | event name → consumer use case | replay 工具需显式 capability |
| internal/server(NewServer+闭包桥+SSE+路径 hack) | internal/app + internal/server(瘦) + internal/stream/transport + internal/workspace | 拆四 |
| internal/bizdev | stageflow/chatflow/docflow(app 层)+ 各领域端口 | 拆解 |
| internal/coordinator + internal/chat | chatflow(编排)+ UserProjectContext 收权 | 收敛 |
| internal/ctxmgr | internal/chatlog + internal/contextasm | 一拆二 |
| internal/squad | internal/squadrun(+contracts 契约) | 换壳+版本化 |
| internal/kb / docgov / docrevision / docduty / freedoc | 同名保留 + 新增 internal/docquery 读模型 | 收紧+聚合读 |
| internal/intent / taskrun / workspace / notification | 同名保留(依赖修正) | 修正 |
| — | internal/contracts | 新增 |
例外必须记录 owner、原因、范围、到期日和移除里程碑。
warn/block 不按固定“两周”切换;每条规则在对应纵向切片清零后单独转 block。
### 9.2 行为门禁
架构检查不能替代以下测试:
- 同文档并发编辑、批准和 agent commit;
- 任意事务步骤失败时全量回滚;
- worker 崩溃、lease 过期、重复投递和多订阅者部分失败;
- workspace 删除、换根、重启和 projection 重建;
- FAV 降级读取与 scratch 恢复;
- 匿名、非成员、跨用户、跨项目、错误 duty、错误 stage、授权依赖失败;
- 真实浏览器刷新/重登/rebuild 与真实 PI 主链。
## 10. 可观测性与容量
### 10.1 必须指标
- 数据库事务时长、锁等待、deadlock、serialization retry、版本冲突率。
- outbox pending/oldest age、delivery attempts、lease steal、dead letter 数。
- projection missing/mismatch/repair、FAV degraded read、vault verification lag。
- 授权 deny 按 action/reason 计数,不记录正文或敏感资源名。
- workspace active lease、过期清理、fencing rejection、storage identity mismatch。
### 10.2 高并发基线
首个试点必须建立并保存基线,而不是直接承诺未经测量的容量数字:
- 同一文档热点写入与不同文档并行写入分开压测。
- 1、2、4 个 app 实例下验证进程内锁不影响正确性。
- 1、2、4 个 dispatcher 下验证无重复可见副作用、无饥饿和有界积压。
- p50/p95/p99 延迟、锁等待、事务重试、CPU/连接池和队列年龄进入 test report。
- 正确性门禁固定;吞吐阈值在基线评审后写入环境配置与发布 SLO,不能靠降低一致性通过。
## 11. 迁移与兼容
采用 expand → migrate → contract:
1. 新增兼容 schema、端口和读路径,不改变旧写入。
2. 新写路径 shadow/dual-read 验证,禁止无审计双写。
3. 按 checkpoint 幂等回填,异常进入 quarantine。
4. 切主写者,保留旧 reader 一个明确发布窗口。
5. 验证真实刷新/restart/rebuild、FAV coverage 和回滚。
6. 删除旧路径前再次审计引用和数据差异。
旧 workspace 文件缺少 `schema_ver` 时按只读 legacy-v0 解析。
首次受控 Resume 先校验并原子升级到 v1,保留可回滚备份;未知 major 版本 fail closed。
回滚只保证回到最近兼容点。
已被下游里程碑消费的 schema 或契约必须按逆依赖顺序回滚,不能单独 revert 早期提交。
## 12. 首个交付边界
首个里程碑只覆盖受控文档可靠性:
```mermaid
flowchart TB
Read[Authorized content read] --> Ledger[Immutable ledger]
Ledger --> Projection{Projection aligned?}
Projection -->|yes| Return[Return canonical content]
Projection -->|no| Vault{Authorized FAV fallback enabled?}
Vault -->|yes| Degraded[Return verified degraded content]
Vault -->|no| Conflict[Typed consistency error]
Commit[Edit or agent commit] --> Tx[Single UnitOfWork]
Tx --> Ledger
Tx --> Root[Document root pointer]
Tx --> Stage[Artifact staging]
Tx --> Event[Outbox]
```
只有这个切片完成刷新、重启、并发、权限和恢复验收后,才启动其他包的物理拆分。
## 13. 后续扩展顺序
1. 文档可靠性试点。
2. taskrun finalize、RunManifest 持久化和 FAV 集成。
3. 逐个事件替换闭包桥。
4. chatlog/contextasm 原地端口化,再按证据移动包。
5. squadrun capability 化和 backend policy。
6. app 组合根迁移。
7. UserProjectContext 增量收权。
8. server/SSE 收口。
9. 错误信封与 PI Runner 协议作为独立项目实施。
详细依赖、文件和测试场景见整改计划。
@@ -1,475 +0,0 @@
# 多意图多任务识别、持久计划与 HITL 统一确认方案
> 状态: planned(方案已复核,未实施)
> 日期: 2026-09-15
> 作者: Cline(初稿)/ Codex(架构、安全与实施计划复核)
> 关联: [方案审计](../audit/2026-09-15-multi-intent-hitl-plan-review.md);[意图识别深读](./intent-recognition/01-意图识别框架-设计-架构-实现-难点-解决方案-亮点与优势.md);[模块化单体架构](./2026-09-14-module-decoupling-architecture.md);[任务总览](../ops/short-term/2026-09-15-multi-intent-hitl.md)
---
## 一、结论与目标
方向可行,但原稿不能直接实施。需要先闭合计划生命周期、确认回路、授权、并发和模块归属。修订目标是:
1. 一次输入可安全识别 2–4 个候选子任务,并让用户核对系统理解;
2. 只有确定的低风险只读组合可自动执行;批量生成、写入、控制、缺槽、冲突或不确定组合必须进入服务端持久化 HITL;
3. 刷新、双标签页、服务/worker 重启和 SSE 晚到时,计划与卡片从 PostgreSQL 权威状态恢复;
4. 确认只表达用户意愿,不授予权限。每一步执行前按当前主体、成员关系、资源状态和版本重新授权;
5. 不回退已完成的解耦:`internal/intent` 保持纯规则领域模块;跨属主写入继续使用端口、单一写者、`app/uow` 和静态事件契约。
第一版按显式依赖顺序执行,每步独立提交,不承诺跨步骤原子回滚或并行 DAG 调度。
这项能力的直接价值不是替代逐条对话,而是消除当前“用户已经明确给出多个任务,系统却只执行 TopIntent 且不告知”的不可信行为,并让有依赖的“先查再生成”在一次可审计确认中完成。逐条提交仍是低复杂度场景的有效入口;如果 shadow 期显示多意图采用率低、确认放弃率高或用户普遍主动拆单,U7 之后的写动作扩面应停止,而不是为了完成路线图继续建设。
---
## 二、当前事实与缺口
| 能力 | 当前事实 | 证据 |
|------|----------|------|
| 单意图识别 | 18+ Intent、四级漏斗、三分支已实现;FEATURE-MATRIX 仍为 `partial`,不能称“已成熟” | `internal/intent/recognizer.go`、`.doc/status/FEATURE-MATRIX.md` |
| V2 帧/动作表 | `IntentFrameV2`、ActionRegistry、风险、必填槽位、灰度开关已存在 | `internal/intent/types_v2.go`、`registry.go`、`flags.go` |
| 有限多意图 | 默认开启;只按首个连接词拆两段;写意图返回 `nil` | `internal/intent/plan_builder.go` |
| 有限执行 | 只读步骤顺序执行;需确认步骤只有文字提示 | `internal/coordinator/action_planner.go` |
| HITL 基础 | PendingExpectation、四类卡片和 ExpiresAt 已存在;前端仍有本地业务状态修改路径 | `internal/intent/types.go`、`web/src/App.tsx` |
| 可靠事件 | PG dispatcher、delivery、静态契约已 live;FAV 关闭 | `internal/events`、`.doc/ops/CURRENT.md` |
| 模块边界 | `intent` 只允许依赖 `maturity`;chatflow/stageflow/doccontent 等解耦已完成 | `.doc/system-design/module-boundaries.yaml` |
关键缺口:分段不确定时可能退回 TopIntent 并静默丢任务;计划没有 revision、决策凭据、执行账本或可恢复状态机;确认没有统一服务端命令;ActionRegistry 风险容易被误当授权;未处理重复提交、双标签决策、过期竞态和 worker 抢占;卡片/SSE 不是权威状态;原稿把 agent backend 引入 L1 会破坏 intent 边界;T1–T5 全用 `intent` mutex 与实际跨模块范围不符;自由文本结果传递存在提示注入和数据泄露风险;固定样例数不能代替质量门槛。
---
## 三、硬约束与非目标
### 3.1 不可回退的解耦约束
| 约束 | 强制规则 | 验证 |
|------|----------|------|
| L1 纯度 | `internal/intent` 只做确定性分段、识别、帧和计划提案;不得访问网络、PG、文件或 agent backend | arch-check 保持 `intent -> maturity` |
| 应用编排 | 新增 `internal/app/intentflow` 作为计划生命周期唯一编排入口 | chat/server 只依赖深接口,不获得 store/engine |
| 单一写者 | `intent_plans*` 仅由 intentflow repository owner 写;业务动作仍写自己的表 | table owner + SQL write archtest |
| 跨属主一致性 | 计划、决策、投影请求和 outbox 需要一致时使用不透明 `app/uow.TxScope` | 不暴露 pool/pgx.Tx |
| 事件契约 | 新事件先登记 YAML 与 `events.StaticContracts`,再接 dispatcher | registry parity + 未注册 fail closed |
| 授权归属 | intentflow 不复制 docgov/taskrun/workflow 权限,调用动作属主用例端口 | 每个 adapter 有即时授权负例 |
| 组合根 | store、adapter、clock、ID generator、event sink 仅在 `internal/app/app.go` 装配 | server 不重新接线 |
### 3.2 非目标
- 不拆微服务或新增 RPC;不支持 >4 步、并行 DAG、多个活动写计划自动合并;
- 不承诺跨步骤 ACID 或自动补偿;
- 当前作用域没有活动写/生成计划时,不改变单意图生成任务行为;已有活动计划时统一进入冲突/替换流程,禁止启动第二个写计划;
- 不让 LLM 决定风险、权限、槽位真值或执行顺序;
- 不启用 FAV,也不把中间结果归档到 FAV;
- 不借机全量重构 coordinator/chat action executor。
---
## 四、总体架构与权威性
```mermaid
flowchart LR
UI[Web 计划卡] --> API[server HTTP/SSE]
API --> FLOW[app/intentflow\n计划生命周期]
CHAT[chat/chatflow] --> FLOW
FLOW --> L1[intent\n纯规则提案]
FLOW --> STORE[(plan owner store)]
FLOW --> UOW[app/uow]
FLOW --> PORTS[动作属主端口]
FLOW --> EVENTS[events outbox]
EVENTS --> PROJ[projection/notify]
FLOW -.只建议分段.-> SEM[语义 adapter\nagent backend]
```
`app/intentflow` 对外只提供:处理一轮输入、提交计划决策、读取授权后的 PlanView、恢复/推进已有计划。不得向调用者暴露 PlanStore、事务、`docgov.Engine`、`taskrun.Manager` 或 pool。
权威性从高到低:当前认证主体与资源状态 → 动作属主的授权/业务不变量 → PG 计划/步骤/决策 → 消息卡片投影 → SSE/前端内存。下层不得覆盖上层。
### 4.1 端到端流
```mermaid
sequenceDiagram
participant U as 用户
participant W as Web/server
participant F as app/intentflow
participant I as intent
participant D as PG plan store
participant A as 动作属主
U->>W: input + client_turn_id
W->>F: HandleTurn(principal, context, input)
F->>I: 安全扫描、分段、逐段识别
I-->>F: PlanProposal + evidence + digest
alt 独立低风险只读
F->>A: 每步即时授权并执行
F-->>W: 聚合结果
else 需澄清/确认
F->>D: 同事务写 plan/steps/outbox
F-->>W: 权威卡片
U->>W: decision + nonce + expected_revision
W->>F: DecidePlan
F->>D: CAS 状态
F->>A: 每步重新授权、执行
F->>D: CAS step + receipt/ref
F-->>W: PlanView
end
```
---
## 五、领域模型与状态机
- `intent.PlanProposal`:L1 值对象,含规范化分段、候选帧、证据、缺槽和依赖建议;不含授权结论或 DB 状态;
- `intentflow.Plan`:应用实体,含主体/会话/项目作用域、请求摘要、revision、过期、决策与执行账本;
- `PlanView`:脱敏 UI 投影,不回传内部 payload、权限快照或完整中间结果;
- UserProjectContext/消息只保留 `plan_id + revision` 引用,不持久化第二份 PendingPlan。
### 5.1 计划状态
```mermaid
stateDiagram-v2
[*] --> proposed
proposed --> awaiting_clarification
proposed --> awaiting_confirmation
proposed --> executing: 仅低风险只读
awaiting_clarification --> awaiting_confirmation
awaiting_clarification --> executing
awaiting_clarification --> awaiting_clarification: 增量补槽形成新 revision
awaiting_clarification --> superseded
awaiting_confirmation --> executing
awaiting_confirmation --> cancelled
awaiting_confirmation --> expired
awaiting_confirmation --> superseded
executing --> partially_completed
executing --> completed
executing --> failed
executing --> cancelled: 仅未开始步骤
partially_completed --> completed
partially_completed --> failed
partially_completed --> executing: 用户选择重试/继续
partially_completed --> cancelled: 取消全部未开始步骤
```
编辑产生新 revision/digest,旧卡片 `outdated`;取消不能回滚已完成业务副作用;`skip` 只允许独立低风险只读步骤;依赖失败阻塞所有后代;`confirm_retry` 暂停计划并对指定失败步骤重新确认。
### 5.2 步骤、部分确认与幂等
步骤状态:`pending -> eligible -> running -> succeeded | failed | denied | conflicted | blocked_dependency | skipped | cancelled`。
- `eligible -> running` 用条件更新和 fencing token;
- 动作幂等键:`plan_id:plan_revision:step_id:action_digest`;同键同摘要返回既有 receipt,同键异摘要冲突;
- 动作属主端口必须接收 idempotency key、action digest、expected resource version 和 fencing token,并能按同一身份查询 receipt。只有属主事务能原子提交幂等占位与业务副作用,或已证明原生机制等价时,该 action 才能放量;旧 fence 必须被属主拒绝;
- 部分确认必须是依赖闭包;选中步骤进入 eligible,未选独立步骤继续等待确认。只有用户显式“排除未选项”才写 `cancelled_by_user`,其后代取消或阻塞;
- 高风险步骤逐项可见;确认父步骤不自动确认新出现的高风险后代;
- “确认第 1 项并修改第 2 项”拆成决策和新 revision,不混为一个转移。
---
## 六、分段、识别与组合策略
### 6.1 确定性分段
`internal/intent` 内扩展纯规则分段器,支持连接词、句号、分号、换行、序号和“先/再/最后”,上限 4 段。输出包含规范化文本、原文 span、连接证据、结构置信类别和未解析指代。
1. 整句先做 Stage 0 安全扫描;分段规范化、槽位补丁、LLM 建议后再次逐段扫描;原文命中优先,整体拒绝;
2. “查询并总结”“阅读后概括”等单动作内部链不拆;
3. 只有确定为完整单意图时才合并回单意图;低置信、指代补全失败或无法证明完整时进入澄清,禁止退回 TopIntent 执行;
4. 逐段识别后检查同资源冲突、重复动作和依赖;
5. 超过 4 段不创建残缺计划,明确要求分批。
### 6.2 可选语义分段
LLM adapter 位于 intentflow 外围,不放进 `internal/intent`。它只能提出 `text span + connector + reason`,不能输出权限、风险、ActionKey、执行顺序或权威槽位。
- 只发送当前文本和必要的脱敏实体标签;不发送 secrets、完整历史、文档正文或权限表;
- 严格版本化 schema;超时、格式错、span 重叠、越界或安全冲突均 fail closed;
- 每段重新进入确定性 recognizer、ActionRegistry 和安全扫描;护栏优先,无法裁定就澄清;
- 以 `request_digest + segmenter_version + model_contract_version` 固化已展示分段;重试不得因模型漂移改变计划;
- shadow 日志只保留 digest、类别、差异和计数。
### 6.3 组合风险矩阵
ActionRegistry 提供动作身份、目标类别和静态风险提示,但不是授权或批量编排 SSOT。`app/intentflow` 拥有版本化 `BatchActionPolicy`,只记录 action key 的批量确认要求、可开放 tier、adapter 能力和 execution mode,并在启动时校验 key 存在于 ActionRegistry。它不得复制 Risk、RequiredSlots、CapabilityKey 或 AllowedStates。`task.run`/`task.run.adhoc` 的批量策略要求确认,同时保持其单意图 `RequiresConfirm` 不变。
| 条件 | 模式 | 行为 |
|------|------|------|
| 全部独立 RiskLow 查询、槽位齐、无冲突 | `auto_read` | 即时授权后执行 |
| 任一批量生成、mutate/control、中高风险或 BatchActionPolicy 要求确认 | `awaiting_confirmation` | 先持久化并出卡,确认前零副作用 |
| 缺槽、指代/分段/依赖不明 | `awaiting_clarification` | 聚合澄清;有槽位依赖时分组问 |
| 原文或变换结果命中红线 | `rejected` | 整体拒绝,不执行其他段 |
| >4 段 | `rejected_batch_size` | 要求分批 |
V2 灰度不可绕过:只有 ActionRegistry 映射稳定、V2 shadow 达门槛且当前 multi-intent tier 允许的动作可进入 decision;其余走 legacy 或显式澄清。
---
## 七、HITL、授权与并发协议
### 7.1 服务端权威卡片
`PLAN_CONFIRM` 折叠态也必须显示任务数、受影响目标、生成/写入/控制类型、最高风险、不可撤销副作用和“逐步提交、后续失败不回滚”提示;高风险步骤始终逐项可见。只有 action key、revision、digest 等技术元数据和低风险细节可折叠。支持全部确认、依赖闭包内部分确认、编辑、取消。
`CLARIFY_AGGREGATE` 展示逐步缺槽、约束、已知值和冲突。回复形成 slot patch 后必须重新识别、重新计算 digest、风险和授权预检。
用户只回答部分问题时保存可唯一映射的增量 patch,产生新 revision 并继续停留在 awaiting_clarification;新卡同时显示已解决值和剩余问题,旧卡 stale。不会要求重填已经验证的值,也不会在缺槽未闭合时提前执行。
澄清字段按步骤和依赖分组,标记“已验证/待填写/冲突/无效”,显示剩余数量;提交文案为“保存已填写并继续”,提交后保留合法值并聚焦首个未解决字段。
卡片 metadata 是 PG 状态投影。按钮和自然语言“确认/取消/只做第 1 项”统一进入服务端 `DecidePlan`;前端不得本地修改业务资源或先标成功。
部分确认 UI 使用依赖层级列表:选择子步骤时立即勾选并解释必需前置;存在已选后代时不能取消前置;提交按钮显示本次确认的步骤数和目标。未选项标为“继续等待”,显式排除是独立次级动作,并在提交前列出会被取消或阻塞的后代。
自然语言决策采用确定性语法优先:明确 plan/步骤编号或当前会话只有一个活动可见计划时才可绑定;“确认”在多个活动计划、步骤引用不合法或同时包含新任务时不执行,改为定向澄清。聚合槽位优先使用结构化卡片字段;自由文本只把可唯一映射的 `label:value`/已有 PatchSlots 结果写入 patch,冲突值、依赖值无效或多义值保持未解析并再次提问,绝不猜测。
### 7.2 确认不等于授权
执行每一步前,动作属主重新校验当前认证用户与 plan session/project/user、当前成员/duty/capability、资源归属/lifecycle/stage、expected version/ETag、动作允许状态。计划中的角色/权限快照只用于审计。失败进入 `denied/conflicted`,不得换系统身份代执行。
### 7.3 并发规则
- 创建:`(session_id, client_turn_id, request_digest)` 唯一;同 turn 异 digest 冲突;
- 决策:必须带 `expected_revision`、`decision_nonce`、`decision_digest`;同 nonce 同摘要返回 receipt,异摘要冲突;
- 标识:plan_id、step_id、decision_nonce 使用不可预测的随机标识;安全性不依赖其保密,所有访问仍做四元作用域授权;
- 状态:当前 revision 且未过期的等待态才能 CAS;陈旧卡片返回 409 和当前安全视图;
- 过期:服务端 `expires_at` 权威,TTLTurns 只显示;
- 执行:短 lease + owner + lease_until + 单调 fencing;续租失败不再领步骤;
- 竞态:确认/取消/过期、编辑/确认只允许一个 CAS 胜出;
- SSE:允许重复/乱序/丢失,前端按 revision/step version 去重,发现缺口 GET 对账。
同一 user/session/project 同时只允许一个活动写/生成计划。新的低风险查询可独立处理;新的写计划必须让用户完成、取消或显式替换旧计划,不自动合并。计划锁不替代业务资源自己的 lease/version lock。
因此“单意图生成保持现状”仅适用于没有活动写/生成计划的作用域。有活动计划时,无论新输入是单意图还是多意图,都返回同一服务端冲突视图,禁止创建第二个 task/run;真实页面验收分别覆盖无活动计划兼容和有活动计划冲突。
`partially_completed` 必须提供前向收口卡:重试指定失败步骤、继续仍 eligible 的独立步骤、取消所有未开始步骤并关闭计划。已成功 receipt 永不回滚;running 步骤先由 lease/fencing 收口,卡片列明已发生且不可撤销的副作用。
---
## 八、持久化、事务、事件与数据治理
### 8.1 表与所有权
`intent_plans`:plan_id、environment/project/session/user/client_turn、request_digest、segmenter/policy version、status、revision、expires_at、timestamps、last_fencing_token。原始输入沿用 chat message 保留;计划表保存引用、digest 和脱敏展示快照。
`intent_plan_steps`:plan/step、action_key、规范化 slots、依赖、status、expected_resource_version、action_digest、idempotency_key、attempt、result_ref/digest、safe_summary、timestamps、version。
`intent_plan_decisions`:append-only decision id/nonce、plan revision、actor、kind、step selection、patch/request digest、outcome、created_at。关键 CAS、审计和查询字段必须类型化;JSONB 只用于版本化 slots/display snapshot。三表 owner 登记为 `app/intentflow`,其他包只能走端口。
### 8.2 事务与恢复
- 创建:plan + steps + card projection request + outbox 同一 UoW;
- 决策:decision append + plan CAS + eligible steps 同一 UoW;
- 业务副作用由动作属主事务提交,再以 idempotent receipt 更新步骤,不制造跨模块长事务;
- 业务成功但 receipt 写回失败时,通过动作幂等键查既有结果并对账,不盲跑;
- 消息投影失败不回滚权威计划,dispatcher 重试,刷新 GET 修复。
### 8.3 事件与作用域
只发布事实,不发布执行命令。候选事件 `intent.plan.awaiting_input`、`intent.plan.step_changed`、`intent.plan.completed` 必须同时登记 YAML、StaticContracts、schema/golden 和 parity test。
payload 仅含 plan/revision/step/status、environment/project/user/session scope 和安全摘要引用;不含原 prompt、完整 slots、权限快照或完整结果。消费者和 SSE 投递前按当前主体重新读取授权后的 PlanView;同项目不同用户不能互见。
### 8.4 留存与结果传递
- plan/decision 随会话和项目数据政策清理,不早于关联 chat/taskrun 审计窗口;删除由 owner 执行;
- 中间结果仅保存 `ResultReference`:producer、result/artifact ID、digest、类型、敏感级别、允许用途和长度受限 safe summary;
- 不把前序自由文本直接拼入权威槽位或后续指令区。后续生成只能把带来源的数据放入隔离材料区,不能扩大 action/target/tool/capability;
- 若结果导致动作、目标或范围变化,产生新 revision 并重新确认;
- 最终生成物仍归 taskrun/受控文档/FAV(启用后),计划库不充当成果仓。
---
## 九、API、刷新与前端
资源接口必须包括 `GET /api/v1/intent-plans/active`(按当前 principal/environment/project/session/user 发现活动计划)、`GET /api/v1/intent-plans/{plan_id}` 与 `POST /api/v1/intent-plans/{plan_id}/decisions`。页面 bootstrap、刷新和 SSE 缺口恢复先查询 active,再拉 PlanView;消息投影失败时仍能找回计划。
decision API 继承当前服务端认证方式、Origin/CSRF 策略和统一限流;nonce/幂等键只防重放与并发,不替代 CSRF 或身份认证。若当前认证方式不具备适用的 CSRF 防护,U1 必须把它列为 U5 的前置 blocker,而不是在计划端点单独发明一套弱机制。
统一错误码至少包括:`PLAN_NOT_FOUND_OR_HIDDEN`、`PLAN_STALE_REVISION`、`PLAN_EXPIRED`、`PLAN_DECISION_CONFLICT`、`PLAN_DEPENDENCY_INVALID`、`PLAN_ACTION_FORBIDDEN`、`PLAN_ACTION_VERSION_CONFLICT`。无权主体沿用资源隐藏策略,避免枚举 plan_id。
刷新时由 plan 表生成卡片/进度,不从旧按钮或 SSE 推断。页面刷新、重开、SSE 重连均以 GET 覆盖本地缓存。卡片需支持键盘/读屏、依赖说明、错误焦点、过期/陈旧状态;按钮提交后可显示 submitting,但只有服务端 receipt 能变为 executing/resolved。完整结果从 owning API 读取,SSE 只携安全摘要和版本。
状态恢复矩阵:submitting 锁定重复提交并保留选择;outdated/conflict 自动读取最新 PlanView、聚焦状态通知并提供“查看最新版”;expired 禁用原决策,保留只读摘要并提供“按当前上下文重建计划”;服务端字段错误保留未提交输入并聚焦对应字段。会话顶部提供可关闭但可重新发现的活动计划入口,无活动计划返回明确空态。
可访问性契约:步骤用有序列表和带 legend 的选择组;折叠控件暴露 `aria-expanded/aria-controls`;进度用 polite live region,阻断错误用 alert 并聚焦;状态不只靠颜色;键盘顺序为摘要、步骤、主/次动作;窄屏单列、无横向滚动、触控目标至少 44px,并支持 reduced-motion。
---
## 十、灰度、指标与回滚
保留 `MULTI_INTENT_ENABLED` 作为 legacy 开关;在任何行为变更前新增 `MULTI_INTENT_PLAN_TIER=legacy|shadow|auto_read|confirm|full`,默认 `legacy`。
- legacy:保持现有路径,但一旦可靠检测到未处理写/生成段,不得静默只执行 TopIntent,应澄清;
- shadow:只生成提案/指标,不建计划、不改路由;
- auto_read:先保持现状上限,仅开放 2 个低风险只读步骤;3–4 个只读步骤先进入确认/观察,达到单独门槛后再扩大;
- confirm:开放持久卡片;真实 adapter 未启用时只能产生 `validated_only` 预检。Plan、step、receipt 和 PlanView 显式携带 execution mode;`validated_only` 不能写 `succeeded/completed`,UI 必须显示“仅验证,未执行”;
- full:按 action key 逐项开放已验收 adapter。
LLM 分段独立开关且从 shadow 起步。关闭新计划创建后,已有计划仍能读取、取消和收口;不能回滚到无法处理已持久计划的版本。
| 指标 | 停走条件 |
|------|----------|
| 未确认/越权副作用 | 0 |
| 安全红线绕过 | 0 |
| hard-negative 反事实错误自动执行 | 0;shadow 必须计算“若处于 auto_read/confirm 会如何路由”,不能用实际未执行冒充零错误 |
| 重复确认导致重复动作 | 0 |
| refresh/restart 权威状态差异 | 0 |
| split precision/recall、澄清率、放弃率 | U2 先固定数据集与基线,再预注册阈值;未达不切档 |
| 用户采用与确认负担 | 记录多意图采用率、确认放弃率、拆单回退率;若价值不足,停止 U8/U9 而保留“识别后不静默丢弃”的安全改进 |
| projection backlog/dead letter | 不突破 Track E 既有预算 |
观察窗口由样本量和流量决定,不能用固定“一周”代替证据。
---
## 十一、实施计划(核心 U1–U8、按属主扩面 U10–U12、可选实验 U9)
### U1. 契约冻结与架构门禁
**目标:** 冻结 intentflow 边界、状态机、数据字典、错误码、事件和兼容策略。
**依赖:** 无。
**文件:** `.doc/system-design/module-boundaries.yaml`、`internal/events/registry.go`、API/schema 文档、arch/event tests。
**做法:** 注册 app/intentflow allowlist 与 table owner;保持 intent->maturity;冻结 BatchActionPolicy,但不向 intent 回灌 HITL/tier/adapter 字段;先落默认 legacy tier;禁止 server/chat 直写计划表。
**测试:** 新 import/SQL/event 违规 block;YAML/registry parity;未知 action/policy key fail closed;ActionRegistry 不出现批量执行策略;单意图生成策略不变。
**停走门:** 架构测试全绿,授权/状态契约无待实现者猜测。
**mutex:** 纯契约文档用 `architecture-docs`;事件注册变更串行占 `events`。U1 不修改 intent 业务类型,intent 代码变更从 U2 开始。
### U2. 确定性分段、PlanProposal 与 shadow 基线
**目标:** 不改变生产路由地生成 2–4 步提案和差异指标。
**依赖:** U1。
**文件:** `internal/intent/segmenter.go`、`plan_builder.go`、`types_v2.go`、`registry.go`、`internal/intent/testdata/*` 及 tests。
**做法:** characterization-first;规则分段、span、指代/连动护栏、安全复扫、显式依赖、稳定 digest。
**测试:** 连接词/句号/序号;查询并总结不拆;指代失败澄清;红线整体拒绝;5 段拒绝;同输入 digest 稳定;写段不静默丢弃。
**停走门:** shadow 不改响应;对 golden、hard-negative 和真实抽样人工标签做 counterfactual evaluation,报告分母、误拆/漏段/错误自动执行率及置信区间;预注册阈值未达不得切档。
**mutex:** `intent`。
### U3. intentflow、PG 状态机与 repository
**目标:** 建立持久计划/步骤/决策与并发协议,不接真实写动作。
**依赖:** U1、U2。
**文件:** `internal/app/intentflow/*`、`deploy/postgres/goose/*intent_plan*`、`internal/app/app.go`、PG tests。
**做法:** owner repository、UoW、CAS revision、decision nonce、绝对过期、lease/fencing、创建幂等、retention、组合根装配。
**测试:** 双创建;nonce 同/异 digest;确认/取消/过期竞态;两 worker 抢占;租约接管;旧 fencing token 在动作属主处被拒绝;重启恢复;业务成功但 receipt 写回失败;环境隔离。
**停走门:** 无双 owner/双执行,arch-check 无新例外。
**mutex:** 新增 `intent-plan`,迁移窗口协调 `db/app`。
### U4. 事件、卡片与步骤投影
**目标:** 权威计划可靠投影;消息/SSE 丢失不影响恢复。
**依赖:** U3。
**文件:** 新增 intent-plan event registry/schema、intentflow projection subscriber、ctxmgr owner port、对应 parity/dispatcher integration tests。
**做法:** 同 UoW outbox、事实事件、消费者幂等与最小 payload;复用 Track E 已有重试/dead letter/replay。禁止修改通用 claim、lease、delivery、retry 或 replay 语义;若确需修改,另立缺陷任务。
**测试:** 重复/乱序;projection 暂停 replay;消息失败后 GET 修复;worker restart;伪造 producer/字段拒绝;同项目跨用户不可见。
**停走门:** shadow projection 与 DB diff=0,delivery 可查。
**mutex:** `events`;ctxmgr 写入只走 owner 端口。
### U5. 决策 API 与即时授权端口
**目标:** 按钮/自然语言走同一服务端命令,执行前重新授权。
**依赖:** U3。
**文件:** `internal/server/*intent_plan*`、`internal/app/intentflow/*`、授权端口契约、fake/dry-run adapter、auth integration tests。
**做法:** active discovery/GET/decision、错误信封、四元作用域、expected revision、依赖闭包、资源版本;不在本单元接真实业务属主 adapter。
**测试:** 投影缺失仍能发现活动计划;非成员/跨项目/跨 session;角色撤销;资源变更;stale revision;重复点击;非法部分确认;edit 使旧卡失效;按钮/自然语言同 receipt。
**停走门:** 权限负例全绿;确认前零副作用;无系统身份绕过。
**mutex:** `intent-plan` + `server/authz`;动作接入另占 owner mutex。
### U6. Web 卡片、刷新与可访问性
**目标:** UI 只呈现 PlanView,刷新和多标签一致。
**依赖:** U4、U5。
**文件:** `web/src/types/workbench.ts`、`web/src/components/chat/InteractiveCard.tsx`、API client、`web/src/App.tsx`、web/browser tests。
**做法:** 两卡、步骤进度、依赖选择、submitting/outdated/expired/conflict、GET reconcile;计划动作不进入本地 AST/资源修改路径。
**测试:** reload/reopen 与无投影 active discovery;双标签确认/取消;409 查看最新版;过期重建;字段输入保留;键盘/读屏/live-region;窄屏 44px/reduced-motion;SSE 重复乱序;慢请求;validated_only 明示未执行。
**停走门:** 真实浏览器双标签/reload 无本地假成功。
**mutex:** `web`。
### U7. 低风险只读执行与聚合
**目标:** 独立低风险查询从 proposal 安全推进到完成。
**依赖:** U4、U5;可与 U6 并行,开放 auto_read tier 前两者都必须通过。
**文件:** `internal/app/intentflow/*`、query adapters、coordinator/chatflow 兼容入口、integration tests。
**做法:** 每步即时授权、显式依赖、ResultReference、失败/阻塞汇报;旧 executeIntentPlan 仅兼容,不扩成跨模块 switch。
**测试:** 2–4 查询;独立失败继续;依赖失败阻塞;敏感字段脱敏;同 turn 重放;重启续跑。
**停走门:** legacy 单意图无回归,重复执行为 0。
**mutex:** `intent-plan`;触及入口时协调 `chat`。
### U8. 生成任务 adapter
**目标:** 经确认后只开放 `task.run` 与 `task.run.adhoc`,形成第一版生成闭环。
**依赖:** U7。
**文件:** intentflow taskrun adapter、taskrun owner port/tests、real PI/browser tests。
**做法:** shadow/dry-run 后开启;传稳定幂等键,保存 result reference/receipt;不改变无活动计划时的单意图行为。
**测试:** 多意图生成需确认;活动计划冲突;权限撤销;重放;部分完成;receipt 丢失恢复;真实 PI 结果引用。
**停走门:** taskrun owner/PG/auth/browser/real PI 分层证据全绿。
**mutex:** `taskrun` + `intent-plan`。
### U9. LLM 分段 adapter 与全面灰度
**目标:** 仅为规则无法可靠判断的输入提供受控建议。
**依赖:** U2、U7。
**文件:** intentflow segment proposal port/adapter、版本化 schema、eval/real PI tests。
**做法:** 最小输入、严格 schema、固定版本/digest、护栏优先、shadow、超时 fail closed。
**测试:** malformed/timeout;重试稳定;模型改风险/权限无效;红线拆分逃逸失败;敏感内容不出站;冲突澄清。
**停走门:** real PI eval 达预注册阈值且安全错误为 0。
**mutex:** `intent-plan` + `pi-agent`,不得改变 intent imports。
U9 是核心首版之外的独立实验,不参与 U1–U8 的完成判定。未实施或未达阈值时,规则无法裁定的输入继续进入澄清。
### U10. 低风险 mutate adapters
**目标:** 只接入经专项批准的 medium/low mutate action。
**依赖:** U8。
**文件:** 每个动作的 intentflow adapter 与 owner tests。
**做法:** 每个 action 独立 short-term、flag、dry-run、权限负例和回滚;不打包发布。
**停走门:** 单 action 证据齐全后才加入 full tier。
**mutex:** 对应动作 owner + `intent-plan`。
### U11. 文档治理 adapters
**目标:** 按 claim/submit/review/final 等 action 分项接入 docgov,不复制其 duty/lifecycle 规则。
**依赖:** U8。
**文件:** intentflow docgov adapters、docgov owner ports/tests、browser auth negatives。
**做法:** 高风险动作逐个任务、逐个 go/no-go;必须带 expected document version。
**停走门:** 各 action 的跨角色、生命周期和并发负例独立签署。
**mutex:** `docgov` + `intent-plan`。
### U12. Workflow 与 run-control adapters
**目标:** 分别接入 workflow switch/run 与 task run resume/restart/cancel。
**依赖:** U8。
**文件:** intentflow workflow/run adapters、owner ports/tests。
**做法:** workflow 与 run-control 必须拆成独立 short-term,不共用发布开关或回滚点。
**停走门:** 当前 stage/state、权限、幂等和冲突负例分别通过。
**mutex:** `workflow` 或 `taskrun` + `intent-plan`。
---
## 十二、验收矩阵与 DoD
必须覆盖:两个只读查询;查询+生成确认前零副作用;部分确认后未选项仍可稍后确认、显式排除才取消;增量补槽保留已验证值;部分完成可重试/继续/关闭;确认后权限撤销;双标签确认/取消只一方成功;确认/过期竞态;服务/worker 重启不重跑成功步骤;投影停机而 GET 正确;“查法规并总结”不误拆;红线混入整体拒绝;前序结果含提示注入仍只作材料;无活动计划时单意图生成不变、有活动计划时不创建第二任务、批量生成需确认;跨用户/项目/会话隐藏;同 turn/nonce 异摘要冲突;编辑后旧卡 stale。
Definition of Done:
- [ ] 核心首版 U1–U8 按各自停走门独立验收;U9、U10–U12 未实施不阻塞首版,但任何已启用 adapter 必须满足自己的停走门;
- [ ] `intent -> maturity` 保持,intentflow 无 service locator、pool 或跨 owner SQL;
- [ ] 所有写/生成/控制在未确认和越权时副作用为 0;
- [ ] 双标签、刷新、服务/worker 重启、重复/乱序事件下无双执行且可恢复;
- [ ] 按钮与自然语言走同一命令,每步即时授权并校验资源版本;
- [ ] 中间结果不进 FAV,事件不携带敏感正文;
- [ ] arch-check、Go short、PG、web build/test、真实 browser 和适用 real PI 分别有报告;
- [ ] FEATURE-MATRIX、CURRENT、任务与必要时 gap-matrix 一致;
- [ ] 清除废弃实验、旧本地成功路径和临时开关;回滚版本仍能读取/取消已有计划。
---
## 十三、关键决策
1. 采用 `app/intentflow` 深模块,不继续膨胀 coordinator;
2. 单意图生成行为保持;多意图策略由 intentflow 的 BatchActionPolicy 管理并引用 ActionRegistry action key,不把应用编排政策回灌 L1;
3. 同步权威状态 + outbox 投影,不用纯事件驱动 plan state;
4. 服务端绝对过期,不用 TTLTurns 作权威;
5. 逐步骤事务,不制造跨 owner 长事务;
6. LLM 只建议分段且最后实施;
7. 新行为默认 legacy/shadow,现有 `MULTI_INTENT_ENABLED=true` 不是自动放量许可。
不采用:把完整 PendingPlan 塞进 UserProjectContext、扩展前端本地 cardActionEngine 执行业务、用 coordinator switch 持有所有具体 engine、LLM 直接生成可执行计划、跨模块大事务。它们会造成双真相、越权/假成功、service locator 回潮、不可信执行或解耦倒退。
长期维护归属按模块分开:intent owner 维护规则与评测;intentflow owner 维护状态机、schema 和 rollout;web owner 维护卡片交互;events owner 维护投影契约;各 action owner 维护自己的授权 adapter。上线后每次新增 ActionSpec 必须同时给出批量策略、计划适配能力和负例,不能让矩阵靠人工记忆同步。
+9 -29
View File
@@ -99,42 +99,21 @@
---
### 6. 模块化单体解耦架构
### 6. 模块解耦架构设计与实施方案
| 项 | 链接 |
|-----|------|
| 主报告 | [2026-09-14-module-decoupling-architecture.md](2026-09-14-module-decoupling-architecture.md) |
| ADR | [../adr/2026-09-14-modular-monolith-decoupling.md](../adr/2026-09-14-modular-monolith-decoupling.md) |
| 整改计划 | [../remediation/2026-09-14-module-decoupling-refactor-plan.md](../remediation/2026-09-14-module-decoupling-refactor-plan.md) |
| 一句话总结 | 先以文档可靠性纵向试点验证事务、锁、授权、事件与 FAV,再按证据扩展模块边界 |
| 一句话总结 | 模块化单体 + `internal/contracts` 契约通信 + 单一写者 + 编排下沉 + arch-check 机器门禁,Wave 0–6 分阶段落地 |
**核心要点**:
- 单一写者负责 SQL 和不变量,应用 UnitOfWork 负责跨属主原子提交;
- 数据库行锁、事务级 advisory lock、唯一约束和 fencing token 支撑多副本并发;
- workspace 是可清理投影,FAV 只保存已确认终态成果;
- 事件采用逐消费者 delivery、幂等 inbox、租约、重试和 dead letter;
- HTTP、CLI、worker、subscriber 和恢复工具使用同一逐动作授权模型;
- 先原地端口化,行为稳定后才物理搬包。
---
### 7. 多意图持久计划与 HITL
| 项 | 链接 |
|-----|------|
| 主方案 | [2026-09-15-multi-intent-hitl-plan.md](2026-09-15-multi-intent-hitl-plan.md) |
| 复核 | [../audit/2026-09-15-multi-intent-hitl-plan-review.md](../audit/2026-09-15-multi-intent-hitl-plan-review.md) |
| 任务总览 | [../ops/short-term/2026-09-15-multi-intent-hitl.md](../ops/short-term/2026-09-15-multi-intent-hitl.md) |
| U1 契约 | [../ops/short-term/2026-09-15-multi-intent-u1-contracts.md](../ops/short-term/2026-09-15-multi-intent-u1-contracts.md) |
| U2 分段 | [../ops/short-term/2026-09-15-multi-intent-u2-segmenter.md](../ops/short-term/2026-09-15-multi-intent-u2-segmenter.md);[报告](../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md) |
| U3 PG | [../ops/short-term/2026-09-15-multi-intent-u3-intentflow-pg.md](../ops/short-term/2026-09-15-multi-intent-u3-intentflow-pg.md);[报告](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) |
| U4 投影 | [../ops/short-term/2026-09-16-multi-intent-u4-outbox-projection.md](../ops/short-term/2026-09-16-multi-intent-u4-outbox-projection.md);[报告](../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md) |
| U5 API | [../ops/short-term/2026-09-16-multi-intent-u5-decision-api.md](../ops/short-term/2026-09-16-multi-intent-u5-decision-api.md);[报告](../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md) |
| U6 Web | [../ops/short-term/2026-09-16-multi-intent-u6-web-cards.md](../ops/short-term/2026-09-16-multi-intent-u6-web-cards.md);[报告](../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md) |
| 一句话总结 | intent 保持纯规则,intentflow 持久化计划并统一确认、授权、幂等、恢复和逐动作执行 |
**硬边界**:确认不等于授权;PG 是计划真相,卡片/SSE 是投影;写动作按 owner 端口逐项接入;LLM 只能提出不可信分段建议。
- **诊断**:server/bizdev 双组合根、`UserProjectContext` 双向直改、`document_records` 五写者、工作区路径与 squad 文件 schema 为无版本化隐性契约(11 项热点均有文件:行号证据);
- **四例契约**:squadrun(系统备料备工作区、小队按 OutputContract 交货并写 RunManifest)、kb(纯检索)、chatlog(项目ID+用户ID → 结构化 DTO)、docquery(统一文档列表/正文读模型);
- **横切**:事件总线泛化 outbox、表/文件单写者、统一错误信封、DTO golden 契约测试、PI Runner 协议单一 schema 源;
- **门禁**:`scripts/arch-check.sh` + module-boundaries.yaml,warn 两周后 block 进 CI;
- **兼容**:URL 不变、零表结构迁移、每 Wave 独立分支独立回滚。
---
@@ -188,6 +167,8 @@
```
.doc/system-design/
├── README.md ← 本文件(顶层索引)
├── module-boundaries.yaml ← Wave 0 arch-check allowlist
├── 2026-09-14-module-decoupling-architecture.md ← 模块化单体解耦
├── document-revision-management.md ← 文档版本、修订、差异、报告与通知
├── intent-recognition/
│ └── 01-意图识别框架-设计-架构-实现-难点-解决方案-亮点与优势.md
@@ -200,7 +181,6 @@
├── 04-项目多工作流与智能产品经理-测试经理工作流-实施计划.md
├── 05-Phase0-基线确认与契约冻结.md
└── 06-Phase7-全链路验收与发布基线.md
├── 2026-09-14-module-decoupling-architecture.md ← 模块化单体解耦
.tmp/ ← 中间分析文件
├── intent-recognition/
+43 -593
View File
@@ -1,600 +1,50 @@
# U1 architecture baseline. Import allowlist is a 2026-09-14 production go list snapshot.
# SQL write / path / event rules apply only to production Go (not Goose, *_test.go, or fixtures).
# Existing debt lives in exceptions with owner + milestone + expiry. New findings block immediately.
# Wave 0 baseline allowlist. Generated from 2026-09-14 go list, not tightened.
# Target owners are recorded for table/path checks; extra mentions are warnings.
imports:
agent:
- config
auth:
- config
authz:
- docduty
bizdev:
- authz
- config
- ctxmgr
- db
- docduty
- docgov
- docrevision
- freedoc
- kb
- maturity
- projectcontext
- projectworkflow
- quote
- squad
- storage
- stream
- workflowdef
chat:
- app/chatflow
- app/intentflow
- app/stageflow
- coordinator
- ctxmgr
- docgov
- intent
- projectinstance
- replyexport
- squad
- stream
- taskrun
config: []
coordinator:
- agent
- app/stageflow
- ctxmgr
- docgov
- intent
- kb
- maturity
- projectinstance
- squad
- stream
ctxmgr:
- app/uow
- docgov
- replyexport
- storage
db: []
docduty: []
app:
- agent
- app/chatflow
- app/docadvance
- app/docflow
- app/docnotify
- app/docproject
- app/intentflow
- app/stageflow
- app/uow
- artifactvault
- auth
- authz
- bizdev
- config
- coordinator
- ctxmgr
- docgov
- docrevision
- events
- freedoc
- intent
- kb
- notification
- observability
- projectinstance
- projectworkflow
- storage
- taskrun
- workflowdef
- workspace
app/chatflow:
- coordinator
- ctxmgr
- maturity
- projectinstance
app/docnotify:
- docgov
- docrevision
- notification
- events
app/docadvance:
- docgov
- events
- notification
- projectinstance
- projectworkflow
app/docproject:
- docgov
- events
app/docflow:
- app/uow
- docgov
- docquery
- docrevision
- events
app/intentflow:
- app/uow
- events
- intent
app/uow: []
app/stageflow:
- bizdev
docquery:
- docgov
- docrevision
docgov:
- app/uow
- doccontent
- docduty
- fsutil
docrevision:
- app/uow
- doccontent
- fsutil
doccontent: []
freedoc:
- app/uow
- ctxmgr
- docrevision
- replyexport
fsutil: []
httpx: []
intent:
- maturity
kb:
- config
maturity: []
notification: []
observability: []
projectcontext:
- squad
projectinstance:
- docduty
- docgov
- projectworkflow
- workflowdef
projectworkflow:
- auth
quote: []
replyexport: []
server:
- agent
- app
- app/chatflow
- app/docflow
- app/intentflow
- app/stageflow
- app/uow
- auth
- authz
- bizdev
- chat
- config
- coordinator
- ctxmgr
- docduty
- docgov
- docquery
- docrevision
- events
- freedoc
- httpx
- intent
- kb
- notification
- observability
- projectinstance
- projectworkflow
- replyexport
- storage
- squad
- stream
- stream/transport
- taskrun
- upload
- workflowdef
- workspace
- artifactvault
squad:
- agent
- config
- quote
- stream
- template
- workspace
storage: []
stream: []
stream/transport:
- stream
taskrun:
- app/uow
- artifactvault
- bizdev
- ctxmgr
- events
- projectworkflow
- stream
- workspace
template: []
upload: []
workflow: []
workflow/runtime:
- projectinstance
- workflowdef
workflowdef:
- projectworkflow
- storage
- upload
- workflow
agent: config
auth: config
authz: docduty
bizdev: authz,config,ctxmgr,db,docduty,docgov,docrevision,freedoc,kb,projectcontext,projectworkflow,quote,squad,storage,stream,workflowdef
chat: bizdev,coordinator,ctxmgr,docgov,intent,projectinstance,replyexport,squad,stream,taskrun
config:
coordinator: agent,bizdev,ctxmgr,docgov,intent,kb,projectinstance,squad,stream
ctxmgr: docgov,replyexport,storage
db:
docduty:
docgov: docduty,docrevision,fsutil
docrevision: fsutil
freedoc: ctxmgr,docrevision,replyexport
fsutil: ""
intent: bizdev
kb: config
notification:
observability:
projectcontext: squad
projectinstance: docgov,projectworkflow,workflowdef
projectworkflow: auth
quote:
replyexport:
server: agent,auth,authz,bizdev,chat,config,coordinator,ctxmgr,docduty,docgov,docrevision,freedoc,intent,notification,observability,projectinstance,projectworkflow,replyexport,squad,stream,taskrun,upload,workflowdef,workspace
squad: agent,config,quote,stream,template
storage:
stream:
taskrun: bizdev,ctxmgr,projectworkflow,stream
template:
upload:
workflow:
workflowdef: projectworkflow,storage,upload,workflow
workspace:
- app/uow
events:
- app/uow
artifactvault:
- app/uow
- fsutil
dataset:
- artifactvault
- app/uow
contracts:
table_owners:
document_records:
- docgov
chat_messages:
- ctxmgr
chat_turns:
- ctxmgr
freeform_documents:
- freedoc
task_runs:
- taskrun
task_run_manifests:
- taskrun
document_versions:
- docrevision
document_snapshots:
- docrevision
document_change_events:
- docrevision
event_envelopes:
- events
event_deliveries:
- events
event_dead_letters:
- events
event_inventory_decisions:
- events
event_repair_audit:
- events
event_replay_plans:
- events
event_service_principals:
- events
event_delivery_attempts:
- events
event_consumer_modes:
- events
event_consumer_checkpoints:
- events
event_reconciliations:
- events
event_projection_outcomes:
- app/docproject
notifications:
- notification
stage_advance_requests:
- notification
final_artifacts:
- artifactvault
artifact_payload_staging:
- artifactvault
artifact_blob_references:
- artifactvault
artifact_publication_attempts:
- artifactvault
artifact_deletion_ledger:
- artifactvault
artifact_quarantine:
- artifactvault
artifact_backfill_exclusions:
- artifactvault
dataset_registry:
- dataset
dataset_backfill_jobs:
- dataset
dataset_backfill_checkpoints:
- dataset
dataset_backfill_queue:
- dataset
dataset_destroy_requests:
- dataset
intent_plans:
- app/intentflow
intent_plan_steps:
- app/intentflow
intent_plan_decisions:
- app/intentflow
intent_plan_projections:
- app/intentflow
intent_plan_shadow:
- app/intentflow
document_records: docgov
chat_messages: ctxmgr
chat_turns: ctxmgr
freeform_documents: freedoc
task_runs: taskrun
path_owners:
output.md:
- squad
- workspace
data/dev:
- config
- workspace
- artifactvault
workspaces/:
- squad
- workspace
event_producers:
outbox.notify:
- docrevision
- app/docflow
document.agent_candidate_ready:
- docrevision
- app/docflow
- events
document.agent_version_committed:
- docrevision
- app/docflow
- events
- app/docproject
document.downstream_impact_detected:
- docrevision
- app/docflow
- events
document.change_report_degraded:
- docrevision
- app/docflow
- events
document.approved:
- app/docflow
- events
- app/docadvance
taskrun.completed:
- taskrun
taskrun.cancelled:
- taskrun
fav.artifact_staged:
- app/docflow
intent.plan.awaiting_input:
- app/intentflow
- events
intent.plan.step_changed:
- app/intentflow
- events
intent.plan.completed:
- app/intentflow
- events
event_consumers:
outbox.notify:
- app/docnotify
- notification
document.agent_candidate_ready:
- notify
document.agent_version_committed:
- projection
- notify
document.downstream_impact_detected:
- notify
document.change_report_degraded:
- notify
document.approved:
- workflow_advance
- notify
taskrun.completed:
- notify
taskrun.cancelled:
- notify
fav.artifact_staged:
- fav
intent.plan.awaiting_input:
- projection
- notify
intent.plan.step_changed:
- projection
- notify
intent.plan.completed:
- projection
- notify
unwrap_owners:
- docgov
- docrevision
- taskrun
- freedoc
- events
- artifactvault
- ctxmgr
- app/intentflow
exceptions:
- kind: sql_write
package: docduty
file: internal/docduty/revoke.go
symbol: document_records
owner: docduty
reason: duty slot revoke still writes reviewer/approver columns directly; fold into docgov repository during U3
milestone: U3
expires: "2026-09-28"
- kind: sql_write
package: docduty
file: internal/docduty/store.go
symbol: document_records
owner: docduty
reason: heal/store updates duty columns on document_records; move behind docgov repository in U3
milestone: U3
expires: "2026-09-28"
- kind: sql_write
package: docrevision
file: internal/docrevision/pg_store.go
symbol: document_records
owner: docrevision
reason: projectRootPointersTX updates controlled root pointers; U3 must keep this inside the shared UnitOfWork
milestone: U3
expires: "2026-09-28"
- kind: sql_write
package: docrevision
file: internal/docrevision/pg_store.go
symbol: freeform_documents
owner: docrevision
reason: projectRootPointersTX also projects freeform heads; keep atomic in U3 then hand write ownership back
milestone: U3
expires: "2026-09-28"
- kind: sql_write
package: projectinstance
file: internal/projectinstance/store.go
symbol: task_runs
owner: projectinstance
reason: workflow terminate cancels task_runs; U8 owns run finalization in the same UoW
milestone: U8
expires: "2026-10-26"
- kind: path
package: agent
file: internal/agent/cursor.go
symbol: output.md
owner: agent
reason: runner still names the deliverable file; U5 replaces this with WorkspaceRef
milestone: U5
expires: "2026-10-12"
- kind: path
package: agent
file: internal/agent/piagent.go
symbol: output.md
owner: agent
reason: PI runner contract still uses output.md; U5 capability must hide the literal
milestone: U5
expires: "2026-10-12"
- kind: path
package: bizdev
file: internal/bizdev/service.go
symbol: data/dev
owner: bizdev
reason: default data-root example string; U5 resolver owns environment roots
milestone: U5
expires: "2026-10-12"
- kind: path
package: bizdev
file: internal/bizdev/service.go
symbol: output.md
owner: bizdev
reason: orchestration still joins workspace output.md; U5 removes Root/OutputDir
milestone: U5
expires: "2026-10-12"
- kind: path
package: coordinator
file: internal/coordinator/context.go
symbol: output.md
owner: coordinator
reason: coordinator reads projection path; U4/U5 must go through workspace capability
milestone: U5
expires: "2026-10-12"
- kind: path
package: coordinator
file: internal/coordinator/dialogue_llm.go
symbol: data/dev
owner: coordinator
reason: prompt example embeds data/dev; U5 must not leak runtime roots
milestone: U5
expires: "2026-10-12"
- kind: path
package: coordinator
file: internal/coordinator/document_summary.go
symbol: data/dev
owner: coordinator
reason: summary prompt embeds data/dev; U5 must not leak runtime roots
milestone: U5
expires: "2026-10-12"
- kind: path
package: coordinator
file: internal/coordinator/engine.go
symbol: output.md
owner: coordinator
reason: engine joins deliverable path; U5 WorkspaceRef
milestone: U5
expires: "2026-10-12"
- kind: path
package: docgov
file: internal/docgov/lease.go
symbol: output.md
owner: docgov
reason: SaveDocumentContent still writes projection files; U5 capability + U4 ledger-first read
milestone: U5
expires: "2026-10-12"
- kind: path
package: docgov
file: internal/docgov/project_docs.go
symbol: output.md
owner: docgov
reason: project doc helpers still construct output.md; U5
milestone: U5
expires: "2026-10-12"
- kind: path
package: docrevision
file: internal/docrevision/projection.go
symbol: output.md
owner: docrevision
reason: InspectProjection reads workspace file; U4 treats this as optional cache only
milestone: U4
expires: "2026-09-28"
- kind: path
package: docrevision
file: internal/docrevision/reconcile.go
symbol: output.md
owner: docrevision
reason: reconcile still repairs projection files; U5
milestone: U5
expires: "2026-10-12"
- kind: path
package: server
file: internal/server/document_revision_access.go
symbol: output.md
owner: server
reason: handler still reads workspace files; U4 must use docquery ledger
milestone: U4
expires: "2026-09-28"
- kind: path
package: server
file: internal/server/document_revision_handlers.go
symbol: output.md
owner: server
reason: handler error text mentions output.md; U4/U5 remove path leakage
milestone: U4
expires: "2026-09-28"
- kind: path
package: server
file: internal/server/server.go
symbol: workspaces/
owner: server
reason: server still concatenates workspaces/ roots; U5
milestone: U5
expires: "2026-10-12"
- kind: path
package: storage
file: internal/storage/cas.go
symbol: data/dev
owner: storage
reason: CAS default example path; U5 resolver
milestone: U5
expires: "2026-10-12"
baseline_counts:
import: 0
sql_write: 5
path: 16
event: 0
# U12: kinds already at zero production findings fail --mode block.
# sql_write/path keep dated exceptions until their owner milestones clear them.
block_kinds:
- import
- event
output.md: squad,workspace
data/dev: config,workspace
workspaces/: squad,workspace
@@ -1,21 +0,0 @@
# U9 migration corpus 与八条轨道
八条 release 轨道(clean / oldest-supported / previous / hazard / import / reload / rollback / artifact recovery)的可执行夹具在:
- `internal/dataset/testdata/registry.json`(6–10 个批准 dataset:pinned / demo / regression / migration_baseline / ephemeral;quarantine 类不计入导入分母)
- `go test ./internal/dataset -run TestEightTracksPass`
## 轨道含义
| 轨道 | 验证 |
|------|------|
| clean | 空源 backfill 分母为 0 |
| oldest-supported | schema 28 可升级回填 |
| previous | schema 37(U8 节点)可回填 |
| hazard | 缺 snapshot、fork、高 ID、legacy-v0 → quarantine |
| import | 批准 registry 6–10 条 |
| reload | 重放不重复 artifact |
| rollback | 共享 DSN / 缺备份阻止 destroy;scratch 可过门禁 |
| artifact recovery | FAV recover-as-collection 只写 scratch |
回填枚举 SQL 只读 `document_snapshots` / `document_change_events` / `document_records` / `chat_turns`,禁止 `work_dir` 与 `workspaces/`。
@@ -15,7 +15,7 @@
- OS: Linux;Go 模块测试 + `cd web && npm test`
- PG 集成:`TEST_DATABASE_URL` 可用时执行 `chat_history_refresh_pg_test.go`
- 真实 PI E2E:dev `:8080` + 运行中 `pi-agent`(U9 镜像);脚本 `assets/2026-09-15-chat-history-refresh-live/chat-refresh-live.py`
- 真实 PI E2E:待 dev `:8080` + pi-agent 人工补录
## 四、 预期结果 (Expected Results)
@@ -59,12 +59,11 @@
- **Actual Output**: 192 tests PASS
- **Evaluation**: PASS
### 用例 F:真实 PI 闲聊刷新 E2E
### 用例 F:真实 PI 刷新 E2E
- **Input**: 运行中 dev `:8080` + `pi-agent`;新建项目 6252 / `sess-p6252-u10`;`POST /api/v1/chat` 后 `GET /api/v1/chat/messages/window` 与 `GET /api/v1/chat/categories`;guest 读同一 session。产物:`.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json`
- **Actual Output**: `agent_backend=pi-agent`,schema 38;闲聊 200(3481ms);window_msgs=2 且 category_total=2;guest 403 `SESSION_FORBIDDEN`。`core_overall=PASS`。文档任务 `PUT workflow-plan` 400,未跑 intake。
- **Evaluation**: 闲聊刷新同集与跨用户负例 **PASS**;激活后文档任务刷新仍开放
- **Duration**: 3704ms(core)
- **Input**: dev 环境文档生成 → 浏览器刷新
- **Actual Output**: 本轮未执行(需运行中 pi-agent 容器)
- **Evaluation**: DEFERRED — 合入 dev 后占集成槽位补录
## 六、 自动化测试套件汇总 (Test Suite Execution)
@@ -75,5 +74,5 @@ cd web && npm test → PASS (192)
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- 自动化、PG 与真实 PI 闲聊刷新同集已补证据;guest 403 成立。
- 发布门禁中的「激活后文档任务 + 重登/重启」仍未勾选。项目 143 只读,未用作活验样本。
- 代码与 PG 集成测试达到合并标准;真实 PI 刷新 E2E 需在 dev 容器冒烟后补证据。
- 合入后执行 `./scripts/env-service.sh dev restart` 并对 project 143 样本验证 backfill 效果。
@@ -59,18 +59,9 @@
### 用例 E:真实 PI + 浏览器刷新/双标签页
- **Input**: 新建项目 `INTENT双标签-061002`(id **6275**,**禁止 143**)/ `sess-p6275-u10`;Tab A `POST /api/v1/tasks/runs`「请开始编写用户初始需求表」真实 `pi-agent`;租约出现后 Tab B 再 POST;浏览器双标签打开同一项目
- **Actual Output**:
- health/ready schema **38**、`agent_backend=pi-agent`
- Tab A `202` `run_1789452602295343365` status=running;2ms 内 `lease_holder_type=squad`
- Tab B HTTP **409** `DOC_BUSY`,响应无 `run_id`;PG `task_runs` 仅 1 行
- 聊天窗 assistant `error_info.code=DOC_BUSY` 且 `actions=[]`,另有 `task_status=running` 占位;再次 GET window 同集
- 真实 PI **completed**(约 280s,质量 100);租约在终态探测后 **1ms** 已空(无需客户端刷新)
- 终态后再 GET window:DOC_BUSY 卡仍 `actions=[]`,无重试动作
- 浏览器(Docker Playwright,宿主机缺 libatk):双标签可见「本文档正由【项目助手】编辑/生成中」、聊天 `DOC_BUSY`、发送按钮 disabled、刷新后仍无重试。截图 `assets/2026-09-15-conversation-intent-dual-tab/screenshots/`
- **Evaluation**: **PASS**
- **性能与耗时**: API 活验 281s;Docker UI 4.4s。产物:`assets/2026-09-15-conversation-intent-dual-tab/live.json`、`playwright-docker.json`
- 诊断污染:`sess-p143-u9` **未**写入、未删除历史探针
- **Input**: 真实 PI 只读总结已执行;浏览器刷新/双标签页待执行
- **Actual Output**: 只读总结见用例 H;刷新和 busy 可见性尚无浏览器证据
- **Evaluation**: PARTIAL
### 用例 F:dev 集成冒烟
@@ -115,4 +106,4 @@ git diff --check PASS
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
代码级、构建门禁、真实 PI 只读总结与 **新建项目双标签 busy** 已通过。项目 **6275** / `run_1789452602295343365`:并发写 409 `DOC_BUSY` 不新增第二 run;刷新后 `actions=[]`;PI 终态后租约自动解除。浏览器双标签截图见 `assets/2026-09-15-conversation-intent-dual-tab/screenshots/`。真实会话 `sess-p143-u9` 中的诊断消息与误启动产物只记录证据,不在未获确认时删除或回滚。`production_ready` 仍为 no(CI 三工作流 E2E / 前端抽检等其它 blocker)。
代码级、构建门禁及真实 PI 只读总结已通过;原句不会创建任务或租约。最终 dev 镜像重建后 `/ready` 为 HTTP 200;只读复核确认用户原会话最大消息 ID 仍为 567、隔离 fixture 会话/消息/run 均为 0、project 143 无有效文档租约。尚不能标记发布完成:浏览器刷新恢复、双标签页租约可见性与并发写“不新增第二 run”仍需补录。真实会话中的诊断消息与误启动产物只记录证据,不在未获确认时删除或回滚。
@@ -1,131 +0,0 @@
# 文档可靠性 M2(U5–U7)测试报告
## 一、 测试背景 (Background)
M1 活验报告最后一句为 **继续 M2**([2026-09-14-document-reliability-pilot-live-test-report.md](./2026-09-14-document-reliability-pilot-live-test-report.md))。上一份「停止扩面」试点报告保持原句,不改写。本轮只实施并验证 U5 WorkspaceRef、U6 耐久投递、U7 按文件摘取 FAV,并给出能否开工 M3 的停走句。
## 二、 测试目标 (Test Objectives)
- 2/4 dispatcher 无双 owner;crash-before/after-side-effect/ack 可恢复。
- 乱序 aggregate version 不越过缺号。
- 跨项目事件 / 坏 digest / 伪造 producer → quarantine;auth/integrity 立即死信;attempt 12 后死信。
- `SKIP LOCKED` 只用于 claim。
- 业务终态、staging、outbox 同事务;失败回滚无泄漏。
- union-deny;中间态(prompt/tool_trace/scratch)准入率 0。
- `FAV_DEGRADED_READ` 默认 false;授权成功之后才允许 degraded read。
- Goose 00034–00036 重取号;组合 Up+Down;禁止把 FAV 树的 00034 原样合入。
- 占槽后主仓 rebuild;health/ready 为 schema 36,无路径泄漏。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| Go | 本机 `go test`;容器 `agent-dev-app` |
| 合入 | 主仓 `dev` `--no-ff` `refactor/document-reliability-pilot` → `0872d8f` |
| 部署 | 主仓 `./scripts/env-service.sh dev rebuild`(禁止 worktree 内 env-service;禁止 `compose restart` 当证据) |
| Compose | 项目 `agent-dev`,HTTP `:8080` |
| Agent | `agent_backend=pi-agent` |
| Schema | **36**(00034 fencing + 00035 envelopes + 00036 FAV) |
| `FAV_DEGRADED_READ` | 宿主与容器均 unset / 默认 false |
| PostgreSQL | 隔离库 `agent_rel_m2`(`shuimu-system-pg-test:5434`),另建 `agent_rel_m2_goose` 做 Down;测完 `DROP`;禁止 `agent_system_dev/test/main` |
| 项目 143 | **只读**;本轮未 terminate,未改 workflow-plan |
| 证据 | `.doc/test-reports/assets/2026-09-14-document-reliability-m2/` |
镜像身份:`app_image=sha256:8ab9f63a05274e08d55322e162f8fec3f5822bd3e14375376df856308329b511`。见 `rebuild-health-ready.txt`。
## 四、 预期结果 (Expected Results)
| 栏 | 期望 |
|----|------|
| Unit | WorkspaceRef 无物理路径;旧 fencing 被拒;事务内禁止文件 I/O;2/4 dispatcher 单 owner;gap 不跳号;中间态准入 0 |
| PostgreSQL | 00034–00036 Down 到 33 后再 Up;outbox+staging 同 TX,失败零泄漏 |
| 故障注入 | crash-before/after ack 无双副作用;attempt 12 死信 |
| 真实 PI | 本轮不重跑编制;rebuild 后 ready 仍为真实 `pi-agent` |
| 真实浏览器 | 本轮不重跑 Playwright;web 单测 + production build 必须绿 |
| restart/rebuild | health/ready `status=ok`,`schema_version=36`,无路径泄漏,vault 未配置不假绿 |
| 跨用户 / 授权 | 授权失败不碰 vault;tombstone union-deny |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 Unit / stub
- **测试输入**: `unset TEST_DATABASE_URL; go test -short ./...`;目标包 `go test -race -short`;`./scripts/arch-check.sh --mode warn`
- **实际输出**: 全仓 short 包 `ok`。目标包 race:`TestTwoAndFourWorkersNoDoubleOwner`、`TestCrashBeforeAfterAck`、`TestGapDoesNotSkipVersion`、`TestQuarantineBadDigestForgedProducerCrossProject`、`TestAttempt12GoesDeadLetter`、`TestStaleFencingRejected`、`TestEvaluateEligibility_IntermediateAdmissionZero`、`TestTombstoneUnionDeny`、`TestFavDegradedReadDefaultOff` 均为 PASS。`arch-check warn: production gate passed`。`--mode block` 仍会因既有 path/sql_write 例外基线失败(U1 设计;本里程碑新增 import 已清零)。
- **评价判定**: **PASS**
- **性能与耗时**: 全仓 short 约 13s;目标包 race 约 3–4s。日志:`go-test-short.txt`、`go-test-m2-packages-race.txt`、`arch-check-warn.txt`
### 5.2 PostgreSQL 事务与并发
- **测试输入**: 隔离库 `TEST_DATABASE_URL` → `TestGooseM2_00034to00036_DownThenUp`、`TestOutboxAndStagingSameTxRollback`
- **实际输出**:
```
--- PASS: TestGooseM2_00034to00036_DownThenUp (0.36s)
--- PASS: TestOutboxAndStagingSameTxRollback (0.01s)
```
00034–00036 Up 到 36,Down 到 33 后 `event_envelopes`/`final_artifacts`/`lease_fencing_token` 消失,再 Up 回 36。同 UoW 写入 envelope + FAV staging 后故意 `boom`,回滚后两表计数为 0。测完 `DROP DATABASE agent_rel_m2`(goose 子库随测试 Cleanup DROP)。
- **评价判定**: **PASS**
- **性能与耗时**: goose 组合约 0.36s。日志:`goose-00034-36-down-up.txt`
### 5.3 故障注入
- **测试输入**: 内存 dispatcher crash/lease 过期/重放;attempt 12;目标包 `-race`
- **实际输出**: 过期 worker ack 为 `ErrStaleFencing`;后到 worker 副作用恰好 1;inbox 去重。12 次瞬时失败后 status=`dead`。
- **评价判定**: **PASS**
- **性能与耗时**: 亚秒。日志:`go-test-m2-packages-race.txt`
### 5.4 真实 PI
- **测试输入**: 本轮不新编制文档。检查 rebuild 后 `/api/v1/ready` 的 `agent_backend`
- **实际输出**: `agent_backend=pi-agent`,不是 stub。编制活验仍以 M1 报告为准。
- **评价判定**: **PASS**(继承 M1 活验;本轮验证后端身份与 schema 36 ready)
- **性能与耗时**: health/ready 亚秒
### 5.5 真实浏览器
- **测试输入**: 本轮未重跑 Playwright(项目 143 只读约束仍在)。`web`:`npm test` + `npm run build`
- **实际输出**: tsx **365 passed / 0 fail**;vitest **30 passed**;production build `✓ built in 8.07s`(容器 rebuild 内 web build 同样成功)。
- **评价判定**: **PASS**(页面回归以 M1 活验为准;本轮前端门禁绿)
- **性能与耗时**: 单测约 1.4s + vitest 0.5s;本地 build 约 8s。日志:`web-unit.txt`、`web-build.txt`
### 5.6 restart / rebuild
- **测试输入**: 占集成槽后主仓 `./scripts/env-service.sh dev rebuild`;`curl -sf http://127.0.0.1:8080/api/v1/health` 与 `/api/v1/ready`
- **实际输出**: 两者 HTTP 200,body 均为
```
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"database_ready":true,"schema_version":36,"schema_ready":true,"task_store_ready":true}
```
无文件系统路径字段。vault 未配置时 ready 仍按 DB/schema/task_store 判定。
- **评价判定**: **PASS**
- **性能与耗时**: rebuild 约 27s。日志:`rebuild-health-ready.txt`、`health.json`、`ready.json`
### 5.7 跨用户 / 授权负例
- **测试输入**: `TestFavDegradedReadOnlyAfterAuthorize`;`TestTombstoneUnionDeny`;跨项目 envelope Apply
- **实际输出**: 授权失败时 vault `calls=0`;tombstone 读为 `ErrUnionDeny`;跨项目 delivery 为 `quarantine`
- **评价判定**: **PASS**
- **性能与耗时**: 亚秒
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS |
| `go test -short ./...` | PASS |
| 隔离库 goose Down/Up + 同事务回滚 | PASS,随后 `DROP DATABASE` |
| 目标包 `-race` | PASS |
| `arch-check --mode warn` | PASS |
| `arch-check --mode block` | 仍因既有例外基线失败(预期;非本里程碑新增违规) |
| web `npm test` | 365 + 30 PASS |
| web production build | PASS |
| 占槽 rebuild + health/ready | PASS,`schema_version=36` |
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
U5–U7 的停走项在本轮全部观测为 PASS:dispatcher 无双 owner,崩溃与过期 fencing 可恢复,缺号不跳过,坏 digest/伪造 producer/跨项目进入 quarantine,FAV 中间态准入为 0,union-deny 生效,outbox 与 staging 同事务回滚,Goose 00034–00036 可 Down。`document.agent_version_committed` 已从 `OnOutbox` 正确性路径摘除,改由 `events.EventSink` 在 UoW 内追加。剩余 agent/coordinator 的 `output.md` 字面量仍是 U1 例外基线,属 M3 Workspace 清理范围,不构成本轮扩面失败。未把 `feature/final-artifact-vault` 整支 merge,未启用 `FAV_DEGRADED_READ`。
继续 M3
@@ -1,137 +0,0 @@
# 文档可靠性试点 M1 活验签字测试报告
## 一、 测试背景 (Background)
上一份 [M1 试点报告](./2026-09-14-document-reliability-pilot-test-report.md) 在 Unit/隔离库通过后,因未占槽 rebuild、无真实 PI/浏览器/4 会话而把最后一句写成 **停止扩面**。本轮不改写那份结论句;只补活验签字,决定能否开工 U5–U7。
## 二、 测试目标 (Test Objectives)
- A1:占集成槽,本地 `dev` `--no-ff` 合入试点分支,`env-service.sh dev rebuild`,health+ready 来自本分支镜像。
- A2:项目 143 只读打开/刷新/重登;新建项目打开/刷新/重登;`GET .../content` 为 200 且带 `consistency`;禁止把 missing 当 404。
- A3:真实 `pi-agent` + MiniMax 编制一条受控文档,刷新不丢正文。禁止 stub 当终态。
- A4:隔离库两个 pgx pool + 4 会话同 ETag 一赢,同 key+digest 跨 pool 重放。测完 `DROP DATABASE`。
- A5:分栏签字;最后一句只能是「继续 M2」或「停止扩面」。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| Go | 本机 `go test`;容器 `agent-dev-app` |
| 合入 | 主仓 `dev` `--no-ff` `refactor/document-reliability-pilot` → `cb8eaca` |
| 部署 | 主仓 `./scripts/env-service.sh dev rebuild`(禁止 `compose restart` 当证据) |
| Compose | 项目 `agent-dev`,HTTP `:8080` |
| Agent | 真实 `pi-agent`(`AGENT_BACKEND=pi-agent`),模型 `MiniMax-M2.7-highspeed`(云端 API,非 stub) |
| Schema | **33** |
| `FAV_DEGRADED_READ` | unset / 默认 false |
| 浏览器 | `mcr.microsoft.com/playwright:v1.63.0-noble`,`--network host --ipc host` |
| PostgreSQL | 隔离库 `agent_rel_itest`(`shuimu-system-pg-test:5434`),测完 `DROP`;禁止 `agent_system_dev/test/main` |
| 项目 143 | **只读**;未 terminate,未 `PUT /143/workflow-plan` |
| 证据 | `.doc/test-reports/assets/2026-09-14-document-reliability-pilot-live/` |
镜像身份(rebuild 后):`app_image=sha256:251fa99d5de47d452b7f099304aa34b1e2aacf1b4e9d2d23d1cb4b850084910e`;随后把 `pi-agent` force-recreate 到 rebuild 所打的 `sha256:21fc9b64066c33e94d8db83695b4ff64ea5e49f6d65661f8ccab11ead083042d`。见 `rebuild-health-ready.txt`。
## 四、 预期结果 (Expected Results)
| 栏 | 期望 |
|----|------|
| Unit / stub | `go test -short` 全绿;hydrate 把 `missing` 当正文 |
| PostgreSQL | 双 pool 同 ETag 一赢;同 key+digest 跨 pool 重放;4 会话同 ETag 一赢 |
| 故障注入 | 与上一份隔离库 U2 一致,本轮 `-race` 再跑目标包 |
| 真实 PI | 新建项目激活后编制,账本 head 可读 |
| 真实浏览器 | 143 与新项目刷新/重登 200 + markdown;页面无「加载失败」;无 PROJECTION 409 |
| restart/rebuild | health/ready `status=ok`,`agent_backend=pi-agent`,`schema_version=33`;ready 不因 vault 未配置假绿,响应无路径泄漏 |
| 跨用户 | 匿名 401;非成员/跨项目/错误 stage-duty 同一 404 `DOCUMENT_NOT_FOUND` |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 Unit / stub
- **测试输入**: `unset TEST_DATABASE_URL; go test -short ./...`;`npx tsx --test src/lib/controlledDocHydrate.test.ts`;`./scripts/arch-check.sh --mode warn`
- **实际输出**: 全仓 short 包 `ok`;hydrate **17 passed**;`arch-check warn: production gate passed`
- **评价判定**: **PASS**
- **性能与耗时**: `internal/server` 约 9.6s。日志:`go-test-short.txt`、`hydrate-unit.txt`、`arch-check-warn.txt`
### 5.2 PostgreSQL 事务与并发
- **测试输入**: 隔离库 `TEST_DATABASE_URL` → `./internal/docrevision -run 'TestDocumentCommitConcurrencyPG|TestDocumentCommitTwoPoolsAndFourSessionsPG'`
- **实际输出**:
```
--- PASS: TestDocumentCommitConcurrencyPG (0.03s)
--- PASS: TestDocumentCommitTwoPoolsAndFourSessionsPG (0.03s)
```
两个独立 `pgxpool` 打同一 ETag 仅一赢;赢家 key+digest 跨 pool 重放 head 一致;随后 4 个会话同 ETag 仅一赢。测完 `DROP DATABASE agent_rel_itest`。
- **评价判定**: **PASS**(不是 4 个 OS 进程,是计划要求的双 pool 模拟两进程 + 4 会话;未使用进程内全局 mutex)
- **性能与耗时**: 62ms。日志:`go-test-pg-two-pool.txt`
### 5.3 故障注入
- **测试输入**: `go test -race ./internal/app/uow ./internal/app/docflow ./internal/docquery`(同一隔离库,DROP 前)
- **实际输出**: 三包 `ok`(含 cached)
- **评价判定**: **PASS**
- **性能与耗时**: 亚秒到约 1.8s
### 5.4 真实 PI
- **测试输入**: Playwright 新建项目 → 未激活编制被 202 `blocked_pending_governance` → 配置并激活 → 发送「请基于本项目编制首轮《用户需求》摸底文档…」→ 等待小队终态 → 打开 `doc_proj*` intake
- **实际输出**: 编制用例 **4.2min PASS**。`GET /api/v1/docgov/documents/{id}/content` **200** 且 `markdown` 非空;刷新与重登正文相同。截图 `07-new-doc.png` / `08-new-doc-reload.png` / `09-new-doc-relogin.png`
- **评价判定**: **PASS**(真实 `pi-agent`,非 stub)
- **性能与耗时**: 编制+打开约 4.2min
### 5.5 真实浏览器
- **测试输入**: `RUN_UI_ACCEPTANCE=1 BASE_URL=http://127.0.0.1:8080`;`web/e2e/controlled-document-reload.spec.ts`(官方 Playwright 镜像)
- **实际输出**:
```
✓ project 143 content is 200 with consistency; anonymous is 401; unknown is 404 (4.6s)
✓ non-member GET of project 143 is the same 404 as unknown (7.4s)
✓ new project PI compile then reload keeps ledger markdown (4.2m)
✓ cross-project and wrong-stage GET stay DOCUMENT_NOT_FOUND (3.8s)
4 passed (4.5m)
```
143 打开/刷新/重登均为 200 + markdown + typed `consistency`,无 `PROJECTION` 409,页面无「加载失败」。未对 `/143/` 发 `PUT workflow-plan`,未 terminate。
- **评价判定**: **PASS**
- **性能与耗时**: 整套 4.5min。日志:`playwright-controlled-reload.txt`;截图 `screenshots/01`–`10`
### 5.6 restart / rebuild
- **测试输入**: 占槽后 `./scripts/env-service.sh dev rebuild`;`curl -sf http://127.0.0.1:8080/api/v1/health` 与 `/api/v1/ready`
- **实际输出**: 两者 HTTP 200,body 均为
```
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"database_ready":true,"schema_version":33,"schema_ready":true,"task_store_ready":true}
```
无文件系统路径字段。vault 未配置时 ready 仍按 DB/schema/task_store 判定,不是假绿。
- **评价判定**: **PASS**
- **性能与耗时**: rebuild 约 79s。日志:`rebuild-health-ready.txt`、`health.json`、`ready.json`
### 5.7 跨用户负例
- **测试输入**: 匿名 GET 143;局外人 D GET 143 与新项目文档;审核人 B GET 143 与伪造 `_design_control` stage
- **实际输出**: 匿名 **401**;其余均为 **404** `DOCUMENT_NOT_FOUND`,不泄露存在性
- **评价判定**: **PASS**
- **性能与耗时**: 3.8s。截图 `10-fail-closed.png`
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS(合入后、rebuild 前) |
| `go test -short ./...` | PASS |
| 隔离库双 pool / 4 会话 | PASS,随后 `DROP DATABASE` |
| 目标包 `-race` | PASS |
| `arch-check --mode warn` | PASS |
| hydrate 单测 | 17/17 PASS |
| Playwright 活验(官方镜像) | **4 passed** |
| 宿主 `npx playwright` | 因缺 `libatk-1.0.so.0` 无法启动;改走已验证的 `mcr.microsoft.com/playwright:v1.63.0-noble` |
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
活验补齐了上一份报告缺的 rebuild、真实 PI、真实浏览器、双 pool/4 会话与 HTTP 跨用户负例。hazard 真页面 404/409/projection-missing 本轮观测为 0;授权未靠放宽;4 会话赢家来自数据库锁而非进程内 mutex。M1 签字通过,允许按计划实施 U5–U7。上一份「停止扩面」报告保持原句,不改写。
继续 M2
@@ -1,132 +0,0 @@
# 文档可靠性纵向试点(M0–M1 / U1–U4)测试报告
## 一、 测试背景 (Background)
受控文档写路径曾把账本、root pointer 与通知拆到提交后回调;读路径在 ledger 已存在时仍被 `InspectProjection` 绑架成 409。刷新、重登或 projection 缺失会被前端当成 404 再 hydrate。本轮只批准 M0–M1(U1–U4):门禁纠偏、UnitOfWork、文档命令同事务、授权后账本读。明确不授权 FAV 降级读、拆 chat/squad、占槽 rebuild。
## 二、 测试目标 (Test Objectives)
- U1:四类生产规则可重放;新违规 block;Goose/`*_test.go` 不记生产写者债。
- U2:跨属主同事务;第二属主/staging/commit 失败零残留;仅 `40001`/`40P01` 整事务重试。
- U3:人工编辑 / agent commit / approve / reject 锁后重鉴权;同 ETag 一赢一输。
- U4:projection missing/drift/empty 仍返回账本正文 + typed `consistency`;GET 零写入。
- 分栏必须各自签字。未占集成槽不得把 `:8080` 旧镜像或 `docker compose restart` 写成 rebuild 证据。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| Go | 1.27.1 |
| 分支 / worktree | `refactor/document-reliability-pilot` / `.worktrees/refactor-document-reliability-pilot` |
| 实现基线 | `dev@a8f9451` → `c754f77`(另含本报告前的 `fix(docflow)` 竞态修复) |
| Unit / stub | `go test -short ./...`(**未**设置 `TEST_DATABASE_URL`) |
| PostgreSQL | 隔离库 `agent_rel_itest`(`shuimu-system-pg-test:5434`),测完 `DROP DATABASE`;禁止 `agent_system_dev/test/main` |
| 目标包 race | `./internal/app/uow ./internal/app/docflow ./internal/docquery ./internal/archtest` |
| 前端 | `npx tsx --test src/lib/controlledDocHydrate.test.ts`(17 passed) |
| 真实 PI / 浏览器 / rebuild | **未执行**。集成槽 idle;CURRENT 禁止 M1 未签字 rebuild;`:8080` 仍是治理鉴权旧镜像,不能当本分支证据 |
| 证据 | `.doc/test-reports/assets/2026-09-14-document-reliability-pilot/` |
## 四、 预期结果 (Expected Results)
| 栏 | 期望 |
|----|------|
| Unit / stub | 全绿;arch-check `--mode warn` 过门;characterization 同 ETag 一赢、approve/reject 唯一终态 |
| PG 事务与并发 | U2 故障注入绿;同 ETag 双会话 HumanEdit 仅一赢;head revision=1 |
| 故障注入 | 第二属主失败 / staging 失败 / commit 失败零行;`40001` 整事务重跑一条结果 |
| 真实 PI | 本分支容器内真实 `pi-agent` 全链路。**本轮不做** |
| 真实浏览器 | 项目 143 等价 hazard + 新建项目打开/刷新/重登正文 100%,404/409/projection-missing=0。**本轮不做** |
| restart/rebuild | 占槽后 `env-service.sh dev rebuild`。**本轮不做** |
| 跨用户负例 | 匿名/未知文档/授权拒绝 → `docquery.ErrClosed`,不泄露存在性 |
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### 5.1 Unit / stub
- **测试输入**: `go test -short ./...`
- **实际输出**: 38 个有测试包 `ok`,无 `FAIL`。摘录:
```
ok chat-agent-system/internal/app/docflow
ok chat-agent-system/internal/app/uow
ok chat-agent-system/internal/archtest
ok chat-agent-system/internal/docquery
ok chat-agent-system/internal/docrevision
ok chat-agent-system/internal/server 9.796s
```
- **评价判定**: **PASS**
- **性能与耗时**: `internal/server` 约 9.8s,其余亚秒到数秒。日志:`assets/2026-09-14-document-reliability-pilot/go-test-short.txt`
`./scripts/arch-check.sh --mode warn` → `arch-check warn: production gate passed`。`--mode block` 仍会因既有例外基线失败(U1 设计如此)。
### 5.2 PostgreSQL 事务与并发
- **测试输入**: 隔离库 `TEST_DATABASE_URL` → `./internal/app/uow`、`./internal/app/docflow`、`./internal/docquery`;`./internal/docrevision -run TestDocumentCommitConcurrencyPG`
- **实际输出**:
```
ok chat-agent-system/internal/app/uow 0.065s
ok chat-agent-system/internal/app/docflow 0.003s
ok chat-agent-system/internal/docquery 0.003s
ok chat-agent-system/internal/docrevision 0.024s
```
- **评价判定**: **PASS**(1–2 会话级)。**未**跑 4 个独立 app 进程。
- **性能与耗时**: UoW 包 65ms;并发编辑 24ms。日志:`go-test-pg-race.txt`
### 5.3 故障注入
- **测试输入**: `internal/app/uow` PG 用例(第二属主失败、staging/outbox 失败、commit 失败、`40001` 重试、version/permission/digest 不重试)
- **实际输出**: `ok chat-agent-system/internal/app/uow 0.065s`
- **评价判定**: **PASS**
- **性能与耗时**: 与 5.2 同一次隔离库运行
### 5.4 真实 PI
- **测试输入**: 未切本分支容器,未跑真实 `MiniMax-M2.7-highspeed` 编制链路
- **实际输出**: 无
- **评价判定**: **FAIL(未测)** — 禁止用 stub 冒充终态
- **性能与耗时**: n/a
### 5.5 真实浏览器
- **测试输入**: 未对项目 143 / 新建项目做本分支页面打开、刷新、重登
- **实际输出**: 仅前端单测 17/17(`hydrate treats projection missing as ledger content, not 404`)
- **评价判定**: 单测 **PASS**;真实页面 **FAIL(未测)**
- **性能与耗时**: hydrate 套件 149ms
### 5.6 restart / rebuild
- **测试输入**: 未占集成槽,未执行 `./scripts/env-service.sh dev rebuild`
- **实际输出**: 无。`:8080` 仍为既有 dev 镜像(治理鉴权 G5),不得当作本分支部署证据
- **评价判定**: **FAIL(未测)**
- **性能与耗时**: n/a
### 5.7 跨用户负例
- **测试输入**: `TestGetFailClosed`(匿名、Authorize 拒绝、未知 doc_id);`TestReauthDeniesWrongAuthor`;`TestBatchGetLimitsAndCrossProject`(101 条 / 跨项目)
- **实际输出**: 均失败关闭;未知文档与拒绝同一 `ErrClosed`
- **评价判定**: 服务端单测 **PASS**。HTTP 跨登录浏览器负例 **未测**
- **性能与耗时**: 亚秒
## 六、 自动化测试套件汇总 (Test Suite Execution)
| 命令 | 结果 |
|------|------|
| `go vet ./...` | PASS(U4 提交前) |
| `go test -short ./...` | PASS,38 ok |
| 隔离库 `go test ./internal/app/uow ./internal/app/docflow ./internal/docquery` | PASS |
| `go test ./internal/docrevision -run TestDocumentCommitConcurrencyPG` | PASS |
| `go test -race` 目标包 | PASS(修复 `Commands.Auth` 并发写入后) |
| `arch-check --mode warn` | PASS |
| `tsx --test controlledDocHydrate.test.ts` | 17 passed |
| 全仓 `go test`(带 `TEST_DATABASE_URL` 且无 `-short`) | 未作为本报告门禁;会把无关 workflow PG 和「5434=共享 test 口」拒绝用例搅在一起 |
`-race` 初跑曾在 `run()` 里给共享 `Commands.Auth` 赋值,判定为数据竞争;已改为只读 `authorizer()`。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
U1–U4 代码已在实现分支落地,Unit/stub、隔离库事务/故障注入、目标包 race 与前端 hydrate 单测通过。用户可感知的主修复(ledger-first GET)**没有**真实 PI、真实浏览器、restart/rebuild 签字;1/2/4 进程一致性只验证到双会话。按计划停走门,不得用「部分通过」打开 U5–U12。
停止扩面
@@ -1,172 +0,0 @@
# 治理鉴权升级(职责-动作 + 未激活 202-blocked)测试报告
## 一、 测试背景 (Background)
Wave 5 已收口冻结态与 DutyMode,但 full 文档仍因创建者隐式全通行、未激活 run 仍可能拉起小队、`initial_workflow_key` 仍可能直通 active。本轮按已锁定矩阵落地动作-职责鉴权、未激活 202-blocked、关闭创建直通,并在真实 `pi-agent` 开发栈做页面 + API 负例验收。项目 143 **只打开设置/文档做只读回归,未终止、未改规划**。
## 二、 测试目标 (Test Objectives)
- 零治理新项目可普通对话;编制类文档任务 202 + `blocked_pending_governance`,chat 出现固定治理提示,无 workspace / 小队。
- 一份 full + 其余 none 可激活;激活确认页提示「不纳入人工审批的文档激活后不可补配三职」。
- 负例:author/creator 不可审核或批准 full;reviewer 不可 run/submit full;none 无送审/审核/批准;创建者可对处于当前阶段的 none 触发生成。
- `POST /projects` 带 `initial_workflow_key` 仍 `planning`、空 `active_workflow_key`,目录仍挂上;旧切换 API 不能直切 active。
- 项目 143 设置页仍 frozen,不点终止。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| 浏览器 | `mcr.microsoft.com/playwright:v1.63.0-noble`,`--network host --ipc host`,`BASE_URL=http://127.0.0.1:8080` |
| 服务 | 开发环境 `:8080`;rebuild 后 `GET /api/v1/health` → `status=ok`,`env=dev`,`agent_backend=pi-agent`,`schema_version=33` |
| Agent | 真实 `pi-agent`(闲聊走对话后端;未激活编制走 202-blocked,不启小队) |
| 分支 / worktree | `fix/governance-action-level-authz` / `.worktrees/fix-governance-action-level-authz` |
| 合入 | 独立 merge worktree `/tmp/as-dev-wf409-merge` 对本地 `dev` `--no-ff`;编码 worktree **未**执行 `env-service.sh` |
| 脚本 | `web/e2e/governance-action-level-authz.spec.ts`(`RUN_UI_ACCEPTANCE=1`);API 旁证 `assets/.../g5_api_matrix.py` |
| 末次页面矩阵 | **1 passed / 12.9s**(用例墙钟 12.3s) |
| 本轮页面项目 | `GOVAUTH-mu0z*`(管理员新建立项 + 两名协作者;口令不入库) |
| API 旁证项目 | `6209` planning keyed create;`6210` full+none 激活;`6211` 首阶段 none 生成 |
| 对照项目 | 143「对话协同会话」(只读) |
| 证据 | `.doc/test-reports/assets/2026-09-14-governance-action-level-authz/screenshots/` 与 `api-matrix.json` |
未在编码 worktree 内执行 `env-service.sh`。
### 用例矩阵
| ID | 输入 | 期望 |
|----|------|------|
| UI-01 | 零治理创建 | 顶栏可见新项目,可配置工作流 |
| UI-02 | 「今天天气如何,先闲聊一句。」 | 用户消息 + 助手回复,不走任务 run |
| UI-03 | 「请编制用户初始需求收集表」 | 202 blocked、固定治理提示、「待激活工作流」 |
| UI-04 | 首份 full + 其余关审批 → 预览 | 冻结提示「不可补配三职」后激活成功 |
| UI-05 | 打开非编制文档 | 无送审/审核/批准(none 隐藏审批条) |
| UI-06 | 打开 143 设置 | frozen + 「确认终止当前实例」可见但**未点击** |
| API-01 | `POST /projects` + `initial_workflow_key=main` | 201 `planning`,空 key;`PUT /active-workflow` 410 |
| API-02 | 未激活 `POST /tasks/runs` intake | 202 `blocked_pending_governance`,空 workspace |
| API-03 | 未激活 submit/review/approve | 403 `WORKFLOW_NOT_ACTIVATED` |
| API-04 | 激活一份 full + 其余 none | `lifecycle=active` |
| API-05 | 职责负例 + 创建者 run none | 403 `DOC_DUTY_FORBIDDEN`;none 生成 202 running(随即 cancel) |
| API-06 | `GET /projects/143/settings` | live instance,`can_edit_plan=false` |
页面编制话术使用「请编制用户初始需求收集表」:产品里「帮我生成立项文档」会走私密草稿捷径,不会 `POST /tasks/runs`。
## 四、 预期结果 (Expected Results)
未激活:view/闲聊放行;run 建 blocked run 并写固定文案;审批流动作 4xx。激活后 full 只认对应职责,创建者不再越权;none 无审批按钮;当前阶段 none 允许创建者 run。创建带 key 不升 active。项目 143 保持运行中冻结。
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### UI-01 零治理创建
- **测试输入 (Input)**:管理员开通两名协作者后立项 `GOVAUTH-mu0z*`。
- **实际输出 (Actual Output)**:顶栏「当前项目」为新项目;侧栏出现该会话。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `01-zero-gov-created.png`。
### UI-02 普通对话
- **测试输入 (Input)**:`今天天气如何,先闲聊一句。`
- **实际输出 (Actual Output)**:用户气泡与助手闲聊回复可见;未出现治理拦截条。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `02-casual-chat.png`。
### UI-03 未激活编制 → 202 blocked
- **测试输入 (Input)**:`请编制用户初始需求收集表`
- **实际输出 (Actual Output)**:助手气泡为「当前项目尚未激活工作流,文档任务不会启动。请先在设置中配置并激活至少一份纳入人工审批的文档。」;状态「待激活工作流」。`POST /api/v1/tasks/runs` 捕获 202 + `blocked_pending_governance`。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `03-blocked-generate.png`。
首轮页面跑曾因 `chk_task_run_status` 拒收新状态而 500 / `NETWORK_ERROR`。补 `00033` 后复测通过。
### UI-04 激活一份 full + 其余 none
- **测试输入 (Input)**:配置工作流:首份纳入审批并填三职,其余关闭;校验并预览 → 确认激活。
- **实际输出 (Actual Output)**:预览含「不纳入人工审批的文档激活后不可补配三职」;激活后顶栏「运行中」。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `04-activation-confirm.png`、`05-activated-full-none.png`。
### UI-05 按钮级职责门禁
- **测试输入 (Input)**:打开调研/法规等非编制文档。
- **实际输出 (Actual Output)**:无「提交送审」;截图见文档栏与动作条。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `06-duty-gated-actions.png`。
### UI-06 项目 143 只读
- **测试输入 (Input)**:侧栏打开「对话协同会话」→「查看工作流设置」。
- **实际输出 (Actual Output)**:「当前工作流已冻结,只读查看」;「确认终止当前实例」可见,**未点击**。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `07-project-143-readonly.png`。
### API-01 创建不再直通 active
- **测试输入 (Input)**:`POST /api/v1/projects` `{"name":"GOVAUTH-API-KEYED-*","initial_workflow_key":"main"}`;再 `PUT /active-workflow`。
- **实际输出 (Actual Output)**:201,`id=6209`,`lifecycle=planning`,`active_workflow_key=""`,workflows HTTP 200;切换 410 `WORKFLOW_SWITCH_API_RETIRED`。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:26ms。
### API-02 / API-03 未激活 run / 审批
- **测试输入 (Input)**:对 6209 发 intake run;对 `doc_proj6209_intake` 发 submit/review/approve。
- **实际输出 (Actual Output)**:run 202 `run_1789375353946456022` / `blocked_pending_governance`;GET 无 workspace。库:`status=blocked_pending_governance`,`workspace_id` 空。审批三接口 403 `WORKFLOW_NOT_ACTIVATED`。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:run 13ms。
### API-04 / API-05 激活与职责负例
- **测试输入 (Input)**:6210 激活 intake=full、其余 none;审核人 run/submit;创建者 review/approve;再对 6211(intake=none + 后续 full)由创建者 run intake。
- **实际输出 (Actual Output)**:6210 `lifecycle=active`。审核人/创建者审批 403 `DOC_DUTY_FORBIDDEN`。后期 none 的 submit 403 `DOC_TASK_NOT_IN_ACTIVE_STAGE`(当前 `V0.1_triage`)。6211 创建者 run none → 202 `running`(随即 cancel,避免长 PI)。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:激活 461ms;负例合计 43ms。
### API-06 项目 143
- **测试输入 (Input)**:`GET /api/v1/projects/143/settings`
- **实际输出 (Actual Output)**:`lifecycle=active`,`has_live_instance=true`,`can_edit_plan=false`。未调用终止。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:7ms。
## 六、 自动化测试套件汇总 (Test Suite Execution)
在 feature worktree(合入前):
```text
go vet ./...
go test -short ./...
go test -short -race ./internal/projectinstance ./internal/projectworkflow ./internal/server
cd web && npm test && npm run build
```
G5 复测(rebuild 后,2026-09-14):
```text
$ curl -sf http://127.0.0.1:8080/api/v1/health
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"database_ready":true,"schema_version":33,"schema_ready":true,"task_store_ready":true}
$ go test -short -count=1 -timeout 180s ./internal/projectinstance ./internal/projectworkflow ./internal/server
ok chat-agent-system/internal/projectinstance 0.003s
ok chat-agent-system/internal/projectworkflow 0.002s
ok chat-agent-system/internal/server 9.957s
$ npx playwright test e2e/governance-action-level-authz.spec.ts --project=chromium
✓ 1 [chromium] › e2e/governance-action-level-authz.spec.ts:57:3 › governance action-level authz › real page matrix G5 (12.3s)
1 passed (12.9s)
$ python3 g5_api_matrix.py
wrote .../api-matrix.json verdict=PASS cases=6
```
通过率:页面 1/1;API 6/6;上述 Go 包 short 全绿。未用 stub 输出充当验收。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
**结论**:G1–G5 达到合入标准。动作级职责已落地;未激活编制保持 202 且不启小队;创建带 key 不再直通 active;项目 143 只读回归通过。
**后续(不阻塞本任务)**:
- 不把 Wave 5 未跑的「none 文档真实 PI 审批长链路」算进本报告。
- 规划话术「帮我生成立项文档」仍走私密草稿捷径;若产品要它走 intake,需另开 templateMatch 任务。
- `GET /tasks/runs/{id}` 响应仍是 Go 导出字段 PascalCase,前端创建接口用 snake_case;建议后续统一 JSON tag。
- 83 条 planning+残留 key 夹具只审计、未改库。
@@ -1,150 +0,0 @@
# workflow-plan 409 冻结态 + 可选职责 测试报告
## 一、 测试背景 (Background)
已激活项目(现场样本:项目 143 / 侧栏「对话协同会话」)对 `PUT /workflow-plan` 正确返回 409 `PLAN_FROZEN`,但设置页仍渲染职责下拉与「校验并预览」,错误落在长表单视口外,表现为「点击无反应」。同时规划校验把「三职全空」一律当成非法,无法表达「启用文档但不纳入人工审批」。
本轮按整改方案 Wave 1–4 落地 typed error、frozen 只读页、`DutyMode`、门禁/权限/快照/预览统计与逐文档开关;Wave 5 在真实 `pi-agent` 开发栈上做页面矩阵验收。项目 143 **只打开设置页做只读回归,未终止、未改规划**。
## 二、 测试目标 (Test Objectives)
- 项目 143 打开即 frozen:无编辑控件、无 workflow-plan PUT、不点终止。
- 新项目 A:一份纳入人工审批 + 其余不纳入 → 保存、预览、激活成功;激活后再打开为 frozen。
- 新项目 B:只填编制 → 内联/sticky 拒绝「不能只指派部分职责」,**不发出** PUT。
- 新项目 C:全部不纳入 → 预览拒绝「至少一份文档必须纳入人工审批」。
- 双标签:C 在另一页激活后,原标签陈旧草稿保存见冻结文案,草稿策略按 Wave 1 保留本地 plan。
- 非创建者成员打开 A:无「配置工作流」。
- 刷新后项目 143 仍 frozen。
- 质量门禁:相关 Go 短测与 `web` 单测全过。
明确未宣称:本轮 **未** 用真实小队把 full 文档走完审批、也 **未** 对 none 文档做生成 + 版本账本 + 阶段不阻塞的长链路 PI 实测;该项留作后续,不以 stub 或 API 旁证冒充。
## 三、 测试方案与环境 (Test Plan & Environment)
| 项 | 值 |
|----|-----|
| OS | Linux 7.0.0-31-generic |
| 浏览器 | `mcr.microsoft.com/playwright:v1.63.0-noble`,`--network host`,`BASE_URL=http://127.0.0.1:8080` |
| 服务 | 开发环境 `:8080`;`GET /api/v1/health` → `status=ok`,`env=dev`,`agent_backend=pi-agent`,`schema_version=32` |
| Agent | 真实 `pi-agent`(本轮页面矩阵未再触发长文档生成) |
| 分支 / worktree | `fix/workflow-plan-409-frozen-and-optional-duties` / `.worktrees/fix-workflow-plan-409-frozen-and-optional-duties` |
| 脚本 | `web/e2e/workflow-plan-409-frozen-duties.spec.ts`,`RUN_UI_ACCEPTANCE=1` |
| 末次页面矩阵 | **1 passed / 11.4s**(用例墙钟 10.7s) |
| 本轮项目(仅用户名/标题,无口令) | `WP409-A-mu0x38jh` / `WP409-B-mu0x38jh` / `WP409-C-mu0x38jh`;成员 `wpb_*` / `wpc_*` |
| 对照项目 | 143「对话协同会话」(只读) |
| 证据 | `.doc/test-reports/assets/2026-09-14-workflow-plan-409-frozen-and-optional-duties/screenshots/` |
未在 worktree 内执行 `env-service.sh`。合入与 rebuild 在独立 `dev` worktree / 主仓 compose 完成,编码 worktree 只跑单测与 Playwright。
### 用例矩阵
| ID | 输入 | 期望 |
|----|------|------|
| UI-01 | 打开 143 设置 | frozen 说明 + 无下拉/预览/激活;无 PUT `/143/` |
| UI-02 | A:首份开审批并填三职,其余关审批 | 预览可见不纳入统计,确认激活后「运行中」 |
| UI-03 | 再开 A 设置 | frozen,无「纳入人工审批」/「校验并预览」 |
| UI-04 | B:开审批后只选编制 | sticky「不能只指派部分职责」,PUT 计数不增加 |
| UI-05 | C:全部关审批后预览 | sticky「至少一份文档必须纳入人工审批才能激活工作流」 |
| UI-06 | 另一标签激活 C,原标签再预览 | 见「工作流已激活,规划已冻结」并转 frozen 只读 |
| UI-07 | 成员 B 进 A | 无「配置工作流」 |
| UI-08 | 刷新后开 143 | 仍 frozen |
## 四、 预期结果 (Expected Results)
- 三个合法配置态:关闭文档 / 启用但不纳入人工审批 / 启用并纳入人工审批。
- partial、强制空职责、零治理激活、非在任成员由客户端和/或服务端拒绝。
- 已激活项目 `can_edit_plan=false` 或存在 live instance → 只读快照 + 独立受控终止区。
- 409 `PLAN_FROZEN`:保留本地草稿并 `fetchProjectSettings` 后切 frozen。
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
### UI-01 项目 143 只读冻结
- **测试输入 (Input)**:管理员登录,侧栏点「对话协同会话」,点「查看工作流设置」。
- **实际输出 (Actual Output)**:标题「当前工作流已冻结,只读查看」;工作流 `main` / 版本 v2 / 阶段 `V0.1-triage`;无「纳入人工审批」、无「校验并预览」、无「确认激活」;有受控终止区(文案含 pending documents / 将取消任务)。快照区显示「当前没有启用的文档任务。」(历史冻结 JSON 在本页未展开出文档行;**未改 143**)。监听未出现 `PUT` 含 `/143/`。
- **评价判定 (Evaluation / Verdict)**:**PASS**。未点击「确认终止当前实例」。
- **性能与耗时 (Duration & Latency)**:含在 10.7s 总矩阵内;截图 `01-project-143-frozen.png`。
### UI-02 / UI-03 新项目 A 一份 full + 其余 none
- **测试输入 (Input)**:立项 `WP409-A-mu0x38jh`,加入两名协作者;首份「用户初始需求收集表」勾选纳入人工审批,三职分别为系统管理员 / 王总监 / 测试工程师;其余文档开关关闭。
- **实际输出 (Actual Output)**:预览步出现「激活预览」且可见「不纳入」统计;确认后顶栏「商务对接流程 / 运行中」。再次打开设置为 frozen,无开关与预览按钮。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `02-project-a-full-none.png`、`03-project-a-activated.png`、`03b-project-a-frozen.png`。
### UI-04 新项目 B 部分职责
- **测试输入 (Input)**:立项 `WP409-B-mu0x38jh`;勾选首份纳入人工审批,只选编制「系统管理员」,点「校验并预览」。
- **实际输出 (Actual Output)**:文档下内联「文档「用户初始需求收集表」不能只指派部分职责」;底部 sticky 同文案;该步 `PUT /workflow-plan` 计数为 0。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `04-project-b-partial.png`。
### UI-05 新项目 C 零治理激活
- **测试输入 (Input)**:立项 `WP409-C-mu0x38jh`(含协作者);全部「纳入人工审批」关闭后点「校验并预览」。
- **实际输出 (Actual Output)**:sticky「至少一份文档必须纳入人工审批才能激活工作流」。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `05-project-c-no-governed.png`。
### UI-06 双标签 409 → frozen
- **测试输入 (Input)**:标签 2 登录后打开 C,将首份纳入审批并填满三职,预览并激活;标签 1 仍停在 C 的全空草稿上再点「校验并预览」。
- **实际输出 (Actual Output)**:标签 1 转为「当前工作流已冻结,只读查看」;sticky「工作流已激活,规划已冻结」;无编辑下拉。本地快照仍显示激活前全空三职(Wave 1:保留 draftPlan)。
- **评价判定 (Evaluation / Verdict)**:**PASS**
- **性能与耗时 (Duration & Latency)**:截图 `06-dual-tab-frozen.png`。
### UI-07 非创建者成员
- **测试输入 (Input)**:`协作者B-mu0x38jh` 首次改密后进入工作台,点开 `WP409-A-mu0x38jh`。
- **实际输出 (Actual Output)**:顶栏为「商务对接流程 / 运行中」,**没有**「配置工作流」按钮。成员侧栏仅见自己加入的项目。
- **评价判定 (Evaluation / Verdict)**:**PASS**(本步只断言配置入口;未再点审核/批准动作)。
- **性能与耗时 (Duration & Latency)**:截图 `07-member-no-settings.png`。
### UI-08 刷新后 143
- **测试输入 (Input)**:管理员页 `reload`,再开「对话协同会话」设置。
- **实际输出 (Actual Output)**:仍为「当前工作流已冻结,只读查看」。
- **评价判定 (Evaluation / Verdict)**:**PASS**(页面刷新;**未**再做 app 容器 restart)。
- **性能与耗时 (Duration & Latency)**:截图 `08-reload-frozen.png`。
### 未执行:真实生成 / 审批 / 阶段不阻塞
- **测试输入 (Input)**:无(本轮 Playwright 未发送编制任务、未走审核/批准、未推进阶段)。
- **实际输出 (Actual Output)**:无页面证据。
- **评价判定 (Evaluation / Verdict)**:**未测**。门禁/权限/none 不阻塞的契约由 Wave 3 单测覆盖,不能代替真实 PI 页面。
- **性能与耗时 (Duration & Latency)**:—
## 六、 自动化测试套件汇总 (Test Suite Execution)
在 feature worktree:
```text
go vet ./internal/projectinstance/... ./internal/server/... ./internal/workflow/runtime/...
go test -short ./...
# 全部包 ok / no test files,无 FAIL
cd web && npm test -- --run
# 361 passed + vitest 30 passed,fail 0
```
真实页面:
```text
npx playwright test e2e/workflow-plan-409-frozen-duties.spec.ts --project=chromium
# 1 passed (11.4s)
```
Playwright 原始 output/report 按 `.gitignore` 不入库(`playwright-output-*` / `playwright-report-*`);可复核截图已入库。
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
**设置页与激活治理:达到合入标准(页面矩阵 PASS)。** 项目 143 只读回归通过且未被改写/终止。新项目证明了 full+none 激活、partial 不发 PUT、零治理拒绝、双标签转 frozen、成员无配置入口、刷新后 frozen。
**未达到计划中的「真实执行」全链路。** 后续应单独立项:在已激活的 A 上用真实小队生成首份 full 文档并走审批,生成一份 none 文档确认入账本且无审核/批准、不阻塞阶段;必要时再做一次 `dev` app restart 后的 frozen/快照一致性。
**观察(不修 143)**:143 frozen 快照区写「当前没有启用的文档任务」,与现场仍有受控文档并行存在。若要展示历史职责,需另开任务读冻结 JSON,禁止在本任务回写 143。
回链:
- short-term:[2026-09-14-workflow-plan-409-frozen-and-optional-duties.md](../archive/ops/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md)
- FEATURE-MATRIX:工作流治理行
- gap-matrix:`WORKFLOW-PLAN-FROZEN-OPTIONAL-DUTIES`

Some files were not shown because too many files have changed in this diff Show More