Files
Agent-System/.doc/remediation/2026-09-14-module-decoupling-refactor-plan.md
T
weichenandCursor 2269cabf43 docs(arch): archive document reliability pilot plan and claim docgov
Land the revised modular-monolith scheme on the implementation branch so U1–U4 can proceed against a frozen design, and register the docgov mutex without occupying the integration slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 13:43:54 +00:00

48 KiB
Raw Blame History

title, status, created, updated, type, owner, deepened
title status created updated type owner deepened
模块解耦与文档可靠性重构计划 planned 2026-09-14 2026-09-14 refactor TBD 2026-09-14

模块解耦与文档可靠性重构计划

Goal Capsule

  • Objective: 项目文档、任务最终产物和最终智能体回复在并发写入、页面刷新、服务重启、工作区清理和受控恢复后仍能按权限定位到唯一、可校验的内容。
  • Means: 采用模块化单体、纵向绞杀、应用 UnitOfWork、数据库互斥、transactional outbox、opaque workspace capability 和 FAV。
  • Authority: 本计划受 模块化单体解耦 ADR、文档版本边界 ADR 和 工作流运行时权威 ADR 约束。
  • 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
  • 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
  • KTD10. 依赖感知回滚。 每个里程碑只保证回到最近兼容点;进入 contract 阶段后须按逆依赖顺序回滚。
  • KTD11. 按证据收紧门禁。 arch-check 先记录基线,每条规则在对应纵向切片清零后转 block,不按日历统一切换。
  • KTD12. FAV 分支先审后用。 feature/final-artifact-vault 的现有实现作为候选,不直接视为 dev 已有能力;集成前重放迁移、测试、安全和并发审计。

High-Level Technical Design

Component topology

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

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

stateDiagram-v2
  [*] --> pending
  pending --> leased
  leased --> delivered
  leased --> retryable_failed
  leased --> dead_letter
  retryable_failed --> leased
  leased --> pending: lease expired
  delivered --> [*]

Migration lifecycle

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

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

  • 模块解耦方案复核记录当前源码中的事务、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只用于队列式 claim,不用于普通一致性读取。
  • PostgreSQL serialization failure handling要求 serialization/deadlock 重试覆盖完整事务逻辑。
  • OWASP Business Logic Security支持服务端重新推导身份、所有权和安全相关状态。

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。