Accept DOCREV decision gates, archive design short-term, and mark FEATURE-MATRIX partial as implementation starts on feature branch. Co-authored-by: Cursor <cursoragent@cursor.com>
36 KiB
title, status, created, updated, owner
| title | status | created | updated | owner |
|---|---|---|---|---|
| 文档修改、智能体版本与差异认知系统设计 | in_progress | 2026-09-13 | 2026-09-13 | Codex |
文档修改、智能体版本与差异认知系统设计
1. 设计结论
采用“智能体版本(Version)+ 人工修订(Revision)+ 不可变快照(Snapshot)”三层模型:
- 模板或智能体/智能体小队成功产物开启一个版本;
- 用户每次服务端保存产生该版本内的修订,不增加版本号;
- 下次智能体产物提交时封存旧版本当前 head,并以新产物开启下一版本;
- 右侧正文的人工修改标记始终比较“当前版本 baseline → 当前 head”;
- 任意版本比较默认使用每个版本的最终 head;
- 智能体变更说明比较“上一版本最终 head → 新版本 baseline”,与随后人工修改严格分离。
版本、正文、变更报告、影响计算和负责人通知必须在同一数据库事务中提交;智能体工作区 output.md 只作为候选产物和兼容投影,不再是唯一事实源。
2. 目标与非目标
2.1 目标
- 逐次记录用户、单智能体、智能体小队、模板和系统迁移的正文修改。
- 默认视图只标记相对最新智能体 baseline 的人工修改,并能按修改人筛选。
- 支持任意两个业务版本的可信对比,能定位到章节、段落、列表、表格单元格和代码/图表行。
- 每次智能体生成同时形成结构化改动摘要、风险、项目影响和其他文档影响。
- 生成完成后可靠通知文档负责人,并为受影响文档负责人提供最小必要信息。
- 在并发、重试、进程重启和多实例部署下不静默覆盖、不重复建版本、不伪造修改主体。
2.2 非目标
- 首期不做 Google Docs 式多人实时协同光标或 CRDT;继续使用租约 + 乐观并发。
- 不记录每次键盘输入;只记录服务端成功提交的 revision。
- 不让 LLM 决定真实 diff、最终风险级别、权限或上下游依赖。
- 不允许“恢复旧版本”覆盖历史;未来恢复只能把旧快照复制为新的受控 revision/agent candidate。
- 不把自由文档塞入 DocGov 的编制/审核/批准状态机。
3. 统一术语和版本语义
| 术语 | 定义 | 是否可变 |
|---|---|---|
| Snapshot | 某一时刻完整、规范化 Markdown 与 block map 的内容快照 | 不可变 |
| Baseline | 当前版本由模板或智能体建立的起点快照 | 不可变 |
| Head | 当前版本最新一次成功提交后的快照指针 | 随 revision 前进 |
| Revision | 一个版本内的服务端成功修改事件,主要承载人工保存 | 事件不可变 |
| Version | 从一次模板/智能体 baseline 到下一次智能体提交前最终 head 的业务周期 | 开放时 head 可前进,封存后不可变 |
| Agent candidate | 智能体已生成但尚未获准/尚未通过门禁的候选快照 | 不成为正文 head |
| Change report | 绑定确定 before/after 快照的智能体变更说明 | 发布后不可变,可追加更正报告 |
| Review snapshot | 提交审核时冻结的精确 head | 不可变指针,不额外增加 Version |
3.1 示例时间线
| 时点 | 动作 | 当前显示 | baseline | head | 人工标记 |
|---|---|---|---|---|---|
| T0 | 项目激活并复制模板 | V1 · r0 | S0 template | S0 | 0 |
| T1 | 张工修改两处并保存 | V1 · r1 | S0 | S1 | S0→S1 的两处 |
| T2 | 李工获授权后再修改一处 | V1 · r2 | S0 | S2 | S0→S2 的累计人工修改,可按人筛选 |
| T3 | 智能体小队基于 S2 生成 S3 并提交 | V2 · r0 | S3 squad | S3 | 0;V1 以 S2 封存 |
| T4 | 张工修改 S3 | V2 · r1 | S3 | S4 | 只显示 S3→S4,不再显示 S0→S2 |
| T5 | 比较 V1 与 V2 | V1.final=S2 → V2.head=S4 | — | — | 展示版本最终内容差异 |
这正是核心规则:
V1 = 模板/上一次智能体 baseline S0 + T1/T2 的人工修订,最终封存为 S2
V2 = 下一次智能体 baseline S3 + T4 之后的人工修订,当前 head 为 S4
3.2 不产生版本的情况
- 智能体输出与输入 SHA 相同:记录
agent_noop事件和报告,不增加 Version。 - 智能体失败、超时、报告校验失败:保存候选/失败证据,不改变 Version 或 head。
- 只增加批注、查看、认领、租约心跳:进入既有审计,不是正文 Revision。
- 标题、可见性等元数据变化:进入 metadata audit;除非正文也改变,否则不进入正文 diff。
4. 领域状态机
版本状态与文档生命周期是正交的两套状态,不得混入同一状态机(这正是 gap analysis §5.2 指出的根因之一):
stateDiagram-v2
direction TB
state "版本状态 document_versions.status(仅 open/sealed)" as VS {
[*] --> open: template/agent baseline 建立新版本行
open --> open: 人工 revision 提交(head 前进)
open --> sealed: 智能体提交,同事务原子封存
sealed --> [*]: 只读历史;恢复=复制为新受控修订
}
state "文档生命周期 document_records.current_state" as DS {
[*] --> drafting
drafting --> reviewing: submit_review(冻结 review snapshot)
reviewing --> drafting: 驳回回编制
reviewing --> approving
approving --> approved: 批准(终点)
}
状态约束:
- 一个文档至多一个
openVersion、一个 current head;sealed行永久只读。 - 版本状态只有
open/sealed;reviewing/approving/approved属于document_records生命周期,不改变版本状态——送审时版本保持open,仅冻结review_snapshot_id(CHECK 约束与状态机必须一致,迁移中校验)。 - “封存→新版本”是插入新行(旧版行置
sealed、新版行置open),不是同一行状态回转;两者必须在同一事务内完成。 - agent candidate 必须记录
input_snapshot_id,提交时 current head 仍须等于该输入;否则标记stale,禁止自动重放或覆盖。 reviewing/approving/approved状态禁止正文 revision 和 agent commit;驳回回 drafting 后可在当前 Version 继续人工修订;下一次智能体提交仍是唯一的新 Version 边界。submit_review保存review_snapshot_id=head_snapshot_id;审核、批准和导出都引用该快照。
5. 总体架构
右侧 Block Editor / Agent Task Run
│ expected head + idempotency key
▼
DocumentRevisionService ── DocumentPolicyAdapter
│ ├─ controlled: DocGov + stage duty
│ └─ freeform: owner/share policy
├─ SnapshotStore (PostgreSQL immutable content)
├─ DiffEngine (server-authoritative)
├─ ImpactEngine (workflow + lineage)
├─ RiskPolicy (deterministic floor)
└─ ChangeReportValidator
│ same transaction
▼
version + event + report + lineage/stale + outbox
│
▼
notification fanout / SSE cache invalidation
5.1 写模型与读模型
document_records/freeform_documents继续是各自治理根;- 新的 revision ledger 是共享基础设施,不共享两类文档的权限和生命周期;
- PostgreSQL 内的规范化 Markdown snapshot 是内容真源;
- 工作区
output.md、Block AST、DOCX/XLSX 都是从 snapshot 派生的投影; - 旧 API 在兼容期从 current head 读写,但内部必须委托
DocumentRevisionService,禁止双写两套权威。
6. 数据模型
迁移号在实施时取 Goose 最新可用号;按当前基线下一号是 00028,不得在并行合并后硬占用旧号。
6.1 document_content_blobs
| 字段 | 类型/约束 | 说明 |
|---|---|---|
content_sha256 |
CHAR(64) PK | 规范化 Markdown 内容寻址 |
content_markdown |
TEXT NOT NULL | 首期直接存 PostgreSQL,事务一致 |
byte_size |
BIGINT CHECK >= 0 | 限额与性能判断 |
created_at |
TIMESTAMPTZ | 首次出现时间 |
相同正文只存一次。未来迁移对象存储时保留 hash,新增 storage_key;在完成校验前不删除 DB 内容。
6.2 document_snapshots
| 字段 | 类型/约束 | 说明 |
|---|---|---|
id |
BIGSERIAL PK | 快照标识 |
doc_id |
TEXT NOT NULL | 全局业务文档 ID |
content_sha256 |
FK content blobs | 完整正文 |
parent_snapshot_id |
FK self nullable | 直接父快照 |
block_map |
JSONB NOT NULL | 稳定 block id、类型、字符范围、heading path、业务键 |
source_kind |
CHECK | template/human/agent/agent_squad/migration/system |
actor_user_id |
FK nullable | 人工主体,仅来自服务端 session |
actor_ref |
TEXT | agent key / squad run id / template version |
actor_snapshot |
JSONB | 当时名称、角色、agent/squad 配置版本,不随配置漂移 |
source_run_id |
TEXT nullable | 绑定 task run |
created_at |
TIMESTAMPTZ | 创建时间 |
正文和 block_map 不允许 UPDATE/DELETE。相同内容的 no-op 不建新 snapshot。
6.3 document_versions
| 字段 | 类型/约束 | 说明 |
|---|---|---|
id |
BIGSERIAL PK | 内部版本 ID |
doc_id |
TEXT NOT NULL | 文档 |
version_no |
INT NOT NULL | 用户看到的 V1/V2... |
status |
CHECK | open/sealed |
origin_kind |
CHECK | template/agent/agent_squad/migration |
baseline_snapshot_id |
FK snapshot | 人工高亮基准 |
head_snapshot_id |
FK snapshot | 当前/封存最终正文 |
human_revision_count |
INT | 快速展示 |
source_run_id |
TEXT nullable | 创建本版本的 run |
change_report_id |
FK nullable | 上一最终 head → 本 baseline 报告 |
opened_at/sealed_at |
TIMESTAMPTZ | 周期边界 |
关键约束:
UNIQUE(doc_id, version_no);- partial unique:每个
doc_id只有一个status='open'; - baseline/head snapshot 必须属于同一 doc;
- sealed 后
head_snapshot_id不可变。
6.4 document_change_events
| 字段 | 说明 |
|---|---|
id/doc_id/version_id/event_no |
单文档严格递增事件序列 |
from_snapshot_id/to_snapshot_id |
可复算 diff 的精确前后状态 |
change_kind |
human_revision/agent_commit/agent_noop/import/restore_as_new |
actor_kind |
human/agent/agent_squad/template/migration/system |
actor_user_id/actor_ref/actor_snapshot |
人员或执行单元归属 |
change_set |
服务端计算的结构化 hunk 摘要;不是内容真源 |
edit_session_id |
UI 聚合连续自动保存 |
request_id/idempotency_key |
重试幂等与追踪 |
created_at |
服务端时间 |
UNIQUE(doc_id, idempotency_key) 防止网络重试重复生成 revision。UI 可把同一用户同一 edit_session_id 的连续事件折叠成一组,但审计事件不合并、不删除。
6.5 document_agent_candidates
| 字段 | 说明 |
|---|---|
id/doc_id/input_snapshot_id/output_snapshot_id |
候选前后正文 |
run_id/proposal_id |
绑定真实任务和既有授权提案 |
status |
ready/needs_confirmation/committed/rejected/stale/quality_failed |
authorized_scope |
编制人批准的修改范围 |
quality_result |
质量门禁结果 |
change_report_id |
实际 before/after 的说明 |
created_at/decided_at |
时间 |
候选不改变 document_records、Version 或 head。候选被拒绝也永久保留元数据和 hash;正文保留期按安全策略执行。
6.6 document_change_reports
| 字段 | 说明 |
|---|---|
from_snapshot_id/to_snapshot_id |
报告唯一事实范围 |
schema_version |
首期 1 |
summary |
3–8 条快速摘要 |
risk_level/risk_items |
low/medium/high/critical + 结构化原因 |
project_impacts/document_impacts |
项目、阶段、任务、其他文档影响 |
open_questions |
需负责人判断事项 |
analysis_status |
complete/fallback/unassessed/corrected |
model_snapshot/prompt_version |
模型与提示词可审计来源 |
deterministic_facts |
diff 统计、规则风险下限、血缘影响集合 |
原报告不可覆盖;纠错创建新报告并用 corrects_report_id 关联。
6.7 根表指针
document_records 和 freeform_documents 增加统一命名的 ledger 指针列:
ledger_version_id(FK →document_versions.id,NULL=尚未导入);head_snapshot_id(FK →document_snapshots.id);head_revision_no;review_snapshot_id(仅 controlled);revision_schema_version;row_revision(乐观并发)。
命名冲突与旧列退役(实施红线):
freeform_documents.current_version_id已在迁移00008_2026-09-11-freeform-documents.sql中存在,语义是“每次保存 +1 的 legacy 版本号”,不得同名复用承载新语义;新指针列一律用ledger_*/head_*命名,旧列迁移时改名为legacy_version_id(或保留原名并降级为只读投影);document_records.version/content_sha256/work_dir与freeform_documents.current_sha256在兼容期由同一事务投影为旧值,稳定后只读并最终退役;- 自由文档 legacy
freeform_document_versions.version_no与新document_versions.version_no是不同表的独立编号;新 Version 起点规则在 DR-06 契约冻结时确认(推荐从 legacy 最大version_no+1起算,UI 对 legacy checkpoint 加前缀区分)。
7. 修改主体归属
7.1 人工修改
actor_kind=human;actor_user_id只取认证 principal;actor_snapshot保存当时显示名、项目角色和文档 duty;- 客户端提交的
user_id/user_name/user_role一律忽略并逐步移除; - 同一 hunk 被多人先后覆盖时,当前视图标注最后修改人,历史面板仍保留完整事件链。
7.2 单智能体修改
actor_kind=agent,保存 agent key、配置版本、模型、tool policy、on-behalf-of 用户和 run id;- 若任务由人发起,触发者不是内容作者;界面分别显示“发起人”和“执行智能体”。
7.3 智能体小队修改
- 文档基线整体归属
actor_kind=agent_squad与唯一run_id; actor_snapshot固化 squad name/version、参与 agent role/name/model 和 StepManifest hash;- 只有执行链能证明某 agent 直接产出某 block 时,hunk 才显示该 agent contributor;否则显示“小队共同产出”,禁止根据最终文案猜测个人贡献。
8. 写入流程
8.1 人工保存
- API 根据 doc id 加载资源上下文并执行项目、阶段、文档 duty、状态权限判定。
- 校验 human lease token、
expected_head_snapshot_id、expected_revision_no和 idempotency key。 - 服务端规范化 Markdown、校验大小和危险内容,计算 SHA。
SELECT ... FOR UPDATE锁定文档根;再次检查 head,冲突则返回 409 和三方比较所需指针,绝不自动覆盖。- 写 content blob、snapshot、change event;更新 open Version head 和根表 current pointer。
- 同事务写审计与必要的 cache invalidation outbox;提交后再更新工作区投影。
- 返回新 head、revision、人工累计修改统计和增量 decorations。
推荐自动保存每 5–10 秒或失焦触发;同一编辑会话在 UI 时间线折叠显示,服务端仍逐次留痕。
8.2 智能体/小队生成
- L2 解析文档、阶段、任务实例和 actor;按既有认领/提案规则取得修改授权。
- 短事务捕获 current
input_snapshot_id,获取服务端签发的 squad lease;任务只能读取该不可变输入。 - L3 同时生成
output.md和change_report.json;输出落在 candidate workspace。 - 服务端规范化输出并计算真实 diff;ImpactEngine 读取 workflow snapshot 与 document lineage;RiskPolicy 给出不可被模型降低的风险下限。
- 校验 change report schema、内容范围、引用 doc 可见性和 authorized scope。失败可重试报告生成,不重复生成正文。
- 若需要二次确认,创建
candidate_ready通知并释放租约;正文 head 不变。 - 提交时锁根记录并验证
head == input_snapshot、生命周期仍 drafting、授权/提案仍有效。 - 同一事务:封存旧 Version head → 新建 Version 与 agent baseline → 写 event/report/lineage stale/outbox → 更新 current pointers → 标记 candidate committed。
- 提交后异步投影
output.md、刷新右侧读模型并通知负责人。
8.3 与既有变更提案衔接
- 既有
document_change_proposals继续表达“是否允许智能体动这份已认领文档”; - 新 candidate/report 表达“智能体实际改出了什么”;二者不能合并成一条自由文本;
- 未认领模板可按策略自动提交;已认领或由非编制人触发时必须先有有效 proposal;
- 实际 diff 超出授权范围、规则风险达到 high/critical、或影响已批准下游文档时,再次要求编制负责人确认实际 diff;
- 任何确认都绑定 candidate id + input/output SHA,不能批准一个会漂移的“最新内容”。
8.4 失败与并发
| 场景 | 行为 |
|---|---|
| 人工保存 head 冲突 | 409 DOCUMENT_HEAD_CONFLICT,返回 base/current 指针,显示三方 diff,不自动重试 |
| Agent 运行期间输入已变化 | candidate=stale,不提交;负责人选择重新生成 |
| Agent 正文成功、报告失败 | 正文留 candidate;重试报告。最终降级时标 unassessed/high,受控文档不得直接送审 |
| Outbox 写失败 | 整个版本事务回滚,不出现“版本成功但负责人未进入通知队列” |
| 通知投递失败 | outbox 重试,不回滚已经提交的版本;站内通知具有最终一致性 |
| 工作区投影失败 | DB head 仍权威,标 projection lag 并重建,读取不回退旧文件 |
| 相同 run 重试 finalize | 由 (doc_id, run_id, output_sha) 幂等,只能提交一个 Version |
9. Diff 引擎与稳定块定位
9.1 服务端权威
真实增删改必须由服务端根据两个 immutable snapshot 计算;change_report.json 的描述不能替代 diff。Diff 结果按两种用途输出:
manual_overlay:current baseline → current head,仅保留 human events;version_compare:任意 A.final/head → B.final/head,包含所有主体,并按 event 归属着色。
9.2 block map
当前随机 blk_* 不能跨刷新使用。新流程为每个 snapshot 保存 block map:
- 首次解析按类型、heading path、结构位置、业务键(如 REQ-ID/表格主键)生成 node;
- 人工编辑携带当前 stable block id;服务端验证后继承;
- 智能体 Markdown 重新解析时,用“业务键精确匹配 → heading path/type → 内容指纹相似度 → 邻近顺序”对齐旧节点;
- 无法可靠匹配的节点分配新 UUID,并标记 insert/delete,不伪造延续关系。
9.3 粒度
| 内容 | 比较粒度 | 展示 |
|---|---|---|
| 标题/段落 | Unicode grapheme + 中英文词组 | 字词增删、整段移动 |
| 列表 | item,再到 item 内字词 | 新增/删除/改写条目 |
| 表格 | row key/位置 → cell → cell 内字词 | 单元格角标、整行增删 |
| Mermaid/代码/公式 | 行级,必要时 token 级 | 行号和语法安全转义 |
| 块移动 | stable id + 顺序 | “从 2.1 移至 3.2”,不误判为删后新增 |
算法以 Myers/patience line diff 为基础,中文正文再做 grapheme/词组 diff;输出 JSON hunks,不输出未清洗 HTML。前端只用 React 节点渲染,不用不可信 dangerouslySetInnerHTML。
9.4 版本选择规则
final:sealed Version 取封存 head,open Version 取当前 head;默认。baseline:用于查看某次智能体刚生成时的原始内容。revision:高级历史中可选择某一人工保存点。
因此“比较 V1 和 V3”不会因为 V1 曾有多个自动保存而含糊;默认就是 V1.final 对 V3.final/head。
10. 智能体变更报告
10.1 产物契约
每次生成要求 L3 输出两个目标:
output.md
change_report.json
change_report.json 建议 schema:
{
"schema_version": 1,
"summary": ["补充系统边界条件", "调整三项验收阈值"],
"changes": [{
"section_locator": "3.2 性能要求 / REQ-PERF-007",
"change_type": "modified",
"rationale": "依据新增用户材料与法规检索证据",
"evidence_refs": ["material:123#sha256", "kb:GB9706#8.4"]
}],
"risk": {
"level": "high",
"items": [{"category": "verification", "description": "阈值变化会使既有用例失效", "mitigation": "重跑 TC-007"}]
},
"project_impact": {
"schedule": "可能增加验证工作量",
"cost": "待评估",
"scope": "影响性能验证范围",
"compliance": "需复核风险管理文件"
},
"document_impacts": [{
"doc_id": "doc_proj1_test_manager",
"impact_type": "stale_candidate",
"reason": "引用的 REQ-PERF-007 已改变",
"recommended_action": "由测试方案编制人复核并重新基线"
}],
"open_questions": ["阈值是否已获得硬件负责人确认"]
}
禁止在报告中复制大段 before/after 正文;精确内容由 diff API 提供。
10.2 双层校验
| 层 | 权威职责 |
|---|---|
| 确定性层 | SHA、真实 hunk、增删统计、workflow/lineage 影响集合、敏感章节规则、风险最低级别 |
| 智能体层 | 修改理由、可读摘要、业务含义、潜在风险、建议动作和开放问题 |
最终风险:max(rule_risk, model_risk)。模型遗漏真实变更、引用不存在文档、报告说“未修改”但 SHA 改变,均触发校验失败或 conservative fallback。
10.3 风险规则下限
- 删除/降低法规、风险控制、验收标准、关键技术参数:至少 high;
- 改变需求 ID、上游已批准输入、成本/报价、阶段 gate:至少 high;
- 仅格式、错别字且无结构/数值变化:low;
- 影响已批准下游文档、跨阶段范围或职责:critical/high,按政策要求确认;
- 无法评估:
unassessed,UI 按 high 呈现,不能显示绿色安全结论。
11. 通知设计
11.1 事件类型
document.agent_candidate_ready:实际 diff 已生成,等待负责人确认;document.agent_version_committed:新智能体 Version 已生效;document.human_revision_conflict:本人编辑发生并发冲突;document.downstream_impact_detected:其他文档因上游变化需复核;document.change_report_degraded:报告未完整评估,阻断送审。
11.2 收件人矩阵
| 场景 | 必须通知 | 条件通知 |
|---|---|---|
| Agent candidate 就绪 | 当前文档编制负责人 | 发起人(若不同) |
| Agent Version 生效 | 当前文档编制负责人 | 发起人;high/critical 时项目创建人 |
| 影响下游文档 | 每份受影响文档的编制负责人 | 当前 reviewer/approver、项目创建人 |
| 报告降级 | 当前文档编制负责人 | QA/项目监督角色(若配置) |
受影响人只能看到自己有权访问的文档名称和摘要;无权资源只返回“另有 N 份受限文档受影响”,防止侧信道泄露。
11.3 通知内容
通知卡片包含:文档名、Vn-1→Vn、执行主体/发起人、3 条摘要、风险徽章、项目影响一句话、受影响文档数量、查看修改 和 查看完整分析。不把正文片段、Prompt 或私密材料写入 notification body。
去重键:doc_agent_version:{doc_id}:{version_no}:{recipient_id};candidate 使用 candidate id。版本与通知先同事务写入 outbox,worker 幂等 fanout。用户当前正打开文档时可以抑制 toast,但站内通知记录仍必须创建。
12. API 契约
所有端点先通过统一 DocumentAccessDecider,path 中 project/doc/version/snapshot 归属必须一致。
GET /api/v1/documents/{doc_id}/revision-state
-> current version/baseline/head/revision/manual change count/capabilities
GET /api/v1/documents/{doc_id}/versions?cursor=&limit=
-> version timeline; no full content
GET /api/v1/documents/{doc_id}/versions/{version_no}?view=final|baseline
-> immutable snapshot content + ETag
GET /api/v1/documents/{doc_id}/diff
?from_version=1&to_version=3&from_view=final&to_view=final&mode=structured
-> summary, hunks, actor attribution, report refs
GET /api/v1/documents/{doc_id}/manual-overlay
?version=current&actor=all|me
-> baseline→head decorations
PATCH /api/v1/documents/{doc_id}/content
If-Match: "<head_snapshot_id>:<revision_no>"
Idempotency-Key: <uuid>
body: { markdown, edit_session_id, client_block_map_version }
GET /api/v1/documents/{doc_id}/agent-candidates/{candidate_id}
POST /api/v1/documents/{doc_id}/agent-candidates/{candidate_id}/decision
body: { decision, expected_input_sha, expected_output_sha, reason }
GET /api/v1/documents/{doc_id}/change-reports/{report_id}
PATCH /api/v1/notifications/{id}
body: { status: read|acted|dismissed }
内部服务接口(不暴露为普通用户 HTTP):
CommitHumanRevision(ctx, principal, docRef, expectedHead, markdown, idempotencyKey)
CreateAgentCandidate(ctx, servicePrincipal, onBehalfOf, runID, inputSnapshot, output, report)
CommitAgentVersion(ctx, servicePrincipal, candidateID, decisionToken)
12.1 主要错误码
| HTTP | code | UI 行为 |
|---|---|---|
| 403 | DOCUMENT_EDIT_FORBIDDEN |
只读并解释职责/阶段 |
| 409 | DOCUMENT_HEAD_CONFLICT |
打开三方差异,不自动覆盖 |
| 409 | DOCUMENT_BUSY |
显示 holder 类型和可重试时间 |
| 409 | AGENT_CANDIDATE_STALE |
提示重新生成,不允许直接应用 |
| 422 | CHANGE_REPORT_INVALID |
候选保留,显示分析待补全 |
| 423 | DOCUMENT_LIFECYCLE_LOCKED |
跳转审核/变更流程 |
| 413 | DOCUMENT_TOO_LARGE |
分块或附件化建议 |
13. 右侧栏交互设计
13.1 默认阅读态
┌ 文档 Tab ───────────────────────────────────────────┐
│ V3 · 当前 r4 [7 处人工修改] [版本历史] [比较] │
│ 基准:智能体小队 · 10:42 风险:中 影响 2 文档 │
├─────────────────────────────────────────────────────┤
│ ▌ 3.2 性能要求 张工 · 11:03 │
│ 温控范围为 38–45℃,精度由 ±1℃ 改为 ±0.5℃ │
│ ~~~~~~~~~~~~~ (浅琥珀底 + 实线下划线)│
│ │
│ ◀ 删除 1 处 在锚点处显示小型删除标记,悬浮看原文 │
├─────────────────────────────────────────────────────┤
│ [纯净阅读] [人工修改] [全部变更] [仅我] [所有人] │
└─────────────────────────────────────────────────────┘
默认开启“人工修改”,只展示 current baseline→head:
- 左侧 3px gutter 标记整块受影响;
- 字词新增用浅琥珀背景 + 下划线,修改同时显示原/新值的 popover;
- 删除不把大段旧文塞回正文,在原锚点显示删除标记,点击查看;
- 右上角显示修改人、时间和 revision;多人修改显示头像堆叠;
- 颜色之外同时使用线型、图标和文字,满足色觉无障碍;深色/浅色主题分别校验对比度;
- “纯净阅读”一键关闭所有 decoration,导出默认纯净正文;审计版导出可附变更表。
13.2 版本历史抽屉
版本卡片展示:
V3 当前/V2 已封存;- baseline 来源(模板、单智能体、智能体小队)和 actor snapshot;
- 开始/封存时间、人工 revision 数/人数;
- 最终 SHA 短码、生命周期 checkpoint;
- 智能体摘要、风险徽章、影响数量;
- 选择为 A / 选择为 B / 查看生成时原稿。
人工自动保存默认折叠在版本卡片内,展开才显示 r1...rN,避免版本噪声。
13.3 两版本比较
- 宽屏默认左右双栏:A 在左、B 在右,同步滚动和章节对齐;
- 窄屏/右栏宽度不足时使用 unified diff;
- 顶栏允许交换 A/B、只看改动、按主体筛选、跳到上一/下一处;
- 摘要区固定展示“新增/删除/修改/移动块数、人工/Agent 占比、风险、影响文档”;
- 点击任一 hunk 可打开来源事件、修改主体、run、提案、报告和审计记录;
- 比较视图只读,不允许在历史版本上直接编辑。
13.4 智能体完成卡
生成完成后,中间对话与右侧栏显示同一 report id 的摘要卡:
V2 已由「产品经理智能体小队」生成
改动 12 处 · 风险 高 · 影响 3 份文档
摘要:补齐需求边界;调整 3 项验收阈值;新增 2 个开放问题
[查看逐项修改] [风险与影响] [若需:确认应用]
卡片不能只靠 SSE 临时状态;刷新后从 version/report/notification 读模型恢复。
14. 权限和安全
| 动作 | Controlled | Freeform |
|---|---|---|
| 查看版本/正文/diff | active 项目成员 + 阶段可见 + 文档可见 | owner;shared 时需 active 项目成员 |
| 人工编辑 | 指定 author + drafting + human lease | owner(首期) |
| Agent 候选 | service identity + on-behalf-of 用户有触发权限 + active task instance | service identity + owner 明确触发 |
| 提交 Agent Version | 服务端 task finalizer;必要时绑定 author 决策 | owner 授权策略 |
| 查看完整影响 | 对每个受影响资源逐一授权 | 同左 |
| 历史恢复 | 后续受控动作,永不 UPDATE 历史 | owner 新建 revision |
安全要求:
- holder id、actor kind、agent id、run id、project/stage/workdir 不信任客户端;
- snapshot/diff/report API 必须复用列表、正文、导出、RAG 和 Agent tool read 的同一授权决策;
- 日志、通知和 metrics 不记录正文、diff 片段或 Prompt;
- 防止通过版本数量、影响文档名和 actor 名称泄露无权资源;
- DB 层限制 immutable 表 UPDATE/DELETE,审计修正只追加;
- 规范化 Markdown 后再计算 SHA,避免换行/Unicode 形式导致伪差异;
- 所有渲染继续执行 Markdown/Mermaid/XSS 安全策略。
15. 一致性、性能与保留
15.1 事务边界
Agent commit 的最小原子集合:
seal old version
+ create new baseline snapshot/version
+ change event/report
+ update document head/version/hash
+ lineage/stale changes
+ outbox event
任务终态只有在该事务成功后才可从 finalizing 进入 completed。这补上当前“先写工作区,再分别更新文档和消息”的分裂窗口。
15.2 性能
- 列表/时间线不返回正文;正文和 diff 分页/按章节懒加载;
- diff cache key=
algorithm_version:from_sha:to_sha:mode,内容更新天然失效; - 大于阈值的文档异步计算 diff,API 返回 job id,前端显示可恢复进度;
- content blob 按 SHA 去重,snapshot 只存引用和 block map;
- 对极大表格采用 windowed rows,禁止一次渲染全部 cell diff;
- 下载/导出使用选定 snapshot,不从浏览器当前 DOM 拼装。
建议首期限制:Markdown 10 MiB、单次 change report 256 KiB、diff hunks 10,000;超限进入分章节比较,不截断审计正文。
15.3 保留策略
- 受控文档:随项目、质量体系和法规适用策略保留;默认不自动硬删版本、事件和报告;
- 自由文档:默认 365 天可配置,删除文档先进入回收站,历史清理由后台策略和审计事件驱动;
- agent candidate:未提交正文可按较短策略清理,但保留 hash、run、决策和报告元数据;
- 法规适用性、电子签名和法定年限需由组织另行确认,本设计不宣称自动满足特定法规。
16. 迁移与兼容
16.1 历史受控文档
- 对每条
document_records解析服务端规范 workdir,读取当前output.md; - 文件 SHA 与 DB SHA 一致才导入 snapshot;不一致进入 quarantine report,禁止静默选择一方;
- 建立
V1 r0 origin=migration,baseline=head=当前 snapshot;历史人工修改无法可靠推断,因此不伪造高亮; is_template_only=true的文档优先从激活时冻结的 template version 创建 template snapshot;若历史没有冻结模板,标baseline_unavailable;- 回填报告记录成功、缺文件、hash mismatch、无模板四类数量,并支持 dry-run。
16.2 自由文档
现有 freeform_document_versions 每次保存均是不可变内容,可无损导入 snapshot/change event。为避免改写用户历史:
- 旧每-save版本在 UI 标记为
legacy checkpoint; - 切换新模型时以当前版本建立一个
origin=migration的开放 Version; - 后续人工保存变为 revision,下一次智能体生成才增加业务 Version;
- 首期可先完成底层导入和 API,第二波再切换自由文档 UI 语义。
16.3 模板
项目激活时必须把冻结的 workflow template version 内容复制/引用为文档 V1 baseline,不能继续仅在浏览器用 templateFactory 临时生成。这样模板与后续人工修改才可比较、可审计。
17. 可观测性
指标:
document_revision_commit_total{actor_kind,result};document_head_conflict_total{mode};agent_candidate_total{status,risk};change_report_validation_total{result};document_diff_duration_seconds{size_bucket,mode};document_notification_lag_seconds{event_type};workspace_projection_lag_total。
结构化日志只写 doc/project/run/request/version/revision/hash 短码,不写正文。告警关注:版本事务失败、candidate stale 激增、报告 fallback 比例、通知积压和投影不一致。
18. 验收场景
| ID | 场景 | 预期 |
|---|---|---|
| AC-01 | 模板后用户保存 3 次 | 仍为 V1,r3;三事件可审计;overlay=template→head |
| AC-02 | squad 基于 V1 r3 生成 | V1 封存于 r3,V2 r0;人工 overlay 清零 |
| AC-03 | V2 再人工修改 | 只显示 V2 baseline→V2 head,不重复显示 V1 人工修改 |
| AC-04 | 比较 V1 与 V2 | 默认 V1.final→V2.final/head,可切换 V2 baseline |
| AC-05 | 单 agent 与 squad 各生成一次 | 时间线正确显示主体;squad 参与成员快照可查看 |
| AC-06 | 两用户并发保存 | 只成功一个;另一方 409 + 三方 diff;无自动覆盖 |
| AC-07 | agent 输入后用户抢先改变 head | candidate stale,不建新 Version |
| AC-08 | 生成报告漏报真实删除 | validator 拒绝/降级;规则风险不可被降低 |
| AC-09 | 新 Version 影响下游 | lineage/stale 与 outbox 同事务;对应负责人收到授权内通知 |
| AC-10 | 刷新、重登、服务重启 | 版本、overlay、报告、通知完全恢复,不依赖内存/SSE |
| AC-11 | 非成员猜 doc/version/snapshot id | 统一 403/404 策略,无内容/元数据侧信道 |
| AC-12 | 已批准文档直接修改 | 423;历史、head、通知均不变 |
| AC-13 | 同一 run finalize 重试 | 只产生一个 Version/报告/通知 |
| AC-14 | 历史 hash mismatch 回填 | 进入隔离报告,不伪造 baseline |
| AC-15 | DOCX/Markdown 导出历史版本 | 内容和所选 snapshot SHA 一致,默认无 UI 高亮污染 |
19. 评审决策点
建议本轮审核确认以下三项,其他细节可在实施中按本设计收敛:
- 版本语义:采用推荐的“智能体/模板开启 Version,人工保存只增加 Revision”。
- 高风险应用:
high/critical智能体实际 diff 必须由编制负责人二次确认;低/中风险按既有提案授权自动提交。 - 上线范围:Wave 1 先覆盖受控工作流文档;自由文档完成底层兼容后在后续 Wave 切换 UI,避免一次性重写两个治理域。
20. 关联文档
- Gap analysis: ../audit/2026-09-13-document-revision-management-gap-analysis.md
- Implementation plan: ../remediation/2026-09-13-document-revision-management-implementation-plan.md
- Existing workflow authority design: ../remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md
- Historical right-rail design: ../archive/design/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md