Use deliverablesRef + limited poll for post-task server docs; pass reconnectRunId across auto-retry; GetRun reads idempotency_key; StartClaimedRun fails closed on UpdateRun; MessageBubble/E2E scope this-turn assistant; correct audit retry/schema19 wording. Co-authored-by: Cursor <cursoragent@cursor.com>
7.6 KiB
7.6 KiB
title, status, created, updated, severity
| title | status | created | updated | severity |
|---|---|---|---|---|
| 小队完成未同步受控文档状态 + UI-03 选择器非 Tab + Retry 暴露 DB 约束(UI-03) | done | 2026-09-13 | 2026-09-13 | 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. 产品缺陷:前端在小队完成后未同步工作流文档列表
- 服务端已落库受控文档:
后端
document_records表已落库doc_id="doc_proj6089_user_requirements",is_template_only=false,current_state="drafting"。且前端每 5 秒发起的轮询GET /api/v1/projects/6089/documents?category=workflow已正确返回该受控文档记录。 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。syncWorkflowDocs依赖项未触发: 在App.tsx第 1618–1661 行,syncWorkflowDocs(调用mergeWorkflowDocumentsFromServer)仅在currentProjectId或session变动时执行;同一会话内小队完成不会触发该 effect。- 流式结束
case 'done'遗漏文档同步: 在App.tsx第 2571–2593 行,任务流完成时仅调用了await chatWindow.refresh().catch(() => undefined)(仅刷新聊天消息),未同步工作流文档列表。 - 连锁阻断工具条挂载:
前端
deliverables中的user_requirements一直是isTemplateOnly: true。根据revisionToolbarMountMode契约,isTemplateOnly === true时返回'template_hint',阻断DocumentRevisionToolbar([data-testid="doc-rev-version"])挂载。
B. 测试脚本缺陷:定位器假设水平 Tab 且命中页头 Banner 徽章
- 在
web/e2e/document-revision-runtime.spec.ts第 538 行:const tab = page.locator('[role="tab"], button, div').filter({ hasText: /需求|摸底|URS|用户/ }).first(); - 穿透到页头徽章:
[role="tab"], button, div包含全局所有div。页面顶部 Header Banner 含有当前项目: ... V0.1 需求摸底(div元素)。.first()命中了该非交互的 Banner 徽章div,根本没有点击文档切换器。 - 真实 UI 为下拉/抽屉交互:
SlimTabBar.tsx为面包屑下拉(button.dropdown-trigger->.dropdown-menu)或大盘抽屉(DeckDrawer),页面不存在水平文档 Tab。
C. 前端断线自动重试与 DB 约束异常暴露
- 前端断线自动重试导致同 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 幂等)
- 13:02:
- 暴露
task_runs状态约束缺陷: 在二次运行与高风险候选流转路径中,后台服务尝试将task_runs.status更新为pending_author_confirmation时,暴露了数据库底层约束拦截: goose00019原始chk_task_run_status仅允许:该枚举未包含CHECK (status IN ('pending', 'running', 'completed', 'failed', 'cancelled', 'finalizing_failed', 'quality_failed', 'interrupted'))pending_author_confirmation,导致写入状态时触发 PostgreSQL check constraint 违规(由 goose00030补齐)。
3. 严重度与阻断
- 严重度:
critical - 阻断项:
- 产品前端:
App.tsx在小队完成(case 'done')以及定期轮询中必须调用mergeWorkflowDocumentsFromServer动态更新受控文档。 - 数据库约束:
task_runs表的chk_task_run_status约束必须补齐pending_author_confirmation。 - 测试脚本:修正 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) 卷的迁移实测。