Files
Agent-System/.doc/audit/2026-09-13-document-revision-reviewer-duty-sync.md
WeiCHEN 4baa1220ee docs(ops): close docrev UI audits after main+post-restart PASS
Record real Playwright ledgers, mark 20 audits and 9 remediations done, and leave management-implementation-plan as plan-only.
2026-09-23 04:00:49 +08:00

5.4 KiB
Raw Permalink Blame History

title, status, created, updated, severity
title status created updated severity
项目 reviewer 未同步到受控文档职责 done 2026-09-13 2026-09-22 critical

项目 reviewer 未同步到受控文档职责

W3 UI-rerun 关闭(2026-09-22):status=done。真实 Playwright 账本 PASS:ui-acceptance-results.json(main UI-00..16)+ ui-acceptance-results-post-restart.json(UI-15)。任务 tip 已合入本地 dev;详见 short-term 与 测试报告。

现象

第17轮真实 UI(schema 30,dev@639969f):UI-00 至 UI-12 PASS。UI-13a 精确职责断言首次暴露产品缺陷:

  • UI-01 页面建项目把 USER_B 的职责下拉设为 reviewer
  • B 登录打开 doc_proj6145_intake 权限矩阵时,select value / badge data-doc-role 实际为 viewer
  • 失败:reviewer B intake duty select must be reviewer: expected_duty:reviewer;got:viewer

现场文档头仍写「编制人: 编制工程师 / 审核人: 审核负责人 / 批准人: 批准负责人」。

根因分析

只读查本轮 project 6145(不暴露账号密码/token):

层 证据 后果
立项 UI CreateProjectModal 把 B 标成 reviewer;默认还勾选 seed id=3 李主管 / id=4 王总监 用户意图是 B=审核人
成员持久化 toApiProjectRole 禁止 author/reviewer/approver,一律映射 member;payload 无 document duty B=171 落成 project_role=member
project_members 170 owner(A)、171 member(B)、3/4 member 库表无法区分 B 是 reviewer
任务生成 bizdev.service:ReviewerID==0 → 写死 2 +「审核负责人」;ApproverID==0 → 写死 3 与真实成员无关
document_records intake / prelim_design 均为 author_id=170(恰为创建者 UserID)、reviewer_id=2、approver_id=3 第二份文档继承了同一套假职责
列表 API 原样投影 reviewer_id=2 前端拿到权威但错误的 id
resolveCurrentDocRole 受控文档按 id 匹配,fail-closed 为 viewer B=171 ≠ 2 → viewer;不是前端提权,是服务端职责丢失

document_duty_assignments 只挂官方工作流实例任务,聊天 TRIGGER_TASK 生成账本不走该表。

严重度

critical

项目创建时明确指定的审核人在后续每份受控文档上变成查阅者;写路径虽因 fail-closed 未把 B 提成编制人,但审核职责与权限矩阵验收全部失真。

关联整改

证据

  • 失败归档(只读,不改不删):.doc/test-reports/assets/2026-09-13-document-revision-runtime-ui/schema30-ui13a-reviewer-duty-sync-failure/
  • phase-state.json:controlledDocId=doc_proj6145_intake,项目 UI验收-超声微创系统-mu0bvnp8
  • Playwright:expected_duty:reviewer;got:viewer

独立审查收紧(同一分支,暂不合入)

独立审查指出首轮 Heal「已是任意在任成员则保留」会让批准人串位:6145 类场景 approver=3(李主管也是成员)而 assigned=4 时不应保留 3。项目 document_duty 才是权威。

立项后成员增改/恢复若只发 project_role,document_duty 会静默失效。更新成员时若省略 project_role 且带 document_duty,默认 member 会把 owner 降级。

生成/列表路径若吞掉自愈错误,会带着 reviewer_id=2 假成功。

最后一轮缺口(已在同分支修复)

  • 移出成员只改 exited 不同步文档;前端移出不刷新矩阵
  • 空 assigned 若保留非成员占位,退出审核人会留在文档上
  • reviewer→viewer 时人仍 active,generic heal 会把槽位留下,必须按更新前 duty 显式撤销
  • CreateOrGetDocument 错误被 _ 吞掉会假成功

原子清槽约束(已在同分支修复)

职责撤销/转移不得在成员 upsert 已提交后再用服务层前后快照做非原子清理。权威路径是同一 DB 事务:pg_advisory_xact_lock → 读旧 duty / 冲突 holder → 成员更新 → 精确清 reviewer_* / approver_*。随后 heal 填新 holder。

Heal 与成员写竞态(已在同分支修复)

HealProjectDocuments 若无项目锁、用 pool 先读后写,会出现:heal 读到 reviewer A → 成员事务持锁把 A 清槽并提交为 B → 旧 heal 把 A 写回。现已与成员写共用 pg_advisory_xact_lock(project_id),解析与 document_records 更新在同一事务。

开放问题

  • 本轮不重跑真实 UI-13a;不得标 E2E 通过或任务 done
  • 6145 剩余风险:迁移后 owner 会补 author;B(171)当时只落成 member 且 document_duty=''。服务端不能臆造 reviewer。须再次经成员 API 写入 document_duty=reviewer 后,自愈才会把文档从占位 2 对齐到 B。
  • 隔离 PG 集成须用临时库 + TEST_DATABASE_URL,见 scripts/run-isolated-duty-sync-pg-tests.sh;禁止默认连 agent_system_dev