docs(docrev): audit runtime 404 and claim docgov remediation

Record in-memory ledger root cause, PG persistence plan, and CURRENT mutex claim on fix/document-revision-runtime.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
weichen
2026-09-13 08:35:19 +00:00
co-authored by Cursor
parent c6c22494f8
commit 7ea686e6ba
8 changed files with 232 additions and 3 deletions
@@ -0,0 +1,108 @@
---
title: "文档版本账本运行时 404 与修订链路失效现场审计"
status: in_progress
created: 2026-09-13
updated: 2026-09-13
severity: critical
---
# 文档版本账本运行时 404 与修订链路失效现场审计
## 现象
登录项目对话后:
1. `GET /api/v1/documents/doc-upload-1789263145197-0/revision-state` → **404**,body 含 `docrevision: not found`
2. `GET /api/v1/documents/doc_proj143_srs/revision-state` → **404**(同错误)
3. UI 工具条显示「版本账本未就绪:docrevision: not found」
4. 块双击编辑保存无效(或仅改本地 AST)
5. 纯净阅读 / 人工修改 / 全部变更切换无可视效果
6. 未重跑智能体小队时看不到变更摘要、风险、项目/文档影响(预期);但即便重跑,当前接线也会写入**静态假 JSON** 而非真实 diff/报告
## 根因分析(证据)
### R1 — 账本仅进程内 map,PostgreSQL schema 未真正读写(主因)
`internal/docrevision/service.go` 中 `Service` 虽接收 `*pgxpool.Pool`,但全部状态存在:
- `blobs` / `snapshots` / `versions` / `events` / `candidates` / `reports` / `roots` / `idemp`
`GetRevisionState` 仅查内存 `s.roots[docID]`;无 hydrate、无 INSERT/SELECT。
Goose `00028` 已建表且 CURRENT 记录 schema 28 healthy,但**运行态账本与 PG 脱节**。
**后果**:服务重启 / 多副本 / 冷启动后一律 404;backfill CLI 亦 `NewService(nil)`,apply 不落库。
### R2 — GET revision-state 无确定性 bootstrap
账本仅在以下路径创建:
- `OpenTemplateVersion`(PATCH 时 DocGov 命中且先前 404;或 bizdev 首次 agent 成功)
- `CommitHumanRevision` + `AllowCreateBaseline`
- freeform `syncLedgerLocked`(仅走 freeform 保存 API 时)
首次打开文档只读 GET **不会**从 `document_records` / `freeform_documents` / `output.md` 回填 → 老文档与上传文档稳定 404。
### R3 — 上传文档与受控文档解析/权限边界未统一
- `doc-upload-*`:前端本地 `deliverables` + IndexedDB,**未**强制经 freeform API 落库;`governanceMode: freeform`
- `doc_proj143_srs`:受控 DocGov 记录存在,但无 ledger 指针/内存根
- Handler `handleDocRevisionState` 仅 `requirePrincipal`,未走 DocumentAccess / 项目成员校验,也未按 kind 解析事实源
### R4 — 人工块保存未更新用户所见事实源
`web/src/App.tsx` `handleSaveBlockEdit`:
```ts
if (!target || target.governanceMode === 'freeform') {
return; // 上传/自由文档直接跳过 PATCH
}
```
受控路径虽调 PATCH,但:
- `ProjectOutputMarkdown(docID, ".")` 工作目录相对路径易错;
- 成功后仅 `MarkDocumentContentUpdated` 哈希,重启后内存账本仍丢;
- GET 404 时工具条已坏,overlay 无数据。
### R5 — Overlay 三模式未接到块渲染
- `DocumentRevisionToolbar` 在 state=null 时仍可切换 select,但 `onOverlay(null)`
- `ManualChangeOverlay` 仅为提示文案,不装饰块
- `BlockRenderer` 无 `overlayHunks` / 模式 props;App 仅在工具条下显示「人工差异 N 处」统计条
### R6 — Agent/Squad → change report 使用静态假数据
`internal/bizdev/service.go` 硬编码:
```go
reportJSON := `{"schema_version":1,"summary":["智能体交付物已生成"],...}`
```
违反「不可伪造」要求。确定性层(真实 hunk、rule risk、lineage impact)已有 `RuleRiskFloor` / `ImpactFromLineage` / `ValidateChangeReportJSON`,但调用方未喂真实 diff 摘要;智能体叙事层尚未接 PI 生成 → 须标 **不可伪造 blocker**(叙事)同时交付确定性报告。
## 严重度
`critical` — 版本账本对用户表现为全面不可用;保存与差异认知失效;假报告有审计污染风险。
## 关联整改
- Remediation: [../remediation/2026-09-13-document-revision-runtime-remediation.md](../remediation/2026-09-13-document-revision-runtime-remediation.md)
- Short-term: [../ops/short-term/2026-09-13-document-revision-runtime.md](../ops/short-term/2026-09-13-document-revision-runtime.md)
- 前置设计: [../system-design/document-revision-management.md](../system-design/document-revision-management.md)
- 前置 ADR: [../adr/2026-09-13-document-version-boundary.md](../adr/2026-09-13-document-version-boundary.md)
## 证据
| 项 | 路径 |
|----|------|
| 内存账本 | `internal/docrevision/service.go` `NewService` / `GetRevisionState` |
| PG schema 未接线 | `deploy/postgres/goose/00028_2026-09-13-document-revisions.sql` |
| GET 无 bootstrap | `internal/server/document_revision_handlers.go` `handleDocRevisionState` |
| freeform 跳过保存 | `web/src/App.tsx` `handleSaveBlockEdit` |
| 静态 report | `internal/bizdev/service.go` CreateAgentCandidate `ReportJSON` |
| Overlay 空壳 | `web/src/components/doc/ManualChangeOverlay.tsx` |
## 开放问题
1. 纯客户端上传且从未调用 freeform create 的文档:服务端无正文事实源 → bootstrap 需 PATCH/显式注册,或返回可操作的 empty/register 状态(禁止静默假账本)。
2. PI Agent 叙事变更报告(业务含义、开放问题文案)需独立调用链;本轮以确定性 fallback 报告上线,叙事标 blocker。
+8
View File
@@ -13,6 +13,14 @@
## 核心文档(按阅读顺序推荐)
### 文档版本账本运行时失效(2026-09-13)
**文件**: [2026-09-13-document-revision-runtime-404.md](./2026-09-13-document-revision-runtime-404.md)
**结论**: Wave0–6 合入后现场仍 404——账本仅内存、GET 无 bootstrap、freeform 跳过 PATCH、overlay 未装饰、agent 报告为静态假 JSON。
**整改**: [运行时整改方案](../remediation/2026-09-13-document-revision-runtime-remediation.md) · [short-term](../ops/short-term/2026-09-13-document-revision-runtime.md)
### 文档修改与智能体版本专项分析(2026-09-13)
**文件**: [2026-09-13-document-revision-management-gap-analysis.md](./2026-09-13-document-revision-management-gap-analysis.md)
+3 -2
View File
@@ -1,11 +1,11 @@
# 当前焦点
**更新**: 2026-09-13
**production_ready**: no(只读文档总结已通过真实 PI;刷新/双标签页 busy 浏览器 E2E 待补录;DOCREV 待合 dev)
**production_ready**: no(DOCREV 运行时账本未持久化导致现场 404;CHAT/INTENT 并行中)
## 焦点
1. **DOCREV**: feature 分支 Wave0–6 及前端鉴权修复已合入 `dev`;migrate 00028 生效,dev 重建并通过冒烟验证;真实 PI/Playwright 补录中
1. **DOCREV-RT**: [运行时 404/保存/overlay 整改](short-term/2026-09-13-document-revision-runtime.md)(`fix/document-revision-runtime`;不占集成槽)
2. **CHAT**: [刷新恢复整改已实施](short-term/2026-09-13-chat-history-refresh-remediation.md)(待合 dev + PI E2E 补录)
3. **CI**: `TEST_DATABASE_URL` + 真实 PI E2E 实录;INTENT 发布 blocker 见 conversation-intent short-term
@@ -16,6 +16,7 @@
| Cursor | chat-history-refresh-remediation | fix/chat-history-refresh | - | chat | in_progress |
| Codex | conversation-intent-runtime-state | fix/conversation-intent-state | .worktrees/fix-conversation-intent-state | intent | in_progress |
| Cursor | document-revision-wave1-6-implementation | feature/document-revision-management | - | docgov | done |
| Cursor-Auto | document-revision-runtime | fix/document-revision-runtime | - | docgov | in_progress |
> 新任务开始前登记。`branch` 必须为 `feature/<slug>` 或 `fix/<slug>`,**禁止** `dev` / `test` / `main`。同一 `mutex` 同时仅一个 `in_progress`。
@@ -0,0 +1,55 @@
---
title: "文档版本账本运行时整改"
status: in_progress
created: 2026-09-13
updated: 2026-09-13
owner: Cursor-Auto
branch: fix/document-revision-runtime
worktree: "-"
mutex: docgov
---
# 文档版本账本运行时整改
## 目标
消除 revision-state 404、重启丢账本、人工保存无效、overlay 无效,并接通确定性 change report;停在 fix 分支待集成。
## 范围
- `internal/docrevision` PG hydrate/persist + bootstrap
- `internal/server/document_revision_handlers.go` 授权与事实源
- `internal/bizdev` agent candidate 确定性报告
- `cmd/document-revision-backfill` 接真实 pool
- `web` 保存链路与 overlay 三模式
- 工程测试 + UI 验收计划(分栏)
## 非目标
- 不占 CURRENT 集成槽、不 `env-service rebuild`、不 push
- 不伪造 PI 叙事 change report
- 不把 stub 输出写入最终用户验收报告
## 步骤
1. [x] 审计 / 整改 / 本任务 + CURRENT 认领
2. [ ] 分支 `fix/document-revision-runtime`
3. [ ] PG store + bootstrap + backfill
4. [ ] Handler / agent / 前端
5. [ ] 测试与 UI 计划
6. [ ] 分层 commit,输出哈希与集成建议
## 验收标准
- [ ] 工程门禁(单测/vet/前端 build)与 UI 实战计划分栏标识完成
- [ ] 剩余 blocker(PI 叙事、orphan upload)写清且不可用假数据掩盖
## 相关链接
- 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)
## 证据 / 备注
(提交后回填 commit hashes)
@@ -0,0 +1,55 @@
---
title: "文档版本账本运行时持久化与修订链路整改"
status: in_progress
created: 2026-09-13
updated: 2026-09-13
---
# 文档版本账本运行时持久化与修订链路整改
## 背景
现场审计:[../audit/2026-09-13-document-revision-runtime-404.md](../audit/2026-09-13-document-revision-runtime-404.md)
Wave0–6 已合入 `dev` 并完成 schema 00028,但 ledger **未持久化**、GET **无 bootstrap**、前端 freeform **跳过 PATCH**、overlay **未装饰**、agent report **静态假数据**,导致生产可见能力全面失效。
## 目标
1. PostgreSQL 为账本事实源;进程重启后 revision-state / versions / overlay / reports 可恢复
2. 首次访问对已有受控/自由文档确定性 bootstrap;旧数据可 backfill
3. 统一受控与上传/自由文档的解析与授权边界;PATCH 更新用户所见事实源且刷新可恢复
4. Agent/squad 提交写入 immutable snapshot + **确定性** change report(摘要/风险/影响来自 diff+lineage);禁止静态假 JSON
5. 工程单测/门禁与「仅浏览器 UI 实战验收」计划分离标识
## 分波次计划
| 波次 | 内容 | 验收 |
|------|------|------|
| W0 | audit/remediation/short-term + CURRENT 认领 `docgov` + 分支 `fix/document-revision-runtime` | 文档与认领无冲突 |
| W1 | PG store:blob/snapshot/version/event/candidate/report + 根指针投影;hydrate on read;mutate 事务写入 | 单测:写入→新 Service 实例可读;并发冲突 |
| W2 | `EnsureBootstrap`:controlled(output.md)/freeform(content)/orphan(需正文);GET revision-state 触发;backfill CLI 接 pool | 旧 doc_id 首次 GET 200;空正文清晰 empty/404 |
| W3 | Handler:项目/文档授权;PATCH 写 workDir 或 freeform 正文;错误码与空状态 | 授权负例 403;保存后刷新可见 |
| W4 | Agent 接线:`BuildDeterministicChangeReport` + lineage impacts;去掉静态假 JSON;叙事 PI 标 blocker | 报告 AnalysisFallback/Complete 均可追溯 facts |
| W5 | 前端:freeform/upload 走 PATCH;overlay 三模式装饰 BlockRenderer;清晰未就绪/空状态 | 组件/契约测 |
| W6 | 工程门禁 + Ubuntu 无头浏览器 UI 验收计划(与单测分离) | 计划文档落盘;本轮不占 docker 槽 |
## 不可伪造 Blocker(明确写出)
| ID | 内容 | 为何本轮不能安全伪造完成 | 本轮替代 |
|----|------|--------------------------|----------|
| DOCREV-RT-PI-NARRATIVE | 由真实 PI/MiniMax 生成的业务叙事摘要、开放问题措辞、风险业务解释 | 需占集成槽 + 真实 runner + 提示词契约 E2E;本轮禁止 docker rebuild | 确定性报告:`summary` 来自 hunk 统计与标题路径,`risk`=`RuleRiskFloor`,`document_impacts`=lineage,`analysis_status=fallback` |
| DOCREV-RT-UPLOAD-ORPHAN | 从未调用服务端 freeform create、仅 IndexedDB 存在的上传附件二进制预览 | 服务端无 Markdown 事实源,不能凭空造 ledger | GET 返回明确 `DOCUMENT_REVISION_NEEDS_CONTENT` / 引导首次 PATCH 注册;禁止静默假 V1 |
## 验收标准
- [ ] `go vet ./...` 与 `go test -short ./internal/docrevision/...`(含旧数据/重启语义/并发/授权契约)PASS
- [ ] 前端相关 vitest + `npm run build` PASS
- [ ] 代码停在 `fix/document-revision-runtime`,**不**占集成槽、不 rebuild docker、不 push
- [ ] UI 实战计划文档已写,与工程门禁分栏标识
## 相关链接
- Audit: [../audit/2026-09-13-document-revision-runtime-404.md](../audit/2026-09-13-document-revision-runtime-404.md)
- Short-term: [../ops/short-term/2026-09-13-document-revision-runtime.md](../ops/short-term/2026-09-13-document-revision-runtime.md)
- gap-matrix 行: `DOCREV-RUNTIME-404`
- UI 计划: [../ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md](../ops/checklists/2026-09-13-document-revision-runtime-ui-acceptance.md)
+1
View File
@@ -3,6 +3,7 @@
| 文档 | 说明 |
|------|------|
| [gap-matrix.md](./gap-matrix.md) | 发布缺口 SSOT |
| [2026-09-13-document-revision-runtime-remediation.md](./2026-09-13-document-revision-runtime-remediation.md) | 账本 PG 持久化、bootstrap、保存/overlay/确定性 change report |
| [2026-09-13-document-revision-management-implementation-plan.md](./2026-09-13-document-revision-management-implementation-plan.md) | 智能体版本、人工修订、差异认知与负责人通知 |
| [2026-09-13-conversation-intent-runtime-state-remediation.md](./2026-09-13-conversation-intent-runtime-state-remediation.md) | 对话写意图、刷新可恢复任务状态、文档占用可见性与诊断隔离 |
| [2026-09-13-chat-history-refresh-remediation.md](./2026-09-13-chat-history-refresh-remediation.md) | 对话刷新恢复、消息作用域与授权统计一致性 |
+1
View File
@@ -60,6 +60,7 @@
| CHAT-HISTORY-REFRESH | 工作流激活后刷新,对话正文被阶段过滤器清空,但分类数量与锚点仍按全量返回 | **PASS** | [test-report](../test-reports/2026-09-13-chat-history-refresh-test-report.md);代码:`message_scope.go`、`chat_history_auth.go`、goose 00026/00027 | 真实 PI 刷新 E2E 待 dev 容器补录(自动化/PG 已 PASS) |
| CHAT-INTENT-STATE | 真实会话被诊断探针污染;只读查询误启动文档写任务;错误动作与编辑状态刷新后丢失 | **FAIL** | [audit](../audit/2026-09-13-conversation-intent-runtime-state.md);dev `sess-p143-u9` / task run / lease 现场 | [remediation](./2026-09-13-conversation-intent-runtime-state-remediation.md) |
| ENV-RESTART-SOURCE | `docker compose restart` 只重启旧镜像,健康检查无法证明合入代码已部署 | **PASS** | `env-service.sh rebuild` + 真实摘要重测 | 集成冒烟统一使用 `dev rebuild` |
| DOCREV-RUNTIME-404 | revision-state 404;账本内存丢失;块保存/overlay 无效;agent 假报告 | **FAIL** | [audit](../audit/2026-09-13-document-revision-runtime-404.md);`internal/docrevision/service.go` 仅 map | [remediation](./2026-09-13-document-revision-runtime-remediation.md) |
---
+1 -1
View File
@@ -21,7 +21,7 @@
| 工作流治理 | 三正式工作流 + 阶段门禁 | done | [remediation/three-workflows](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[test 2026-09-12](../test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md) | Phase2 设计器 partial | `workflow` |
| IAM / 鉴权 | 项目级 API 鉴权 + RBAC | partial | [audit/authorization](../audit/authorization-matrix-v2.md);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md) | 历史读取端点补统一会话 owner + 阶段授权;旧 API 410 标注(BUG-11 partial) | `authz` |
| 文档治理 | 法定文档生命周期 + 租约 | done | [test docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md) | — | `docgov` |
| 文档版本与修改认知 | 智能体版本边界、人工修订标记、任意版本比较、变更报告与负责人通知 | partial | [test 2026-09-13](../test-reports/2026-09-13-document-revision-management-test-report.md);[ADR](../adr/2026-09-13-document-version-boundary.md);[实施方案](../remediation/2026-09-13-document-revision-management-implementation-plan.md) | feature 分支已交付 Wave0–6 代码;真实 PI / 双用户 Playwright / 00028 容器 migrate 待占集成槽位 | `docgov` |
| 文档版本与修改认知 | 智能体版本边界、人工修订标记、任意版本比较、变更报告与负责人通知 | partial | [test 2026-09-13](../test-reports/2026-09-13-document-revision-management-test-report.md);[运行时审计](../audit/2026-09-13-document-revision-runtime-404.md);[ADR](../adr/2026-09-13-document-version-boundary.md) | **运行时 blocker**:PG 未接线→404/重启丢失;overlay/freeform 保存缺口;PI 叙事报告待集成;见 [runtime remediation](../remediation/2026-09-13-document-revision-runtime-remediation.md) | `docgov` |
| 前端工作台 | 三栏 + 块文档 + SSE | partial | [test workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md) | 错误卡片/任务进度/文档 busy 状态刷新恢复与人工抽检待完成 | `web` |
| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 | done | [test piagent](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md);[container-env](../test-reports/2026-09-13-container-env-configuration-test-report.md) | — | `pi-agent` |
| 三环境运维 | dev/test/main + 共享 KB | done | [PROJECT.md](../../PROJECT.md) §4;四环境 healthy | — | `infra` |