diff --git a/.doc/test-reports/2026-09-24-free-collab-claim-notify-test-report.md b/.doc/test-reports/2026-09-24-free-collab-claim-notify-test-report.md new file mode 100644 index 00000000..93550cf7 --- /dev/null +++ b/.doc/test-reports/2026-09-24-free-collab-claim-notify-test-report.md @@ -0,0 +1,54 @@ +# 自由协作通道 + 认领态分流 + 文档变更提醒 测试报告 + +## 一、 测试背景 (Background) +实现自由协作通道、认领补齐与租约加固、通知 digest 聚合、补充材料影响确认卡与认领态分流执行。 + +## 二、 测试目标 (Test Objectives) +- A:成员级 free-lane 对话不被阶段 ABAC 误拦;非成员仍 403 +- B:负责人查看非模板正文自动认领;租约条件更新与 holder 归属;可读 DOC_BUSY +- C:document.proposal_required + notification_digests ON CONFLICT DO UPDATE;收件箱 UI +- D:supplementimpact 批次/确认卡/分流;批准后负责人 ForceDirectEdit(user:/supplement 触发) + +## 三、 测试方案与环境 (Test Plan & Environment) +- OS: Linux;Go short 单测;web npm test + build +- 层级:工程工具 + Go/接口 + 前端构建(按验证契约并集) +- 真实 PI 全链路:本批 **未运行**(见结论),记为待验证 + +## 四、 预期结果 (Expected Results) +各包 `go test -short` PASS;`npm test`/`npm run build` PASS;arch-check block PASS。 + +## 五、 实际测试结果与判定 (Actual Results & Evaluation) + +### TC-GO-1 server/docgov/projectinstance/supplementimpact/notification/bizdev/app/coordinator/archtest +- **输入**: `go test -count=1 -short` 于 non-author worktree 相关包 +- **实际输出**: `ok`(server ~19s;其余短测均 ok);附件 `assets/2026-09-24-free-collab-claim-notify/server-short.txt` +- **判定**: PASS +- **耗时**: ~20s 量级 + +### TC-WEB-1 npm test +- **输入**: `cd web && npm test` +- **实际输出**: node:test 502 pass;vitest 34 pass +- **判定**: PASS + +### TC-WEB-2 npm run build +- **输入**: `cd web && npm run build` +- **实际输出**: 构建成功(含 precompress) +- **判定**: PASS + +### TC-PI-1 真实产品 PI 全链路 +- **判定**: 未运行 / 待验证(交付铁律要求获授权环境 nightly;本会话未启 pi-agent) + +### TC-BROWSER-1 收件箱铃铛与确认卡 +- **判定**: 未运行 / 待验证(组件单测已覆盖卡片类型与通知 API) + +## 六、 自动化测试套件汇总 (Test Suite Execution) +| 套件 | 结果 | +|---|---| +| arch-check --mode block | PASS(free-collab) | +| go test -short (关键包) | PASS | +| web npm test | PASS | +| web npm run build | PASS | +| 真实 PI / 浏览器 E2E | 未运行 | + +## 七、 测试结论与后续优化建议 (Conclusion & Next Steps) +工程验收目标达成可合入 local dev。真实 PI「补充→确认卡→分流→批准自动应用」与浏览器收件箱实测仍待授权环境补证。 diff --git a/.doc/test-reports/assets/2026-09-24-free-collab-claim-notify/server-short.txt b/.doc/test-reports/assets/2026-09-24-free-collab-claim-notify/server-short.txt new file mode 100644 index 00000000..157be398 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-24-free-collab-claim-notify/server-short.txt @@ -0,0 +1 @@ +ok chat-agent-system/internal/server 19.136s diff --git a/.doc/test-reports/assets/2026-09-24-free-collab-claim-notify/web-npm-test.txt b/.doc/test-reports/assets/2026-09-24-free-collab-claim-notify/web-npm-test.txt new file mode 100644 index 00000000..df81cb2f --- /dev/null +++ b/.doc/test-reports/assets/2026-09-24-free-collab-claim-notify/web-npm-test.txt @@ -0,0 +1,619 @@ + +> shuimu-workbench@1.0.0 test +> tsx --test "src/**/!(*InteractiveCard*|*chatWindowArtifact*|*deliverableSync*).test.ts" && vitest run src/components/chat/InteractiveCard.test.ts src/components/chat/chatWindowArtifact.test.ts src/components/chat/deliverableSync.test.ts + +✔ AuthClient: 基础登录与 .env 超级管理员鉴权 (2.220954ms) +✔ AuthClient: 自主注册受控流程(仅填用户名密码姓名,职位强制绑定访客待指派) (4.752559ms) +✔ AuthClient: 开启注册需审批时,注册账号处于待审状态并禁止登录 (0.504185ms) +✔ AuthClient: 管理员创建账号必须在首次登录修改密码 (0.291711ms) +✔ authErrorMessage: 优先信封 error 领域原因,避免裸 JSON / 无权访问误导 (0.207064ms) +✔ mapUserAccount: snake_case Go contract → camelCase (0.733088ms) +✔ mapUserAccount: prefers snake_case when both present (0.149376ms) +✔ mapLoginResult/mapMeResult use top-level must_change_password as sole authority (0.482776ms) +✔ mapUserAccountList maps admin users list (0.148216ms) +✔ AuthClient.login + fetchMe map real snake_case wire payloads (65.593892ms) +✔ shouldAutoRetryChat: disabled until idempotency (2.164145ms) +✔ shouldAutoRetryTask: transient only, max 2 (0.224574ms) +✔ shouldAutoRetryTask: document busy never retries (0.121937ms) +✔ shouldAutoRetry alias delegates to task path (0.116637ms) +✔ autoRetryDelayMs: 1s then 2s (0.128426ms) +✔ fallbackErrorClass: network → transient, workspace → resumable (0.154435ms) +✔ upsertChatSession surfaces safe INTERNAL envelope instead of raw JSON text (40.123479ms) +[sse] 忽略无法解析的帧: {not valid json SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2) + at JSON.parse () + at parseFrame (/home/weichen/projects/Agent-System/.worktrees/non-author-member-access-2026-09-24/web/src/api/chatStream.ts:124:26) + at parseSSEChunk (/home/weichen/projects/Agent-System/.worktrees/non-author-member-access-2026-09-24/web/src/api/chatStream.ts:173:20) + at TestContext. (/home/weichen/projects/Agent-System/.worktrees/non-author-member-access-2026-09-24/web/src/api/chatStream.test.ts:41:31) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) +✔ parseSSEChunk: parses event and data lines (1.082428ms) +✔ parseSSEChunk: keeps incomplete frame in rest (0.186164ms) +✔ parseSSEChunk: flush parses final frame without trailing delimiter (0.206004ms) +✔ parseSSEChunk: ignores heartbeat comments and keeps last id (0.137505ms) +✔ parseSSEChunk: skips a single malformed frame and keeps parsing the next valid frame (1.958502ms) +✔ parseSSEChunk: parses CRLF-delimited frames (0.157045ms) +✔ parseSSEChunk: mixed LF and CRLF delimiters (0.130586ms) +✔ API_BASE is empty relative base (0.908143ms) +✔ apiFetch attaches Bearer from session storage (32.891703ms) +✔ apiFetch retries GET on 503 then succeeds (201.804788ms) +✔ apiFetch does not retry POST by default (0.594522ms) +✔ readApiError preserves typed envelope for error cards (1.462577ms) +✔ apiFetch auth:false skips Authorization (0.498075ms) +▶ docgov lifecycle API client + ✔ claimDocument posts to /api/v1/docgov/claim with author role (33.68346ms) + ✔ submitForReview posts to /api/v1/docgov/submit-review (0.899763ms) + ✔ reviewDecision posts action and optional reason (4.654622ms) + ✔ approverDecision posts action and rollback_to (2.502746ms) + ✔ proposeModification posts to /api/v1/docgov/proposal (0.729558ms) + ✔ decideModificationProposal posts to /api/v1/docgov/proposal/decide (0.66824ms) +✔ docgov lifecycle API client (44.750521ms) +✔ updateFreeformDoc exposes CONCURRENCY_CONFLICT on 409 (19.750754ms) +▶ notifications inbox helpers + ✔ ranks action_required / proposal ahead of info (2.585234ms) +✔ notifications inbox helpers (3.746608ms) +✔ addProjectMember exposes structured ProjectSettingsApiError on 403 (27.243681ms) +✔ updateProjectMember surfaces safe INTERNAL message on 500 duty-sync failure (0.806976ms) +▶ projectSettingsError + ✔ keeps status, code, message and issues on PLAN_FROZEN (1.3315ms) + ✔ maps revision and concurrent conflicts to distinct recovery (0.119436ms) + ✔ joins validation issues but still keeps typed codes (0.136446ms) + ✔ prefers envelope code over legacy error field (0.092307ms) + ✔ unwraps nested business JSON inside VERSION_CONFLICT envelope (0.128526ms) + ✔ maps bare VERSION_CONFLICT envelope to retry_after_switch (0.080187ms) + ✔ retains the local draft when a late tab hits PLAN_FROZEN (0.093948ms) + ✔ prefers error_code over legacy bare error string (DOC_BUSY) (0.088498ms) +✔ projectSettingsError (3.475787ms) +✔ fetchProjectTrace turns null arrays into empty arrays (29.447715ms) +✔ fetchProjectTrace keeps real arrays and rejects failed responses (1.440377ms) +✔ Project workflow types validation (3.787797ms) +✔ createTaskRun exposes DOC_BUSY detail without a retryable run (28.069556ms) +✔ parseSSEChunk tracks id seq for after_seq reconnect (0.596663ms) +✔ subscribeTaskRunEvents reconnects on EOF with advancing after_seq (3.089188ms) +✔ readTaskRunSSEOnce marks non-terminal EOF for reconnect (0.616861ms) +✔ subscribeTaskRunEvents fails fast on 401 without retrying (0.905563ms) +✔ subscribeTaskRunEvents fails fast on 404 without retrying (0.450007ms) +✔ buildTaskRequest: maps five project fields + task_key + user identity (0.771017ms) +✔ buildTaskRequest: omits optional fields when absent (0.145886ms) +✔ buildTaskRequest: includes materials when provided and non-empty (0.667021ms) +✔ buildResumeRequest: adds work_dir on top of task request (0.179035ms) +✔ buildTaskRequest: canonicalizes legacy doc-p doc_id (0.286372ms) +✔ buildTaskRequest: UI-05 pinned intake keeps task_key + doc_proj6109_intake (0.206624ms) +✔ buildResumeRequest: forwards add_steps when provided (0.150946ms) +✔ CategoryDock: 渲染顶部 🔔 未读提醒项及角标数字 (14.694014ms) +✔ CategoryDock: isAllReadCompleted 为 true 时渲染完成态提示 (2.832846ms) +✔ CategoryDock: 0 未读时不渲染红色未读角标 (1.881625ms) +✔ CategoryDock: 分类项包含依次跳转与遍历提示信息 (2.510766ms) +✔ chat column lives outside the workbench shell (1.404088ms) +✔ InputArea keeps draft when send preflight fails (1.297631ms) +✔ InputArea clears draft only after accepted send (0.264422ms) +✔ InputArea shows thinking block message (0.057068ms) +✔ InputArea keeps draft when attachment registration fails (0.096398ms) +✔ TaskRunCard renders timeline with title badge and current step (12.025343ms) +✔ TaskRunCard completed state keeps card with duration and artifact (2.310781ms) +✔ TaskRunCard sanitizes frozen progress labels on completed steps (2.100487ms) +✔ TaskRunCard keeps shell when only taskRunId is present (0.860244ms) +✔ active document pane lives outside the workbench shell (1.280272ms) +✔ isTemplateOnly 交付物应正确识别为初始模板展示态 (0.951852ms) +✔ workbench shell lives outside App (1.861105ms) +✔ 左侧栏鼠标严密绝对跟随与夹紧测试 (Left Rail Exact Pointer Following & Clamping) (0.883934ms) +✔ 右侧栏鼠标严密绝对跟随与反向位移测试 (Right Rail Exact Pointer Following & Inverted Delta) (0.163265ms) +✔ trace panel is not mounted above the chat stream (0.905634ms) +✔ detects legacy mock and neuropulse/ten-projects ids (1.176836ms) +✔ detects colliding demo project ids (0.205224ms) +✔ applyRestoredFileRaw: 以 prev 为权威,只补丁缺失 fileRaw,不丢新增条目 (1.01672ms) +✔ applyRestoredFileRaw: 无可用 fileRaw 时返回同一引用 (0.148976ms) +✔ login member sync stays one request for 1, 30 and 100 projects (1.803037ms) +✔ viewer seed keeps session visibility without a member-list call (0.34485ms) +✔ later session response cannot overwrite a newer user (0.173694ms) +✔ in-flight member sync collapses to one call (1.381129ms) +✔ 每人独立私聊:同一项目不同用户拥有不同 sessionId (0.803227ms) +✔ 左侧会话列表按当前用户过滤,不可见他人私聊 (0.198084ms) +✔ 消息严格归属各自私聊 session,无跨用户混聊 (1.882874ms) +✔ 切换用户时 resolve 到该用户同项目私聊会话 (0.261082ms) +✔ resolve 优先有消息的私聊,跳过空壳 sess-p{N}-u{id} (0.33248ms) +✔ ensurePrivateSessionsForUser 为缺失用户补齐空私聊 (0.403668ms) +✔ 多项目会话消息隔离测试仍成立(endo vs ultrasound) (0.252882ms) +✔ window cache LRU: 驱逐带 userId 前缀的完整 cache key,不留孤儿条目 (2.453317ms) +✔ window cache: 无 schema 的旧载荷不当作有效缓存 (0.172265ms) +✔ window cache: 读写同一 userId 前缀,跨用户不串读 (0.192934ms) +✔ same account and first login do not reset workbench storage (2.573724ms) +✔ switching accounts resets workbench storage (0.165725ms) +✔ resetWorkbenchStorage preserves org user directory for cross-account project create (1.32949ms) +✔ parseAnchorHash: 正确解析标准深链 hash (1.710729ms) +✔ formatAnchorHash: 正确构造深链格式 (0.186195ms) +✔ navigateToAnchor: 快路径直接命中 DOM 节点 (0.473186ms) +✔ navigateToAnchor: 慢路径拉取分片后命中 (81.045313ms) +✔ resolveTurnAnchorId: 方案 A 轮次归一化测试 (0.449786ms) +✔ 全链路场景 1: 用户自主受控注册(仅填用户名/密码/姓名,职位严格绑定访客待指派) (1.597373ms) +✔ 全链路场景 2: 系统准入策略(关闭自主注册与开启强制审批流转) (0.741828ms) +✔ 全链路场景 3: 管理员开通账号首次强制改密闭环 (0.183805ms) +✔ 全链路场景 4: 环境标识随登录会话返回(dev/test/main) (0.110727ms) +✔ cleanHeadingContent: 手工多级序号前缀清洗与专业词汇保护 (1.318371ms) +✔ 标题多层级自动编号:单 H1 文档总标题自适应模式 (1 -> 1.1 -> 1.1.1) (0.446737ms) +✔ 标题多层级自动编号:多 H1 标准大章模式 (0.204884ms) +✔ 跨章节图、表、公式多级按章重编号测试 (表 1-1, 表 2-1, 图 3-1, 式 (4-1)) (0.180585ms) +✔ 有序列表与无序列表编号与渲染功能测试 (10.80066ms) +✔ 动态块操作闭环重编号验证 (Insert, Move, Delete) (0.31354ms) +✔ findMatchingBlockForReview: 能够精准按审查关键词(电气安全/EMC/竞品)定位段落块 (2.577543ms) +✔ findMatchingBlockForReview: 能够按外部指定 hint 线索精确命中目标块 (0.188104ms) +✔ createRejectConfirmationCard: 生成合规危险级驳回门禁卡片 (2.961992ms) +✔ isAffirmativeResponse: 准确识别双轨交互中的肯定意图输入 (0.290491ms) +✔ findLastActiveCard: 正确在会话历史中提取最新的待决策卡片 (0.254123ms) +✔ decrementActiveCardsTtl: 多轮对话超时递减与自动失效归档 (0.209834ms) +✔ applyConfirmRejectToDoc & applyUndoRejectToDoc: 驳回挂载批注与60s窗口期撤销完整闭环 (0.858225ms) +✔ resolveCardInMessages & cancelCardInMessages: 消息流中卡片终态沉淀 (0.229683ms) +✔ classifyRejectUtterance: 询问原因 → QUERY_REJECT_REASON (1.01016ms) +✔ classifyRejectUtterance: 明确执行 → EXECUTE_REJECT (0.165115ms) +✔ classifyRejectUtterance: 模糊 → OTHER (0.194494ms) +✔ resolveDocGovCard: 编制人查询 → 信息卡且无 confirm_reject (0.67676ms) +✔ resolveDocGovCard: 审核人执行 + reviewing → 确认卡 (0.228233ms) +✔ resolveDocGovCard: 编制人误说执行驳回 → 无权纯文本 (0.115776ms) +✔ resolveDocGovCard: 批准人 + approving → 终审确认卡 (0.244853ms) +✔ resolveDocGovCard: 编制人 OTHER → 引导查询无危险按钮 (0.110776ms) +✔ canConfirmReject: 仅审核/批准 (0.122747ms) +✔ deriveFallbackCategory identifies categories correctly (1.169535ms) +✔ enrichMessagesWithCategories backfills categories without overwriting existing ones (0.31532ms) +✔ Markdown ➔ Block AST 解析测试 (标题自适应编号与图表公式全链路) (3.192015ms) +✔ 动态重编号引擎测试 (多 H1 规范章节重排验证) (1.431487ms) +✔ Block AST ➔ Markdown 双向无损往返还原测试 (1.618682ms) +✔ 三层交付物多用户隐私绝对隔离测试 (Multi-user Strict Privacy Isolation) (0.910653ms) +✔ 一键共享至项目参考库流转测试 (Promote to Shared Reference Test) (0.153975ms) +✔ 撤回共享恢复私有草稿测试 (Revoke Shared Reference Test) (0.297781ms) +✔ 受控工作流纯净性红线检验 (Workflow Purity Security Red Line) (0.069408ms) +✔ isSameMessage: clientTurnId match (6.118139ms) +✔ isSameMessage: serverId match without turn (0.202264ms) +✔ filterPendingLiveMessages: real temp vs server id (0.191724ms) +✔ mergeLiveOverHistory preserves server id from live (0.137536ms) +✔ applyPhaseEvent: appends first phase as running node (0.987321ms) +✔ applyPhaseEvent: completes predecessors when a new phase arrives (0.239813ms) +✔ applyPhaseEvent: same phase refreshes label in place (no duplicate node) (0.207464ms) +✔ applyPhaseEvent: unknown phase falls back to hourglass meta (0.131726ms) +✔ applyPhaseEvent: prefers backend message over short label (0.101637ms) +✔ applyPhaseEvent: step_completed closes running entry without appending (0.221844ms) +✔ applyPhaseEvent: stage_completed closes entries (0.131446ms) +✔ applyPhaseEvent: task_failed appends warning node (0.109827ms) +✔ applyPhaseEvent: decorates label with step index / total steps (0.208763ms) +✔ applyPhaseEvent: repeated step_executing with step_index gets separate nodes (0.188555ms) +✔ applyPhaseEvent: ignores event without phase payload (0.098597ms) +✔ applyPhaseEvent: step_failed marks running entry as failed (keeps step label) (0.103367ms) +✔ applyPhaseEvent: step_failed appends failed node when no running entry exists (0.082538ms) +✔ applyPhaseEvent: retry of a failed step resets it to running (0.145646ms) +✔ applyPhaseEvent: stores detail from phase.message (0.078338ms) +✔ PHASE_META: document_parsing and document_summarizing are registered (0.378958ms) +✔ PLAN_CONFIRM 卡片来自 PlanView 且不触达 AST (1.157546ms) +✔ 409 冲突把卡片标为 outdated 并换上最新 revision (0.262372ms) +✔ GET reconcile 用权威 PlanView 覆盖本地 executing,不假装成功 (0.35571ms) +✔ 过期计划映射 expired (0.163705ms) +✔ 非计划卡不被误判 (0.135056ms) +✔ 集成验证:项目切换时交付物严格隔离,新建项目即刻包含 7 份模板副本 (5.036741ms) +✔ 集成验证:三层隐私与项目物理隔离双重约束 (3.921474ms) +✔ 用例 1: DEFAULT_ROLES 包含 5 种默认角色且具备预期权限 (1.205684ms) +✔ 用例 2: 系统管理员 (ADMIN) 与具备 perm:manage 用户的通配豁免特权 (0.195294ms) +✔ 用例 3: 常规工作流基线可见性 (workflow:view_all) 判定 (0.67402ms) +✔ 用例 4: 单文档覆盖 - designated_only (仅编制/审核/批准人可见,其他用户被精确拦截) (0.135776ms) +✔ 用例 5: 单文档覆盖 - role_whitelist (仅白名单内角色可见,其他角色被精确拦截) (1.546704ms) +✔ 用例 6: 单文档覆盖 - public (放宽可见性,无 workflow:view_all 权限的访客也能查阅) (0.147105ms) +✔ 用例 7: 私密文档隔离强红线 (category === private 无论任何管理员或单文档覆盖,非创建者绝对不可见) (0.445197ms) +✔ 用例 8: 核心业务动作权限拦截判定 (canPerformDocAction & hasPermission) (0.585722ms) +✔ 用例 9: filterVisibleDeliverablesWithRBAC 能够批处理过滤大盘交付物 (1.520515ms) +✔ 集成场景 1: 动态新增合规审计员角色,并配置其仅能查阅特定单文档覆盖 (2.72334ms) +✔ 集成场景 2: 服务端 capabilities 变更后权限即刻生效 (0.233953ms) +✔ 集成场景 3: 单文档覆盖 designated_only 严格收紧与撤回恢复全流程 (0.305671ms) +✔ renderInlineMarkdown: renders bold, italic, strikethrough (1.056228ms) +✔ renderInlineMarkdown: escapes raw HTML tags to prevent XSS (0.490515ms) +✔ renderInlineMarkdown: blocks javascript: link hrefs (0.139836ms) +✔ renderInlineMarkdown: renders inline code and preserved line breaks (0.194264ms) +✔ renderInlineMarkdown: renders headings lists and tables for chat replies (0.353519ms) +✔ renderInlineMarkdown loads katex only after a formula is seen (18.692495ms) +✔ sanitizeMermaidCode: auto wraps unquoted labels containing brackets or comparison operators (0.36064ms) +(node:1061994) ExperimentalWarning: localStorage is not available because --localstorage-file was not provided. +(Use `node --trace-warnings ...` to show where the warning was created) +✔ DOCX 渲染器行内文本与公式解析测试 (parseInlineContent) (5.019961ms) +✔ DOCX 渲染器 LaTeX 原生 OMML 转换引擎测试 (latexToOmml) (2.050139ms) +✔ DOCX 渲染器 Mermaid 语法净化与容错测试 (sanitizeMermaidCode) (0.260913ms) +✔ DOCX 渲染器 SVG 净化防 Canvas 污染测试 (cleanSvgForCanvas) (0.34272ms) +✔ DOCX 渲染器全量编译测试 (buildDocxModel & exportDocumentToDocx) (58.786185ms) +✔ XLSX 渲染器多表提取与工作簿编译测试 (buildXlsxWorkbook & exportDocumentToXlsx) (6.169477ms) +▶ Reply Document IR & Export Engine + ✔ deriveReplyTitle and sanitizeFilename derive title and safe file name (1.145146ms) + ✔ deriveReplyTitle handles text without heading (0.272912ms) + ✔ parseReplyMarkdown parses headers, lists, code, and tables (2.351771ms) + ✔ renderClipboardHtml renders self-contained styling for office tools (0.551354ms) + ✔ renderClipboardHtml converts LaTeX formulas to native MathML for Word/Office (3.253484ms) + ✔ renderPlainText strips formatting cleanly (0.33474ms) + ✔ serializeMarkdown round-trips to valid markdown (0.266123ms) + ✔ stripUnsafeHtml strips script tags and dangerous event handlers (0.535695ms) + ✔ escapeHtml escapes math error payloads used by BlockEditorModal catch path (0.552753ms) +✔ Reply Document IR & Export Engine (11.08641ms) +✔ createProjectTemplateDeliverables: 必须精确生成 7 份全生命周期受控文档副本 (4.456837ms) +✔ resolveRequirementsTaskKey prefers intake for 初始需求表 (5.872326ms) +✔ resolveRequirementsTaskKey selects user_requirements for explicit URS (0.176685ms) +✔ UI-02 first-round prompt with 首轮+用户需求+摸底 must be intake not user_requirements (0.461056ms) +✔ 首轮 / 需求摸底 / 摸底 beat bare 用户需求 (0.105796ms) +✔ bare 用户需求 without V0.1 markers stays user_requirements (0.097267ms) +✔ matchTemplateDeliverable uses intake key when pool only has URS template (0.262842ms) +✔ resolveTaskTemplateForMessage keeps intake key with URS-only pool (0.136166ms) +✔ matchTemplateDeliverable prefers intake when both templates exist (0.097677ms) +✔ read-only request does not start a document task: 总结一下用户初始需求表 (1.99431ms) +✔ read-only request does not start a document task: 查看用户初始需求表 (0.380438ms) +✔ read-only request does not start a document task: 用户初始需求表现在谁在编辑 (0.635351ms) +✔ read-only request does not start a document task: 分析一下用户需求表里的风险 (0.085017ms) +✔ read-only request does not start a document task: 用户初始需求表 (0.047269ms) +✔ explicit write action still starts intake (0.260272ms) +✔ explicit update action still starts URS (0.263282ms) +✔ UI-05 prompt without active doc still keyword-routes to feasibility_reg (0.409527ms) +✔ UI-05 prompt + registered intake pins intake and doc_proj6109_intake (0.222973ms) +✔ read-only current-doc request does not start a task (0.063558ms) +✔ summary/analysis with write verbs stays chat (read-only priority) (0.074218ms) +✔ pure write intent still routes to task (0.037249ms) +✔ template-only active slot is not pinned; keywords still apply (0.080947ms) +✔ explicit named deliverable can switch away from active intake (0.138576ms) +✔ domain 注册法规 without current-doc deixis still routes feasibility_reg (0.069488ms) +✔ mismatched title vs docId suffix prefers docId taskKey (0.072148ms) +✔ deixis 当前文档 pins registered intake (0.190704ms) +✔ deixis 本文件 pins registered intake (0.053359ms) +✔ deixis 这份文档 pins registered intake (0.035669ms) +✔ deixis 本文档 pins registered intake (0.03241ms) +✔ deixis 本受控文档 pins registered intake (0.034429ms) +✔ no active doc does not invent a pin (0.080027ms) +✔ UI-11 named 系统设计输入 beats negated 需求 background (0.064138ms) +✔ mixed generate-design + do-not-cover-requirements stays prelim_design (0.047099ms) +✔ current-doc pin still wins when no other deliverable is named (0.229593ms) +✔ v3 bd_ task key wins over unprefixed intake alias (0.131226ms) +✔ word-order variants of the intake sheet stay on intake, not the shorter URS title (0.564533ms) +✔ resolveTaskTemplateForMessage blocks cross-workflow document mentions (0.32767ms) +✔ resolveTaskTemplateForMessage keeps in-scope main docs when active is main (0.268452ms) +✔ weighted mode does not let a cross-workflow title hijack an in-scope write (0.725168ms) +▶ document revision overlay modes + ✔ pure hides all decorations (0.609571ms) + ✔ manual only marks human hunks (0.096108ms) + ✔ all marks human and agent differently (0.051108ms) + ✔ same human hunk stays amber in manual and all (no pairwise style guarantee) (0.069988ms) + ✔ exposes needs-content error code for empty orphan docs (0.047788ms) + ✔ matches overlay hunks by section or text when ids differ (0.217174ms) + ✔ aligns client block ids from head_block_map by order (0.150525ms) +✔ document revision overlay modes (2.061798ms) +▶ toolbar refresh + report entry reachability + ✔ pickLatestChangeReportId prefers highest version with report (0.266352ms) + ✔ first squad run alone still exposes a reachable report id (0.249983ms) + ✔ second squad run keeps both history report entries and latest shortcut (0.275022ms) + ✔ revisionRefreshKey is an independent refresh signal from docId (0.108117ms) +✔ toolbar refresh + report entry reachability (1.134907ms) +▶ change report view model + ✔ surfaces risk items, project impact, doc impacts with advice, and open questions (0.745428ms) + ✔ marks complete analysis as PI narrative vs factual fields (0.185874ms) + ✔ preferReportId prioritizes pending over committed latest (0.077988ms) +✔ change report view model (1.598062ms) +▶ revisionToolbarMount + ✔ exposes clear non-error template preview hint copy (3.674211ms) + ✔ template doc-p + isTemplateOnly=true does not mount (0.247763ms) + ✔ legacy doc-001 does not mount (0.214304ms) + ✔ unregistered doc-upload orphan does not mount (must register first) (0.179374ms) + ✔ server-registered upload (doc-free) and freeform mount (0.199134ms) + ✔ canonical doc_proj and generated non-template doc-p mount (0.186705ms) +✔ revisionToolbarMount (6.005461ms) +✔ login workspace sync lives in one hook (0.99735ms) +✔ block editing lives in one hook (4.254104ms) +✔ interactive card actions live in one hook (0.906433ms) +✔ useChatWindow: 所有 saveSessionWindowCache 调用必须传入 userId (1.306442ms) +✔ window fetch race: stale response ignored by generation (0.967271ms) +✔ mapRecordToMessage: 正确映射服务端消息记录为前端 ChatMessage (1.521115ms) +✔ refresh window: 空 messages 日桶不算有效窗口 (0.195345ms) +✔ mapRawBucket: 正确映射服务端按日分片桶 (0.219904ms) +✔ Category navigation: chip 选中后准确匹配目标分类最新轮次并触发归一化定位 (0.30806ms) +✔ mapRecordToMessage: restores task phase snapshot into card fields (0.229063ms) +✔ controlled document hydration lives in one hook (1.139177ms) +✔ project creation lives in one hook called before the login return (1.090157ms) +✔ document lifecycle actions live in one hook (1.864384ms) +✔ freeform document actions live in one hook (1.02049ms) +✔ in-flight states cover pending and running only (0.806586ms) +✔ hasInFlightParse detects parse polling needs (0.210924ms) +✔ hook + reparse API surface wired (0.299531ms) +✔ project member writes live in one hook before the login return (1.043249ms) +✔ sending a message lives in one hook (0.99326ms) +✔ server document list sync lives in one hook (2.879605ms) +✔ chat and task attempts live in one hook (0.816756ms) +✔ stage unresolved and not-in-active-stage degrade to chat once (0.141236ms) +✔ failed run with error_message surfaces TASK_FAILED not NETWORK_ERROR (0.599282ms) +✔ snake_case blocked_pending_governance is governance, not a network error (0.714558ms) +✔ unknown 4xx business code is not reported as a network error (0.339599ms) +✔ turn runtime: session A stream survives session B switch (1.070678ms) +✔ abortAllSessions aborts controllers across all sessions (0.279282ms) +✔ App persists workbench state through one hook and migrates legacy messages once (4.749369ms) +✔ syncAdminUserDirectories calls local reload then parent onRefreshUsers (1.394408ms) +✔ syncAdminUserDirectories fails closed when onRefreshUsers is a dead/missing prop (1.68199ms) +✔ syncAdminUserDirectories surfaces parent refresh errors (no silent swallow) (0.231463ms) +✔ afterProjectMemberPersisted syncs members then refreshes workflow docs (1.419238ms) +✔ afterProjectMemberPersisted does not refresh when member sync fails (0.557954ms) +▶ blockEditorDialogPolicy + ✔ pins an accessible dialog label and exact save name (0.65478ms) + ✔ rejects page-wide fuzzy /保存/ that would hit private-library buttons (0.286742ms) +✔ blockEditorDialogPolicy (1.956922ms) +▶ resolveSaveTargetBlock + ✔ keeps the editor and does not fake success when the block id is gone (0.640741ms) + ✔ never retargets another block that happens to share the same content (0.722498ms) +✔ resolveSaveTargetBlock (2.299672ms) +▶ editor session document binding + ✔ fail-closes when activeDocId drifts away from the opened editor doc (0.183294ms) + ✔ accepts a save only when the editor is still bound to the active doc (0.099027ms) + ✔ blocks switching documents while the editor is open (0.122607ms) +✔ editor session document binding (0.604182ms) +▶ interpretBlockSaveError + ✔ 409 keeps the draft in the editor (0.158296ms) + ✔ other PATCH failures also keep the editor (0.188235ms) +✔ interpretBlockSaveError (0.511364ms) +▶ blockedGovernanceCopy + ✔ recognizes blocked run status and fixed hint, not generation success (0.757027ms) +✔ blockedGovernanceCopy (1.573653ms) +▶ resolveChatComposerStreaming + ✔ is false when no inflight assistant bubbles (0.829505ms) + ✔ is true when inflight bubble and live turn (0.173005ms) + ✔ is true when inflight bubble and live task run (0.123306ms) + ✔ is false for orphan streaming_status after runtime cleared (0.104267ms) +✔ resolveChatComposerStreaming (8.822298ms) +▶ commentPolicy + ✔ lets author/reviewer/approver annotate and keeps their comment role (0.68002ms) + ✔ keeps viewer read-only: no add entry and no reviewer/approver cast (0.173515ms) +✔ commentPolicy (1.896274ms) +▶ controlledContentInvalidation + ✔ hydrate success then late list_sync keeps cache/ready and does not bump resume (6.829977ms) + ✔ post_task invalidation drops active cache and requires a new hydrate epoch (0.34254ms) + ✔ editor open / save epoch keeps draft and rejects a stale GET after PATCH (0.476846ms) + ✔ never drops the active doc without signaling rehydrate (0.258143ms) + ✔ candidate helper keeps template / doc-001 / freeform / upload out of wipe lists (1.838735ms) + ✔ dropRecordKeys is a no-op when ids are absent (0.162155ms) +✔ controlledContentInvalidation (13.376683ms) +▶ controlledDocHydrate + ✔ shouldLoadControlledContent when non-template workflow doc (1.037059ms) + ✔ shouldLoadControlledContent rejects local legacy/mock ids like doc-001 (0.187985ms) + ✔ shouldLoadControlledContent keeps canonical, freeform-off, and template preview rules (0.173205ms) + ✔ hydrateControlledDocumentContent never requests content/revision for doc-001 (0.286841ms) + ✔ hydrateControlledDocumentContent never requests for template preview or registered freeform (0.166965ms) + ✔ shouldLoadControlledContent stays inside toolbar server-backed eligibility (0.204394ms) + ✔ resolveCanonicalDocId maps doc-p56-intake to doc_proj56_intake (0.32674ms) + ✔ canonicalDocIdForTask maps doc-p56-research to doc_proj56_research (0.180285ms) + ✔ hydrate treats projection missing as ledger content, not 404 (1.960911ms) + ✔ attaches hydrate ETag as PATCH baseline and ignores a later GET (0.803226ms) + ✔ rejects hydrate when revision-state network or 5xx fails (0.66032ms) + ✔ aligns markdownToBlockAST random ids onto revision-state head_block_map (1.327921ms) + ✔ leaves Math.random ids when head_block_map is omitted (why gate + fail-closed remain) (0.429047ms) + ✔ rejects controlled hydrate on NOT_FOUND or NEEDS_CONTENT (0.293371ms) + ✔ fingerprint stays stable when only object identity changes (0.122616ms) + ✔ dedupes in-flight hydrate for the same doc fingerprint (0.35351ms) + ✔ aligned late hydrate still cannot overwrite a PATCH-success baseline (0.522415ms) +✔ controlledDocHydrate (11.516818ms) +✔ createClientTurnId uses randomUUID when available (0.768527ms) +✔ createClientTurnId falls back to getRandomValues UUID v4 (0.413278ms) +✔ createClientTurnId throws when no secure random API exists (0.373089ms) +✔ selectNonCreatorInitialMembers skips creator only (1.481006ms) +✔ buildManagedMemberUpsertPayload sends document_duty on add/update/restore (0.320031ms) +✔ buildInitialMemberUpsertPayload maps reviewer UI role to member API role (0.318631ms) +✔ persistInitialProjectMembers awaits each add and stops on failure (0.907233ms) +✔ ensureCreatedProjectWithMembers skips recreate on bootstrap id and retries members (0.700769ms) +✔ beginCreateProjectSubmit rejects concurrent second entry until end (30.437236ms) +✔ resolveCreateProjectSubmitPhase uses bootstrap to choose syncing label (0.607862ms) +✔ createProjectSubmitButtonLabel and close block while submitting (0.265192ms) +✔ shouldCloneMedicalTemplates skips the 7-pack for software domain (0.122746ms) +▶ resolveCurrentDocRole + ✔ resolves A as author by authoritative user id (0.724288ms) + ✔ does not promote reviewer B or stranger to author (0.146535ms) + ✔ resolves real USER_B id as reviewer and never name-promotes placeholder 2 (0.119106ms) + ✔ fail-closes unknown identity to viewer even if projectPermission says author (0.091157ms) + ✔ matches name only for legacy local docs without duty ids (0.110357ms) + ✔ does not name-promote when server controlled duties are zero ids (0.097377ms) +✔ resolveCurrentDocRole (2.488576ms) +▶ currentProjectRestore + ✔ rejects empty project names (4.796408ms) + ✔ rejects page-wide project name when banner and sidebar both match (0.383788ms) + ✔ scopes the visible entry to complementary exact title (0.845434ms) + ✔ scopes the current project assertion to banner exact text (0.222983ms) +✔ currentProjectRestore (9.978943ms) +▶ deliverableLeaseSync + ✔ returns the same array reference when leases are unchanged (1.552514ms) + ✔ returns a new array only when a lease actually changes (0.206234ms) +✔ deliverableLeaseSync (2.619103ms) +▶ docGovActionVisibility + ✔ hides all approval actions on unmanaged docs (0.705409ms) + ✔ gates separated duties by user id, not folded role label (0.178835ms) + ✔ author_only: same user holds all three duties and sees all actions (0.154316ms) + ✔ author_only: non-duty user sees no actions (0.117616ms) +✔ docGovActionVisibility (2.547564ms) +▶ documentBlockDomAttrs + ✔ marks a real DocumentBlock in pure mode without overlay kind (0.66697ms) + ✔ keeps the same stable attrs when overlay is later attached separately (0.186634ms) +✔ documentBlockDomAttrs (1.687239ms) +▶ durableBodySnippet + ✔ rejects empty persisted snippets (0.865284ms) + ✔ lets a later successful revision replace the old snippet (0.170605ms) + ✔ does not promote a conflict-failed draft to the expected body (0.208114ms) +✔ durableBodySnippet (2.291862ms) +▶ dutyCellAssertion + ✔ parses author, reviewer, and viewer from select value or badge role (1.105337ms) + ✔ must not infer author from a row whose option labels include 编制负责人 (0.553904ms) + ✔ accepts only a disabled non-assignable reviewer select (0.144256ms) + ✔ rejects an enabled reviewer select when the reviewer cannot assign leads (0.120146ms) + ✔ rejects canAssignLead=true even if the reviewer select is disabled (0.120916ms) + ✔ rejects viewer, author, approver, and unknown values for USER_B (0.140886ms) +✔ dutyCellAssertion (3.461287ms) +▶ decideHydrationApply + ✔ applies only when gen, doc, save epoch match and editor is closed (1.6714ms) + ✔ rejects a response for another document (0.148755ms) + ✔ rejects a superseded generation (0.093687ms) +✔ decideHydrationApply (2.992051ms) +▶ createEditorHydrationGate + ✔ does not start a new hydrate while the editor is open (UI-06 fill-window GET) (0.479656ms) + ✔ deferred hydrate that resolves after the editor opens does not replace the session (0.169265ms) + ✔ covers hydrate resolving between fill and save (0.154915ms) + ✔ asks for a hydrate resume after editor_open blocked the first apply (0.381478ms) + ✔ asks for a hydrate resume when beginHydration is skipped while editing (0.31428ms) + ✔ requestHydrationResume is consumed once after a protected edit session (0.227353ms) + ✔ late hydrate after a successful PATCH does not roll back the new baseline (0.453486ms) +✔ createEditorHydrationGate (2.793117ms) +✔ redactResourceUrl drops query and origin (0.928642ms) +✔ summarizeResources flags deferred heavy chunks (1.136976ms) +✔ firstPaintHeavyHits lists only deferred module paths (0.215464ms) +✔ countInitRequests separates member fanout from session lists (0.296801ms) +✔ percentile uses nearest-rank and stays null on empty input (0.173175ms) +✔ summarizeLatencies reports p50/p75/p95 (0.226973ms) +✔ mergeSessionUser prefers session identity over stale catalog entry (2.618923ms) +▶ playwrightPhaseArtifacts + ✔ defaults unknown or empty UI_PHASE to main (0.852684ms) + ✔ keeps post-restart distinct from main so the second run cannot overwrite traces (0.195724ms) + ✔ keeps main results at the historical filename and isolates post-restart recordPass (0.192644ms) + ✔ shares phase-state and secrets across phases (0.085337ms) + ✔ defaults assets to the 2026-09-22 rerun tree, not project-143 history (0.246022ms) + ✔ refuses historical controlled-content and Round20 evidence dirs (0.521204ms) + ✔ lists closeout groups covering UI-03/05/06/07-08-09/11/13/post-restart (0.729798ms) +✔ playwrightPhaseArtifacts (4.123078ms) +✔ resolvePostTaskActiveDocId prefers server doc_proj for taskKey (0.917523ms) +✔ resolvePostTaskActiveDocId honors preferred server doc id (0.188924ms) +✔ shouldSwitchTemplateSlotToServer when active is local template slot (0.160895ms) +✔ pollUntilPostTaskServerDoc retries until same taskKey server doc appears (0.432127ms) +✔ pollUntilPostTaskServerDoc returns null after maxAttempts without relying on setState (0.238963ms) +✔ mapServerProjectToProjectInfo maps creator and preserves local members (0.962852ms) +✔ mergeProjectLists drops local-only demo seed projects by default (0.3448ms) +✔ mergeProjectLists can retain local-only demo when explicitly opted in (0.146285ms) +✔ documentDutyFromMemberRole maps UI reviewer and creator (0.765327ms) +✔ exclusiveMemberRoleChange keeps a single reviewer (0.179905ms) +✔ memberRoleFromDocumentDuty does not invent reviewer from access role (0.085687ms) +✔ toApiProjectRole maps doc roles to member and creator to owner (1.03036ms) +✔ fromApiProjectRole maps owner to creator for project creator (0.164725ms) +✔ mapApiMemberToProjectMember builds UI record (0.206844ms) +▶ projectSettingsDuties + ✔ toggles full to none by atomically clearing duties (1.437948ms) + ✔ blocks partial saves and locates required/governance issue codes (0.457076ms) + ✔ allows an all-none configurable draft without three members (0.192334ms) + ✔ requires three members once any document is managed (0.090798ms) + ✔ resolves author_only to A/A/A without three-member requirement (0.210734ms) + ✔ rejects author_only without author or with conflicting reviewers (0.150416ms) + ✔ mixed full + author_only still requires three members for the full doc (0.104557ms) + ✔ toggleAuthorOnly clears review/approve slots and restores on disable (0.171885ms) + ✔ folds later rdev stages and batches human approval keys (0.654591ms) +✔ projectSettingsDuties (4.920804ms) +▶ projectSettingsMode + ✔ enters frozen when can_edit_plan is false or the project is active (0.706269ms) + ✔ keeps an active workflow editable except the definition switch (0.180045ms) + ✔ stays planning only for an editable draft (0.105596ms) + ✔ lists enabled duties for the frozen snapshot and skips disabled tasks (0.730448ms) + ✔ keeps the local draft after PLAN_FROZEN refresh and switches to frozen (0.139405ms) +✔ projectSettingsMode (2.946023ms) +▶ recheckAck + ✔ requires an explicit acknowledgement before advance (0.657091ms) +✔ recheckAck (1.546974ms) +▶ revisionEtag + ✔ uses stale hydrate ETag for PATCH and never the latest GET (2.492326ms) + ✔ does not invent 0:0 when controlled hydrate misses etag or errors (0.163465ms) + ✔ refuses controlled save without a hydrate ETag (0.499515ms) + ✔ allows freeform bootstrap 0:0 only (0.121266ms) +✔ revisionEtag (4.398049ms) +▶ saveControlledBlockEdit + ✔ successful save calls PATCH once with bound docId, hydrate ETag, body and client_block_map (2.166035ms) + ✔ does not PATCH when editorDocId and activeDocId diverge (0.222743ms) + ✔ does not PATCH on stale block id and keeps the draft (0.188285ms) + ✔ 409 does not close the editor or drop the draft (0.660871ms) + ✔ network errors do not close the editor or drop the draft (0.213814ms) +✔ saveControlledBlockEdit (4.548415ms) +✔ parseProjectIdFromSessionId decodes sess-p{id}-u{user} (0.932092ms) +✔ resolveSessionProjectId prefers explicit id then session id encoding (0.210904ms) +✔ mapServerSessionToProjectSession fills project metadata (0.602772ms) +✔ mergeSessionLists keeps local stage while applying server counts (0.146476ms) +▶ squadCompletionObservation + ✔ accepts a directly completed adjacent assistant without requiring inflight (0.733869ms) + ✔ accepts a turn that passed through inflight then completed (0.144116ms) + ✔ rejects error terminals, missing correspondence, and visible errors (0.131116ms) + ✔ keeps waiting while still inflight and does not treat inflight as success (0.126096ms) + ✔ cancelInflightAssistantMessages settles only this-session assistant inflight (0.185724ms) +✔ squadCompletionObservation (2.512285ms) +✔ running bubble without phases needs replay (0.793236ms) +✔ interrupted bubble without phases needs replay (0.169875ms) +✔ bubble that already has phases is not replayed (0.114247ms) +✔ completed bubble without snapshot needs replay for legacy rows (0.074838ms) +✔ completed bubble with snapshot is not replayed (0.084718ms) +✔ phase replay key ignores completed chatter (0.110227ms) +✔ resolveTaskRunCardTitle prefers artifact title (1.252292ms) +✔ resolveTaskRunCardTitle falls back to user message then taskKey (0.211294ms) +✔ truncateTitle ellipsizes long text (0.135145ms) +✔ formatTaskDuration covers seconds minutes hours (0.157296ms) +✔ resolveTaskRunCardBadge maps terminal and live states (0.763898ms) +✔ shouldRenderTaskRunCard keeps card shape when run id exists (0.161665ms) +✔ runningPhaseDetail prefers live label when it differs from step (0.164465ms) +✔ 403 revision denial is not reported as a network error (0.68865ms) +✔ 403 author-duty denial surfaces draft-vs-submit guidance (0.143515ms) +✔ DOC_DUTY_FORBIDDEN keeps draft-vs-submit guidance (0.074598ms) +✔ TASK_SCOPE_UNRESOLVED names the missing workflow stage (1.512816ms) +✔ resolveReconnectRunId prefers explicit opts and ignores attempt without opts (2.657971ms) +✔ shouldSubscribeExistingRun only for in-flight statuses (0.160685ms) +✔ isRemoteTaskTerminal covers confirmation and quality_failed (0.105817ms) +✔ nextAttemptOpts carries retained runId for reconnect without new POST (0.076368ms) +✔ template documents are labeled as preview, not 编制中 or 已生效受控 (0.884124ms) +▶ uploadFreeformRegister + ✔ buildUploadClientKey prefers explicit hint then doc-upload stamp (0.715649ms) + ✔ registerUploadAttachments hard-fails without creating orphan on API error (14.050122ms) + ✔ registerUploadAttachments rejects local doc-upload id from server (0.32681ms) + ✔ registerUploadAttachments returns server doc-free ids and freeform facts (0.529584ms) + ✔ deliverableFromFreeformUpload maps server id and upload facts (0.201974ms) +✔ uploadFreeformRegister (17.008845ms) +▶ workflowCategoryNavigation + ✔ private menu cannot see doc_proj* so it must switch to workflow before exact select (1.335081ms) + ✔ fail-closes when the workflow menu is showing but the exact doc is missing (0.932512ms) + ✔ label and taskKey opens always require the workflow category (0.157376ms) +✔ workflowCategoryNavigation (3.401259ms) +✔ rdev selection explains the CDO prerequisite (0.708309ms) +✔ login shell does not statically import export, preview, admin, or chart engines (18.947867ms) +▶ no external Google Fonts on login shell + ✔ index.html has no fonts.googleapis / fonts.gstatic (0.66708ms) + ✔ styles reference self-hosted fonts.css (0.225123ms) +✔ no external Google Fonts on login shell (1.575233ms) +▶ 用户上传文档多格式在线预览体系与渲染分流测试 + ✔ 1. 上传附件时正确注入 sourceType: "uploaded_file" 与完整 fileMeta 元数据 (1.236594ms) + ✔ 2. 扩展名分类规则准确分发至对应的高保真渲染器类型 (0.295631ms) + ✔ 3. 受控工作流交付物严格隔离:绝不命中 FilePreviewPanel,保持 BlockRenderer 纯净 (0.181624ms) + ✔ 4. 上传文档支持受控流转:从个人私密一键共享至项目参考库后,在线预览依然可用且权限标态正确 (0.182204ms) +✔ 用户上传文档多格式在线预览体系与渲染分流测试 (3.300122ms) +▶ 项目立项、成员职责分配与退出留痕治理测试套件 + ✔ 1. 默认项目库包含完整元数据与法定三权成员 (active 状态) (0.65831ms) + ✔ 2. 跨用户会话可见性严格隔离:未加入成员完全不可见 (0.326861ms) + ✔ 3. 创建者添加新成员并分配职责后,新成员即刻可见该项目会话 (0.150476ms) + ✔ 4. 中途加入后期退出 (exited):保留项目会话但标记已退出只读留痕 (0.145286ms) + ✔ 5. 超级管理员 (ADMIN) 享有全量通配可见与管理兜底特权 (0.113227ms) +✔ 项目立项、成员职责分配与退出留痕治理测试套件 (2.604362ms) +▶ 新建项目工程文档模板质量与纯净性保障套件(对标官方参考系统) + ✔ 1. 必须精确生成 7 份官方全流程受控工作流模板且标记纯净 (0.585282ms) + ✔ 2. 杜绝旧项目 CUSA-NeuroPulse 串号泄露,动态注入新项目信息 (0.614482ms) + ✔ 3. 严格对标参考系统模板规范要素,绝非 3 行残缺摘要 (0.32582ms) + ✔ 4. 缓存丢失场景下即时自愈重建 AST 能力验证 (0.242013ms) +✔ 新建项目工程文档模板质量与纯净性保障套件(对标官方参考系统) (5.585084ms) +▶ 用户上传文档私密归档与共享流转测试 + ✔ 10 个评审项目均包含已共享的 URS 交付物与 AST,支持跨角色合规查阅且会话均以 assistant 闭环 (1.251983ms) + ✔ 用户上传附件自动生成私密交付物并在 AST 中建立隔离,支持流转至项目参考库 (1.286641ms) + ✔ 单轮对话支持一次上传多个文档(上限5个),批量生成私密交付物并遵循数量约束 (0.415868ms) +✔ 用户上传文档私密归档与共享流转测试 (3.637732ms) +▶ 工作流切换与消息展示时序测试套件 + ✔ 1. 当存在历史 seed 消息且追加新实时消息时,新消息必须严格沉淀在末尾 (0.696069ms) + ✔ 2. 切回项目时相同正文不应因 temp/server id 差异重复展示 (0.110857ms) +✔ 工作流切换与消息展示时序测试套件 (1.439708ms) +✔ DeliverableItem 必须包含 projectId 与 isTemplateOnly 属性 (1.275872ms) +ℹ tests 502 +ℹ suites 39 +ℹ pass 502 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 1411.816679 + + RUN  v5.0.0 /home/weichen/projects/Agent-System/.worktrees/non-author-member-access-2026-09-24/web + + ✓ src/components/chat/deliverableSync.test.ts (7 tests) 4ms + ✓ src/components/chat/chatWindowArtifact.test.ts (7 tests) 4ms + ✓ src/components/chat/InteractiveCard.test.ts (20 tests) 17ms + + Test Files  3 passed (3) + Tests  34 passed (34) + Start at  11:48:55 + Duration  315ms (transform 63%, import 28%, tests 7%, worker 2%) +