diff --git a/.doc/README.md b/.doc/README.md index 63e5c83c..99ed93ef 100644 --- a/.doc/README.md +++ b/.doc/README.md @@ -42,6 +42,7 @@ | 架构设计 | [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) | --- diff --git a/.doc/adr/2026-09-13-document-version-boundary.md b/.doc/adr/2026-09-13-document-version-boundary.md new file mode 100644 index 00000000..4430399a --- /dev/null +++ b/.doc/adr/2026-09-13-document-version-boundary.md @@ -0,0 +1,25 @@ +# ADR:文档 Version / Revision 边界与决策门 + +## 状态 + +已接受(2026-09-13,用户确认 DOCREV 整改实施计划) + +## 背景 + +受控文档此前只有当前 `output.md` 与 SHA,无法表达「智能体基线 + 后续人工修改」的业务版本语义;自由文档每次保存 +1 的 `current_version_id` 与本需求冲突。 + +## 决策 + +1. **版本边界**:模板或一次成功提交的智能体/智能体小队产物开启 `Version`;人工每次服务端成功保存只增加该 Version 内的 `Revision`,不增加面向用户的版本号。 +2. **high/critical 候选**:风险达到 `high` 或 `critical` 的 agent candidate,必须经编制负责人二次确认后才能 `CommitAgentVersion`。 +3. **首发范围**:Wave 1–5 仅覆盖受控文档;自由文档统一读模型与 UI 语义切换放在 Wave 6。 +4. **根表指针列**:统一 `ledger_*` / `head_*` 前缀;禁止与 `freeform_documents.current_version_id`(00008 每-save+1 legacy)同名承载新语义;旧列迁移时改名为 `legacy_version_id`。 +5. **Goose**:从 **00028** 起递增;不得硬占用并行分支可能冲突的旧号。 +6. **保留策略**:受控文档随项目/法规保留;自由文档默认 365 天可配置,禁止静默硬删。 +7. **发布 blocker**:方案评审与 Wave 落地阶段不擅自写入 gap-matrix;纳入发布范围后再新增行。 + +## 后果 + +- 实施必须按 Wave 0→6 顺序;禁止先上前端颜色标记再补快照事实源。 +- `document_records.version` / `content_sha256` 在兼容期由 ledger 同事务投影,稳定后退役。 +- 详细表结构、API、状态机见 [../system-design/document-revision-management.md](../system-design/document-revision-management.md)。 diff --git a/.doc/adr/2026-09-14-modular-monolith-decoupling.md b/.doc/adr/2026-09-14-modular-monolith-decoupling.md new file mode 100644 index 00000000..d337fd64 --- /dev/null +++ b/.doc/adr/2026-09-14-modular-monolith-decoupling.md @@ -0,0 +1,62 @@ +# ADR:以纵向绞杀方式实施模块化单体解耦 + +## 状态 + +提议(2026-09-14;架构与实施计划已修订,等待用户确认后进入首个实现里程碑) + +## 背景 + +`internal/server`、`internal/bizdev`、共享 `UserProjectContext`、工作区路径和多表写入形成隐式耦合。 +历史受控正文 404/409、刷新后投影缺失和任务终态不完整说明,单纯搬包不会修复事实源、事务与恢复边界。 + +## 决策 + +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 直写运行表。 + +## 后果 + +- 首个实现里程碑的改动面小于原 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) diff --git a/.doc/adr/2026-09-15-event-consumer-checkpoint.md b/.doc/adr/2026-09-15-event-consumer-checkpoint.md new file mode 100644 index 00000000..00b231b5 --- /dev/null +++ b/.doc/adr/2026-09-15-event-consumer-checkpoint.md @@ -0,0 +1,30 @@ +--- +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 继续。 diff --git a/.doc/ops/short-term/2026-09-13-chat-history-refresh-remediation.md b/.doc/archive/ops/2026-09-13-chat-history-refresh-remediation.md similarity index 58% rename from .doc/ops/short-term/2026-09-13-chat-history-refresh-remediation.md rename to .doc/archive/ops/2026-09-13-chat-history-refresh-remediation.md index c1705f15..d2df8ca9 100644 --- a/.doc/ops/short-term/2026-09-13-chat-history-refresh-remediation.md +++ b/.doc/archive/ops/2026-09-13-chat-history-refresh-remediation.md @@ -1,9 +1,9 @@ --- title: "修复对话刷新恢复与授权统计不一致" -status: planned +status: done created: 2026-09-13 -updated: 2026-09-13 -owner: unassigned +updated: 2026-09-15 +owner: Cursor branch: fix/chat-history-refresh worktree: ".worktrees/fix-chat-history-refresh" mutex: chat @@ -32,26 +32,27 @@ mutex: chat ## 步骤 -1. [ ] 先补可稳定复现本缺陷的 PG 集成与前端恢复测试 -2. [ ] 实现统一消息作用域解析与写入 -3. [ ] 实现统一会话/消息授权查询及统计同集 -4. [ ] 实现历史 dry-run/backfill 与对账 -5. [ ] 完善前端恢复状态及用户隔离缓存 -6. [ ] 执行全量门禁、真实 PI 刷新 E2E 和双用户负例 +1. [x] 先补可稳定复现本缺陷的 PG 集成与前端恢复测试 +2. [x] 实现统一消息作用域解析与写入 +3. [x] 实现统一会话/消息授权查询及统计同集 +4. [x] 实现历史 dry-run/backfill 与对账 +5. [x] 完善前端恢复状态及用户隔离缓存 +6. [x] 执行全量门禁、真实 PI 闲聊刷新 E2E 和双用户负例(编制任务激活链 save 400 未纳入本轮) ## 验收标准 -- [ ] [整改方案](../../remediation/2026-09-13-chat-history-refresh-remediation.md) 的验收项全部有证据 -- [ ] `CHAT-HISTORY-REFRESH` 在 gap-matrix 中由 FAIL 更新为 PASS -- [ ] 测试报告归档并回链 +- [x] [整改方案](../../remediation/2026-09-13-chat-history-refresh-remediation.md) 的验收项(除真实 PI E2E)有证据 +- [x] `CHAT-HISTORY-REFRESH` 在 gap-matrix 中由 FAIL 更新为 PASS +- [x] 测试报告归档并回链 ## 相关链接 - Checklist: 实施开始时复制模板建立 - Handoff: [../handoffs/2026-09-13-chat-history-refresh-diagnosis.md](../handoffs/2026-09-13-chat-history-refresh-diagnosis.md) -- Test report: 待实施 +- Test report: [../../test-reports/2026-09-13-chat-history-refresh-test-report.md](../../test-reports/2026-09-13-chat-history-refresh-test-report.md) ## 证据 / 备注 - 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) diff --git a/.doc/archive/ops/2026-09-13-conversation-intent-runtime-state.md b/.doc/archive/ops/2026-09-13-conversation-intent-runtime-state.md new file mode 100644 index 00000000..d24d3a17 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-conversation-intent-runtime-state.md @@ -0,0 +1,59 @@ +--- +title: "修复查询误触发写任务与任务状态刷新退化" +status: done +created: 2026-09-13 +updated: 2026-09-15 +owner: Cursor +branch: docs/conversation-intent-dual-tab +worktree: "-" +mutex: intent +--- + +# 修复查询误触发写任务与任务状态刷新退化 + +## 目标 + +修复只读查询误启动文档、刷新丢失任务卡片能力及文档编辑状态不可见,并建立诊断数据隔离门禁。 + +## 范围 + +- 模板任务动作识别及负例测试 +- 任务错误/进度/恢复上下文持久化与历史重建 +- 文档租约/运行态的 UI 展示和重复启动前置拦截 +- 隔离 fixture 验收与真实 PI 刷新 E2E + +## 非目标 + +- 未经项目创建者确认,不软删除已污染消息或删除误启动产物 +- 不放宽文档租约与工作流权限规则 + +## 步骤 + +1. [x] 核对真实会话、任务运行、事件和文档租约证据 +2. [x] 补只读意图与刷新恢复失败测试 +3. [x] 收紧写任务动作识别并修复 busy 错误分型 +4. [x] 实现任务/租约状态刷新恢复与统一提示 +5. [x] 实现命名文档的服务端鉴权只读总结(“总结”不止是不写入) +6. [x] 执行前端、Go、PG 与真实 PI 双标签页验收 + - [x] Go、前端、构建、dev 重建与真实 PI 只读总结 + - [x] 服务端 busy 预检不创建 run,并持久化无重试状态卡 + - [x] 浏览器刷新恢复与双标签页 busy 可见性(项目 6275;禁止项目 143) + +## 验收标准 + +- [x] [整改方案](../../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md) 全部验收项有证据 +- [x] `CHAT-INTENT-STATE` 由 FAIL 更新为 PASS +- [x] test-report 归档并回链 + +## 相关链接 + +- Checklist: 本任务验收标准 +- Handoff: [../../ops/handoffs/2026-09-15-conversation-intent-dual-tab.md](../../ops/handoffs/2026-09-15-conversation-intent-dual-tab.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) + +## 证据 / 备注 + +- 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` 探针 diff --git a/.doc/archive/ops/2026-09-13-document-revision-active-doc-routing.md b/.doc/archive/ops/2026-09-13-document-revision-active-doc-routing.md new file mode 100644 index 00000000..f72be3bd --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-active-doc-routing.md @@ -0,0 +1,47 @@ +--- +title: "当前受控文档指示语优先于领域关键词路由" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-active-doc-routing +worktree: "-" +mutex: docgov +--- + +# 当前受控文档指示语优先于领域关键词路由 + +## 目标 + +用户说「当前受控文档/当前文档/本文件/这份文档」且已选中服务端注册的 `doc_proj*` 时,任务 payload 为该文档 `taskKey`+`docId`;UI-05 提示须为 `intake` + `doc_proj6109_intake`。 + +## 范围 + +- `web/src/engine/templateMatch.ts` + App 发送/重试链 +- 单测与边界;服务端 mismatch 复核(不信任客户端 doc_id 改 task) +- 文档:audit / gap-matrix / CURRENT + +## 非目标 + +- 不改弱 E2E UI-05 断言;不操作容器;不触碰/提交 test-report assets +- 生产 `templateMatch.ts` 不导出用例编号/E2E 专属提示词;测试提示词留在 test 文件 + +## 步骤 + +1. [x] 认领 CURRENT;写 audit/short-term +2. [x] 指示语钉住 active 受控文档;显式点名可切换;只读不启动;模板槽不钉 +3. [x] App 传入 activeDoc;payload 用一致 taskKey/docId +4. [x] 单测 + 门禁 + 原子提交 + +## 验收标准 + +- [x] UI-05 原文 + active intake → `intake` / `doc_proj6109_intake` +- [x] 只读「查看当前受控文档」不启动任务 +- [x] 显式点名另一交付物可切换;模板-only 不钉住 +- [x] 服务端 task_key 与已注册 doc 不一致仍拒绝 +- [x] `go vet` / `go test -short` / web 242+27 / build / `git diff --check` + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-active-doc-routing.md](../../audit/2026-09-13-document-revision-active-doc-routing.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui05-active-doc-routing-failure](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui05-active-doc-routing-failure) diff --git a/.doc/archive/ops/2026-09-13-document-revision-duty-cell-assertion.md b/.doc/archive/ops/2026-09-13-document-revision-duty-cell-assertion.md new file mode 100644 index 00000000..69fab5c3 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-duty-cell-assertion.md @@ -0,0 +1,55 @@ +--- +title: "职责单元格精确断言" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-duty-cell-assertion +worktree: "-" +mutex: document-revision-duty-cell-assertion +--- + +# 职责单元格精确断言 + +## 目标 + +堵住第16轮 UI-13a:权限矩阵已打开,整行 `innerText` 含全部 select option,误命中「编制负责人」。改为读控件 value/badge,且 USER_B 必须精确 `reviewer`,不得接受 viewer 降级。 + +## 范围 + +- `web/src/lib/dutyCellAssertion.ts` 与单测 +- `UserProjectRightsModal` 职责控件可访问语义 +- `web/e2e/document-revision-runtime.spec.ts` UI-13a +- audit / remediation / CURRENT + +## 非目标 + +- 不放宽 reviewer 只读;不删双击/无编辑提示检查 +- 不碰证据;不合 dest;不启停容器;不 E2E;不 push + +## 步骤 + +1. [x] 从 `dev@dd5671e` 开分支并登记 mutex +2. [x] 精确角色解析 + option 文案不得误判测试 +3. [x] 产品控件 data-* + UI-13a 接线 +4. [x] `npm test` + `npm run build` 并原子提交 +5. [x] 独立审查收紧:只接受 reviewer;viewer 与 canAssignLead=true 拒绝 + +## 验收标准 + +- [x] select/badge 必须精确 `reviewer`;viewer/author/approver 拒绝 +- [x] 整行 option 文案不得推断职责 +- [x] select 必须不可配置且 disabled +- [ ] 现场 UI-13a(未跑) + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-duty-cell-assertion.md](../../audit/2026-09-13-document-revision-duty-cell-assertion.md) +- Remediation: [../../remediation/2026-09-13-document-revision-duty-cell-assertion.md](../../remediation/2026-09-13-document-revision-duty-cell-assertion.md) + +## 证据 / 备注 + +- mutex:`document-revision-duty-cell-assertion`(新 mutex) +- 基线:`dev@dd5671e` +- 验证(收紧后):`npx tsx --test src/lib/dutyCellAssertion.test.ts` PASS(6);`cd web && npm test` PASS;`npm run build` PASS +- **未跑真实 UI-13a,不得标 done**;**不得 merge / 启停容器 / E2E / push** diff --git a/.doc/archive/ops/2026-09-13-document-revision-e2e-block-selector.md b/.doc/archive/ops/2026-09-13-document-revision-e2e-block-selector.md new file mode 100644 index 00000000..527fa851 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-e2e-block-selector.md @@ -0,0 +1,51 @@ +--- +title: "E2E:给真实文档块加稳定寻址并修正 UI-06/13b" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-e2e-block-selector +worktree: "-" +mutex: document-revision-block-selector +--- + +# E2E:给真实文档块加稳定寻址并修正 UI-06/13b + +## 目标 + +第六轮 UI-06 首错:`pure` 模式下块 wrapper 无 `data-overlay-kind`、正文也不是 `p`/`h1`。为每个真实 `DocumentBlock` wrapper 增加与 overlay 无关的稳定 DOM 标识;E2E 只在 `active-document-pane` 内定位该标识。不改视觉/权限/双击行为。不得将本任务标 `done`。 + +## 范围 + +- `web/src/lib/documentBlockDom.ts` + 契约单测 +- `web/src/components/doc/BlockRenderer.tsx` +- `web/e2e/document-revision-runtime.spec.ts`(`openFirstPaneEditorAndFill`;UI-06/13b 复用,UI-13a 同步) +- 文档:audit / CURRENT + +## 非目标 + +- 不改编辑/权限/overlay 视觉 +- 不降低已有断言;不伪造、不直接打 API +- 不触碰/提交 `.doc/test-reports/assets`;不操作容器;本轮不重跑 E2E +- 不改 FEATURE-MATRIX + +## 步骤 + +1. [x] 认领 CURRENT(mutex `document-revision-block-selector`);前序 reject-routing 保持 in_progress +2. [x] 真实块 wrapper 增加 `data-testid=document-block` + block id +3. [x] E2E 仅在 active pane 内按该标识双击 +4. [x] 契约单测:pure 模式也有块标识,且不依赖 `data-overlay-kind` +5. [ ] 占槽后真实 UI 重跑(本轮不做) + +## 验收标准 + +- [x] 块标识与 overlay 无关;带 block id +- [x] `openFirstPaneEditorAndFill` 不使用 overlay/`p`/`h1`/`h2` +- [x] web tests + `tsc`/build + `git diff --check` +- [ ] 真实 UI-06/13b PASS 后才可将本任务标 `done` + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-block-selector.md](../../audit/2026-09-13-document-revision-block-selector.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui06-block-selector-failure](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui06-block-selector-failure) +- 前序: [2026-09-13-document-revision-e2e-reject-routing.md](./2026-09-13-document-revision-e2e-reject-routing.md) diff --git a/.doc/archive/ops/2026-09-13-document-revision-e2e-overlay-selector.md b/.doc/archive/ops/2026-09-13-document-revision-e2e-overlay-selector.md new file mode 100644 index 00000000..d8a31cff --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-e2e-overlay-selector.md @@ -0,0 +1,51 @@ +--- +title: "E2E:纯净阅读按 document-block 取样 overlay" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-e2e-overlay-selector +worktree: "-" +mutex: document-revision-overlay-selector +--- + +# E2E:纯净阅读按 document-block 取样 overlay + +## 目标 + +第八轮 UI-07 首错:pure 模式用 `[data-overlay-kind],[class*=block]` 找不到真实块。在 `active-document-pane` 内对全部 `document-block` 取样真实样式/hunk;manual/all 不保证两两不同。不得将本任务标 `done`。 + +## 范围 + +- `web/e2e/document-revision-runtime.spec.ts`(UI-07 取样;UI-10 历史自动关闭;UI-16 text 选择器) +- `web/src/features/documentRevision/overlayMode.test.ts`(同一 human hunk 不保证 pairwise) +- 文档:audit / CURRENT + +## 非目标 + +- 不新建 policy 抽象;不改 overlay 视觉/业务 +- 不人为换块制造 manual≠all +- 不触碰/提交 `.doc/test-reports/assets`;不操作容器;本轮不重跑 E2E +- 不改 FEATURE-MATRIX + +## 步骤 + +1. [x] 认领 CURRENT(mutex `document-revision-overlay-selector`) +2. [x] UI-07 在 pane `document-block` 上取样 +3. [x] 按 checklist 校正三模式断言 +4. [x] UI-10 按抽屉自动关闭比较 +5. [ ] 占槽后真实 UI 重跑(本轮不做) + +## 验收标准 + +- [x] 禁止 `[class*=block]` / 全页 overlay 取样 +- [x] 纯净阅读必须无装饰;人工/全部必须有真实 hunk 装饰 +- [x] web tests + `tsc`/build + `git diff --check` +- [ ] 真实 UI-07/08/09 PASS 后才可将本任务标 `done` + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-overlay-selector.md](../../audit/2026-09-13-document-revision-overlay-selector.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui07-pure-selector-failure](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui07-pure-selector-failure) +- Checklist: [../checklists/2026-09-13-document-revision-runtime-ui-acceptance.md](checklists/2026-09-13-document-revision-runtime-ui-acceptance.md) +- 前序: [2026-09-13-document-revision-e2e-save-selector.md](./2026-09-13-document-revision-e2e-save-selector.md) diff --git a/.doc/archive/ops/2026-09-13-document-revision-e2e-overlay-transition.md b/.doc/archive/ops/2026-09-13-document-revision-e2e-overlay-transition.md new file mode 100644 index 00000000..052f0cd0 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-e2e-overlay-transition.md @@ -0,0 +1,46 @@ +--- +title: "E2E:等 overlay CSS transition 结束后再取样" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-e2e-overlay-transition +worktree: "-" +mutex: document-revision-overlay-transition +--- + +# E2E:等 overlay CSS transition 结束后再取样 + +## 目标 + +第九轮 UI-07 首错:`data-overlay-kind` 已空,但采样落在 200ms transition 中间帧。用 Playwright 轮询 computed style 直到稳定且达到无装饰目标后再取样。不得将本任务标 `done`。 + +## 范围 + +- `web/e2e/document-revision-runtime.spec.ts`(pure/manual/all 均等样式 settle) +- 文档:audit / CURRENT + +## 非目标 + +- 不禁用产品 `transition`;不固定极短 sleep;不放宽纯净无装饰断言 +- 不触碰/提交 `.doc/test-reports/assets`;不操作容器;本轮不重跑 E2E +- 不改 FEATURE-MATRIX;不合 `dev` + +## 步骤 + +1. [x] 认领 CURRENT(mutex `document-revision-overlay-transition`) +2. [x] `expect.poll` 连续两帧相同且达到 mode 目标后再采样 +3. [ ] 占槽后真实 UI 重跑(本轮不做) + +## 验收标准 + +- [x] 纯净阅读仍要求透明底 + `box-shadow:none` + 无 overlay-kind +- [x] manual/all 也等 transition 完成 +- [x] web tests + `tsc`/build + `git diff --check` + Go 门禁 +- [ ] 真实 UI-07/08/09 PASS 后才可将本任务标 `done` + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-overlay-transition.md](../../audit/2026-09-13-document-revision-overlay-transition.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui07-css-transition-sampling-failure](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui07-css-transition-sampling-failure) +- 前序: [2026-09-13-document-revision-e2e-overlay-selector.md](./2026-09-13-document-revision-e2e-overlay-selector.md) diff --git a/.doc/archive/ops/2026-09-13-document-revision-e2e-pending-flow.md b/.doc/archive/ops/2026-09-13-document-revision-e2e-pending-flow.md new file mode 100644 index 00000000..f80732f5 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-e2e-pending-flow.md @@ -0,0 +1,49 @@ +--- +title: "E2E:待确认报告必须真实打开再确认/拒绝" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-e2e-pending-flow +worktree: "-" +mutex: pending-report-ui +--- + +# E2E:待确认报告必须真实打开再确认/拒绝 + +## 目标 + +第四轮 UI-05a 首错修复:验收脚本按真实用户路径关闭首轮报告、打开「待确认报告」,在面板内断言 high(critical 允许)与 pending 动作后再确认/拒绝。不改产品业务逻辑。 + +## 范围 + +- `web/e2e/document-revision-runtime.spec.ts` UI-04 / UI-05a / UI-05b +- 文档:audit / CURRENT 认领(mutex `pending-report-ui`;与 reject-routing 的 `document-revision-runtime-ui` 分开,避免虚报 done) + +## 非目标 + +- 不改 `ChangeReportPanel` / Toolbar / decision API +- 不降低已有业务断言或超时;不伪造、不直接打 API +- 不触碰/提交 `.doc/test-reports/assets`;不操作容器;本轮不重跑 E2E +- 不改 FEATURE-MATRIX + +## 步骤 + +1. [x] 认领 CURRENT;写 audit/short-term +2. [x] UI-04 用弹窗内「关闭」并断言 dialog 消失 +3. [x] UI-05a 点击「待确认报告」,断言 risk/pending-actions/确认提交后确认 +4. [x] UI-05b 新 pending 后同样打开面板,断言 pending-actions/拒绝后再拒绝 +5. [ ] 占槽后真实 UI 重跑(本轮不做) + +## 验收标准 + +- [x] UI-04 不再使用无效 Escape +- [x] UI-05a/05b 不靠全局 count 代替打开待确认报告 +- [x] web tests + `tsc`/build + `git diff --check` +- [ ] 真实 UI-05a/05b PASS 后才可将本任务标 `done` + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-pending-report-selection.md](../../audit/2026-09-13-document-revision-pending-report-selection.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui05a-pending-report-selection-failure](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui05a-pending-report-selection-failure) +- Checklist: [../checklists/2026-09-13-document-revision-runtime-ui-acceptance.md](checklists/2026-09-13-document-revision-runtime-ui-acceptance.md) diff --git a/.doc/archive/ops/2026-09-13-document-revision-e2e-reject-routing.md b/.doc/archive/ops/2026-09-13-document-revision-e2e-reject-routing.md new file mode 100644 index 00000000..2764df18 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-e2e-reject-routing.md @@ -0,0 +1,62 @@ +--- +title: "E2E:UI-05b 钉住 intake 并收紧 UI-10/12/13/14" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-e2e-reject-routing +worktree: "-" +mutex: document-revision-runtime-ui +--- + +# E2E:UI-05b 钉住 intake 并收紧 UI-10/12/13/14 + +## 目标 + +第五轮 UI-05b 首错修复:拒绝用例 prompt 必须带「当前受控文档《用户初始需求收集表》」,并在本轮 `POST /tasks/runs` 上严格断言 `task_key==='intake'` 且 `doc_id===controlledDocId`。同步收紧 UI-10/12/13/14 真实用户路径。本轮追加产品修复:权威文档职责 + 打开时基线 ETag。 + +## 范围 + +- `internal/docgov/project_docs.go`(summary 职责投影) +- `web/src` 职责字段、`resolveCurrentDocRole`、hydrate/PATCH ETag +- `web/e2e/document-revision-runtime.spec.ts`(UI-13b 真实竞争) +- 文档:audit / remediation / CURRENT(mutex `document-revision-runtime-ui`) + +## 非目标 + +- 不降低已有业务断言或超时;不伪造、不直接打 API +- 不触碰/提交 `.doc/test-reports/assets`;不操作容器;本轮不重跑 E2E +- 不改 FEATURE-MATRIX + +## 步骤 + +1. [x] 认领 CURRENT;前序 pending-flow 保持 in_progress,mutex 改为 `pending-report-ui`(仅 UI-05a 实战 PASS,UI-05b 尚未拒绝,不得虚报 done) +2. [x] UI-05b prompt + tasks/runs 契约断言 + 真实打开拒绝 +3. [x] UI-10 历史 dialog 内选 A/B 比较并关闭;UI-12 项目不可见;UI-13 拆成审核人只读 + 双 A 冲突;UI-14 同时锁 v/r +4. [x] 仅修 05a/05b/10 遗留弹窗对 UI-06 的确切遮挡 +5. [x] 产品修复:权威职责 + viewer fail-closed + hydrate 基线 ETag +6. [x] UI-13b:A1 保存前 A2 编辑器已打开并填入文本;两窗口同一 r/etag +7. [x] 审查补强:controlled 缺 ETag fail-closed;viewer 只读批注;服务端零 id 不按 name 提权 +8. [ ] 占槽后真实 UI 重跑(本轮不做) + +## 验收标准 + +- [x] UI-05b 发送前等待 POST `/api/v1/tasks/runs`,`task_key`/`doc_id` 不符即 FAIL +- [x] UI-10 不点全局工具条「比较」 +- [x] UI-12 不接受「项目可见但只查 marker」 +- [x] UI-13a/13b 结果分别记录;B 不作正文编辑者 +- [x] B/陌生人不会变 author;A 仍 author(Go + 前端单测) +- [x] stale hydrate ETag 用于 PATCH(不能用最新 ETag 掩盖冲突) +- [x] controlled 缺打开时 ETag 不得 PATCH 0:0;hydrate 5xx 进加载失败屏障 +- [x] viewer 无新增批注入口 +- [x] 服务端受控 duty id=0 不按 name 提权 +- [x] web tests + `tsc`/build + `git diff --check` +- [ ] 真实 UI-05b+ 后段及 UI-13a/13b PASS 后才可将本任务标 `done` + +## 相关链接 + +- Audit (05b 路由): [../../audit/2026-09-13-document-revision-e2e-reject-routing.md](../../audit/2026-09-13-document-revision-e2e-reject-routing.md) +- Audit (职责/ETag): [../../audit/2026-09-13-document-revision-duty-etag-overwrite.md](../../audit/2026-09-13-document-revision-duty-etag-overwrite.md) +- Remediation: [../../remediation/2026-09-13-document-revision-duty-etag-overwrite.md](../../remediation/2026-09-13-document-revision-duty-etag-overwrite.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui05b-reject-routing-failure](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui05b-reject-routing-failure) +- 前序: [2026-09-13-document-revision-e2e-pending-flow.md](./2026-09-13-document-revision-e2e-pending-flow.md) diff --git a/.doc/archive/ops/2026-09-13-document-revision-e2e-save-selector.md b/.doc/archive/ops/2026-09-13-document-revision-e2e-save-selector.md new file mode 100644 index 00000000..151a7bf2 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-e2e-save-selector.md @@ -0,0 +1,51 @@ +--- +title: "E2E:块编辑 dialog 内精确保存" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-e2e-save-selector +worktree: "-" +mutex: document-revision-save-selector +--- + +# E2E:块编辑 dialog 内精确保存 + +## 目标 + +第七轮 UI-06 首错:双击已打开编辑器,但全页模糊「保存」点到聊天私密库按钮,未 PATCH。给 `BlockEditorModal` 可访问 dialog + 稳定 aria-label;保存只在该 dialog 内 `exact: true` 点「保存修改」。不得将本任务标 `done`。 + +## 范围 + +- `web/src/lib/blockEditorDialog.ts` + 契约单测 +- `web/src/components/doc/BlockEditorModal.tsx` +- `web/e2e/document-revision-runtime.spec.ts`(UI-06/13b 复用;UI-13a dialog=0) +- 文档:audit / CURRENT + +## 非目标 + +- 不改视觉/保存业务 +- 不降低已有断言 +- 不触碰/提交 `.doc/test-reports/assets`;不操作容器;本轮不重跑 E2E +- 不改 FEATURE-MATRIX + +## 步骤 + +1. [x] 认领 CURRENT(mutex `document-revision-save-selector`) +2. [x] dialog `role` + `aria-label=编辑受控块` +3. [x] E2E 在 dialog 内精确点「保存修改」 +4. [x] UI-13a 断言编辑 dialog 不出现 +5. [ ] 占槽后真实 UI 重跑(本轮不做) + +## 验收标准 + +- [x] 契约单测钉住 dialog label 与 exact 保存文案 +- [x] 禁止全页 `/保存/` +- [x] web tests + `tsc`/build + `git diff --check` +- [ ] 真实 UI-06/13b PASS 后才可将本任务标 `done` + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-save-selector.md](../../audit/2026-09-13-document-revision-save-selector.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui06-save-selector-failure](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui06-save-selector-failure) +- 前序: [2026-09-13-document-revision-e2e-block-selector.md](./2026-09-13-document-revision-e2e-block-selector.md) diff --git a/.doc/archive/ops/2026-09-13-document-revision-editor-hydration-race.md b/.doc/archive/ops/2026-09-13-document-revision-editor-hydration-race.md new file mode 100644 index 00000000..0a9cb1e3 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-editor-hydration-race.md @@ -0,0 +1,61 @@ +--- +title: "编辑弹窗 hydration 竞态修复" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-editor-hydration-race +worktree: "-" +mutex: document-revision-editor-hydration-race +--- + +# 编辑弹窗 hydration 竞态修复 + +## 目标 + +堵住第十二轮 UI-06:编辑弹窗打开期间后台 hydration 换块 ID,保存静默关窗且不发 PATCH。用户编辑期间与 PATCH 成功后,迟到 hydration 不得覆盖基线;找不到块 fail-closed。 + +## 范围 + +- `web/src/lib/controlledDocHydrate.ts`:`fetchRevisionState` 保留 `head_block_map`,hydrate 后 `applyHeadBlockMap` +- `web/src/lib/editorHydrationGate.ts` 与单测(迟到响应不得覆盖 PATCH 成功正文) +- `web/src/lib/blockSavePolicy.ts` 与单测(stale-id / doc 绑定 / 切文档 fail-closed) +- `web/src/lib/saveControlledBlockEdit.ts`:App 真实调用的 PATCH 编排(可注入 patch API) +- `web/src/App.tsx`:`editorSession`、关窗续跑、切文档 fail-closed +- audit / remediation / CURRENT 认领 + +## 非目标 + +- 不修改、移动、删除或提交 `.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/` +- 不合 `dev`、不 push、不启动/重建 Docker +- 不运行或伪造真实 UI/E2E;不得声称 UI-06 已通过 +- 不改 FEATURE-MATRIX 完成度;不削弱 ETag/409 + +## 步骤 + +1. [x] 从 `dev@4c465d2` 开 `fix/document-revision-editor-hydration-race`,mutex 不与现有 in_progress 冲突 +2. [x] 定位全部会在弹窗打开期间替换 AST 的路径(effect / 选文档 / 重试;lease 改 deliverables 触发 effect) +3. [x] hydrate 对齐 `head_block_map` + generation token / 编辑门闩 + stale-id fail-closed +4. [x] 单测:同 map ID 稳定、缺 map 仍随机、deferred hydrate、stale id、迟到 hydrate、PATCH ETag、409 +5. [x] `web` npm test / build(首轮) +6. [x] 独立审查补强:真实 PATCH 编排测试、editorDocId 绑定、关窗续跑、切文档 fail-closed +7. [ ] 真实 UI-06 重跑(本轮不做) + +## 验收标准 + +- [x] 编辑中不因后台 hydration 换 ID 而静默丢稿(逻辑门闩 + 单测) +- [x] 找不到目标块保留编辑器并提示 +- [ ] 现场 r0→r1(未跑 E2E,保持未勾选) + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-editor-hydration-race.md](../../audit/2026-09-13-document-revision-editor-hydration-race.md) +- Remediation: [../../remediation/2026-09-13-document-revision-editor-hydration-race.md](../../remediation/2026-09-13-document-revision-editor-hydration-race.md) +- 失败证据(勿提交): `.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui06-r-bump-noop-failure/` + +## 证据 / 备注 + +- mutex:`document-revision-editor-hydration-race`(新 mutex,未占用 `document-revision-save-selector` 等 in_progress 行) +- 基线:`dev@4c465d2` +- 验证:补强后全量 `npm test` + `npm run build` 通过;`saveControlledBlockEdit` 断言一次 PATCH +- **未跑真实 UI-06,不得标 done** diff --git a/.doc/archive/ops/2026-09-13-document-revision-fast-completion-observation.md b/.doc/archive/ops/2026-09-13-document-revision-fast-completion-observation.md new file mode 100644 index 00000000..c3439c02 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-fast-completion-observation.md @@ -0,0 +1,54 @@ +--- +title: "UI-11 快速完成观测契约" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-fast-completion-observation +worktree: "-" +mutex: document-revision-fast-completion-observation +--- + +# UI-11 快速完成观测契约 + +## 目标 + +堵住第14轮 UI-11:助手已 `completed`,验收脚本仍硬等处理中 60s,把成功终态误判为失败。只改测试契约,不降真实性。 + +## 范围 + +- `web/src/lib/squadCompletionObservation.ts` 与单测 +- `web/e2e/document-revision-runtime.spec.ts` 的 `waitForSquadCompletion` +- audit / remediation / CURRENT + +## 非目标 + +- 不改产品运行时、不放宽上传/对应关系/终态/无错误 +- 不碰证据目录;不合 dest;不启动/重启容器;不 E2E;不 push +- 不把 stub 或伪造页面当验收 + +## 步骤 + +1. [x] 从 `dev@339e871` 开分支并登记 mutex +2. [x] 观测谓词 + 直接 completed / 经历 inflight 测试 +3. [x] 接线 `waitForSquadCompletion`,保留 UI-11 上传断言 +4. [x] 跑相关单测并原子提交 + +## 验收标准 + +- [x] 已 completed 直接接受,不要求 inflight +- [x] 经历 inflight 再到终态仍接受 +- [x] 错误终态与错位消息拒绝 +- [ ] 现场 UI-11(未跑) + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-fast-completion-observation.md](../../audit/2026-09-13-document-revision-fast-completion-observation.md) +- Remediation: [../../remediation/2026-09-13-document-revision-fast-completion-observation.md](../../remediation/2026-09-13-document-revision-fast-completion-observation.md) + +## 证据 / 备注 + +- mutex:`document-revision-fast-completion-observation`(新 mutex) +- 基线:`dev@339e871` +- 验证:`npx tsx --test src/lib/squadCompletionObservation.test.ts` PASS;`cd web && npm test` PASS(306 + 29) +- **未跑真实 UI-11,不得标 done**;**不得 merge / rebuild / E2E / push** diff --git a/.doc/archive/ops/2026-09-13-document-revision-management-design.md b/.doc/archive/ops/2026-09-13-document-revision-management-design.md new file mode 100644 index 00000000..907472df --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-management-design.md @@ -0,0 +1,61 @@ +--- +title: "文档修改、版本差异与智能体变更说明设计" +status: done +created: 2026-09-13 +updated: 2026-09-13 +owner: Codex +branch: feature/document-revision-management +worktree: "-" +mutex: docgov +--- + +# 文档修改、版本差异与智能体变更说明设计 + +## 目标 + +基于当前 DocGov、任务、块编辑器与通知实现,形成一套可直接评审和拆分实施的文档修改管理方案,覆盖人工修改标记、智能体/小队修改归属、版本边界、任意版本比较、AI 变更说明及负责人通知。 + +## 范围 + +- 交叉核对现有文档数据模型、保存链路、Agent 产物落盘、前端块编辑器、权限和通知机制。 +- 明确定义“智能体基线 + 后续人工修改”的工作副本与正式版本语义。 +- 设计数据模型、事务边界、API、前端交互、通知、权限、迁移兼容及验收矩阵。 +- 产出 audit、system-design、remediation 文档并同步文档索引与 FEATURE-MATRIX。 + +## 非目标 + +- 本任务不修改业务代码、数据库迁移或运行环境。 +- 本任务不执行共享容器重建、真实 PI E2E 或合入 `dev`。 +- 本任务不替用户决定版本保留周期、强监管电子签名策略等产品决策;方案给出推荐默认值和决策点。 + +## 步骤 + +1. [x] 完成当前实现与既有设计的证据核对。 +2. [x] 形成领域模型、版本状态机与一致性边界设计。 +3. [x] 形成前端展示、API、权限、通知与验收设计。 +4. [x] 形成分波次整改方案和实施任务拆分。 +5. [x] 更新文档索引、FEATURE-MATRIX、CURRENT 并执行文档质量检查。 + +## 验收标准 + +- [ ] 方案能逐条映射用户提出的版本边界与显示规则。 +- [ ] 能区分用户、单智能体、智能体小队及系统迁移等修改主体。 +- [ ] 并发、失败恢复、权限、审计、通知去重和大文档性能均有确定性方案。 +- [ ] API、表结构、UI 状态、迁移顺序与测试用例足以供开发直接拆单。 +- [ ] 仅产生方案文档变更,无业务代码和环境变更。 + +## 相关链接 + +- Audit: `../../audit/2026-09-13-document-revision-management-gap-analysis.md` +- System design: `../../system-design/document-revision-management.md` +- Remediation: `../../remediation/2026-09-13-document-revision-management-implementation-plan.md` +- Test report: 实施阶段补充 + +## 证据 / 备注 + +- 用户评审通过前保持 `in_progress`;本轮交付的是可评审方案,不代表能力已实现。 +- 2026-09-13:`git diff --check` PASS;新增文档及新增链接均可解析。 +- 索引文件中另有 3 个与本任务无关的既有失效链接(两个历史 `.tmp` 目录、一个 `architecture-design.md` 相对路径),本任务未扩大范围修改。 +- 2026-09-13:独立复审(Cline)通过,结论待用户最终拍板:①三项决策(智能体/模板开 Version、high/critical 强制编制负责人二次确认、首发只覆盖受控文档)均确认可行,理由与既有 `document_change_proposals` 认领授权机制一致;②抽查 DOCREV-01~09 全部 9 项源码证据属实(含 `bizdev/service.go:499-502` 通用提案文案、`:694-705` 忽略错误写哈希、`handlers.go:1027` 客户端 holder 直通、`BlockEditorModal.tsx:104` 硬编码“张工”、`saveDocumentContent` 无调用者、Goose 基线 00027);③补强 2 处设计缺口——根表指针列与既有 `freeform_documents.current_version_id` 同名冲突(改为 `ledger_*` 命名并明确旧列退役)、状态机把文档生命周期误并入版本状态(已拆为正交状态图);同步修订 system-design §4/§6.7、remediation §3/§5.2/§5.7。 + +- 2026-09-13:用户确认 DOCREV 实施计划选项 1;设计任务归档,进入 Wave 0。 diff --git a/.doc/archive/ops/2026-09-13-document-revision-pg-id-remap.md b/.doc/archive/ops/2026-09-13-document-revision-pg-id-remap.md new file mode 100644 index 00000000..d7e68e94 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-pg-id-remap.md @@ -0,0 +1,57 @@ +--- +title: "文档账本 PG ID 与计数器重映射" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-pg-id-remap +worktree: "-" +mutex: document-revision +--- + +# 文档账本 PG ID 与计数器重映射 + +## 目标 + +堵住 schema31-round19:首次生成 PG 已写入 snapshot/version/candidate,但 `CommitAgentVersion` 因内存 map 误删 baseline 而 `not found`。 + +## 范围 + +- `internal/docrevision` ID 分配、adopt、PG persist +- 确定性单测 + 隔离 PG 回归 +- audit / remediation / CURRENT / FEATURE-MATRIX / gap-matrix + +## 非目标 + +- 本任务编码阶段不 merge / 不启停容器 / 不 push;Round20 验收见运行时 UI 报告 +- 不删不改证据目录 +- 不忽略 `ErrNotFound`,不伪造基线/报告 + +## 步骤 + +1. [x] 从 `dev@fa6a033` 开分支并登记 mutex +2. [x] 独立验证 openTemplate 不推进 counter + 无条件 delete 误删 +3. [x] 统一 helper + 全路径 adopt +4. [x] `gofmt` / `go vet` / `go test -short` / 相关包测试 +5. [x] 原子提交 + +## 验收标准 + +- [x] 占用 ID 不覆盖;adopt 只删同一对象 +- [x] 高序列首次生成:自动提交、V2、candidate committed、baseline 未丢、重启 hydration +- [x] 现场 UI-03:Round20 项目 6159 首次生成 V2/r0,任务 `run_1789343479579646533` 成功(相对 6158 candidate id=175 / output snapshot 250 的 not found) + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-pg-id-remap.md](../../audit/2026-09-13-document-revision-pg-id-remap.md) +- Remediation: [../../remediation/2026-09-13-document-revision-pg-id-remap.md](../../remediation/2026-09-13-document-revision-pg-id-remap.md) +- Checklist: [../checklists/2026-09-13-document-revision-pg-id-remap.md](checklists/2026-09-13-document-revision-pg-id-remap.md) +- Handoff: [../handoffs/2026-09-13-document-revision-pg-id-remap.md](handoffs/2026-09-13-document-revision-pg-id-remap.md) + +## 证据 / 备注 + +- 基线:`dev@fa6a033` +- 验证:`gofmt`/`go vet` PASS;`go test -short ./...` PASS;隔离临时库 `HighSequenceFirstGen` PASS(拒绝 `agent_system_dev`,测完 DROP) +- 失败归档(只读):`.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/schema31-round19-ui03-advisor-briefing-docrevision-not-found/` +- 验收:Round20 UI-03 PASS,见 [../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) +- 工程修复已合入 `dev@b258ab8` diff --git a/.doc/archive/ops/2026-09-13-document-revision-post-restart-final-snippet.md b/.doc/archive/ops/2026-09-13-document-revision-post-restart-final-snippet.md new file mode 100644 index 00000000..b570b04f --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-post-restart-final-snippet.md @@ -0,0 +1,56 @@ +--- +title: "post-restart 期望正文须为最终持久 marker" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-post-restart-final-snippet +worktree: "-" +mutex: document-revision-post-restart-final-snippet +--- + +# post-restart 期望正文须为最终持久 marker + +## 目标 + +第二次 post-restart 已恢复 login/项目/文档/`revision-state` 200/`V3`/`r2`/正文,但 `phase-state.bodySnippet` 仍是 UI-06 marker,断言旧文失败。UI-13b A1 成功保存后须把最终持久正文写入 phase-state;不得放宽 post body 断言。 + +## 范围 + +- `web/src/lib/durableBodySnippet.ts` 纯函数契约 +- UI-06 / UI-13b / UI-15-pre 同步 `latestDurableBodySnippet` → `phase-state.bodySnippet` +- audit / checklist / handoff / CURRENT + +## 非目标 + +- 不改生产业务代码、不重跑真实 UI、不动容器、不 merge、不 push +- 不改删 assets +- 不改删历史失败 assets;不声称全仓 `production_ready=yes` + +## 步骤 + +1. [x] 从 `dev@eb85b8a` 认领分支并登记 mutex +2. [x] 成功修订覆盖旧 snippet;冲突失败稿不成为期望正文 +3. [x] UI-13b 完成后与 UI-15-pre 写入最终 marker +4. [x] `npm test` / `npm run build` +5. [x] 原子提交 +6. [x] Round20 `UI_PHASE=post-restart` PASS(V3/r2 / `A1-win-mu0gwiez`) + +## 验收标准 + +- [x] 契约测试:A1 覆盖 UI06;A2 conflict 不覆盖 A1 +- [x] post-restart 仍断言 `st.bodySnippet` 可见 +- [x] 真实 UI-15 post-restart:Round20 1 passed / 18 skipped;页面恢复 V3/r2/正文 + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-post-restart-final-snippet.md](../../audit/2026-09-13-document-revision-post-restart-final-snippet.md) +- Checklist: [../checklists/2026-09-13-document-revision-post-restart-final-snippet.md](checklists/2026-09-13-document-revision-post-restart-final-snippet.md) +- Handoff: [../handoffs/2026-09-13-document-revision-post-restart-final-snippet.md](handoffs/2026-09-13-document-revision-post-restart-final-snippet.md) + +## 证据 / 备注 + +- 基线:`dev@eb85b8a` +- 失败归档(只读):`.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/schema31-postrestart-stale-body-snippet-failure/`(当时 `bodySnippet=UI06-mu0eq020`) +- Round20 `phase-state`:`versionText=V3` `revisionText=r2` `bodySnippet=A1-win-mu0gwiez` +- 报告:[../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) diff --git a/.doc/archive/ops/2026-09-13-document-revision-post-restart-selector.md b/.doc/archive/ops/2026-09-13-document-revision-post-restart-selector.md new file mode 100644 index 00000000..f3844ea5 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-post-restart-selector.md @@ -0,0 +1,59 @@ +--- +title: "post-restart 项目名 selector 与阶段产物隔离" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-post-restart-selector +worktree: "-" +mutex: document-revision-post-restart-selector +--- + +# post-restart 项目名 selector 与阶段产物隔离 + +## 目标 + +第18轮 main 18 PASS 后,post-restart 在页面已恢复项目时因项目名同时出现在顶栏与侧栏而 strict violation。改为 banner 内唯一 exact 断言,点击仍走可见项目入口;Playwright output/report 与结果 JSON 按 `UI_PHASE` 分离(main 仍用 `ui-acceptance-results.json`)。 + +## 范围 + +- `web/e2e/document-revision-runtime.spec.ts` post-restart 项目恢复断言 +- `web/src/lib/currentProjectRestore.ts` 与契约测试 +- `web/playwright.config.ts` + `playwrightPhaseArtifacts` 按阶段分目录 +- audit / checklist / handoff / CURRENT + +## 非目标 + +- 不改业务逻辑、不重跑真实 UI、不动容器、不 merge、不 push +- 不改删 `.doc/test-reports/assets/` 证据 +- 不声称 post-restart / UI-15 通过 + +## 步骤 + +1. [x] 从 `dev@b824948` 认领分支并登记 mutex +2. [x] 项目入口 click + banner exact 断言;禁 `.first()` 弱化 +3. [x] `UI_PHASE` 分离 `playwright-output-*` / `playwright-report-*` +4. [x] 结果 JSON:main 保持 `ui-acceptance-results.json`;post-restart 写 `ui-acceptance-results-post-restart.json` +5. [x] `npm test` / `npm run build` +6. [x] 原子提交 +7. [ ] 占槽后重跑 post-restart(本轮不做) + +## 验收标准 + +- [x] 页面级 `getByText(项目名)` 在 2 命中时契约判定失败 +- [x] 入口为 complementary exact title;当前项目为 banner exact text +- [x] main / post-restart 产物目录不同 +- [x] post-restart `recordPass` 不覆盖 main 的 `ui-acceptance-results.json` +- [ ] 真实 UI-15 post-restart(未跑) + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-post-restart-selector.md](../../audit/2026-09-13-document-revision-post-restart-selector.md) +- Checklist: [../checklists/2026-09-13-document-revision-post-restart-selector.md](checklists/2026-09-13-document-revision-post-restart-selector.md) +- Handoff: [../handoffs/2026-09-13-document-revision-post-restart-selector.md](handoffs/2026-09-13-document-revision-post-restart-selector.md) + +## 证据 / 备注 + +- 基线:`dev@b824948` +- 失败归档(只读):`.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/schema31-postrestart-project-title-selector-failure/` +- **未跑真实 post-restart,不得标 done** diff --git a/.doc/archive/ops/2026-09-13-document-revision-prelim-output.md b/.doc/archive/ops/2026-09-13-document-revision-prelim-output.md new file mode 100644 index 00000000..dbd9a73a --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-prelim-output.md @@ -0,0 +1,62 @@ +--- +title: "prelim_design 缺 output.md 产物契约修复" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-pi-runner-module +worktree: "-" +mutex: document-revision-prelim-output +--- + +# prelim_design 缺 output.md 产物契约修复 + +## 目标 + +第11轮 UI-11:202 + `prelim_design` 已正确,但 `step_01_draft` 缺真实 `output.md`。embed 官方模板、归一化 runner 路径、缺产物 fail-closed;对「进程 0 + settled failure / 缺产物」的**瞬时**失败做有界全新 step 重试。不得标 `done`。 + +## 范围 + +- `internal/template` embed + loader +- `internal/agent` 路径映射、目标强制、瞬时/永久分类、`Result.Retryable` +- `internal/squad` `runOneStep` 有界全新 invocation +- `deploy/pi-agent/runner.mjs` + `settle-policy.mjs` +- `deploy/pi-agent/Dockerfile` 必须 COPY runner 的全部相对 import 到 `/app` +- `deploy/app/Dockerfile` `COPY templates` / `COPY configs` 到 `/app`;`.dockerignore` 放行官方 markdown +- Docker build context / `/app/templates/docs` 读路径实测(不执行 env-service 重建) +- 文档:audit / remediation / CURRENT + +## 非目标 + +- 不伪造 `output.md`;不执行截断 `write` 参数;不改 E2E prompt;不放宽缺失校验 +- 不触碰/提交证据目录;不执行 env-service 重建/重启;本轮不重跑 E2E +- 不改 FEATURE-MATRIX;不合 `dev`;不 push +- 不对永久缺失(干净 settle 后无产物、`prompt_empty`、治理)无限重试 + +## 步骤 + +1. [x] 从 `dev@2a58674` 开 `fix/document-revision-prelim-output` 并认领 mutex +2. [x] 定位:stub 模板 + `agent_settled` 假成功 + 只认精确 `output.md` 键 +3. [x] embed / 映射 / runner fail-closed + 单测 + 门禁 +4. [x] 纳入现场时序:write 已流出但 `terminated`;SDK retry 1–3 Connection error;`auto_retry_end success=false`;仍 `agent_settled`;trace `success=true` +5. [x] settle-policy + Go 分类 + `runOneStep` 有界全新重试 + 单测 +6. [x] `.dockerignore` 放行 `templates/**/*.md`;Docker context 实测 `/app/templates/docs/prelim_design.md` +7. [x] 本次写入的目标不覆盖、不再调用;backend 明确失败仍 FAIL(不把文件存在当成功);上一轮残留不当成功 +8. [x] `dev@55a4f39` 重建后 runner `ERR_MODULE_NOT_FOUND settle-policy.mjs`:Dockerfile COPY 齐相对模块 + COPY 契约测试 +9. [ ] 占槽后真实 UI 重跑(本轮不做) + +## 验收标准 + +- [ ] 无盘模板时 `prelim_design` 仍为官方「系统初步设计方案」 +- [ ] 绝对/`./`/重复子目录 `rel_path` 能落到目标文件 +- [ ] `ok:true` 但无非空目标 → 失败,不发明正文 +- [x] 瞬时 settled failure → 最多一次全新 step;永久缺失不重试;耗尽 fail-closed +- [x] pi-agent 镜像 COPY 含 runner 全部相对 import(含 `settle-policy.mjs`) +- [ ] intake 工作流单测仍绿 +- [ ] 真实 UI-11 PASS 后才可标 `done` + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-prelim-output.md](../../audit/2026-09-13-document-revision-prelim-output.md) +- Remediation: [../../remediation/2026-09-13-document-revision-prelim-output.md](../../remediation/2026-09-13-document-revision-prelim-output.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui11-prelim-design-missing-output-failure](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui11-prelim-design-missing-output-failure) diff --git a/.doc/archive/ops/2026-09-13-document-revision-quality-context.md b/.doc/archive/ops/2026-09-13-document-revision-quality-context.md new file mode 100644 index 00000000..37c197cb --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-quality-context.md @@ -0,0 +1,46 @@ +--- +title: "质量门禁:行动计划表状态「待续」窄豁免" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-quality-context +worktree: "-" +mutex: docgov +--- + +# 质量门禁:行动计划表状态「待续」窄豁免 + +## 目标 + +结构化行动计划表中独立状态单元格「待续」不再误报;正文/标题/列表/普通表中的「待续」仍 FAIL。禁词表不得删除「待续」。 + +## 范围 + +- `internal/squad/quality_gate.go` 窄 Markdown 表结构识别 +- 敌意单测 + 既有自检豁免 / 投影 / repair 隔离不回归 +- 文档:audit / gap-matrix / CURRENT / FEATURE-MATRIX + +## 非目标 + +- 不删除「待续」禁词;不放宽普通正文/任意同行表格 +- 不触碰 assets / E2E;不操作容器 + +## 步骤 + +1. [x] 认领 CURRENT;写 audit/short-term +2. [x] 仅豁免行动计划表「阶段/状态/进度」列独立单元格(去粗体精确等于「待续」+ 表头列索引对齐 + 实质行动 + 负责/触发完整) +3. [x] 敌意用例:正文「后续章节待续」、`| 内容 | 待续 |`、待续说明、残行/空动作、负责方/触发=待续仍 FAIL;列重排仅状态列可 PASS +4. [x] 门禁 + 原子提交 + +## 验收标准 + +- [x] 现场同构行动表 PASS,且不触发 repair +- [x] 敌意上下文仍记录 `待续` +- [x] `ProhibitedPhrases` 仍含「待续」 +- [x] targeted / `go vet` / `go test -short` / `go test -race ./internal/taskrun` / web test+build / `git diff --check` + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-quality-status-false-positive.md](../../audit/2026-09-13-document-revision-quality-status-false-positive.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui03-quality-status-false-positive](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui03-quality-status-false-positive) diff --git a/.doc/archive/ops/2026-09-13-document-revision-quality-repair-workspace-contract.md b/.doc/archive/ops/2026-09-13-document-revision-quality-repair-workspace-contract.md new file mode 100644 index 00000000..14dffd62 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-quality-repair-workspace-contract.md @@ -0,0 +1,57 @@ +--- +title: "质量修复子工作区契约" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-quality-repair-workspace-contract +worktree: "-" +mutex: document-revision-quality-repair-workspace-contract +--- + +# 质量修复子工作区契约 + +## 目标 + +堵住第13轮 UI-03:repair 步 TASK 引导 `../../output.md`,模型越界改根文件,本地目标缺失导致 `quality_failed` 停在 70。门禁判定保持,修复契约改为本地快照 + containment。 + +## 范围 + +- `internal/squad/repair_workspace.go` 与单测 +- `EnsureQualityOrRepair` / `buildSubWorkspaces` snapshot 布局 +- audit / remediation / CURRENT + +## 非目标 + +- 不放宽必填章节;不把越界根文件当成功;不隐藏 `quality_failed` +- 不改默认步骤的 `../../` context 导航 +- 不碰证据目录;不合 dev;不 rebuild Docker;不 E2E;不 push + +## 步骤 + +1. [x] 从 `dev@8b1a531` 开分支并登记 mutex +2. [x] 快照契约 + containment + 测试 +3. [x] 独立审查 fail-open:`runErr` / containment 不得提升;restore 失败硬返回;创建/删除计入 mutation +4. [x] gofmt / vet / `go test -short ./...` / `-race` squad+agent / settle-policy.test.mjs / `git diff --check` +5. [ ] 真实 UI-03(本轮不做) + +## 验收标准 + +- [x] 仅 `runErr==nil` ∧ 无 containment ∧ `TrustedLocalDeliverable=true` 才覆盖根并重验 +- [x] 越界(含创建/删除受保护父级)恢复后不提升,报告 FAIL +- [x] backend 失败/超时即使留下本地目标也不提升 +- [x] restore 失败立即返回,可测策略能断言错误传播 +- [ ] 现场 UI-03(未跑) + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-quality-repair-workspace-contract.md](../../audit/2026-09-13-document-revision-quality-repair-workspace-contract.md) +- Remediation: [../../remediation/2026-09-13-document-revision-quality-repair-workspace-contract.md](../../remediation/2026-09-13-document-revision-quality-repair-workspace-contract.md) + +## 证据 / 备注 + +- mutex:`document-revision-quality-repair-workspace-contract`(新 mutex,不与现有 in_progress 冲突) +- 基线:`dev@8b1a531` +- 验证(fail-closed 追加):`gofmt` / `go vet ./...` / `go test -short ./...` / `go test -short -race ./internal/squad/ ./internal/agent/` / `node --test deploy/pi-agent/settle-policy.test.mjs` / `git diff --check` PASS +- 保护范围仅 `output.md` / `template.md` / `blackboard.json`;其它父级文件是剩余风险 +- **未跑真实 UI-03,不得标 done**;**不得 merge / rebuild / E2E / push** diff --git a/.doc/archive/ops/2026-09-13-document-revision-reviewer-duty-sync.md b/.doc/archive/ops/2026-09-13-document-revision-reviewer-duty-sync.md new file mode 100644 index 00000000..27123bf8 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-reviewer-duty-sync.md @@ -0,0 +1,68 @@ +--- +title: "项目 reviewer 同步到受控文档职责" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-reviewer-duty-sync +worktree: "-" +mutex: document-revision-reviewer-duty-sync +--- + +# 项目 reviewer 同步到受控文档职责 + +## 目标 + +堵住第17轮 UI-13a:UI-01 已把 USER_B 设为 reviewer,但 `doc_proj6145_intake` 矩阵为 viewer。项目创建时的 reviewer 必须成为后续每份受控文档的权威 `reviewerId`。 + +## 范围 + +- `project_members.document_duty` 迁移与成员 upsert +- 任务生成/账本创建解析项目职责;禁止硬编码 2/3 +- 已有文档缺失/非成员占位的服务端自愈 +- 前端立项 persist `document_duty` + 职责互斥 +- audit / remediation / CURRENT + +## 非目标 + +- 不 merge、不启停/重建容器、不跑/声称真实 UI E2E、不 push +- 不删不改证据目录 +- 不向用户索要 token;不提交账号密码 + +## 步骤 + +1. [x] 从 `dev@639969f` 开分支并登记 mutex +2. [x] RED/GREEN:解析、自愈、成员 duty、前端映射 +3. [x] `gofmt` / `go vet` / `go test -short` / 相关 `-race` / `npm test` / `npm run build` +4. [x] 原子提交 +5. [x] 独立审查收紧(暂不合入):Heal 以 assigned 为权威;成员变更带 duty 并同步文档;缺 role 不降 owner;写权精确断言;迁移多 owner 确定回填;并发 upsert PG 用例;自愈失败不假成功 +6. [x] 最后一轮:移出成员 sync + 前端刷新;空 assigned 只清失效 holder;显式 revoke 再 heal;账本创建失败不成功 +7. [x] 补充审查:lock + 读旧/冲突 holder + 成员写 + 精确清槽同事务;提交后 heal;失败仍 `ERR_DUTY_SYNC` +8. [x] Heal 与成员写共用 `pg_advisory_xact_lock(project_id)`;解析与文档读写同事务;确定性并发 PG 证明旧 reviewer 不复活 + +## 验收标准 + +- [x] A=author、B=reviewer、C=none;第二文档继承;重复执行幂等;旧文档缺失回填 +- [x] 服务端写操作仍按权限拒绝 +- [x] 前端不按名字提升 +- [ ] 现场 UI-13a(未跑) + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-reviewer-duty-sync.md](../../audit/2026-09-13-document-revision-reviewer-duty-sync.md) +- Remediation: [../../remediation/2026-09-13-document-revision-reviewer-duty-sync.md](../../remediation/2026-09-13-document-revision-reviewer-duty-sync.md) +- Checklist: [../checklists/2026-09-13-document-revision-reviewer-duty-sync.md](checklists/2026-09-13-document-revision-reviewer-duty-sync.md) +- Handoff: [../handoffs/2026-09-13-document-revision-reviewer-duty-sync.md](handoffs/2026-09-13-document-revision-reviewer-duty-sync.md) + +## 证据 / 备注 + +- mutex:`document-revision-reviewer-duty-sync`(新 mutex,不占用已有 in_progress) +- 基线:`dev@639969f` +- 证据(只读):`.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui13a-reviewer-duty-sync-failure/` +- 验证(原子清槽轮):`gofmt`/`go vet` PASS;`go test -short ./...` PASS;相关 `-race` PASS;`npm test`/`build` PASS;隔离 PG PASS +- 原子性:成员写与 `HealProjectDocuments` 均先 `pg_advisory_xact_lock(project_id)`,再在同一事务内读成员/文档并更新;旧 heal 不能在转移提交后把 reviewer A 写回 +- PG 集成已写 heal/空 assigned/多 owner 回填/并发 upsert;`-short` 或无 `TEST_DATABASE_URL` 时跳过 +- 隔离跑法:`scripts/run-isolated-duty-sync-pg-tests.sh`(`TEST_DATABASE_URL` 或 `PG_ADMIN_URL` 建临时库)。拒绝 `agent_system_dev` +- 本轮已在已运行的 context Postgres 上 `CREATE DATABASE agent_duty_sync_itest_*`,串行跑通后 `DROP`;未 `env-service`、未动共享库数据 +- **兼容**:旧二进制不读 `document_duty` 仍可运行;新代码在 assigned 为空时不臆造 reviewer。6145 的 B 仍是空 duty,须再走成员 API +- **未跑真实 UI-13a,不得标 done**;**不得 merge / 启停容器 / E2E / push** diff --git a/.doc/archive/ops/2026-09-13-document-revision-runtime.md b/.doc/archive/ops/2026-09-13-document-revision-runtime.md new file mode 100644 index 00000000..dee8479d --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-runtime.md @@ -0,0 +1,107 @@ +--- +title: "文档版本账本运行时整改" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-runtime-ui03 +worktree: "-" +mutex: docgov +--- + +# 文档版本账本运行时整改 + +## 目标 + +消除 revision-state 404、重启丢账本、人工保存无效、overlay 无效;接通首轮/二轮可见确定性 change report;PATCH 权限→账本→投影顺序正确;停在 fix 分支待集成。 + +## 范围 + +- `internal/docrevision` PG hydrate/persist + bootstrap + `MaterializeAgentOutput` +- `internal/server` 授权、PATCH 顺序、orphan 不静默建账 +- `internal/bizdev` 小队成功走 Materialize(禁止仅 OpenTemplate) +- `cmd/document-revision-backfill` gofmt +- `web` 保存链路与 overlay 三模式 +- 工程测试 + 扩展 UI 验收计划(分栏) + +## 非目标 + +- 不占 CURRENT 集成槽、不 `env-service rebuild`、不 push、不 merge `dev` +- 不伪造 PI 叙事 change report;不把 fallback 说成完整 PI 分析 +- 不把 stub 输出写入最终用户验收报告 + +## 步骤 + +1. [x] 审计 / 整改 / 本任务 + CURRENT 认领 +2. [x] 分支 `fix/document-revision-runtime` +3. [x] PG store + bootstrap + backfill +4. [x] Handler / agent / 前端 +5. [x] 首轮报告 Materialize + PATCH 顺序 + 单测 +6. [x] gofmt + UI checklist 扩展 + 文档证据 +7. [x] 分层 commit,输出哈希与剩余 blocker(不 merge/push) + +## 验收标准 + +- [x] 工程门禁与 UI 实战计划分栏 +- [x] Round20 真实 UI **PASS**(见 [../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md)) +- [x] 剩余开放:PI 叙事仍为 fallback;orphan 禁止假 V1(UI-16 验证已注册路径);不可用假数据掩盖 + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-runtime-404.md](../../audit/2026-09-13-document-revision-runtime-404.md) +- Remediation: [../../remediation/2026-09-13-document-revision-runtime-remediation.md](../../remediation/2026-09-13-document-revision-runtime-remediation.md) +- Checklist/UI: [../checklists/2026-09-13-document-revision-runtime-ui-acceptance.md](checklists/2026-09-13-document-revision-runtime-ui-acceptance.md) + +## 证据 / 备注 + +### 工程门禁(非 UI 验收) + +```text +gofmt -l cmd/document-revision-backfill/main.go internal/docrevision/risk.go +go vet ./... +go test -short ./... +cd web && npm test && npm run build +``` + +本轮门禁(2026-09-13 10:11 UTC 独立复跑):`go vet ./...` PASS;`go test -short ./... -count=1` PASS(含 Materialize 首/二轮 change_report_id、PATCH 顺序、Materialize 失败透出、Assert 先职责后租约、SaveDocumentContent 审计、pending 事实源不越权、同步/异步待确认文案、完成活动仅 committed、pending 活动标明待确认、MarkProposalApplied 失败显式可重试);`web npm test` 199+27 PASS;`npm run build` PASS。使用 dev PostgreSQL(schema 28)执行 `TestPGPersistSurvivesNewServiceInstance` PASS,证明新 Service 实例可恢复账本。上述均为工程门禁,不能替代 UI 验收。 + +UI-01 目录同步补丁门禁(2026-09-13):`node --test adminUserDirectorySync.test.ts` 3 PASS;`web npm test` 219+27 PASS;`npm run build` PASS;`go vet ./...` + `go test -short ./...` PASS。未提交 `web/e2e/*` 与 `test-reports/assets/`。 + +UI-01/02 访问与成员落库门禁(2026-09-13):`go test ./internal/projectinstance -short` PASS;`TEST_DATABASE_URL=… go test ./internal/projectinstance -run TestPG_GoverningAccess` PASS;`TEST_DATABASE_URL=… go test ./internal/server -run TestChatProjectAccess` PASS;`go vet ./...` + `go test -short ./...`;`web npm test` + `npm run build`。未提交 e2e/assets。 + +复核补强(同日): +- A:`MaterializeAgentOutput` 错误写入 `TaskRunResult.Success=false` + `ErrorReason`,不再空白忽略 +- B:cand 非空且 report invalid/unassessed 时禁止自动提交(候选标 needs_confirmation) +- C:`AssertHumanCanEdit` 先职责/生命周期再租约;受控投影改 `SaveDocumentContent` 保留 author_last_edited/审计;失败 `DOCUMENT_PROJECTION_FAILED` 可幂等重试 +- D:ChangeReportPanel 完整展示风险条目/项目影响/文档影响建议/开放问题;加载失败显式错误 +- E:revision-state 暴露 `pending_candidate_id` / `pending_change_report_id` / `pending_risk_level` + `can_decide_pending`;工具条「待确认报告」确认/拒绝调 decision API(不绕过确认) +- F:**高风险事实源门禁**:Materialize 后仅 committed 才 MarkDocumentContentUpdated / MarkProposalApplied;`needs_confirmation` 立即 `ProjectOutputMarkdown` 恢复 ledger head,候选仅留 immutable blob;decision=commit 投影后再 Mark;decision=reject 保持旧 head;投影失败显式错误 +- G:**对话可见状态**:`TaskRunResult` 带 `pending_agent_candidate_id` / report / risk;`RequiresAuthorApproval` 可复用但用 `PendingProposal` vs `PendingAgentCandidateID` 区分 DocGov 提案;terminal=`pending_author_confirmation`;同步 coordinator 与异步 `CompletionSummary` 显示「文档候选已生成,待编制人确认」+ artifact 元数据;确认并投影后才「已完成」 +- H:**活动与提案收口**:`RecordActivity(完成交付物)` 仅在 committed 投影成功后;pending 记「候选待编制人确认」;落盘/投影失败不记完成。`MarkProposalApplied` 失败返回显式错误(bizdev / `DOCUMENT_GOVERNANCE_FAILED`)可重试 +- I:**阶段链防传播**:`ExecuteStage` 遇 `PendingAgentCandidateID` 立即停阶段(Success=false + 待确认文案),SubArtifacts 保留候选,**不**吸收 ExtractedData / PriorDoc;确认后由用户重新发起阶段 +- J:**前端历史映射**:`pending_author_confirmation` 显式映射为气泡状态(不再默认 completed);刷新窗口显示「待编制人确认」标签 +- K:**决策幂等收口**:`CommitAgentVersion` 已 committed 且 expected hashes 一致时返回当前 state(可继续投影/MarkProposalApplied);已 committed 禁止 reject。`MarkProposalApplied` 先写 DB 再改内存;已 applied 幂等(包内 Propose+Decide 验证)。decision 失败 hint 指向同决策重试;**不**暴露内存补种 helper(避免内存/DB 分叉) +- L:**Playwright 骨架**:`web` 增加 `@playwright/test` + `playwright.config.ts` + `e2e/document-revision-runtime.spec.ts`(`RUN_UI_ACCEPTANCE=1` 才跑;无 mock/route/API/DB fixture) +- M:**上传注册事实源**:发送前 `await registerUploadAttachments` → `POST /api/v1/freeform-documents`(`client_key` 幂等);失败 UI 显式错误且不发消息、不生成本地 `doc-upload` orphan;成功使用 `doc-free-*` 写入 deliverable/fileStore 并挂 toolbar +- N:**Auth 契约映射(UI-00 实战)**:Go `UserAccount` 为 snake_case;前端在 API 边界 `mapUserAccount`/`mapLoginResult`/`mapMeResult` 统一转 camelCase(login/me/admin users/create/role/status);`BootstrapAdminFromConfig` 的 `UpdateUserRole` 错误不再静默。详见 [../../audit/2026-09-13-auth-useraccount-snake-case-mapping.md](../../audit/2026-09-13-auth-useraccount-snake-case-mapping.md) +- O:**全局用户目录同步(UI-01 实战)**:管理员创建/角色/状态成功后必须经 `syncAdminUserDirectories` 调用父级 `onRefreshUsers`(禁止死 prop / 静默 catch);同浏览器立项候选可立即看到新账号。跨设备/清缓存缺口见 audit 残留风险,**不**下放 admin users API。详见 [../../audit/2026-09-13-admin-user-directory-sync-ui01.md](../../audit/2026-09-13-admin-user-directory-sync-ui01.md) +- P:**无 live 访问 + chat 项目门禁 + 立项成员落库(UI-01/02)**:`GetGoverningInstanceForAccess` 区分从未激活 vs completed/terminated;chat/chatStream 先 `RequireProjectAccess` 再 stage(SSE 拒绝不得先 200);`createProject` 后持久化非创建者成员。详见 [../../audit/2026-09-13-workflow-access-chat-members-ui01-02.md](../../audit/2026-09-13-workflow-access-chat-members-ui01-02.md) +- Q:**立项确认双击竞态**:`handleCreateProjectConfirm` 加同步 in-flight `useRef` 锁 + `createProjectBootstrapIdRef`(取代 state);`createProjectSubmitting`/`submitPhase` 驱动 Modal「立项中/同步成员中」、禁用确认与关闭;失败可串行幂等重试,成功清 bootstrap。证据:`createProjectSubmitGuard.test.ts` +- R:**UI-02 任务作用域契约**:`ResolveMessageScopeForTask` 三态(preactivation / live stage / closed→Err);handler 无 live 创建 202 非 409;E2E UI-02 以 `POST /api/v1/tasks/runs` 2xx 为硬门禁(409/连接异常 FAIL)。证据:`message_scope_test.go`、`TestCreateTaskRun_PreActivationAcceptedNot409`、`document-revision-runtime.spec.ts` UI-02 +- S:**UI-03 客户端同步 + 任务幂等(本分支)**:`templateMatch` intake 标记优先;任务终态后 `postTaskDeliverableSync` merge `doc_proj*`;goose `00030` 放行 `pending_author_confirmation` + `idempotency_key` 部分唯一;`ClaimRun` 先占键再写 chat;FE reconnect 同 run 订阅。审计:[../../audit/2026-09-13-controlled-doc-client-sync-ui03.md](../../audit/2026-09-13-controlled-doc-client-sync-ui03.md)。门禁:`go test -short ./internal/taskrun ./internal/server`;`web npm test` 232+27;`npm run build`。**schema30 真实现卷迁移合入前独立验证**;真实 UI-03 待占槽重跑。 + +### 用户 UI 实战验收 + +Round20 **PASS**。见 [checklist](checklists/2026-09-13-document-revision-runtime-ui-acceptance.md) 与 [test-report](../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md)。项目 6159;UI-03 V2/r0;终态 V3/r2;post-restart 恢复最终正文 `A1-win-mu0gwiez`。 + +### Blockers + +- **DOCREV-RT-PI-NARRATIVE**(仍开放):真实 PI 业务叙事摘要/风险解释未替代确定性 fallback;Round20 已可见 fallback 字段,不得宣称为完整 PI +- **DOCREV-RT-UPLOAD-ORPHAN**(约束仍在,UI-16 PASS):仅 IndexedDB、无服务端正文 → 禁止假 V1 +- **DOCREV-RT-UI-E2E**:**PASS**(Round20) +- **DOCREV-RT-SCHEMA30-VOLUME**:goose 00030 对既有重复卷的迁移仍属合入前独立验证残留 +- **DOCREV-RT-USER-DIR-CROSS-DEVICE**:跨设备/新浏览器可能仍缺成员候选(本轮同浏览器未暴露) + +### Commits(历史) + +- `7ea686e` … `ec8a45a`(见 git log);本轮追加见会话结束提交号 diff --git a/.doc/archive/ops/2026-09-13-document-revision-second-doc-routing-lease.md b/.doc/archive/ops/2026-09-13-document-revision-second-doc-routing-lease.md new file mode 100644 index 00000000..97c90c72 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-second-doc-routing-lease.md @@ -0,0 +1,55 @@ +--- +title: "UI-11 点名优先路由 + PATCH 请求级释租" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-second-doc-routing-lease +worktree: "-" +mutex: document-revision-second-doc-routing-lease +--- + +# UI-11 点名优先路由 + PATCH 请求级释租 + +## 目标 + +第十轮 UI-11 首错:否定句「需求」压过「系统设计输入」,且 PATCH 残留 human lease 使小队 DOC_BUSY。点名优先 + 请求级 defer 释租 + E2E 202 门闩。不得将本任务标 `done`。 + +## 范围 + +- `web/src/engine/templateMatch.ts` + 单测 +- `internal/server/document_revision_handlers.go` + `document_revision_patch_order_test.go` +- `web/e2e/document-revision-runtime.spec.ts` UI-11 waiter +- 文档:audit / remediation / CURRENT + +## 非目标 + +- 不改 E2E prompt;不改 `SaveDocumentContent` 内部释租 +- 不触碰/提交 `.doc/test-reports/assets`;不操作容器;本轮不重跑 E2E +- 不改 FEATURE-MATRIX;不合 `dev`;不 push + +## 步骤 + +1. [x] 认领 CURRENT(mutex `document-revision-second-doc-routing-lease`) +2. [x] 点名优先 +「系统设计输入」别名 + 单测 +3. [x] PATCH 已授权后 defer 释租(成功 / 409 / 投影失败)+ 服务端测试 +4. [x] UI-11 send 前 `tasks/runs` waiter,断言 202 后再 wait completion +5. [ ] 占槽后真实 UI 重跑(本轮不做) + +## 验收标准 + +- [x] UI-11 原文 / 混合句 → `prelim_design`;当前文档钉住、UI-05 pin、首轮摸底仍 intake +- [x] PATCH 后无 human lease,squad 可获取 +- [x] UI-11 非 202 即 fail;`requireInflight` 拒绝同步 busy +- [ ] 真实 UI-11 PASS 后才可将本任务标 `done` + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-second-doc-routing-lease.md](../../audit/2026-09-13-document-revision-second-doc-routing-lease.md) +- Remediation: [../../remediation/2026-09-13-document-revision-second-doc-routing-lease.md](../../remediation/2026-09-13-document-revision-second-doc-routing-lease.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui11-second-doc-routing-human-lease-failure](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui11-second-doc-routing-human-lease-failure) + +## 证据 / 备注 + +- Prompt 别名「系统设计输入」≠ 卡片标题。真实 UI / 模板 / squad 标题均为「系统初步设计方案」。 +- UI-11 打开第二份文档必须用已注册 `doc_proj{n}_prelim_design`(`data-doc-id`),禁止 `/设计输入|系统设计/`:既匹配不到真实标题,也容易误命中其他设计类文案或同标题模板槽。 diff --git a/.doc/archive/ops/2026-09-13-document-revision-sse-idempotency.md b/.doc/archive/ops/2026-09-13-document-revision-sse-idempotency.md new file mode 100644 index 00000000..730bc674 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-sse-idempotency.md @@ -0,0 +1,57 @@ +--- +title: "任务 SSE 幂等 + 质量门禁自污染与 auto_repair 产品契约" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-sse-idempotency +worktree: "-" +mutex: docgov +--- + +# 任务 SSE 幂等 + 质量门禁自污染与 auto_repair 产品契约 + +## 目标 + +1. 同 turn 在 SSE 断线重连时返回既有 run 202、不重复聊天、不误 409 DOC_BUSY;长任务 events SSE 不被 120s WriteTimeout 切断;前端 EOF 按 after_seq 重订阅同一 run。 +2. 受控文档小队任务质量门禁:**服务端启用修复预算**;否定性自检引用不误报;`quality_failed` UI 保持失败且不激活未过门禁稿。 + +## 范围 + +- SSE/幂等:`task_run_handlers`、SSE write deadline、FE subscribe 重连 +- 质量 A–D:`repairBudgetForSquadTask`、`quality_gate` 语境检测、prompt 去原词、Materialize/`TerminalStatus`、FE `quality_failed`、单测 +- 证据:`data/dev/workspaces/bizdev/intake_1789308825666278807`(output.md:204;events seq10) + +## 非目标 + +- 不改全局 HTTP 超时为「无超时」;不 rebuild Docker;不 push/merge;不删证据 assets + +## 步骤 + +1. [x] 从 `dev` 开 `fix/document-revision-sse-idempotency`;CURRENT 认领 +2. [x] 幂等先查 + 属主校验 +3. [x] SSE write deadline + heartbeat +4. [x] FE subscribe 重连 +5. [x] A 服务端修复预算产品契约 +6. [x] B 门禁否定/元语境 + prompt 去原词 +7. [x] C quality_failed UI/Materialize 契约 +8. [x] D 真实问题单测 + 门禁回归 +9. [x] E 质量失败在 SetDocumentWorkDir/Materialize 前短路(无正式投影副作用) +10. [x] 豁免收窄为同行 meta+否定紧邻/引号;handlers 阶段请求字段边界单测锁定 +11. [x] ExecuteStage 质量失败停链:不吸收事实、不追加 PriorDoc +12. [x] 小队 AutoRepair/Success 语义恢复;受控修复仅在 bizdev docRec 与 HTTP 边界强制 +13. [x] 补强:quality projection / 阶段停链 / 非受控不强制 repair 单测;全量 Go+Web 门禁 PASS + +## 验收标准 + +- [x] 同 turn + 活跃租约 → 同 run 202、仅一对消息;不同 turn → 仍 409 +- [x] SSE 心跳/写期限可测;FE EOF/after_seq 单测 +- [x] TaskKey 任务 AutoRepair=false 仍有 DefaultMaxRepairRounds;L204 自检引用不误报;真敷衍仍 FAIL +- [x] quality_failed ≠ completed;Materialize 跳过未过门禁稿 +- [x] `go test -short ./...`、`go vet`、`npm test`/`build`、`git diff --check` + +## 相关链接 + +- Audit SSE: [../../audit/2026-09-13-document-revision-sse-idempotency.md](../../audit/2026-09-13-document-revision-sse-idempotency.md) +- Audit 质量: [../../audit/2026-09-13-document-revision-quality-gate-self-pollution.md](../../audit/2026-09-13-document-revision-quality-gate-self-pollution.md) +- Evidence: [../../test-reports/assets/2026-09-13-document-revision-runtime-ui/](../../test-reports/assets/2026-09-13-document-revision-runtime-ui/) diff --git a/.doc/archive/ops/2026-09-13-document-revision-wave0-contract.md b/.doc/archive/ops/2026-09-13-document-revision-wave0-contract.md new file mode 100644 index 00000000..7a33b6bb --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-wave0-contract.md @@ -0,0 +1,49 @@ +--- +title: "DOCREV Wave 0:契约冻结" +status: done +created: 2026-09-13 +updated: 2026-09-13 +owner: Cursor +branch: feature/document-revision-management +worktree: "-" +mutex: docgov +--- + +# DOCREV Wave 0:契约冻结 + +## 目标 + +冻结 Version/Revision/Snapshot/Candidate/Report 契约、黄金 diff fixture、前后端类型与先红契约测试。 + +## 范围 + +- ADR 决策门落盘 +- `internal/docrevision` 契约类型、schema、testdata、契约测试 +- `web/src/features/documentRevision/types.ts` + +## 非目标 + +- 不写生产写路径;不跑容器重建;不合入 `dev` + +## 步骤 + +1. [ ] 写入 ADR 与决策门 +2. [ ] 实现契约类型、change-report schema、黄金 fixture +3. [ ] 契约测试先红后绿(随 Wave 1 内核实现变绿) +4. [ ] 前端 types 对齐 + +## 验收标准 + +- [ ] ADR 已接受且与实施计划冻结表一致 +- [ ] 黄金 diff 覆盖中文段落/表格/列表/Mermaid/移动块/no-op +- [ ] 契约测试可独立运行 + +## 相关链接 + +- ADR: `../../adr/2026-09-13-document-version-boundary.md` +- Design: `../../system-design/document-revision-management.md` +- Remediation: `../../remediation/2026-09-13-document-revision-management-implementation-plan.md` + +## 证据 / 备注 + +实施中。 diff --git a/.doc/archive/ops/2026-09-13-document-revision-wave1-6-implementation.md b/.doc/archive/ops/2026-09-13-document-revision-wave1-6-implementation.md new file mode 100644 index 00000000..b6a436f3 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-wave1-6-implementation.md @@ -0,0 +1,45 @@ +--- +title: "DOCREV Wave 1–6:ledger 实施" +status: done +created: 2026-09-13 +updated: 2026-09-13 +owner: Cursor +branch: feature/document-revision-management +worktree: "-" +mutex: docgov +--- + +# DOCREV Wave 1–6:ledger 实施 + +## 目标 + +在 feature 分支交付快照内核、人工 PATCH、Agent candidate、比较 UI、通知与自由文档兼容。 + +## 范围 + +- Goose 00028、`internal/docrevision`、HTTP API、前端工具条、bizdev/freedoc/notification 接线 + +## 非目标 + +- 本任务不占集成槽位合入 `dev`;真实 PI 全链路补录另开集成窗口 + +## 步骤 + +1. [x] Wave 0 契约与 ADR +2. [x] Wave 1 迁移与内核 +3. [x] Wave 2 人工编辑 API/UI +4. [x] Wave 3 Agent candidate/commit +5. [x] Wave 4 比较 UI +6. [x] Wave 5 通知 +7. [x] Wave 6 自由文档兼容 + +## 验收标准 + +- [x] `go test -short ./internal/docrevision/...` PASS +- [x] 相关包回归 PASS +- [ ] 真实 PI + Playwright 双用户(集成槽位) + +## 相关链接 + +- Test report: `../../test-reports/2026-09-13-document-revision-management-test-report.md` +- ADR: `../../adr/2026-09-13-document-version-boundary.md` diff --git a/.doc/archive/ops/2026-09-13-document-revision-workflow-category-navigation.md b/.doc/archive/ops/2026-09-13-document-revision-workflow-category-navigation.md new file mode 100644 index 00000000..b36d34ce --- /dev/null +++ b/.doc/archive/ops/2026-09-13-document-revision-workflow-category-navigation.md @@ -0,0 +1,52 @@ +--- +title: "受控文档分类导航契约" +status: done +created: 2026-09-13 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-workflow-category-navigation +worktree: "-" +mutex: document-revision-workflow-category-navigation +--- + +# 受控文档分类导航契约 + +## 目标 + +堵住第15轮 UI-13a:UI-11 后停在「我的私密」,未切「流程受控」就展开文档菜单,找不到 `doc_proj*_intake`。只改验收导航,不降真实性。 + +## 范围 + +- `web/src/lib/workflowCategoryNavigation.ts` 与单测 +- `web/e2e/document-revision-runtime.spec.ts` 三个 opener +- audit / remediation / CURRENT + +## 非目标 + +- 不改产品分类状态机;不用 API/内存规避 UI +- 不碰证据;不合 dest;不启停容器;不 E2E;不 push + +## 步骤 + +1. [x] 从 `dev@48a4dcb` 开分支并登记 mutex +2. [x] 导航谓词 + private→workflow / 缺失 fail-closed 测试 +3. [x] 三个 opener 先真实切分类 +4. [x] `npm test` + `npm run build` 并原子提交 + +## 验收标准 + +- [x] 从私密分类可恢复到精确受控文档 +- [x] 目标缺失 fail-closed +- [ ] 现场 UI-13a(未跑) + +## 相关链接 + +- Audit: [../../audit/2026-09-13-document-revision-workflow-category-navigation.md](../../audit/2026-09-13-document-revision-workflow-category-navigation.md) +- Remediation: [../../remediation/2026-09-13-document-revision-workflow-category-navigation.md](../../remediation/2026-09-13-document-revision-workflow-category-navigation.md) + +## 证据 / 备注 + +- mutex:`document-revision-workflow-category-navigation`(新 mutex) +- 基线:`dev@48a4dcb` +- 验证:`npx tsx --test src/lib/workflowCategoryNavigation.test.ts` PASS;`cd web && npm test` PASS(309 + 29);`npm run build` PASS +- **未跑真实 UI-13a,不得标 done**;**不得 merge / 启停容器 / E2E / push** diff --git a/.doc/archive/ops/2026-09-13-herdr-agent-governance.md b/.doc/archive/ops/2026-09-13-herdr-agent-governance.md new file mode 100644 index 00000000..eca91c56 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-herdr-agent-governance.md @@ -0,0 +1,62 @@ +--- +title: "Herdr Agent 角色、备援与自动审批治理" +status: done +created: 2026-09-13 +updated: 2026-09-13 +owner: Codex +branch: feature/herdr-agent-governance +worktree: .worktrees/feature-herdr-agent-governance +mutex: ops-governance +--- + +# Herdr Agent 角色、备援与自动审批治理 + +## 目标 + +建立可审计的 Herdr Agent 能力分工、额度保护、故障接管和免人工工具审批入口,并明确 Herdr PI 与产品容器 PI Agent Runner 不是同一执行体。 + +## 范围 + +- 持久化主责、备份顺序、任务泳道和接管条件。 +- 为已安装的 Claude、Codex、Cursor、Antigravity、PI、Kimi、Cline CLI 提供统一启动入口。 +- 自动审批仍受仓库、worktree、mutex、集成槽和破坏性操作红线约束。 +- 提供保守的自动派发:只向同工作目录、空闲的规范命名实例投递;明确失败时降级,超时停止重复投递。 + +## 非目标 + +- 不重启或接管当前正在执行 DOCREV/CHAT/INTENT 的实例。 +- 不修改容器内 PI Agent Runner 的模型、凭证、配置或运行状态。 +- 不操作共享 Docker 或推送远端。 +- 不将删库、强推、密钥读取/外传等不可逆动作纳入无条件许可。 + +## 步骤 + +1. [x] 盘点 Herdr 0.9.0、在线实例、集成状态、CLI 版本和审批参数。 +2. [x] 写入项目级角色与备援 SSOT,并在 AGENTS/PROJECT 建立入口。 +3. [x] 实现统一自动审批启动脚本和保守派发脚本。 +4. [x] 完成静态检查、脚本 dry-run 与路由验收。 +5. [x] 更新任务状态、提交 feature 分支并合入 `dev`。 + +## 验收标准 + +- [x] 每种当前可调用 CLI 都有明确角色、主备关系和自动审批启动参数。 +- [x] Codex/Claude 的高成本推理与 Cursor/Flash 模型的实施负载分离。 +- [x] 明确禁止因 timeout/unknown 状态盲目重复派发。 +- [x] Herdr PI 与产品容器 PI 在名称、职责和动作上不会混淆。 +- [x] 启动和派发脚本通过 `bash -n`,dry-run 不启动实例、不执行任务。 + +## 相关链接 + +- 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) +- Test report: 本任务文“证据 / 备注” + +## 证据 / 备注 + +- `herdr status`: client/server 0.9.0,protocol 22,兼容。 +- `herdr integration status`: Claude/Codex/Cursor/Antigravity/PI/Kimi integration current;Cline CLI 3.0.61 可调用。 +- CLI 版本:Claude 2.1.270、Codex 0.154.0、Cursor 2026.09.10、Antigravity 1.2.2、PI 0.85.1、Kimi 0.41.0、Cline 3.0.61。 +- `bash -n scripts/herdr-agent-start.sh scripts/herdr-agent-dispatch.sh`: PASS。 +- 七种启动 profile dry-run:PASS;未启动或重启实例。 +- 七条 lane `--explain`:PASS。 +- 非法标准名:exit 2;无在线标准实例:逐级跳过并 exit 69,未误投任务。 diff --git a/.doc/archive/ops/2026-09-14-controlled-content-ui-acceptance.md b/.doc/archive/ops/2026-09-14-controlled-content-ui-acceptance.md new file mode 100644 index 00000000..6e32c928 --- /dev/null +++ b/.doc/archive/ops/2026-09-14-controlled-content-ui-acceptance.md @@ -0,0 +1,37 @@ +--- +title: "受控文档正文修复真实 UI 实战验收" +status: done +owner: verifier_antigravity +branch: fix/controlled-content-ui-acceptance +mutex: document-content-ui-acceptance +created: 2026-09-14 +updated: 2026-09-14 +--- + +# 目标 + +仅通过真实浏览器页面操作,验证项目 143 历史文档恢复,并以真实产品 PI Agent Runner / 智能体小队完成新项目文档全链路。API、数据库和 stub 不能替代 UI 验收结果。 + +# 范围 + +- 项目 143:登录、打开正文、30 秒空闲、双击编辑保存、三种变更视图、刷新与重新登录持久化。(clean-run3 已全部 PASS) +- 新项目:从 UI 创建,真实对话触发工作流/小队生成文档,再次对话触发修改;页面查看助手回复、文档正文、版本账本、影响、风险、开放问题。(full-chain-final UI-00..UI-16 全部 18 项 PASS) +- 冲突与权限:双页面并发编辑、审核人/无关用户访问边界均通过;宿主容器重启后 post-restart 复验通过。 +- Ubuntu Server 浏览器:统一使用 Playwright 官方 `mcr.microsoft.com/playwright:v1.63.0-noble` 容器。 + +# 红线 + +- 不用 API 直建用户、项目、会话、文档或测试数据。 +- 不注入/伪造 assistant 消息、文档、账本、change report 或通过结果。 +- 所有通过项必须有页面可见证据;失败如实记录为 FAIL。 +- 测试账号凭证只读本机既有 secrets/phase 文件,不输出、不提交。 + +# 阶段判据与进展 + +- [x] 项目 143 页面正文可见且无 content/revision 404(UI-143-01..06 全 PASS,产物在 `clean-run3/`)。 +- [x] 人工编辑、视图切换、刷新/重登持久化通过(项目 143 回归)。 +- [x] 新项目真实 PI/小队链路及文档影响风险报告页面可见(UI-00..05b 通过,首轮 toolbar V2/r0,UI-05 pending 保持 V2,UI-05a 确认后晋升 V3,UI-05b 拒绝后保持 V3)。 +- [x] UI-06 硬刷新正文保留通过(合入 08bf615 修复后 1.1 秒内秒级通过)。 +- [x] 并发、权限、重启前凭据生成有真实 UI 判定(UI-12/13a/13b/15/16 全 PASS)。 +- [x] 容器重启后恢复核验通过(UI-15 post-restart 2.8 秒秒级通过,V3/r2 与标记完好呈现,目标 404=0)。 +- [x] 测试报告落盘至 `.doc/test-reports/2026-09-14-controlled-content-ui-acceptance.md`。 diff --git a/.doc/archive/ops/2026-09-14-document-revision-evidence-count.md b/.doc/archive/ops/2026-09-14-document-revision-evidence-count.md new file mode 100644 index 00000000..890810be --- /dev/null +++ b/.doc/archive/ops/2026-09-14-document-revision-evidence-count.md @@ -0,0 +1,42 @@ +--- +title: "运行时 UI 证据计数与 race 秒数纠错" +status: done +created: 2026-09-14 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/document-revision-evidence-count +worktree: "-" +mutex: document-revision-evidence-count +--- + +# 运行时 UI 证据计数与 race 秒数纠错 + +## 目标 + +把顶层截图写成 21(20 main/pre + 1 post),并把全包 race 写成 `FAIL 109.279s`,不与 21 条 results 混淆。 + +## 范围 + +- 最终报告、UI checklist、CURRENT +- 本短任务登记后即关闭 + +## 非目标 + +- 不改业务代码、assets、容器,不 push +- 不改 UI PASS 判定,不提交 secrets + +## 步骤 + +1. [x] 从 `dev@5d79da6` 开 `fix/document-revision-evidence-count` 并登记 +2. [x] 截图 21 = 20 main/pre + 1 post;race `FAIL 109.279s` +3. [x] `git diff --check`;只提交文档 + +## 验收标准 + +- [x] 报告/清单不再把 20 张截图与 21 条 JSON 混写 +- [x] 全包 race 不再写成 `ok ... 110.723s` +- [x] assets 未 stage + +## 相关链接 + +- Test report: [../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) diff --git a/.doc/archive/ops/2026-09-14-document-revision-runtime-ui-final-report.md b/.doc/archive/ops/2026-09-14-document-revision-runtime-ui-final-report.md new file mode 100644 index 00000000..ead211d5 --- /dev/null +++ b/.doc/archive/ops/2026-09-14-document-revision-runtime-ui-final-report.md @@ -0,0 +1,45 @@ +--- +title: "文档账本运行时 UI 最终报告收口" +status: done +created: 2026-09-14 +updated: 2026-09-14 +owner: Cursor-Auto +branch: feature/document-revision-runtime-ui-final-report +worktree: "-" +mutex: document-revision-runtime-ui +--- + +# 文档账本运行时 UI 最终报告收口 + +## 目标 + +在 `dev@b258ab8` 上只写文档,把 Round20 真实 UI 验收收口为 test-report,并释放运行时集成槽。 + +## 范围 + +- `.doc/test-reports/2026-09-14-document-revision-runtime-ui-test-report.md` +- management report、UI checklist、runtime / PG-id 文档、FEATURE-MATRIX、gap-matrix、CURRENT + +## 非目标 + +- 不改业务代码、不跑容器、不 push、不提交 assets +- 不引用 `phase-secrets.local.json` 内容 +- 不把全仓标 `production_ready=yes` + +## 步骤 + +1. [x] 从 `dev@b258ab8` 开 `feature/document-revision-runtime-ui-final-report` +2. [x] 按 results JSON 写 Input/Actual/Verdict/Duration +3. [x] 同步任务文档并释放集成槽 +4. [x] 原子 docs commit + +## 验收标准 + +- [x] 运行时范围 PASS/done +- [x] `production_ready` 仍为 no;`CHAT-INTENT` 保留 +- [x] 历史失败资产未改删 + +## 相关链接 + +- Test report: [../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) +- Checklist: [../checklists/2026-09-13-document-revision-runtime-ui-acceptance.md](checklists/2026-09-13-document-revision-runtime-ui-acceptance.md) diff --git a/.doc/archive/ops/2026-09-14-document-revision-session-close.md b/.doc/archive/ops/2026-09-14-document-revision-session-close.md new file mode 100644 index 00000000..3f23ef2e --- /dev/null +++ b/.doc/archive/ops/2026-09-14-document-revision-session-close.md @@ -0,0 +1,47 @@ +--- +title: "文档账本运行时会话关闭归档" +status: done +created: 2026-09-14 +updated: 2026-09-14 +owner: Cursor-Auto +branch: feature/document-revision-session-close +worktree: "-" +mutex: document-revision-session-close +--- + +# 文档账本运行时会话关闭归档 + +## 目标 + +按 AGENTS 会话关闭清单:把已 done 的 document-revision short-term / checklist / handoff 迁入 archive,并修好相对链接。 + +## 范围 + +- `.doc/ops/short-term/*document-revision*` +- 4 个专项 checklist + runtime-ui-acceptance +- 4 个 document-revision handoff +- `.doc` 内因移动失效的相对链接 +- 本任务完成后一并归档 + +## 非目标 + +- 不改业务代码、assets、容器,不 push +- 不改 `production_ready=no`、fallback / race 结论 +- 不改非 document-revision 任务 + +## 步骤 + +1. [x] 从 `dev@4bf8b6d` 开 `feature/document-revision-session-close` 并登记 +2. [x] short-term / checklist / handoff 标 done 后 `git mv` 入 archive +3. [x] 扫描并重写失效相对链接;`git diff --check` + +## 验收标准 + +- [x] CURRENT 焦点仅非 DOCREV;槽位 idle +- [x] 本次移动文件的相对 Markdown 链接可解析 +- [x] assets 未 stage + +## 相关链接 + +- Test report: [../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) +- CURRENT: [CURRENT](../../ops/CURRENT.md) diff --git a/.doc/archive/ops/2026-09-14-durable-event-fav-integration.md b/.doc/archive/ops/2026-09-14-durable-event-fav-integration.md new file mode 100644 index 00000000..22b15e1c --- /dev/null +++ b/.doc/archive/ops/2026-09-14-durable-event-fav-integration.md @@ -0,0 +1,61 @@ +--- +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 的事务主链。 diff --git a/.doc/archive/ops/2026-09-14-governance-action-level-authz.md b/.doc/archive/ops/2026-09-14-governance-action-level-authz.md new file mode 100644 index 00000000..77b0ef27 --- /dev/null +++ b/.doc/archive/ops/2026-09-14-governance-action-level-authz.md @@ -0,0 +1,81 @@ +--- +title: "治理鉴权升级:职责-动作严格对应 + 未激活拦截 + 关闭创建直通" +status: done +created: 2026-09-14 +updated: 2026-09-14 +owner: implementer_cursor +branch: fix/governance-action-level-authz +worktree: ".worktrees/fix-governance-action-level-authz" +mutex: workflow +--- + +# 治理鉴权升级:职责-动作严格对应 + 未激活拦截 + 关闭创建直通 + +## 目标 + +采纳 [MVP 治理规则评审](../../ops/research/2026-09-14-mvp-governance-rules-review.md) 修正版原则:**允许零治理创建与普通对话;禁止零治理激活与执行文档任务(审批流动作)**。文档动作按职责鉴权,创建者不隐式越权,`initial_workflow_key` 不再直通 active。 + +## 决策记录(已定,不再开放) + +- **A(用户拍板 2026-09-14)**:`DutyModeNone` 文档 = 不走人工审批但**可生成**(创建者触发,维持已实施 D4);「不可发起任务」收窄为不可发起**审批流动作**(submit/review/approve)。 +- **B(按评审建议采纳)**:pre-activation 保留 202 契约——`POST /tasks/runs` 仍 202 创建 run,但置 blocked 状态、不启动小队、不取文档租约,chat 流内返回自然语言治理提示。 +- **C(按评审建议采纳)**:移除 `isCreator` 对 full 文档的隐式全通行;`view` 豁免阶段收窄(项目访问成员可查看);创建者保留:配置成员/职责 + none 文档生成触发。 +- **D(按评审建议采纳)**:关闭 `initial_workflow_key` 直通 active(仅挂载目录);后端/前端 types 字段废弃标注;E2E legacy 用例语义更新;dev 库 81 个 planning+with_wf 异态项目**只审计分类,不改库**。 + +## 采纳版职责-动作矩阵 + +| 动作 | full 文档 | none 文档 | 未激活(gov==nil) | +|------|-----------|-----------|--------------------| +| view | 项目访问成员 | 项目访问成员 | 项目访问成员 | +| run(首次生成/重生成) | 编制负责人 | **创建者**(无审批链) | 202 + blocked 状态,chat 内提示,不启小队/不取租约 | +| edit/submit(编辑/提交审核) | 编制负责人 | 拒绝(无审批链) | 拒绝 | +| review(审核/退回) | 审核负责人 | 拒绝 | 拒绝 | +| approve(批准/拒绝批准) | 批准负责人 | 拒绝 | 拒绝 | +| 配置成员/文档职责 | 创建者 | 创建者 | 创建者(planning 期配置正是本阶段语义) | + +退回后形成「待编制人修订」;审核人不得直接启动重编(由编制负责人发起修订)。 + +## 范围 + +- `internal/projectinstance/document_access.go`(动作-职责映射、creator 例外移除、gov==nil 未激活拦截) +- `internal/projectinstance/stage_access.go`(view 豁免语义;`docTaskDutyForUser` 拆分为按职责判定) +- `internal/projectinstance/message_scope.go` + taskrun/chat handler(blocked 状态 + 自然语言提示) +- `internal/projectworkflow/service.go`(关闭 `initial_workflow_key` 直通)+ `types.go` 前后端字段废弃 +- 受影响单测重写(`access_governing_pg_test.go` creator 断言、`TestCreateTaskRun_PreActivationAcceptedNot409` 语义细化)与 E2E legacy 用例 + +## 非目标 + +- 不改三权互斥与 DutyMode 校验(Wave 2 已完成) +- 不做运行中动态补配职责 / 按文档单独激活(冻结语义维持,激活页提示「留空文档不参与、不可补配」) +- 不做成员 role 枚举演进(MVP 维持创建者=项目管理员;role 演进留 backlog) +- 不改 dev 库存量数据(仅审计) + +## 步骤 + +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 集成验证 + 测试报告归档(新项目全链路:零治理创建→对话→配置→激活→职责动作负例) + +## 验收标准 + +- [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] 异态审计报告与测试报告归档并回链 + +## 相关链接 + +- Research(评审与决策记录): [2026-09-14-mvp-governance-rules-review.md](../../ops/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)。 diff --git a/.doc/archive/ops/2026-09-14-module-decoupling-remediation-plan.md b/.doc/archive/ops/2026-09-14-module-decoupling-remediation-plan.md new file mode 100644 index 00000000..2ba98905 --- /dev/null +++ b/.doc/archive/ops/2026-09-14-module-decoupling-remediation-plan.md @@ -0,0 +1,55 @@ +--- +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` 均通过。 diff --git a/.doc/archive/ops/2026-09-14-project143-controlled-content-404-diagnosis.md b/.doc/archive/ops/2026-09-14-project143-controlled-content-404-diagnosis.md new file mode 100644 index 00000000..71ae6c0a --- /dev/null +++ b/.doc/archive/ops/2026-09-14-project143-controlled-content-404-diagnosis.md @@ -0,0 +1,48 @@ +--- +title: "项目 143 受控文档正文 404 现场诊断" +status: done +created: 2026-09-14 +updated: 2026-09-14 +owner: Codex +branch: fix/project143-controlled-content-404-diagnosis +worktree: "-" +mutex: docgov-content-diagnosis +--- + +# 项目 143 受控文档正文 404 现场诊断 + +## 目标 + +定位已登录用户打开项目 143 时 `doc_proj143_intake` 正文接口返回 404 的当前根因,并形成可复核的整改边界。 + +## 范围 + +- 对照当前 dev 源码、数据库、工作区文件与既有真实 UI 证据。 +- 分析服务端 404 条件、前端 hydration 与重复请求条件。 +- 形成审计记录和整改建议;本轮不修改业务代码。 + +## 非目标 + +- 不恢复或覆盖用户文档数据。 +- 不以 API 探针或伪造数据替代后续真实浏览器验收。 +- 不继续纯软件项目自举方案实施。 + +## 步骤 + +1. [x] 核对项目 143 的项目、文档记录、账本与工作区事实源。 +2. [x] 核对正文 handler 的 404 分支和前端 hydration 重试条件。 +3. [x] 记录根因、影响范围、整改顺序和验收要求。 + +## 验收标准 + +- [x] 404 的直接原因与数据/代码证据相互印证。 +- [x] 明确区分历史项目数据缺口、当前能力回归和前端错误放大。 +- [x] 不宣称未执行的浏览器或真实 PI 结果。 + +## 相关链接 + +- Audit: [../../audit/2026-09-14-project143-controlled-content-404.md](../../audit/2026-09-14-project143-controlled-content-404.md) + +## 证据 / 备注 + +结论:文件存在;raw/canonical 哈希因 5 处 Markdown 双空格硬换行产生 10-byte 差异。该空格具有渲染语义,须保全原文修复。详见 Audit 与 Remediation。 diff --git a/.doc/archive/ops/2026-09-14-software-project-bootstrap-plan.md b/.doc/archive/ops/2026-09-14-software-project-bootstrap-plan.md new file mode 100644 index 00000000..b278aaba --- /dev/null +++ b/.doc/archive/ops/2026-09-14-software-project-bootstrap-plan.md @@ -0,0 +1,51 @@ +--- +title: "纯软件项目自举工作流方案" +status: done +created: 2026-09-14 +updated: 2026-09-14 +owner: Codex +branch: feature/software-project-bootstrap-plan +worktree: "-" +mutex: workflow-design +--- + +# 纯软件项目自举工作流方案 + +## 目标 + +基于当前 Agent-System 的真实能力,设计一套可创建、可配置、可冻结、可执行、可验收的纯软件项目自举工作流,并明确复用智能体小队、文档模板、权限与阶段门禁的实施路线。 + +## 范围 + +- 当前项目创建、工作流、阶段、文档、智能体小队和 UI 能力盘点 +- 纯软件项目的创建选项、阶段模型、交付物、门禁、角色与小队设计 +- 从最小可用版本到完整自举闭环的实施拆分、数据迁移、API/UI 与验收计划 + +## 非目标 + +- 本轮不修改 Go、React、数据库迁移、模板或智能体配置 +- 不把医疗器械合规要求默认带入纯软件项目 +- 不宣称尚未实现的方案已经可用 + +## 步骤 + +1. [x] 盘点当前实现与可复用能力 +2. [x] 完成详细系统设计和创建向导设计 +3. [x] 给出分阶段实施与真实验收计划 +4. [x] 更新 FEATURE-MATRIX、CURRENT 并完成文档校验 + +## 验收标准 + +- [x] 方案覆盖工作流、文档、智能体小队、角色权限、项目创建选项、状态机、API/UI、迁移和验收 +- [x] 清楚区分已实现、可复用、需新增和暂缓项 +- [x] 自举机制有边界、有人工确认点且不会让智能体自行修改治理规则 + +## 相关链接 + +- Research: [../../ops/research/2026-09-14-software-project-bootstrap-current-state.md](../../ops/research/2026-09-14-software-project-bootstrap-current-state.md) +- Design: [../../system-design/2026-09-14-software-project-bootstrap-workflow.md](../../system-design/2026-09-14-software-project-bootstrap-workflow.md) +- Checklist: [../../ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md](../../ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md) + +## 证据 / 备注 + +本轮为设计任务;所有当前态结论已回链源码、迁移或现有测试报告。主方案 599 行,验收计划 207 行;`git diff --check` 通过,相关文档 84 条相对链接校验无坏链。未运行产品功能测试,验收清单全部保持 `NOT RUN`。 diff --git a/.doc/archive/ops/2026-09-14-vite-frp-allowed-hosts.md b/.doc/archive/ops/2026-09-14-vite-frp-allowed-hosts.md new file mode 100644 index 00000000..84644700 --- /dev/null +++ b/.doc/archive/ops/2026-09-14-vite-frp-allowed-hosts.md @@ -0,0 +1,40 @@ +--- +title: "Vite 允许 FRP Host(frp-mix.com)" +status: done +created: 2026-09-14 +updated: 2026-09-14 +owner: Cursor-Auto +branch: fix/vite-frp-allowed-hosts +worktree: "-" +mutex: web-devserver +--- + +# Vite 允许 FRP Host(frp-mix.com) + +## 目标 + +通过 FRP 映射访问 `:3100` 时,Vite 不再拦截 `Host: frp-mix.com`。 + +## 范围 + +- `web/vite.config.ts`:`server.allowedHosts` 增加 `.frp-mix.com` + +## 非目标 + +- 不改生产 nginx / 反向代理配置 +- 不放开全部任意 Host(保持显式白名单) + +## 步骤 + +1. [x] 在 `fix/vite-frp-allowed-hosts` 上改 `allowedHosts` +2. [x] 重启本地 Vite `:3100` + +## 验收标准 + +- [x] 通过 `frp-mix.com`(FRP→3100)可打开开发页,不再出现 `Blocked request. This host is not allowed` + +## 相关链接 + +- Checklist: — +- Handoff: — +- Test report: — diff --git a/.doc/archive/ops/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md b/.doc/archive/ops/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md new file mode 100644 index 00000000..676228d4 --- /dev/null +++ b/.doc/archive/ops/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md @@ -0,0 +1,71 @@ +--- +title: "workflow-plan 409 冻结态守卫 + 文档职责可选治理" +status: done +created: 2026-09-14 +updated: 2026-09-14 +owner: implementer_cursor +branch: fix/workflow-plan-409-frozen-and-optional-duties +worktree: ".worktrees/fix-workflow-plan-409-frozen-and-optional-duties" +mutex: workflow +--- + +# workflow-plan 409 冻结态守卫 + 文档职责可选治理 + +## 目标 + +已激活项目的设置页进入明确的冻结只读态;非必需且允许裁剪的文档可选择“不纳入人工审批”,部分职责、必需文档空职责、非成员职责和零治理激活由服务端拒绝;门禁、权限、快照与页面语义保持一致。 + +## 范围 + +- `web/src/components/project/ProjectSettingsModal.tsx`:frozen 视图、逐文档审批开关、内联/sticky 错误、并发恢复。 +- `web/src/api/projectSettings.ts`:保留 status/code/message/issues 的 typed error。 +- `internal/projectinstance/validator.go`:统一 DutyMode、工作流定义约束、结构与成员校验。 +- `internal/projectinstance/service.go`:保存/预览/激活重复复核 active members。 +- `internal/projectinstance/gate.go`、`stage_access.go`、`document_access.go`:none/full/disabled 一致语义。 +- `internal/projectinstance/store.go`、`internal/workflow/runtime/orchestrator.go`:快照清理、零 assignment rows、零职责运行时契约。 +- 激活预览统计与相应前后端测试。 + +## 非目标 + +- 不修改项目 143 的现有工作流配置,不在验收中终止项目 143。 +- 不支持部分指派或自动补齐职责。 +- 不允许项目配置降低工作流定义中必需/阻断文档的治理要求。 +- 不把“无需人工审批”文档改成无版本、无审计的非受控文档。 +- 不迁移历史 active 实例;冻结快照继续作为历史 SSOT。 + +## 步骤 + +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 生成/审批长链路未跑,见报告。 + +## 验收标准 + +- [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 用例有截图证据并回链;生成/审批长链路另立项。 + +## 相关链接 + +- 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) + +## 证据 / 备注 + +- dev 项目 143:`lifecycle_status=active`、`active_workflow_key=main`、实例 89 active;409 与三名职责人选择内容无关。 +- 当前 `parseError` 已读取后端 message;前端改造重点是 typed error、冻结态切换和视口内呈现。 +- 当前职责校验只检查正数/互异,数据库只外键到 users;项目成员有效性必须补服务端校验。 +- 当前终止实现会取消运行任务、关闭实例并退回 planning;关闭实例访问 fail closed,因此项目 143 不能作为终止测试对象。 +- 方案已迁移至基于最新 dev 的 `fix/workflow-plan-409-frozen-and-optional-duties` 独立 worktree;用户已批准实施。 diff --git a/.doc/archive/ops/2026-09-15-app-composition-u11-u12.md b/.doc/archive/ops/2026-09-15-app-composition-u11-u12.md new file mode 100644 index 00000000..e89c9ce4 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-app-composition-u11-u12.md @@ -0,0 +1,63 @@ +--- +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`。 diff --git a/.doc/archive/ops/2026-09-15-bizdev-locator-removal.md b/.doc/archive/ops/2026-09-15-bizdev-locator-removal.md new file mode 100644 index 00000000..582b9edf --- /dev/null +++ b/.doc/archive/ops/2026-09-15-bizdev-locator-removal.md @@ -0,0 +1,45 @@ +--- +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 diff --git a/.doc/archive/ops/2026-09-15-chatflow-orchestration-boundary.md b/.doc/archive/ops/2026-09-15-chatflow-orchestration-boundary.md new file mode 100644 index 00000000..a4686001 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-chatflow-orchestration-boundary.md @@ -0,0 +1,39 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-chatlog-contextasm-u10.md b/.doc/archive/ops/2026-09-15-chatlog-contextasm-u10.md new file mode 100644 index 00000000..0f44a563 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-chatlog-contextasm-u10.md @@ -0,0 +1,59 @@ +--- +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。 diff --git a/.doc/archive/ops/2026-09-15-dataset-lifecycle-u9.md b/.doc/archive/ops/2026-09-15-dataset-lifecycle-u9.md new file mode 100644 index 00000000..6a4c4441 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-dataset-lifecycle-u9.md @@ -0,0 +1,59 @@ +--- +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。 diff --git a/.doc/archive/ops/2026-09-15-doccontent-canonical-boundary.md b/.doc/archive/ops/2026-09-15-doccontent-canonical-boundary.md new file mode 100644 index 00000000..969af3f3 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-doccontent-canonical-boundary.md @@ -0,0 +1,46 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-durable-event-track-e.md b/.doc/archive/ops/2026-09-15-durable-event-track-e.md new file mode 100644 index 00000000..de9b3b48 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-durable-event-track-e.md @@ -0,0 +1,53 @@ +--- +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 建分支。 diff --git a/.doc/archive/ops/2026-09-15-event-e0a-production-scope-contract.md b/.doc/archive/ops/2026-09-15-event-e0a-production-scope-contract.md new file mode 100644 index 00000000..f6ff1657 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-event-e0a-production-scope-contract.md @@ -0,0 +1,49 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-event-e0b-dispatcher-pg.md b/.doc/archive/ops/2026-09-15-event-e0b-dispatcher-pg.md new file mode 100644 index 00000000..ef39e752 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-event-e0b-dispatcher-pg.md @@ -0,0 +1,43 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-event-e1a-notify-cutover.md b/.doc/archive/ops/2026-09-15-event-e1a-notify-cutover.md new file mode 100644 index 00000000..29898367 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-event-e1a-notify-cutover.md @@ -0,0 +1,48 @@ +--- +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`。 diff --git a/.doc/archive/ops/2026-09-15-event-e1b-workflow-advance.md b/.doc/archive/ops/2026-09-15-event-e1b-workflow-advance.md new file mode 100644 index 00000000..90f92a20 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-event-e1b-workflow-advance.md @@ -0,0 +1,44 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-event-e1c-projection.md b/.doc/archive/ops/2026-09-15-event-e1c-projection.md new file mode 100644 index 00000000..e26b5c54 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-event-e1c-projection.md @@ -0,0 +1,41 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-event-e2-hook-guard.md b/.doc/archive/ops/2026-09-15-event-e2-hook-guard.md new file mode 100644 index 00000000..feac6197 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-event-e2-hook-guard.md @@ -0,0 +1,48 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-event-shared-live-cutover-task.md b/.doc/archive/ops/2026-09-15-event-shared-live-cutover-task.md new file mode 100644 index 00000000..a759df1a --- /dev/null +++ b/.doc/archive/ops/2026-09-15-event-shared-live-cutover-task.md @@ -0,0 +1,54 @@ +--- +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 注册已删;方法本体保留一个窗口。 diff --git a/.doc/archive/ops/2026-09-15-event-shared-live-cutover.md b/.doc/archive/ops/2026-09-15-event-shared-live-cutover.md new file mode 100644 index 00000000..cef45874 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-event-shared-live-cutover.md @@ -0,0 +1,34 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-intent-bizdev-boundary.md b/.doc/archive/ops/2026-09-15-intent-bizdev-boundary.md new file mode 100644 index 00000000..c4b24516 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-intent-bizdev-boundary.md @@ -0,0 +1,39 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-leftover-branch-cleanup.md b/.doc/archive/ops/2026-09-15-leftover-branch-cleanup.md new file mode 100644 index 00000000..bca58a36 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-leftover-branch-cleanup.md @@ -0,0 +1,50 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-module-decoupling-phase2-plan-review.md b/.doc/archive/ops/2026-09-15-module-decoupling-phase2-plan-review.md new file mode 100644 index 00000000..f01cdd86 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-module-decoupling-phase2-plan-review.md @@ -0,0 +1,57 @@ +--- +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。 diff --git a/.doc/archive/ops/2026-09-15-pi-typed-result.md b/.doc/archive/ops/2026-09-15-pi-typed-result.md new file mode 100644 index 00000000..e109482f --- /dev/null +++ b/.doc/archive/ops/2026-09-15-pi-typed-result.md @@ -0,0 +1,47 @@ +--- +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` diff --git a/.doc/archive/ops/2026-09-15-stageflow-type-ownership.md b/.doc/archive/ops/2026-09-15-stageflow-type-ownership.md new file mode 100644 index 00000000..384ae2d1 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-stageflow-type-ownership.md @@ -0,0 +1,40 @@ +--- +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) diff --git a/.doc/archive/ops/2026-09-15-taskrun-runmanifest-u8.md b/.doc/archive/ops/2026-09-15-taskrun-runmanifest-u8.md new file mode 100644 index 00000000..0a36da1d --- /dev/null +++ b/.doc/archive/ops/2026-09-15-taskrun-runmanifest-u8.md @@ -0,0 +1,60 @@ +--- +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`。 diff --git a/.doc/archive/ops/2026-09-15-track-p-protocol-implementation.md b/.doc/archive/ops/2026-09-15-track-p-protocol-implementation.md new file mode 100644 index 00000000..773d2cd5 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-track-p-protocol-implementation.md @@ -0,0 +1,31 @@ +--- +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) diff --git a/.doc/archive/ops/checklists/2026-09-13-chat-history-refresh-remediation.md b/.doc/archive/ops/checklists/2026-09-13-chat-history-refresh-remediation.md new file mode 100644 index 00000000..8eec8422 --- /dev/null +++ b/.doc/archive/ops/checklists/2026-09-13-chat-history-refresh-remediation.md @@ -0,0 +1,45 @@ +--- +title: "对话刷新恢复整改 Checklist" +status: done +created: 2026-09-13 +updated: 2026-09-15 +related_task: "../2026-09-13-chat-history-refresh-remediation.md" +--- + +# 对话刷新恢复整改 Checklist + +## Wave 0 — 锁定回归 + +- [x] `MessageVisible` / `ScopeFromMetadata` 单测 — 证据:`internal/projectinstance/message_scope_test.go` +- [x] PG 集成:激活前 + 任务 scope + 刷新窗口 — 证据:`internal/server/chat_history_refresh_pg_test.go` +- [x] 前端:空 messages 日桶不覆盖缓存 — 证据:`web/src/hooks/useChatWindow.ts` + +## Wave 1 — 写入作用域 + +- [x] Goose `00026` 列迁移 — 证据:`deploy/postgres/goose/00026_2026-09-13-chat-message-scope.sql` +- [x] `ResolveMessageScopeForChat/Task` — 证据:`internal/projectinstance/message_scope.go` +- [x] 任务/聊天写入接线 — 证据:`task_run_handlers.go`, `session.go`, `ctxmgr/manager.go` + +## Wave 2 — 授权同集 + +- [x] `authorizeSessionRead` + 可见性谓词 — 证据:`internal/server/chat_history_auth.go` +- [x] window/day/search/dates/categories/unread/digest 授权 — 证据:各 `*_api.go` + +## Wave 3 — 历史回填 + +- [x] Goose `00027` backfill SQL — 证据:`deploy/postgres/goose/00027_2026-09-13-chat-message-scope-backfill.sql` + +## Wave 4 — 前端恢复态 + +- [x] `useChatWindow` 阶段态 + 用户隔离缓存 — 证据:`web/src/hooks/useChatWindow.ts`, `web/src/data/storage.ts` + +## 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;编制任务链未通过) +- [x] 测试报告归档 — 证据:`.doc/test-reports/2026-09-13-chat-history-refresh-test-report.md` + +## 完成定义 + +- [x] 全部勾选且有证据链接 +- [x] gap-matrix `CHAT-HISTORY-REFRESH` → PASS diff --git a/.doc/archive/ops/checklists/2026-09-13-document-revision-pg-id-remap.md b/.doc/archive/ops/checklists/2026-09-13-document-revision-pg-id-remap.md new file mode 100644 index 00000000..ae2a6c93 --- /dev/null +++ b/.doc/archive/ops/checklists/2026-09-13-document-revision-pg-id-remap.md @@ -0,0 +1,23 @@ +--- +title: "PG ID 重映射收紧" +status: done +created: 2026-09-13 +updated: 2026-09-14 +related_task: "2026-09-13-document-revision-pg-id-remap.md" +--- + +# PG ID 重映射收紧 + +## Wave 0 + +- [x] `adopt*ID` 推进 counter,仅删同一对象 +- [x] 临时 ID 跳过已占用键(snapshot/version/event/report/candidate) +- [x] openTemplate / human / candidate / commit / noop event 全走 adopt +- [x] 纯函数 + 高序列首次生成 PG 回归 +- [x] `gofmt` / `go vet` / `go test -short ./...` +- [x] 真实 UI-03:Round20 PASS(6159 / `doc_proj6159_intake` / V2/r0) + +## 完成定义 + +- [x] 上述实现项有测试证据 +- [x] 现场 UI-03 Round20 已通过;Round19 失败归档不删 diff --git a/.doc/archive/ops/checklists/2026-09-13-document-revision-post-restart-final-snippet.md b/.doc/archive/ops/checklists/2026-09-13-document-revision-post-restart-final-snippet.md new file mode 100644 index 00000000..ef6b6dce --- /dev/null +++ b/.doc/archive/ops/checklists/2026-09-13-document-revision-post-restart-final-snippet.md @@ -0,0 +1,23 @@ +--- +title: "post-restart 最终持久正文 snippet" +status: done +created: 2026-09-13 +updated: 2026-09-14 +related_task: "2026-09-13-document-revision-post-restart-final-snippet.md" +--- + +# post-restart 最终持久正文 snippet + +## 本轮 + +- [x] `nextDurableBodySnippet`:后续成功修订覆盖旧 snippet +- [x] 冲突失败稿不成为期望正文 +- [x] UI-13b 冲突断言完成后回写 `markerA1`;UI-15-pre 写出最终值 +- [x] 不放宽/删除 post-restart body 断言 +- [x] `npm test` / `npm run build` +- [x] 真实 UI-15 post-restart:Round20 PASS + +## 完成定义 + +- [x] 上述实现项有单测或脚本证据 +- [x] 现场 post-restart Round20 已通过;stale-snippet 失败归档不删 diff --git a/.doc/archive/ops/checklists/2026-09-13-document-revision-post-restart-selector.md b/.doc/archive/ops/checklists/2026-09-13-document-revision-post-restart-selector.md new file mode 100644 index 00000000..5db5d7a4 --- /dev/null +++ b/.doc/archive/ops/checklists/2026-09-13-document-revision-post-restart-selector.md @@ -0,0 +1,23 @@ +--- +title: "post-restart 项目名 selector 收紧" +status: done +created: 2026-09-13 +updated: 2026-09-14 +related_task: "2026-09-13-document-revision-post-restart-selector.md" +--- + +# post-restart 项目名 selector 收紧 + +## 本轮 + +- [x] 点击来自侧栏可见项目入口(complementary exact title),不用 `.first()` 弱化 +- [x] 恢复断言为 banner 内 exact 项目名 +- [x] `UI_PHASE` 分离 `playwright-output-main|post-restart` 与 `playwright-report-main|post-restart` +- [x] 结果 JSON 分文件:`ui-acceptance-results.json`(main)与 `ui-acceptance-results-post-restart.json`;phase-state/secrets 仍共享 +- [x] helper 契约测试 + `npm test` / `npm run build` +- [ ] 真实 UI-15 post-restart(本轮不做) + +## 完成定义 + +- [x] 上述实现项有单测或脚本证据 +- [ ] 现场 post-restart 仍开放,不得标 done diff --git a/.doc/archive/ops/checklists/2026-09-13-document-revision-reviewer-duty-sync.md b/.doc/archive/ops/checklists/2026-09-13-document-revision-reviewer-duty-sync.md new file mode 100644 index 00000000..f0fd5ecb --- /dev/null +++ b/.doc/archive/ops/checklists/2026-09-13-document-revision-reviewer-duty-sync.md @@ -0,0 +1,25 @@ +--- +title: "项目 reviewer 职责同步收紧" +status: done +created: 2026-09-13 +updated: 2026-09-14 +related_task: "2026-09-13-document-revision-reviewer-duty-sync.md" +--- + +# 项目 reviewer 职责同步收紧 + +## 最后一轮严格修复 + +- [x] 移出成员后端 reconcile + `ERR_DUTY_SYNC`;前端 `afterProjectMemberPersisted` 刷新文档 +- [x] Heal 空 assigned 仅清退出/非成员;在任成员保留;author 不清空 +- [x] 显式 revoke:reviewer→viewer、职责转移、退出、幂等;author 不进撤销集 +- [x] `CreateOrGetDocument` 失败任务不成功;fault test +- [x] 成员 upsert/退出:advisory lock、读旧/冲突 holder、成员更新、`document_records` 精确清槽同一事务;提交后 heal;失败 `ERR_DUTY_SYNC` +- [x] `HealProjectDocuments` 与成员写同锁键/顺序;解析与文档更新同事务;转移后旧 holder 不复活;第二次 heal 幂等 +- [x] `gofmt` / `go vet` / `go test -short` / 相关 `-race` / `npm test` / `build` / 隔离 PG +- [ ] 真实 UI-13a(本轮不做) + +## 完成定义 + +- [x] 上述实现项有测试或隔离 PG 证据 +- [ ] 现场 UI-13a 仍开放,不得标 done diff --git a/.doc/archive/ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md b/.doc/archive/ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md new file mode 100644 index 00000000..eb623960 --- /dev/null +++ b/.doc/archive/ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md @@ -0,0 +1,149 @@ +--- +title: "文档版本账本运行时 — Ubuntu Server 无头浏览器真实 UI 验收计划" +status: done +created: 2026-09-13 +updated: 2026-09-14 +--- + +# 文档版本账本运行时 — Ubuntu Server 无头浏览器真实 UI 验收计划 + +> **与工程门禁分离**:本文件仅描述**用户限定的最终实战验收**(浏览器页面操作)。 +> **严禁**用 API 直灌、DB fixture、`page.route` mock、stub 模型、或伪造 SSE 冒充小队完成。 +> 工程单测 / `go vet` / `npm test` / `npm run build` 属于「工程门禁」,见 short-term 证据区,**不能替代**本计划。 + +## 0. 环境前置(必须占 CURRENT 集成槽位后执行) + +| 项 | 要求 | +|----|------| +| OS | Ubuntu Server 22.04+(无图形桌面亦可) | +| 服务 | `./scripts/env-service.sh dev rebuild` → `curl -sf http://127.0.0.1:8080/health`;schema ≥ 28 | +| Agent | 真实 `pi-agent` + 运行中的 `MiniMax-M2.7-highspeed` 容器(禁止 stub) | +| 账号 | ≥2 名项目成员(编制人 A、协作者 B);禁止共用 token 串号;**管理员凭据仅来自 `ADMIN_USERNAME`/`ADMIN_PASSWORD` 环境变量(禁止 spec 硬编码)** | +| 认证契约 | 真实 login/me 返回 snake_case `role_id` 等;前端须映射为 `roleId`,否则管理员入口隐藏(UI-00 已踩坑,见 audit) | +| 用户目录 | 管理员开通 A/B 后,同浏览器立项成员候选须含新账号(`onRefreshUsers` 不得死 prop);跨设备缺口见 [../../audit/2026-09-13-admin-user-directory-sync-ui01.md](../../../audit/2026-09-13-admin-user-directory-sync-ui01.md) | +| 证据根 | `.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/` | +| 报告 | `.doc/test-reports/YYYY-MM-DD-document-revision-runtime-ui-test-report.md` | + +### 0.1 Ubuntu Server 无头 Playwright(Round20 实际路径) + +**本轮采用官方容器,无需给 Ubuntu host 安装浏览器:** + +```bash +# 测试前部署合入基线(Round20:b258ab8) +./scripts/env-service.sh dev rebuild +curl -sf http://127.0.0.1:8080/health + +# 官方镜像跑页面验收(host 网络;BASE_URL 指向工作台 :3100) +docker run --rm --network host --ipc host \ + -e RUN_UI_ACCEPTANCE=1 \ + -e BASE_URL=http://127.0.0.1:3100 \ + -v "$PWD":/work -w /work/web \ + mcr.microsoft.com/playwright:v1.63.0-noble \ + npx playwright test e2e/document-revision-runtime.spec.ts --project=chromium +``` + +**备选(本轮未走)**:宿主 `cd web && npx playwright install --with-deps chromium`。仅当不能跑官方容器时使用。 + +### 0.2 两阶段(验收轮) + +1. `RUN_UI_ACCEPTANCE=1 UI_PHASE=main BASE_URL=http://127.0.0.1:3100` 跑主场景(写 `phase-state.json`,密码仅落本地 `phase-secrets.local.json`,不得提交)。产物:`playwright-output-main` / `playwright-report-main` / `ui-acceptance-results.json` +2. 宿主仅 `restart shuimu-agent-app-dev` 一次(PG/PI 未动;不是再次 rebuild) +3. `RUN_UI_ACCEPTANCE=1 UI_PHASE=post-restart` 仅页面登录校验 UI-15。产物:`playwright-output-post-restart` / `playwright-report-post-restart` / `ui-acceptance-results-post-restart.json`(不得覆盖 main 总账或 trace) +4. 文档收口阶段不再动容器。 + +证据:`.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/`(trace/video/screenshot);结果 JSON 不得含凭证与 URL query。 + +--- + +## 1. 数据来源铁律(FAIL 即整轮作废) + +| 允许 | 禁止(一票否决) | +|------|------------------| +| 页面登录后创建项目 | `INSERT`/`psql` 灌 document_records / snapshots | +| 页面上传附件 | 测试进程直连 Postgres 插 fixture | +| 对话输入框真实提问触发小队 | `page.route` 劫持 `/api/v1/chat` 或 SSE 返回假成功 | +| 等待真实 runner 完成 | `AgentBackend=stub` 或 mock MiniMax | +| 打开生成的文档 Tab 观察 UI | API-only 调用 PATCH/OpenTemplate 冒充「用户操作」 | + +--- + +## 2. 用例矩阵(全部必须页面可见) + +| ID | 步骤(仅 UI) | 期望页面现象 | 证据 | 判定 | +|----|---------------|--------------|------|------| +| UI-01 | 管理员开通 B 后,tech-lead A **页面创建**项目并勾选成员 | 立项成员候选含 B;项目工作台三栏可见 | 截图 `01-project.png` | PASS | +| UI-02 | 对话输入框发起真实任务(触发真实小队编排) | 助手流式回复;任务进度/文档 busy 可见;网络可见真实 agent 请求 | 截图 + trace | PASS | +| UI-03 | 等待小队**首轮**完成,打开生成的受控文档 Tab | 右侧出现文档;版本工具条 `Vn`/`r*`(非「账本未就绪」) | 截图 `03-first-doc.png` | PASS | +| UI-04 | 打开变更报告:工具条「变更报告」/「待确认报告」或版本历史「报告」 | **首轮**可见:摘要、**风险条目**、项目影响内容、各文档影响原因/建议、开放问题;加载失败显式错误非永久加载中;`fallback` 不得宣称为完整 PI | 截图 `04-first-report.png` | PASS | +| UI-05 | 同项目再触发**二轮**更新生成(真实对话) | 低/中风险:新版本+报告;**高风险**:工具条显示「待确认报告」与 pending 徽章,**版本历史尚无新 V**,打开报告可见完整字段 | 截图 `05-second-report.png` | PASS | +| UI-05a | 编制人对高风险候选点「确认提交」 | decision API `confirmed:true`;版本前进;pending 消失;历史出现带 `change_report_id` 的新版本 | 截图+网络 | PASS | +| UI-05b | 编制人对高风险候选点「拒绝」 | 候选拒绝;pending 消失;版本号不前进;无权用户无确认/拒绝按钮或 decision 403 | 截图+网络 | PASS | +| UI-06 | 双击块编辑 → 保存 → **硬刷新** | 无冲突时工具条 `r` **立即**递增(`revisionRefreshKey`);硬刷新后正文仍为保存内容 | 截图前后对比 | PASS | +| UI-07 | 切换「纯净阅读」 | 块无琥珀/蓝色装饰底 | 截图 | PASS | +| UI-08 | 切换「人工修改」 | 相对当前 Version 的人工修订块琥珀底+下划线暗示 | 截图 | PASS | +| UI-09 | 切换「全部变更」 | 智能体+人工差异;仅人工时允许与 UI-08 相同 | 三模式并排或连续截图 | PASS | +| UI-10 | 「版本历史」+「比较」 | 抽屉列出版本;比较视图展示 hunk | 截图 | PASS | +| UI-11 | **多文档**:同项目再生成/打开第二份受控文档 + **页面上传**附件 Tab | 多 Tab 可切换;各文档 revision-state 独立;附件可预览 | 截图 | PASS | +| UI-12 | 用户 C 打开无权限项目(非成员) | 项目不可见,**不泄漏正文** | 截图 + 网络 403/404 | PASS | +| UI-13 | 拆为 13a reviewer 只读 + 13b A/A 同 r 冲突 | B 无正文编辑;A2 `409 DOCUMENT_HEAD_CONFLICT` 保留草稿 | 双 context 截图 | PASS | +| UI-14 | A 退出 → **重登录** → 打开同一文档 | revision-state 200;正文与 `r` 与退出前一致 | 截图 | PASS | +| UI-15 | (集成槽内)**重启 app 容器**后再打开同一文档 | 账本与正文仍可恢复;非「未就绪」除非确无事实源 | 截图 + `docker restart` 日志摘录 | PASS | +| UI-16 | 页面上传经 freeform 注册后打开;禁止 `doc-upload` 假账本 | 已注册 `doc-free-*` 工具条 V 可见;无 orphan revision-state | 截图 | PASS | + +--- + +## 3. 证据要求(归档规范) + +| 类型 | 路径约定 | 最低要求 | +|------|----------|----------| +| 截图 | `assets/.../screenshots/UI-XX-*.png` | 每用例 ≥1;UI-07/08/09 必须能看出三模式差异 | +| Trace | `assets/.../traces/UI-XX.zip`(Playwright trace) | 失败用例必留;PASS 建议全留 | +| 录像 | `assets/.../videos/*.webm` | 首轮生成 + 二轮报告 + 双人冲突 必留 | +| 网络摘录 | 报告正文粘贴关键响应 | `revision-state` 200;`change-reports` 含 summary/risk/open_questions;禁止贴 token | + +报告正文每个用例必须含:**Input(页面操作)** / **Actual(可见文本+状态码)** / **Verdict PASS|FAIL** / **Duration**。 + +--- + +## 4. 失败标准(任一即 FAIL) + +1. 使用 stub / `page.route` mock / DB fixture / 纯 API 灌库冒充 UI 路径 +2. 首轮成功生成后仍无变更报告入口,或报告摘要为固定假句「智能体交付物已生成」;或报告面板缺少风险条目/项目影响/文档影响原因建议/开放问题 +2b. 高风险二轮仅有小队成功文案但工具条无「待确认报告」、或未确认就静默进版本历史、或 `confirmed:false` 仍提交成功 +3. 把 `analysis_status=fallback` 文案写成「PI 完整分析」或隐瞒开放问题 +4. 人工保存返回成功但刷新丢正文,或投影失败仍 200 +5. 三 overlay 视觉无差异(截图无法区分) +6. 双上下文后写静默覆盖 +7. 无权限用户可见正文片段 +8. 容器重启后受控已落盘文档仍永久「账本未就绪」(在确有 output.md / 记录的前提下) +9. 证据目录缺失或无法打开 trace/截图复盘 + +--- + +## 5. 通过标准 + +- UI-01…UI-16 全部 PASS,证据归档完整 +- 工程门禁另栏 PASS(不记入本计划勾选) +- 已知 blocker `DOCREV-RT-PI-NARRATIVE`:允许 fallback,但必须可见真实 diff 摘要 + 开放问题标明叙事待补 +- `DOCREV-RT-UPLOAD-ORPHAN`:UI-16 按空状态 PASS,不得伪造成功账本 + +--- + +## 6. 与工程门禁对照 + +| 类型 | 命令/产物 | 可否代替 UI 验收 | +|------|-----------|------------------| +| 工程 | `go vet ./...`;`go test -short ./...`;`cd web && npm test && npm run build` | **否** | +| PG 可选 | `TEST_DATABASE_URL=... go test ./internal/docrevision -run TestPGPersist` | **否** | +| 本计划 | Playwright 无头真实页面 + 真实小队 | **是(唯一最终)** | + +## 7. 本轮状态 + +- Round20(2026-09-14)真实页面验收 **PASS**:results JSON 21/21;Playwright main 18 passed / 1 post skipped;仅 `restart shuimu-agent-app-dev` 后 post 1 passed / 18 skipped。 +- 测试前 `env-service.sh dev rebuild` 部署 `b258ab8`;文档收口不再动容器。 +- 项目 `UI验收-超声微创系统-mu0gwiez`(6159);intake `doc_proj6159_intake`;终态 V3/r2 / `A1-win-mu0gwiez`。 +- 报告:[../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) +- Ubuntu 无头:`mcr.microsoft.com/playwright:v1.63.0-noble`(`--network host --ipc host`,`BASE_URL :3100`);本次无需给 host 装浏览器。宿主 `npx playwright install` 仅备选。 +- 顶层截图 **21** 个文件:主阶段 20 张(含 UI-15-pre)+ post-restart 1 张;与 results JSON 21 条不是同一计数。 +- 工程门禁另栏:`go test -short` / `go vet` / web 333+30 / build PASS;`-race` 全包并行 **NOT PASS**(`TestCreateTaskRun_PreActivationAcceptedNot409` TempDir cleanup)。 +- 全仓仍 `production_ready=no`(`CHAT-INTENT` 等)。 diff --git a/.doc/archive/ops/handoffs/2026-09-13-document-revision-pg-id-remap.md b/.doc/archive/ops/handoffs/2026-09-13-document-revision-pg-id-remap.md new file mode 100644 index 00000000..9c5e31d9 --- /dev/null +++ b/.doc/archive/ops/handoffs/2026-09-13-document-revision-pg-id-remap.md @@ -0,0 +1,57 @@ +--- +title: "PG ID 重映射:Round20 后关闭" +created: 2026-09-13 +updated: 2026-09-14 +from: Cursor-Auto +to: next-agent +status: done +--- + +# 交接:PG ID 重映射(已合入并经 Round20 验证) + +## 目标(下一位 Agent 应完成什么) + +- 不要重开本缺陷,除非新现场再次出现 `CommitAgentVersion` not found +- 不要改删 Round19 失败归档 +- 全仓焦点已离开文档运行时 UI;勿占用已释放的 DOCREV-RT 集成槽,除非新任务登记 + +## 已完成 + +- 统一 `advanceID` / `nextFreeID` / `adopt*ID` +- 隔离 PG 高序列首次生成:baseline 不丢、重启 hydration +- 合入 `dev@b258ab8` +- Round20 真实 UI-03:项目 6159 首次生成 V2/r0,不再 `docrevision: not found` + +## 未完成 + +- 无(本缺陷)。PI 叙事 fallback 与 `CHAT-INTENT` 属其他条目 + +## 认领 / 槽位状态 + +| 项 | 值 | +|----|-----| +| mutex 已释放 | yes | +| 集成槽位 holder | idle(运行时 UI 收口后释放) | +| branch | 已合入 `dev`(`merge: fix/document-revision-pg-id-remap`) | +| worktree | - | + +## 关键文件 + +| 路径 | 说明 | +|------|------| +| `internal/docrevision/ids.go` | counter / adopt | +| `internal/docrevision/pg_mutate.go` | PG 写入后 adopt | +| `internal/docrevision/pg_id_remap_test.go` | 隔离 PG 碰撞 | + +## 如何验证 + +见 [../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md)。不要把 output snapshot 250 写成 candidate 250(6158 现场:candidate id=175、output snapshot id=250、report id=175)。 + +## 风险 / Blocker + +- 不得把 `ErrNotFound` 改成忽略 + +## 相关链接 + +- CURRENT: [../CURRENT.md](../../../ops/CURRENT.md) +- Task: [../short-term/2026-09-13-document-revision-pg-id-remap.md](../2026-09-13-document-revision-pg-id-remap.md) diff --git a/.doc/archive/ops/handoffs/2026-09-13-document-revision-post-restart-final-snippet.md b/.doc/archive/ops/handoffs/2026-09-13-document-revision-post-restart-final-snippet.md new file mode 100644 index 00000000..3b3f5417 --- /dev/null +++ b/.doc/archive/ops/handoffs/2026-09-13-document-revision-post-restart-final-snippet.md @@ -0,0 +1,40 @@ +--- +title: "post-restart 最终正文 snippet:Round20 后关闭" +created: 2026-09-13 +updated: 2026-09-14 +from: Cursor-Auto +to: next-agent +status: done +--- + +# 交接:post-restart 最终正文 snippet(已验证) + +## 目标(下一位 Agent 应完成什么) + +- 不要改删 `schema31-postrestart-stale-body-snippet-failure` +- 不要删除 post-restart `bodySnippet` 可见断言 +- 新 UI 轮次必须继续把 UI-13b A1 成功正文写入 phase-state + +## 已完成 + +- `durableBodySnippet`:成功修订覆盖;冲突稿不入账 +- UI-13b / UI-15-pre 同步最终 marker +- Round20 post-restart:login / 项目 6159 / `revision-state` 200 / V3/r2 / `A1-win-mu0gwiez` + +## 未完成 + +- 无(本缺陷) + +## 认领 / 槽位状态 + +| 项 | 值 | +|----|-----| +| mutex 已释放 | yes | +| 集成槽位 holder | idle | +| branch | 已合入 `dev` | +| worktree | - | + +## 相关链接 + +- Test report: [../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md](../../../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) +- Task: [../short-term/2026-09-13-document-revision-post-restart-final-snippet.md](../2026-09-13-document-revision-post-restart-final-snippet.md) diff --git a/.doc/archive/ops/handoffs/2026-09-13-document-revision-post-restart-selector.md b/.doc/archive/ops/handoffs/2026-09-13-document-revision-post-restart-selector.md new file mode 100644 index 00000000..a8dfd38f --- /dev/null +++ b/.doc/archive/ops/handoffs/2026-09-13-document-revision-post-restart-selector.md @@ -0,0 +1,70 @@ +--- +title: "post-restart 项目名 selector:编码后交接" +created: 2026-09-13 +from: Cursor-Auto +to: next-agent +status: done +updated: 2026-09-14 + +--- + +# 交接:post-restart 项目名 selector(暂不合入) + +## 目标(下一位 Agent 应完成什么) + +- 不要在本分支继续改职责/业务语义 +- 合入前占 CURRENT 集成槽位;本轮禁止 merge / 重建容器 / 声称 post-restart 通过 +- 占槽后重跑 `UI_PHASE=post-restart`,确认 UI-15 走到 revision-state + +## 已完成 + +- post-restart:侧栏 exact title 点击 + banner exact 项目名断言 +- Playwright 产物按 `UI_PHASE` 分目录,避免第二阶段覆盖主阶段 +- 结果 JSON:main 仍写 `ui-acceptance-results.json`;post-restart 写 `ui-acceptance-results-post-restart.json`;`phase-state` / secrets 共享 +- helper 契约测试;`npm test` / `npm run build` + +## 未完成 + +- 真实 UI-15 post-restart +- 合入 `dev` + +## 认领 / 槽位状态 + +| 项 | 值 | +|----|-----| +| mutex 已释放 | no(`document-revision-post-restart-selector` 仍 `in_progress`) | +| 集成槽位 holder | 他人 e2e;本任务未占槽 | +| branch | `fix/document-revision-post-restart-selector` | +| worktree | - | + +> 若 mutex 未释放,下一位须先在 CURRENT 认领或写 blocker。 + +## 关键文件 + +| 路径 | 说明 | +|------|------| +| `web/src/lib/currentProjectRestore.ts` | 入口 / banner locator 契约 | +| `web/src/lib/playwrightPhaseArtifacts.ts` | 阶段目录名 | +| `web/e2e/document-revision-runtime.spec.ts` | post-restart UI-15 | +| `web/playwright.config.ts` | 分阶段 outputDir / HTML report | + +## 如何验证 + +```bash +cd web && npm test && npm run build +# 真实 UI(本轮不做): +# RUN_UI_ACCEPTANCE=1 UI_PHASE=post-restart npx playwright test e2e/document-revision-runtime.spec.ts +``` + +产物:`playwright-output-main` / `playwright-report-main` / `ui-acceptance-results.json` 与 `playwright-output-post-restart` / `playwright-report-post-restart` / `ui-acceptance-results-post-restart.json`。`phase-state.json` 与 `phase-secrets.local.json` 跨阶段共享;`UI-15-post-restart.png` 可与主阶段截图同目录。 + +## 风险 / Blocker + +- 侧栏折叠时 complementary 入口不可见,应 FAIL 而非 `.first()` 跳过 +- 不得改删 schema31 失败归档 + +## 相关链接 + +- CURRENT: [../CURRENT.md](../../../ops/CURRENT.md) +- Task: [../short-term/2026-09-13-document-revision-post-restart-selector.md](../2026-09-13-document-revision-post-restart-selector.md) +- Checklist: [../checklists/2026-09-13-document-revision-post-restart-selector.md](../checklists/2026-09-13-document-revision-post-restart-selector.md) diff --git a/.doc/archive/ops/handoffs/2026-09-13-document-revision-reviewer-duty-sync.md b/.doc/archive/ops/handoffs/2026-09-13-document-revision-reviewer-duty-sync.md new file mode 100644 index 00000000..3ad221f5 --- /dev/null +++ b/.doc/archive/ops/handoffs/2026-09-13-document-revision-reviewer-duty-sync.md @@ -0,0 +1,73 @@ +--- +title: "reviewer 职责同步:heal 同事务锁后交接" +created: 2026-09-13 +from: Cursor-Auto +to: next-agent +status: done +updated: 2026-09-14 + +--- + +# 交接:reviewer 职责同步(暂不合入) + +## 目标(下一位 Agent 应完成什么) + +- 不要在本分支继续改职责语义,除非新审查点 +- 合入前占 CURRENT 集成槽位,再 `--no-ff` 合 `dev`;本轮禁止 merge / 重建容器 / 声称 E2E +- 6145 的 B 仍是空 `document_duty`,须再走成员 API 写成 reviewer 后自愈才会对齐文档 + +## 已完成 + +- Heal 以 assigned 为权威;空 assigned 只清失效审核/批准 holder +- 成员增改/移出:同一事务内 advisory lock + 读旧/冲突 holder + 成员写 + 精确清 reviewer/approver 槽;提交后服务层 heal 新 holder +- `HealProjectDocuments` 与成员写共用 `pg_advisory_xact_lock(project_id)`;解析与文档读写同事务;错误回滚 +- 确定性并发 PG:成员写持锁未提交时 heal 进入 `pg_locks` 等待;提交后旧 reviewer 不复活;第二次 heal 幂等 +- 同步失败仍显式 `ERR_DUTY_SYNC`;author 不因普通成员变更清空 +- 账本创建失败任务失败 + +## 未完成 + +- 真实 UI-13a +- 合入 `dev` 与共享容器 schema 31 晋升 + +## 认领 / 槽位状态 + +| 项 | 值 | +|----|-----| +| mutex 已释放 | no(`document-revision-reviewer-duty-sync` 仍 `in_progress`) | +| 集成槽位 holder | 他人 e2e;本任务未占槽 | +| branch | `fix/document-revision-reviewer-duty-sync` | +| worktree | - | + +> 若 mutex 未释放,下一位须先在 CURRENT 认领或写 blocker。 + +## 关键文件 + +| 路径 | 说明 | +|------|------| +| `internal/docduty/revoke.go` | `AcquireProjectDutyLock`(与成员写同键) | +| `internal/docduty/store.go` | heal lock + 解析 + 回填同事务 | +| `internal/authz/authorizer.go` | upsert / setStatus 走同一 lock helper | +| `scripts/run-isolated-duty-sync-pg-tests.sh` | 隔离 PG 入口 | + +## 如何验证 + +```bash +go test -short ./... +go test -short -race ./internal/docduty ./internal/authz ./internal/bizdev ./internal/server +cd web && npm test && npm run build +# 隔离库,禁止 agent_system_dev: +./scripts/run-isolated-duty-sync-pg-tests.sh +``` + +## 风险 / Blocker + +- 旧项目未写 `document_duty` 时,在任成员仍留在文档槽位(有意兼容) +- 显式降级/退出才会撤 reviewer/approver;author 永不被 revoke +- 6145 B 不会被臆造为 reviewer + +## 相关链接 + +- CURRENT: [../CURRENT.md](../../../ops/CURRENT.md) +- Task: [../short-term/2026-09-13-document-revision-reviewer-duty-sync.md](../2026-09-13-document-revision-reviewer-duty-sync.md) +- Checklist: [../checklists/2026-09-13-document-revision-reviewer-duty-sync.md](../checklists/2026-09-13-document-revision-reviewer-duty-sync.md) diff --git a/.doc/audit/2026-09-13-admin-user-directory-sync-ui01.md b/.doc/audit/2026-09-13-admin-user-directory-sync-ui01.md new file mode 100644 index 00000000..3140fe37 --- /dev/null +++ b/.doc/audit/2026-09-13-admin-user-directory-sync-ui01.md @@ -0,0 +1,55 @@ +--- +title: "管理员开通账号后立项成员候选缺失(UI-01)" +status: done +created: 2026-09-13 +updated: 2026-09-13 +severity: high +--- + +# 管理员开通账号后立项成员候选缺失(UI-01) + +## 现象 + +Antigravity 真实 UI:UI-00 管理员入口已 PASS。UI-01 产品失败——管理员经 UI 成功创建账号 B,但 tech-lead A 打开「新建项目」时成员候选列表中无 B。 + +## 根因分析 + +1. `AdminSettingsModalProps` 已声明 `onRefreshUsers`;`App` 已传入 `getAdminUsers → setAllUsers`。 +2. 组件 **destructuring 漏掉** `onRefreshUsers`,成为死 prop。 +3. 模态内 `refreshUsers()` 仅 `setAdminUsers`,创建/角色/状态成功后从未同步父级 `allUsers`。 +4. `CreateProjectModal` / `ProjectMembersModal` 的 `availableUsers` 来自 App `allUsers`(并经 `saveUsers` 写入 localStorage),故同会话内立项候选仍是旧目录。 +5. 附带:App 原 `onRefreshUsers` 用 `.catch(() => {})` 静默吞错,即使接线也会掩盖同步失败。 + +## 严重度 + +`high`(同浏览器管理员开通后立项立刻缺人;阻断 UI-01) + +## 本轮修复(本任务范围内) + +- 抽出可测 helper:`web/src/lib/adminUserDirectorySync.ts`(缺 `onRefreshUsers` / 父级抛错均 fail-closed) +- `AdminSettingsModal` 正确 destructure;创建/角色/状态/审批/重置后 `await refreshUsers()`;同步失败对用户可见 +- `App` `onRefreshUsers` 改为 async 上抛,禁止静默 + +## 残留审计风险(本任务不越权补齐) + +| 风险 ID | 说明 | 为何本轮不修 | +|---------|------|--------------| +| **DOCREV-RT-USER-DIR-CROSS-DEVICE** | 立项成员目录仍以浏览器 `allUsers`/localStorage 为事实源。tech-lead 在**新设备 / 清缓存 / 从未在本机跑过管理员同步**的会话中,即使服务端已有 B,本地候选仍可能只有 MOCK/`loadUsers` 缓存。非管理员无 `GET /api/v1/admin/users` 权限。 | 安全补齐需**非 admin 的成员目录/搜索 API**(最小权限、按项目或组织范围),属授权面扩展;禁止把 admin users API 下放给 tech-lead。 | + +相关代码锚点:`App.tsx` `availableUsers={allUsers}`;`storage.loadUsers`/`saveUsers`;服务端仅 `GET /api/v1/admin/users`。 + +## 关联整改 + +- Short-term: [../ops/short-term/2026-09-13-document-revision-runtime.md](../archive/ops/2026-09-13-document-revision-runtime.md) +- Checklist: [../ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md](../archive/ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md) +- 前序 auth 映射: [2026-09-13-auth-useraccount-snake-case-mapping.md](./2026-09-13-auth-useraccount-snake-case-mapping.md) + +## 证据 + +- 实战:UI-00 PASS;UI-01 创建 B 后 A 立项候选无 B +- 代码:`AdminSettingsModal` 原未解构 `onRefreshUsers`;App 静默 catch +- 单测:`web/src/lib/adminUserDirectorySync.test.ts`(死 prop / 父级错误上浮) + +## 开放问题 + +- 跨设备成员目录 API(见上表)→ 记入 short-term blocker,勿用 admin API workaround diff --git a/.doc/audit/2026-09-13-auth-useraccount-snake-case-mapping.md b/.doc/audit/2026-09-13-auth-useraccount-snake-case-mapping.md new file mode 100644 index 00000000..6fbe0591 --- /dev/null +++ b/.doc/audit/2026-09-13-auth-useraccount-snake-case-mapping.md @@ -0,0 +1,39 @@ +--- +title: "Auth UserAccount snake_case 契约漏映射导致管理员入口隐藏" +status: done +created: 2026-09-13 +updated: 2026-09-13 +severity: high +--- + +# Auth UserAccount snake_case 契约漏映射导致管理员入口隐藏 + +## 现象 + +真实浏览器 UI-00(Antigravity):管理员登录后左侧「系统管理」入口不可见,无法开通 A/B 账号。控制台侧 `currentUser.roleId` 为 `undefined`(服务端实际返回 `role_id: "role-admin"`)。 + +## 根因分析 + +- Go `auth.UserAccount` JSON 标签为 snake_case:`role_id` / `employee_id` / `must_change_password` / `created_at` / `updated_at`。 +- 前端 `AuthClient` 将 login / me / admin users 响应直接当作 camelCase `UserAccount` 使用,未在 API 边界映射。 +- 既有单测使用内存 `auth.local` 或驼峰假响应,未覆盖真实 wire 契约,故漏检。 +- `BootstrapAdminFromConfig` 对已存在非 admin 账号调用 `UpdateUserRole` 时静默忽略错误(`_, _ =`),可能留下非 `role-admin` 管理员配置账号。 + +## 严重度 + +`high` + +## 关联整改 + +- Short-term: [../ops/short-term/2026-09-13-document-revision-runtime.md](../archive/ops/2026-09-13-document-revision-runtime.md) +- Checklist: [../ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md](../archive/ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md) + +## 证据 + +- UI-00 实战:管理员登录后无系统管理入口(roleId undefined) +- `internal/auth/models.go` UserAccount json tags +- `web/src/api/auth.ts` 原直接 `resp.json()` 赋给 UserAccount + +## 开放问题 + +- 无(映射层 + bootstrap 错误上浮已落地;占槽后需重跑 UI-00 验证管理员入口) diff --git a/.doc/audit/2026-09-13-chat-history-refresh-disappears.md b/.doc/audit/2026-09-13-chat-history-refresh-disappears.md index daf2a4d8..caa94c28 100644 --- a/.doc/audit/2026-09-13-chat-history-refresh-disappears.md +++ b/.doc/audit/2026-09-13-chat-history-refresh-disappears.md @@ -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: [../ops/short-term/2026-09-13-chat-history-refresh-remediation.md](../ops/short-term/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) - Gap matrix: [../remediation/gap-matrix.md](../remediation/gap-matrix.md) ## 证据 diff --git a/.doc/audit/2026-09-13-controlled-doc-client-sync-ui03.md b/.doc/audit/2026-09-13-controlled-doc-client-sync-ui03.md new file mode 100644 index 00000000..62e7c3dd --- /dev/null +++ b/.doc/audit/2026-09-13-controlled-doc-client-sync-ui03.md @@ -0,0 +1,106 @@ +--- +title: "小队完成未同步受控文档状态 + UI-03 选择器非 Tab + Retry 暴露 DB 约束(UI-03)" +status: done +created: 2026-09-13 +updated: 2026-09-13 +severity: critical +--- + +# 小队完成未同步受控文档状态 + UI-03 选择器非 Tab + Retry 暴露 DB 约束(UI-03) + +## 1. 现场实战概况与判定 + +在真实 UI 验收(`UI_PHASE=main`,dev 环境 `schema 29`,真实 `pi-agent` + `MiniMax-M2.7-highspeed`): + +- **UI-00 PASS**(4.9s):管理员真实创建 A/B/C,准确按 DOM 作用域关闭模态,三用户完成首次登录改密。 +- **UI-01 PASS**(774ms):A 页面立项并分配 B 为 reviewer,项目工作台就绪,零 404,模板预览正确。 +- **UI-02 PASS**(191ms):真实发任务,`POST /api/v1/tasks/runs` 返回 202 Accepted,小队编排启动;真实模型耗时约 157 秒完成编排,后端成功生成受控文档 `doc_proj6089_user_requirements`(质量评分 100/100)。 +- **UI-03 FAIL**:`await expect(page.locator('[data-testid="doc-rev-version"]')).toBeVisible({ timeout: 60_000 });` 超时失败。 + - **页面真实状态**:页面已明确显示小队任务完成,正文标出 `📄 受控文档:doc_proj6089_user_requirements`。 + - **右栏面板状态**:右栏仍保持为 `doc-p intake` 初始模板(`用户初始需求收集表 模板`,`模板预览:首轮编制后启用版本账本`),版本工具条 `[data-testid="doc-rev-version"]` 根本未挂载。 +- **UI-04 ~ UI-16**:**NOT RUN**(因 UI-03 失败立即停机保全现场,未执行后续用例)。 + +--- + +## 2. 根因与现场异常分析 + +### A. 产品缺陷:前端在小队完成后未同步工作流文档列表 + +1. **服务端已落库受控文档**: + 后端 `document_records` 表已落库 `doc_id="doc_proj6089_user_requirements"`,`is_template_only=false`,`current_state="drafting"`。且前端每 5 秒发起的轮询 `GET /api/v1/projects/6089/documents?category=workflow` 已正确返回该受控文档记录。 +2. **`syncLeases` 轮询丢弃新文档**: + 在 `web/src/App.tsx` 第 1664–1697 行,每 5 秒执行的 `syncLeases` 仅提取 `doc.lease_holder_type` 并更新既有 `doc.docId` 的租约。由于本地 React 状态 `deliverables` 初始仅有 `doc-p6089-*` 模板,`leases.has(doc.docId)` 匹配不上 `doc_proj*`,新文档从未被合并进 `deliverables`。 +3. **`syncWorkflowDocs` 依赖项未触发**: + 在 `App.tsx` 第 1618–1661 行,`syncWorkflowDocs`(调用 `mergeWorkflowDocumentsFromServer`)仅在 `currentProjectId` 或 `session` 变动时执行;同一会话内小队完成不会触发该 effect。 +4. **流式结束 `case 'done'` 遗漏文档同步**: + 在 `App.tsx` 第 2571–2593 行,任务流完成时仅调用了 `await chatWindow.refresh().catch(() => undefined)`(仅刷新聊天消息),未同步工作流文档列表。 +5. **连锁阻断工具条挂载**: + 前端 `deliverables` 中的 `user_requirements` 一直是 `isTemplateOnly: true`。根据 `revisionToolbarMountMode` 契约,`isTemplateOnly === true` 时返回 `'template_hint'`,阻断 `DocumentRevisionToolbar`(`[data-testid="doc-rev-version"]`)挂载。 + +### B. 测试脚本缺陷:定位器假设水平 Tab 且命中页头 Banner 徽章 + +1. 在 `web/e2e/document-revision-runtime.spec.ts` 第 538 行: + `const tab = page.locator('[role="tab"], button, div').filter({ hasText: /需求|摸底|URS|用户/ }).first();` +2. **穿透到页头徽章**: + `[role="tab"], button, div` 包含全局所有 `div`。页面顶部 Header Banner 含有 `当前项目: ... V0.1 需求摸底`(`div` 元素)。`.first()` 命中了该非交互的 Banner 徽章 `div`,根本没有点击文档切换器。 +3. **真实 UI 为下拉/抽屉交互**: + `SlimTabBar.tsx` 为面包屑下拉(`button.dropdown-trigger` -> `.dropdown-menu`)或大盘抽屉(`DeckDrawer`),页面不存在水平文档 Tab。 + +### C. 前端断线自动重试与 DB 约束异常暴露 + +1. **前端断线自动重试导致同 turn 二次触发(非 Playwright retries)**: + `web/playwright.config.ts` 中 **`retries: 0`**。现场 13:02 完成首轮后,13:05 再次出现同 prompt 处理中,根因是前端 `runTaskAttempt` 在连接异常路径上自动重试,且重试开头 `setRunId(null)` / 未显式传递 `reconnectRunId`,导致重复 `POST /tasks/runs` 而非订阅既有 run: + - 13:02:`TRIGGER_TASK 请基于本项目编制首轮...` → `《用户需求表》已生成。当前状态:已完成` + - 13:05:同 turn 自动重试路径再次进入处理中(工程修复:`reconnectRunId` 跨 attempt + Claim 幂等) +2. **暴露 `task_runs` 状态约束缺陷**: + 在二次运行与高风险候选流转路径中,后台服务尝试将 `task_runs.status` 更新为 `pending_author_confirmation` 时,暴露了数据库底层约束拦截: + goose **`00019`** 原始 `chk_task_run_status` 仅允许: + ```sql + CHECK (status IN ('pending', 'running', 'completed', 'failed', 'cancelled', 'finalizing_failed', 'quality_failed', 'interrupted')) + ``` + 该枚举**未包含** `pending_author_confirmation`,导致写入状态时触发 PostgreSQL check constraint 违规(由 goose `00030` 补齐)。 + +--- + +## 3. 严重度与阻断 + +- **严重度**:`critical` +- **阻断项**: + 1. 产品前端:`App.tsx` 在小队完成(`case 'done'`)以及定期轮询中必须调用 `mergeWorkflowDocumentsFromServer` 动态更新受控文档。 + 2. 数据库约束:`task_runs` 表的 `chk_task_run_status` 约束必须补齐 `pending_author_confirmation`。 + 3. 测试脚本:修正 UI-03 文档切换定位器,禁止使用全局 `div` 通配,走真实 `SlimTabBar` 下拉或 `DeckDrawer` 动作;关闭非幂等的单用例重试。 + +--- + +## 4. 证据保全清单 + +- **归档路径**:`.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/ui03-controlled-doc-sync-failure/` + - `playwright-output/`(含完整 `trace.zip`、`test-failed-1.png`、`error-context.md`) + - `playwright-report/`(HTML 完整执行报告) + - `screenshots/`(UI-00~UI-02 真实过程截图) + - `traces/`、`videos/` + - `ui-acceptance-results.json`(UI-00~UI-02 逐项 PASS 记录) + - `phase-secrets.local.json`、`phase-state.json` +- 历史归档目录全部原位保全: + - `post-auth-ui00-backdrop-click-failure/` + - `post-auth-ui00-close-selector-failure/` + - `post-auth-ui00-wrong-close-locator-failure/` + - `pre-auth-fix-ui00-failure/` + - `ui01-parent-directory-sync-failure/` + - `ui01-strict-mode-title-selector-failure/` + - `ui02-task-scope-409-failure/` + - `ui02-workflow-access-failure/` + +--- + +## 5. 工程修复落盘(`fix/document-revision-runtime-ui03`,合入前) + +| 根因 | 修复 | 门禁 | +|---|---|---| +| A 任务完成后未 merge 受控文档 | `pollUntilPostTaskServerDoc` + `deliverablesRef` 显式快照(禁止 setState updater 取 mergedSnap)+ 有限重试至 `doc_proj*` | focused + `npm test` / `build` | +| A′ intake vs URS 误匹配 | `templateMatch`:**intake 标记优先**于裸「用户需求」 | 单测 PASS | +| B UI-03 选择器命中 Banner | SlimTabBar/DeckDrawer;`data-chat-role/status` + 本轮 assistant sibling 等待;UI-11 禁止全局 div | 待真实 UI 重跑 | +| C `pending_author_confirmation` 约束 | goose `00030` 扩展 `chk_task_run_status`(相对 **00019** 枚举) | 真实现卷迁移合入前独立验证 | +| C′ 断线自动重试重复 POST | `reconnectRunId` 显式跨 retry;`ClaimRun`;`GetRun` 读回 `idempotency_key`;`StartClaimedRun` UpdateRun 失败不启 worker | `go test -short ./internal/taskrun` | + +**未做**:占槽 rebuild、真实 UI UI-03 重验、schema30 对现有重复 `(session_id,client_turn_id)` 卷的迁移实测。 diff --git a/.doc/audit/2026-09-13-conversation-intent-runtime-state.md b/.doc/audit/2026-09-13-conversation-intent-runtime-state.md new file mode 100644 index 00000000..0c940682 --- /dev/null +++ b/.doc/audit/2026-09-13-conversation-intent-runtime-state.md @@ -0,0 +1,71 @@ +--- +title: "真实会话被调试探针污染、查询误触发写任务与刷新状态退化" +status: done +created: 2026-09-13 +updated: 2026-09-13 +severity: critical +--- + +# 真实会话被调试探针污染、查询误触发写任务与刷新状态退化 + +## 现象 + +- 用户在“对话协同会话”中看到 `test` 等非本人业务输入,多次任务失败。 +- “总结一下用户初始需求表”没有读取/总结已有文档,而是启动 `intake` 写任务。 +- 实时失败卡片带恢复动作;刷新后只剩错误正文,重试/继续/重新开始能力消失。 +- 文档被智能体小队编辑期间,页面没有持续、醒目的占用状态,用户继续工作后才从失败中得知冲突。 + +## 根因分析 + +### 1. 诊断请求写入了真实用户会话 + +dev PostgreSQL 的 `sess-p143-u9` 在 03:17–03:32 记录了 `debug ping`、`test task`、`test`、`验证租约修复`。这些请求带有 `debug-turn-*` 等诊断标识,并与真实用户消息混排。结论不是“意图模型把输入改成 test”,而是调试过程直接复用了真实会话和项目 143,污染了审计记录与 UI。 + +### 2. 前端用名词命中代替动作意图识别 + +`web/src/engine/templateMatch.ts` 的 `resolveTaskKeyFromMessage` 只要文本包含“需求/用户”等名词就返回 `intake` 或 `user_requirements`。`App.tsx` 在聊天请求进入后端意图识别前先执行该匹配,并直接调用 `/api/v1/tasks/runs`。因此查询句“总结一下用户初始需求表”被确定性误判为写任务。 + +这不是模型偶发误判,而是客户端关键词捷径绕过了服务端意图合同;现有测试只覆盖“开始编写”,没有任何“总结/查看/当前状态/谁在编辑”等只读负例。 + +### 3. 结构化失败状态只存在于实时 SSE + +实时路径把 `error_info`、`taskRequest`、`phaseEvents` 保存在 React 内存消息中;失败投影到 `chat_messages` 时只持久化 `run_id/workspace_id/task_status` 和错误正文。`mapRecordToMessage` 刷新恢复时也只依据 `task_status` 还原 `failed`,没有恢复 `errorInfo.actions`、原始任务请求或事件进度,导致 `MessageBubble` 无法渲染重试/继续/重新开始按钮。 + +### 4. 编辑租约存在,但不是可恢复的页面状态 + +`task_run_events` 已保存 `lease_acquired/lease_released`,`document_records` 也保存 `lease_holder_type/id/expires_at/heartbeat_at`。但 `App.tsx` 的任务事件处理只消费 `phase/status/delta/deliverable/error/done`,忽略 `governance`;刷新历史也不回放运行中任务事件。租约提示只可能短暂出现在内部数据,不能驱动会话、文档列表和编辑器的统一 busy 状态。 + +### 5. 文档忙被错误分型为系统内部错误 + +并发请求因有效租约拒绝时,事件被分类为 `INTERNAL_ERROR/fatal/actions=[restart]`,用户看到“系统内部错误,请重新开始会话”。实际是可预期的 `DOC_BUSY` 状态;除正确分型外,还必须在创建 `task_runs` 之前做服务端 busy 预检,持久化“未创建新任务”的只读状态卡,且不提供重试动作。 + +### 6. dev restart 不会加载新代码,健康检查可对旧镜像误报通过 + +`env-service.sh dev restart` 调用的是 `docker compose restart`;应用代码未挂载进容器,因此该命令只重启旧镜像。第一次修复后真实验证仍返回旧的 `CASUAL_CHAT`,但 `/health` 与 `/ready` 都为绿色。重建 app 镜像后,同一句话才返回 `QUERY_DOC_STATUS/doc_summary`。已新增显式 `rebuild` 动作,并将集成冒烟命令改为 `dev rebuild`。 + +## 严重度 + +`critical`:真实会话污染破坏可审计性;只读请求触发写入违反用户意图;刷新丢失恢复能力;后台编辑不可见导致重复劳动和冲突。 + +## 关联整改 + +- Remediation: [../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md](../remediation/2026-09-13-conversation-intent-runtime-state-remediation.md) +- Short-term: [../ops/short-term/2026-09-13-conversation-intent-runtime-state.md](../ops/short-term/2026-09-13-conversation-intent-runtime-state.md) + +## 证据 + +- dev PostgreSQL:`chat_sessions.id=138/session_id=sess-p143-u9/project_id=143/user_id=9` +- `chat_messages.id=554..567`:诊断探针、误路由与失败投影 +- `task_runs.run_id=run_1789269755258510844`:03:22–03:32 持有租约;并发请求均因 busy 失败 +- `task_runs.run_id=run_1789270446838831656`:由“总结一下用户初始需求表”启动的新写任务 +- `task_run_events`:租约获取/释放与 `INTERNAL_ERROR` 分型 +- `web/src/engine/templateMatch.ts` +- `web/src/App.tsx` +- `web/src/api/chatWindow.ts` +- `internal/taskrun/manager.go` +- `scripts/env-service.sh`(`restart` 与 `rebuild` 语义) + +## 开放问题 + +- 已污染的四条诊断消息是否由项目创建者确认后做可审计软删除;本任务不擅自修改用户数据。 +- 误启动的最新任务是否保留其产物;本任务不擅自取消或删除。 diff --git a/.doc/audit/2026-09-13-document-revision-active-doc-routing.md b/.doc/audit/2026-09-13-document-revision-active-doc-routing.md new file mode 100644 index 00000000..d2cb272a --- /dev/null +++ b/.doc/audit/2026-09-13-document-revision-active-doc-routing.md @@ -0,0 +1,48 @@ +--- +title: "当前受控文档改写被领域关键词改路由到另一交付物" +status: in_progress +created: 2026-09-13 +updated: 2026-09-13 +severity: high +--- + +# 当前受控文档改写被领域关键词改路由到另一交付物 + +## 现象 + +第二轮真实 UI(schema 30)**UI-05 首个失败**: + +- 页面打开 `doc_proj6109_intake`(用户初始需求收集表,V2/r0) +- 用户输入含「当前受控文档」的高风险改写提示(YY/T、GB 9706.1、NMPA 注册法规) +- 前端按法规关键词路由为 `feasibility_reg` +- `POST` 启动 `run_1789313290400899325`,生成 `doc_proj6109_feasibility_reg` 并 `completed` +- 当前 intake **无 pending badge**;E2E 等待 60s 失败 + +## 根因分析 + +| 层 | 问题 | +|---|---| +| `resolveTaskKeyFromMessage` | 写动词「改写」通过后,正文「注册」命中 `feasibility_reg`,无视当前打开文档 | +| `handleSendMessage` | 只把文案+模板池交给 `resolveTaskTemplateForMessage`,未传入 active `doc_proj` | +| 产品 | 「当前受控文档/本文件/这份文档」是指示语,领域词是改写内容,不是切换交付物 | + +服务端 `ResolveAndValidateDocID` 已校验 project + task_key 与已注册文档一致,**不得**用客户端 `doc_id` 覆盖 `task_key`。本轮补了 `feasibility_reg` + `doc_proj6109_intake` mismatch 拒绝用例:攻击或误路由不得借 intake 文档改写另一任务键。 + +## 严重度 + +`high` + +## 关联整改 + +- Short-term: [../ops/short-term/2026-09-13-document-revision-active-doc-routing.md](../archive/ops/2026-09-13-document-revision-active-doc-routing.md) +- 分支: `fix/document-revision-active-doc-routing` + +## 证据 + +- Evidence root(勿删、勿提交本轮):`.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui05-active-doc-routing-failure` +- E2E:`web/e2e/document-revision-runtime.spec.ts` UI-05(断言不改弱) +- 审查约束:E2E/用例提示词只留在 test 文件,生产 `templateMatch.ts` 不导出用例编号常量 + +## 开放问题 + +- 占槽后真实 UI-05 重跑;本轮不操作容器 diff --git a/.doc/audit/2026-09-13-document-revision-block-selector.md b/.doc/audit/2026-09-13-document-revision-block-selector.md new file mode 100644 index 00000000..9756b7ca --- /dev/null +++ b/.doc/audit/2026-09-13-document-revision-block-selector.md @@ -0,0 +1,45 @@ +--- +title: "UI-06 用 overlay/p/h 选择器找不到真实文档块" +status: in_progress +created: 2026-09-13 +updated: 2026-09-13 +severity: high +--- + +# UI-06 用 overlay/p/h 选择器找不到真实文档块 + +## 现象 + +第六轮真实 UI(schema 30): + +- UI-00~05b **PASS** +- UI-06 在 `editFirstPaneBlockAndSave` 里对 `[data-overlay-kind], p, h1, h2` **双击前超时** +- 失败页正文真实存在;工具条版本徽章可见 + +## 根因分析 + +| 层 | 问题 | +|---|---| +| DOM | `BlockRenderer` 块 wrapper 是 generic `div`;`HeadingBlockView` / `ParagraphBlockView` 也不是 `h1`/`p` | +| overlay | `data-overlay-kind` 仅在非 `pure` 且命中 hunk 时出现;默认 `pure` 模式该属性不存在 | +| 脚本 | `openFirstPaneEditorAndFill` 依赖 overlay 装饰或原生标题/段落标签,与产品 DOM 契约不符 | + +这是 **UI 自动化可寻址缺口**,不是正文未加载。继续用 overlay 选择器会误点标题栏/骨架/报告,或在 pure 模式直接超时。 + +## 严重度 + +`high` + +## 关联整改 + +- Short-term: [../ops/short-term/2026-09-13-document-revision-e2e-block-selector.md](../archive/ops/2026-09-13-document-revision-e2e-block-selector.md) +- 分支: `fix/document-revision-e2e-block-selector` + +## 证据 + +- Evidence root(已归档、本轮勿提交):`.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui06-block-selector-failure/` +- `ui-acceptance-results.json`:UI-00~05b PASS;UI-06 未写入 PASS + +## 开放问题 + +- 占槽后真实 UI-06/13b 重跑;本任务保持 `in_progress`,不得标 `done` diff --git a/.doc/audit/2026-09-13-document-revision-duty-cell-assertion.md b/.doc/audit/2026-09-13-document-revision-duty-cell-assertion.md new file mode 100644 index 00000000..0dc37063 --- /dev/null +++ b/.doc/audit/2026-09-13-document-revision-duty-cell-assertion.md @@ -0,0 +1,48 @@ +--- +title: "UI-13a 用整行 option 文案误判编制负责人" +status: in_progress +created: 2026-09-13 +updated: 2026-09-13 +severity: high +--- + +# UI-13a 用整行 option 文案误判编制负责人 + +## 现象 + +第16轮真实 UI(schema 30,`dev@dd5671e`):UI-00 至 UI-12 PASS;分类导航修复已实证,UI-13a 已能从「我的私密」切回「流程受控」并打开 reviewer B 权限矩阵。 + +失败在职责断言:`intakeRow.innerText` 被整行匹配,报 `reviewer B must not be 编制负责人`。实际 `innerText` 为: + +`V0.5 用户初始需求收集表当前打开 状态: drafting ✍️ 编制负责人 🔍 审核负责人 👑 批准负责人 👁️ 查阅者 (只读) 前往` + +## 根因分析 + +| 层 | 问题 | 后果 | +|---|---|---| +| 职责单元格 | `onRoleChangeForDoc` 存在时渲染 ` onOverlayModeChange(e.target.value as OverlayMode)} + disabled={!state} + > + + + + + + + + + {historyOpen && ( + setHistoryOpen(false)} + onSelectCompare={async (a, b) => { + const diff = await getDiff(docId, a, b); + setCompare({ a, b, diff }); + setHistoryOpen(false); + }} + onOpenReport={(id) => setReportId(id)} + /> + )} + {compare && compare.diff && ( + setCompare(null)} + /> + )} + {reportId != null && ( + setReportId(null)} + pendingDecision={ + hasPending && + state?.pending_change_report_id != null && + reportId === state.pending_change_report_id && + state.pending_candidate_id + ? { + candidateId: state.pending_candidate_id, + canDecide: Boolean(state.can_decide_pending), + riskLevel: state.pending_risk_level, + busy: decideBusy, + error: decideError, + onConfirm: () => { + void onConfirmPending(); + }, + onReject: () => { + void onRejectPending(); + }, + } + : undefined + } + /> + )} + {overlayMode === 'manual' && state && } + + ); +} diff --git a/web/src/components/doc/ManualChangeOverlay.tsx b/web/src/components/doc/ManualChangeOverlay.tsx new file mode 100644 index 00000000..67d5d934 --- /dev/null +++ b/web/src/components/doc/ManualChangeOverlay.tsx @@ -0,0 +1,8 @@ +/** Marker component — decorations are applied via overlay hunks on blocks. */ +export function ManualChangeOverlay() { + return ( + + 人工修改标记:琥珀底 + 下划线(相对最新智能体 baseline) + + ); +} diff --git a/web/src/components/doc/SlimTabBar.tsx b/web/src/components/doc/SlimTabBar.tsx index 0d322fd5..764df614 100644 --- a/web/src/components/doc/SlimTabBar.tsx +++ b/web/src/components/doc/SlimTabBar.tsx @@ -177,6 +177,7 @@ export const SlimTabBar: React.FC = ({
+
+

+ +{diff.summary.inserts} / -{diff.summary.deletes} / ~{diff.summary.modifies} / ↔{diff.summary.moves} + {narrow ? '(窄屏 unified)' : '(宽屏 side-by-side)'} +

+ +
+ {diff.hunks.map((h) => ( +
+
{h.kind} · {h.section || '正文'}
+ {h.before_text != null &&
{h.before_text}
} + {h.after_text != null &&
{h.after_text}
} +
+ ))} +
+ + ); +} diff --git a/web/src/components/doc/VersionHistoryDrawer.tsx b/web/src/components/doc/VersionHistoryDrawer.tsx new file mode 100644 index 00000000..3365de5b --- /dev/null +++ b/web/src/components/doc/VersionHistoryDrawer.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import type { DocumentVersion } from '../../features/documentRevision/types'; + +export function VersionHistoryDrawer(props: { + versions: DocumentVersion[]; + onClose: () => void; + onSelectCompare: (a: number, b: number) => void; + onOpenReport: (reportId: number) => void; +}) { + const { versions, onClose, onSelectCompare, onOpenReport } = props; + const [a, setA] = React.useState(null); + const [b, setB] = React.useState(null); + return ( +
+
+

版本历史

+ +
+
    + {versions.map((v) => ( +
  • +
    + V{v.version_no} {v.status === 'open' ? '当前' : '已封存'} · {v.origin_kind} +
    +
    人工修订 {v.human_revision_count}
    +
    + + + {v.change_report_id ? ( + + ) : null} +
    +
  • + ))} +
+ +
+ ); +} diff --git a/web/src/components/notifications/DocumentNotificationList.tsx b/web/src/components/notifications/DocumentNotificationList.tsx new file mode 100644 index 00000000..7bdf6e42 --- /dev/null +++ b/web/src/components/notifications/DocumentNotificationList.tsx @@ -0,0 +1,55 @@ +import { patchNotification } from '../../api/documentRevision'; + +export type DocNotificationItem = { + id: number; + type: string; + title: string; + body: string; + status: string; + created_at?: string; +}; + +export function DocumentNotificationList(props: { + items: DocNotificationItem[]; + onChanged?: () => void; +}) { + return ( +
    + {props.items.map((n) => ( +
  • +
    {n.title}
    +
    {n.body}
    +
    + + + +
    +
  • + ))} +
+ ); +} diff --git a/web/src/components/project/CreateProjectModal.tsx b/web/src/components/project/CreateProjectModal.tsx index ccdadefa..f04c1428 100644 --- a/web/src/components/project/CreateProjectModal.tsx +++ b/web/src/components/project/CreateProjectModal.tsx @@ -2,6 +2,12 @@ import React, { useEffect, useState } from 'react'; import { X, Sparkles, FolderPlus, Users, Check } from 'lucide-react'; import { UserProfile } from '../../types/docgov'; import { ProjectMemberRole } from '../../types/workbench'; +import { + createProjectSubmitButtonLabel, + shouldBlockCreateProjectClose, + type CreateProjectSubmitPhase, +} from '../../lib/createProjectSubmitGuard'; +import { exclusiveMemberRoleChange } from '../../lib/projectDocumentDuty'; interface CreateProjectModalProps { isOpen: boolean; @@ -19,6 +25,9 @@ interface CreateProjectModalProps { }>; }) => void | Promise; submitError?: string | null; + /** 立项/同步成员进行中:禁用确认、阻止关闭 */ + submitting?: boolean; + submitPhase?: CreateProjectSubmitPhase | null; currentUser: UserProfile; availableUsers: UserProfile[]; } @@ -30,6 +39,8 @@ export const CreateProjectModal: React.FC = ({ onClose, onSubmit, submitError = null, + submitting = false, + submitPhase = null, currentUser, availableUsers, }) => { @@ -69,7 +80,16 @@ export const CreateProjectModal: React.FC = ({ if (!isOpen) return null; + const closeBlocked = shouldBlockCreateProjectClose(submitting); + const confirmLabel = createProjectSubmitButtonLabel(submitting, submitPhase); + + const requestClose = () => { + if (closeBlocked) return; + onClose(); + }; + const handleToggleUser = (userId: number) => { + if (submitting) return; if (userId === currentUser.id) return; // 创建者不可取消 setSelectedMembers((prev) => ({ ...prev, @@ -81,17 +101,13 @@ export const CreateProjectModal: React.FC = ({ }; const handleChangeRole = (userId: number, role: ProjectMemberRole) => { - setSelectedMembers((prev) => ({ - ...prev, - [userId]: { - ...prev[userId], - role, - }, - })); + if (submitting) return; + setSelectedMembers((prev) => exclusiveMemberRoleChange(prev, userId, role)); }; const handleConfirm = (e: React.FormEvent) => { e.preventDefault(); + if (submitting) return; const cleanTitle = title.trim(); if (!cleanTitle) { setErrorMsg('请输入项目名称'); @@ -151,7 +167,7 @@ export const CreateProjectModal: React.FC = ({ justifyContent: 'center', padding: '20px', }} - onClick={onClose} + onClick={requestClose} >
= ({