
> 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.36032ms)
✔ AuthClient: 自主注册受控流程（仅填用户名密码姓名，职位强制绑定访客待指派） (0.506655ms)
✔ AuthClient: 开启注册需审批时，注册账号处于待审状态并禁止登录 (0.586823ms)
✔ AuthClient: 管理员创建账号必须在首次登录修改密码 (0.308111ms)
✔ mapUserAccount: snake_case Go contract → camelCase (1.500635ms)
✔ mapUserAccount: prefers snake_case when both present (0.292481ms)
✔ mapLoginResult + mapMeResult map nested user and top-level must_change_password (0.980681ms)
✔ mapUserAccountList maps admin users list (0.205094ms)
✔ AuthClient.login + fetchMe map real snake_case wire payloads (31.29732ms)
✔ shouldAutoRetryChat: disabled until idempotency (0.871114ms)
✔ shouldAutoRetryTask: transient only, max 2 (0.218044ms)
✔ shouldAutoRetryTask: document busy never retries (0.290802ms)
✔ shouldAutoRetry alias delegates to task path (0.214073ms)
✔ autoRetryDelayMs: 1s then 2s (0.168625ms)
✔ fallbackErrorClass: network → transient, workspace → resumable (0.126596ms)
✔ upsertChatSession surfaces safe INTERNAL envelope instead of raw JSON text (30.437616ms)
[sse] 忽略无法解析的帧: {not valid json SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)
    at JSON.parse (<anonymous>)
    at parseFrame (/home/weichen/projects/Agent-System/web/src/api/chatStream.ts:123:26)
    at parseSSEChunk (/home/weichen/projects/Agent-System/web/src/api/chatStream.ts:147:20)
    at TestContext.<anonymous> (/home/weichen/projects/Agent-System/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.014139ms)
✔ parseSSEChunk: keeps incomplete frame in rest (0.246162ms)
✔ parseSSEChunk: flush parses final frame without trailing delimiter (0.308091ms)
✔ parseSSEChunk: ignores heartbeat comments and keeps last id (0.165105ms)
✔ parseSSEChunk: skips a single malformed frame and keeps parsing the next valid frame (2.574834ms)
▶ docgov lifecycle API client
  ✔ claimDocument posts to /api/v1/docgov/claim with author role (31.264031ms)
  ✔ submitForReview posts to /api/v1/docgov/submit-review (7.375151ms)
  ✔ reviewDecision posts action and optional reason (0.895863ms)
  ✔ approverDecision posts action and rollback_to (0.745978ms)
  ✔ proposeModification posts to /api/v1/docgov/proposal (0.755858ms)
  ✔ decideModificationProposal posts to /api/v1/docgov/proposal/decide (0.65576ms)
✔ docgov lifecycle API client (46.846989ms)
✔ updateFreeformDoc exposes CONCURRENCY_CONFLICT on 409 (41.44241ms)
✔ addProjectMember exposes structured ProjectSettingsApiError on 403 (25.500913ms)
✔ updateProjectMember surfaces safe INTERNAL message on 500 duty-sync failure (0.733898ms)
▶ projectSettingsError
  ✔ keeps status, code, message and issues on PLAN_FROZEN (1.809536ms)
  ✔ maps revision and concurrent conflicts to distinct recovery (0.198244ms)
  ✔ joins validation issues but still keeps typed codes (0.186784ms)
  ✔ prefers envelope code over legacy error field (0.160185ms)
  ✔ unwraps nested business JSON inside VERSION_CONFLICT envelope (0.180435ms)
  ✔ maps bare VERSION_CONFLICT envelope to retry_after_switch (0.122906ms)
  ✔ retains the local draft when a late tab hits PLAN_FROZEN (0.107517ms)
  ✔ prefers error_code over legacy bare error string (DOC_BUSY) (0.253902ms)
✔ projectSettingsError (4.914584ms)
✔ Project workflow types validation (1.167705ms)
✔ createTaskRun exposes DOC_BUSY detail without a retryable run (19.844201ms)
✔ parseSSEChunk tracks id seq for after_seq reconnect (0.378759ms)
✔ subscribeTaskRunEvents reconnects on EOF with advancing after_seq (1.803177ms)
✔ readTaskRunSSEOnce marks non-terminal EOF for reconnect (0.461516ms)
✔ subscribeTaskRunEvents fails fast on 401 without retrying (0.366009ms)
✔ subscribeTaskRunEvents fails fast on 404 without retrying (0.31701ms)
✔ buildTaskRequest: maps five project fields + task_key + user identity (1.154226ms)
✔ buildTaskRequest: omits optional fields when absent (0.176735ms)
✔ buildTaskRequest: includes materials when provided and non-empty (0.747018ms)
✔ buildResumeRequest: adds work_dir on top of task request (0.156125ms)
✔ buildTaskRequest: canonicalizes legacy doc-p doc_id (0.250932ms)
✔ buildTaskRequest: UI-05 pinned intake keeps task_key + doc_proj6109_intake (0.165745ms)
✔ buildResumeRequest: forwards add_steps when provided (0.121796ms)
✔ CategoryDock: 渲染顶部 🔔 未读提醒项及角标数字 (18.299496ms)
✔ CategoryDock: isAllReadCompleted 为 true 时渲染完成态提示 (3.04884ms)
✔ CategoryDock: 0 未读时不渲染红色未读角标 (2.771678ms)
✔ CategoryDock: 分类项包含依次跳转与遍历提示信息 (3.096658ms)
✔ InputArea keeps draft when send preflight fails (3.293343ms)
✔ InputArea clears draft only after accepted send (0.65808ms)
✔ InputArea shows thinking block message (0.181135ms)
✔ InputArea keeps draft when attachment registration fails (0.277352ms)
✔ isTemplateOnly 交付物应正确识别为初始模板展示态 (0.722139ms)
✔ 左侧栏鼠标严密绝对跟随与夹紧测试 (Left Rail Exact Pointer Following & Clamping) (0.799306ms)
✔ 右侧栏鼠标严密绝对跟随与反向位移测试 (Right Rail Exact Pointer Following & Inverted Delta) (3.654992ms)
✔ detects legacy mock and neuropulse/ten-projects ids (1.01765ms)
✔ detects colliding demo project ids (0.183125ms)
✔ applyRestoredFileRaw: 以 prev 为权威，只补丁缺失 fileRaw，不丢新增条目 (1.089738ms)
✔ applyRestoredFileRaw: 无可用 fileRaw 时返回同一引用 (0.158255ms)
✔ 每人独立私聊：同一项目不同用户拥有不同 sessionId (0.765487ms)
✔ 左侧会话列表按当前用户过滤，不可见他人私聊 (0.241232ms)
✔ 消息严格归属各自私聊 session，无跨用户混聊 (0.863025ms)
✔ 切换用户时 resolve 到该用户同项目私聊会话 (0.246963ms)
✔ resolve 优先有消息的私聊，跳过空壳 sess-p{N}-u{id} (0.3339ms)
✔ ensurePrivateSessionsForUser 为缺失用户补齐空私聊 (0.442747ms)
✔ 多项目会话消息隔离测试仍成立（endo vs ultrasound） (0.280472ms)
✔ window cache LRU: 驱逐带 userId 前缀的完整 cache key，不留孤儿条目 (1.133546ms)
✔ window cache: 读写同一 userId 前缀，跨用户不串读 (0.259122ms)
✔ parseAnchorHash: 正确解析标准深链 hash (1.784847ms)
✔ formatAnchorHash: 正确构造深链格式 (0.202834ms)
✔ navigateToAnchor: 快路径直接命中 DOM 节点 (0.499195ms)
✔ navigateToAnchor: 慢路径拉取分片后命中 (81.15696ms)
✔ resolveTurnAnchorId: 方案 A 轮次归一化测试 (0.867534ms)
✔ 全链路场景 1: 用户自主受控注册（仅填用户名/密码/姓名，职位严格绑定访客待指派） (1.631291ms)
✔ 全链路场景 2: 系统准入策略（关闭自主注册与开启强制审批流转） (0.68869ms)
✔ 全链路场景 3: 管理员开通账号首次强制改密闭环 (0.254653ms)
✔ 全链路场景 4: 环境标识随登录会话返回（dev/test/main） (1.144106ms)
✔ cleanHeadingContent: 手工多级序号前缀清洗与专业词汇保护 (1.220074ms)
✔ 标题多层级自动编号：单 H1 文档总标题自适应模式 (1 -> 1.1 -> 1.1.1) (0.459877ms)
✔ 标题多层级自动编号：多 H1 标准大章模式 (0.222793ms)
✔ 跨章节图、表、公式多级按章重编号测试 (表 1-1, 表 2-1, 图 3-1, 式 (4-1)) (0.225843ms)
✔ 有序列表与无序列表编号与渲染功能测试 (2.181595ms)
✔ 动态块操作闭环重编号验证 (Insert, Move, Delete) (0.284481ms)
✔ findMatchingBlockForReview: 能够精准按审查关键词（电气安全/EMC/竞品）定位段落块 (2.512585ms)
✔ findMatchingBlockForReview: 能够按外部指定 hint 线索精确命中目标块 (0.243222ms)
✔ createRejectConfirmationCard: 生成合规危险级驳回门禁卡片 (0.637661ms)
✔ isAffirmativeResponse: 准确识别双轨交互中的肯定意图输入 (0.243303ms)
✔ findLastActiveCard: 正确在会话历史中提取最新的待决策卡片 (0.258322ms)
✔ decrementActiveCardsTtl: 多轮对话超时递减与自动失效归档 (0.205684ms)
✔ applyConfirmRejectToDoc & applyUndoRejectToDoc: 驳回挂载批注与60s窗口期撤销完整闭环 (0.35438ms)
✔ resolveCardInMessages & cancelCardInMessages: 消息流中卡片终态沉淀 (0.194655ms)
✔ classifyRejectUtterance: 询问原因 → QUERY_REJECT_REASON (1.236494ms)
✔ classifyRejectUtterance: 明确执行 → EXECUTE_REJECT (0.206654ms)
✔ classifyRejectUtterance: 模糊 → OTHER (0.222504ms)
✔ resolveDocGovCard: 编制人查询 → 信息卡且无 confirm_reject (0.864404ms)
✔ resolveDocGovCard: 审核人执行 + reviewing → 确认卡 (0.386939ms)
✔ resolveDocGovCard: 编制人误说执行驳回 → 无权纯文本 (1.904913ms)
✔ resolveDocGovCard: 批准人 + approving → 终审确认卡 (0.242293ms)
✔ resolveDocGovCard: 编制人 OTHER → 引导查询无危险按钮 (0.139546ms)
✔ canConfirmReject: 仅审核/批准 (0.166155ms)
✔ deriveFallbackCategory identifies categories correctly (1.057539ms)
✔ enrichMessagesWithCategories backfills categories without overwriting existing ones (0.33838ms)
✔ Markdown ➔ Block AST 解析测试 (标题自适应编号与图表公式全链路) (7.07526ms)
✔ 动态重编号引擎测试 (多 H1 规范章节重排验证) (0.489675ms)
✔ Block AST ➔ Markdown 双向无损往返还原测试 (0.521475ms)
✔ 三层交付物多用户隐私绝对隔离测试 (Multi-user Strict Privacy Isolation) (1.873875ms)
✔ 一键共享至项目参考库流转测试 (Promote to Shared Reference Test) (0.283601ms)
✔ 撤回共享恢复私有草稿测试 (Revoke Shared Reference Test) (0.524474ms)
✔ 受控工作流纯净性红线检验 (Workflow Purity Security Red Line) (0.515395ms)
✔ isSameMessage: clientTurnId match (5.167817ms)
✔ isSameMessage: serverId match without turn (0.255322ms)
✔ filterPendingLiveMessages: real temp vs server id (0.244913ms)
✔ mergeLiveOverHistory preserves server id from live (0.236403ms)
✔ applyPhaseEvent: appends first phase as running node (2.731859ms)
✔ applyPhaseEvent: completes predecessors when a new phase arrives (0.212283ms)
✔ applyPhaseEvent: same phase refreshes label in place (no duplicate node) (0.223033ms)
✔ applyPhaseEvent: unknown phase falls back to hourglass meta (0.104037ms)
✔ applyPhaseEvent: prefers backend message over short label (0.084508ms)
✔ applyPhaseEvent: step_completed closes running entry without appending (0.111846ms)
✔ applyPhaseEvent: stage_completed closes entries (0.084058ms)
✔ applyPhaseEvent: task_failed appends warning node (0.095717ms)
✔ applyPhaseEvent: decorates label with step index / total steps (0.118007ms)
✔ applyPhaseEvent: repeated step_executing with step_index gets separate nodes (0.217453ms)
✔ applyPhaseEvent: ignores event without phase payload (0.106837ms)
✔ applyPhaseEvent: step_failed marks running entry as failed (keeps step label) (0.120837ms)
✔ applyPhaseEvent: step_failed appends failed node when no running entry exists (0.100117ms)
✔ applyPhaseEvent: retry of a failed step resets it to running (0.085328ms)
✔ PLAN_CONFIRM 卡片来自 PlanView 且不触达 AST (0.759087ms)
✔ 409 冲突把卡片标为 outdated 并换上最新 revision (0.180015ms)
✔ GET reconcile 用权威 PlanView 覆盖本地 executing，不假装成功 (0.127966ms)
✔ 过期计划映射 expired (0.107397ms)
✔ 非计划卡不被误判 (0.078247ms)
✔ 集成验证：项目切换时交付物严格隔离，新建项目即刻包含 7 份模板副本 (4.826057ms)
✔ 集成验证：三层隐私与项目物理隔离双重约束 (1.486596ms)
✔ 用例 1: DEFAULT_ROLES 包含 5 种默认角色且具备预期权限 (1.00728ms)
✔ 用例 2: 系统管理员 (ADMIN) 与具备 perm:manage 用户的通配豁免特权 (0.234323ms)
✔ 用例 3: 常规工作流基线可见性 (workflow:view_all) 判定 (0.245353ms)
✔ 用例 4: 单文档覆盖 - designated_only (仅编制/审核/批准人可见，其他用户被精确拦截) (0.235103ms)
✔ 用例 5: 单文档覆盖 - role_whitelist (仅白名单内角色可见，其他角色被精确拦截) (2.558334ms)
✔ 用例 6: 单文档覆盖 - public (放宽可见性，无 workflow:view_all 权限的访客也能查阅) (0.164935ms)
✔ 用例 7: 私密文档隔离强红线 (category === private 无论任何管理员或单文档覆盖，非创建者绝对不可见) (0.272462ms)
✔ 用例 8: 核心业务动作权限拦截判定 (canPerformDocAction & hasPermission) (0.182035ms)
✔ 用例 9: filterVisibleDeliverablesWithRBAC 能够批处理过滤大盘交付物 (3.571864ms)
✔ 集成场景 1: 动态新增合规审计员角色，并配置其仅能查阅特定单文档覆盖 (1.071709ms)
✔ 集成场景 2: 服务端 capabilities 变更后权限即刻生效 (0.241582ms)
✔ 集成场景 3: 单文档覆盖 designated_only 严格收紧与撤回恢复全流程 (0.232353ms)
✔ renderInlineMarkdown: renders bold, italic, strikethrough (1.370409ms)
✔ renderInlineMarkdown: escapes raw HTML tags to prevent XSS (0.517285ms)
✔ renderInlineMarkdown: blocks javascript: link hrefs (0.155095ms)
✔ renderInlineMarkdown: renders inline code and preserved line breaks (0.221124ms)
✔ renderInlineMarkdown: renders headings lists and tables for chat replies (0.380619ms)
✔ sanitizeMermaidCode: auto wraps unquoted labels containing brackets or comparison operators (0.33966ms)
(node:367351) 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.175546ms)
✔ DOCX 渲染器 LaTeX 原生 OMML 转换引擎测试 (latexToOmml) (2.148146ms)
✔ DOCX 渲染器 Mermaid 语法净化与容错测试 (sanitizeMermaidCode) (0.282702ms)
✔ DOCX 渲染器 SVG 净化防 Canvas 污染测试 (cleanSvgForCanvas) (0.380619ms)
✔ DOCX 渲染器全量编译测试 (buildDocxModel & exportDocumentToDocx) (53.321226ms)
✔ XLSX 渲染器多表提取与工作簿编译测试 (buildXlsxWorkbook & exportDocumentToXlsx) (6.375551ms)
▶ Reply Document IR & Export Engine
  ✔ deriveReplyTitle and sanitizeFilename derive title and safe file name (1.434858ms)
  ✔ deriveReplyTitle handles text without heading (0.302901ms)
  ✔ parseReplyMarkdown parses headers, lists, code, and tables (2.02298ms)
  ✔ renderClipboardHtml renders self-contained styling for office tools (0.579783ms)
  ✔ renderClipboardHtml converts LaTeX formulas to native MathML for Word/Office (4.175486ms)
  ✔ renderPlainText strips formatting cleanly (0.517545ms)
  ✔ serializeMarkdown round-trips to valid markdown (0.387529ms)
  ✔ stripUnsafeHtml strips script tags and dangerous event handlers (0.642771ms)
✔ Reply Document IR & Export Engine (11.944965ms)
✔ createProjectTemplateDeliverables: 必须精确生成 7 份全生命周期受控文档副本 (4.38929ms)
✔ resolveRequirementsTaskKey prefers intake for 初始需求表 (1.392979ms)
✔ resolveRequirementsTaskKey selects user_requirements for explicit URS (0.190325ms)
✔ UI-02 first-round prompt with 首轮+用户需求+摸底 must be intake not user_requirements (2.768718ms)
✔ 首轮 / 需求摸底 / 摸底 beat bare 用户需求 (0.185615ms)
✔ bare 用户需求 without V0.1 markers stays user_requirements (0.138556ms)
✔ matchTemplateDeliverable uses intake key when pool only has URS template (0.530825ms)
✔ resolveTaskTemplateForMessage keeps intake key with URS-only pool (0.229823ms)
✔ matchTemplateDeliverable prefers intake when both templates exist (0.859164ms)
✔ read-only request does not start a document task: 总结一下用户初始需求表 (0.235643ms)
✔ read-only request does not start a document task: 查看用户初始需求表 (0.159335ms)
✔ read-only request does not start a document task: 用户初始需求表现在谁在编辑 (1.497015ms)
✔ read-only request does not start a document task: 分析一下用户需求表里的风险 (0.090067ms)
✔ read-only request does not start a document task: 用户初始需求表 (0.608802ms)
✔ explicit write action still starts intake (0.129526ms)
✔ explicit update action still starts URS (0.092547ms)
✔ UI-05 prompt without active doc still keyword-routes to feasibility_reg (2.181215ms)
✔ UI-05 prompt + registered intake pins intake and doc_proj6109_intake (0.32544ms)
✔ read-only current-doc request does not start a task (0.121597ms)
✔ template-only active slot is not pinned; keywords still apply (0.101057ms)
✔ explicit named deliverable can switch away from active intake (0.168065ms)
✔ domain 注册法规 without current-doc deixis still routes feasibility_reg (0.073708ms)
✔ mismatched title vs docId suffix prefers docId taskKey (0.081858ms)
✔ deixis 当前文档 pins registered intake (0.086398ms)
✔ deixis 本文件 pins registered intake (0.049318ms)
✔ deixis 这份文档 pins registered intake (0.043139ms)
✔ deixis 本文档 pins registered intake (0.040189ms)
✔ deixis 本受控文档 pins registered intake (0.042068ms)
✔ no active doc does not invent a pin (0.081707ms)
✔ UI-11 named 系统设计输入 beats negated 需求 background (0.070618ms)
✔ mixed generate-design + do-not-cover-requirements stays prelim_design (0.055039ms)
✔ current-doc pin still wins when no other deliverable is named (0.065488ms)
▶ document revision overlay modes
  ✔ pure hides all decorations (0.844865ms)
  ✔ manual only marks human hunks (0.249672ms)
  ✔ all marks human and agent differently (0.155085ms)
  ✔ same human hunk stays amber in manual and all (no pairwise style guarantee) (2.599062ms)
  ✔ exposes needs-content error code for empty orphan docs (0.164005ms)
  ✔ matches overlay hunks by section or text when ids differ (0.297302ms)
  ✔ aligns client block ids from head_block_map by order (0.232113ms)
✔ document revision overlay modes (10.336083ms)
▶ toolbar refresh + report entry reachability
  ✔ pickLatestChangeReportId prefers highest version with report (0.318001ms)
  ✔ first squad run alone still exposes a reachable report id (0.185435ms)
  ✔ second squad run keeps both history report entries and latest shortcut (4.05202ms)
  ✔ revisionRefreshKey is an independent refresh signal from docId (0.214494ms)
✔ toolbar refresh + report entry reachability (5.153077ms)
▶ change report view model
  ✔ surfaces risk items, project impact, doc impacts with advice, and open questions (2.721909ms)
  ✔ marks complete analysis as PI narrative vs factual fields (0.768257ms)
  ✔ preferReportId prioritizes pending over committed latest (0.119146ms)
✔ change report view model (3.838086ms)
▶ revisionToolbarMount
  ✔ exposes clear non-error template preview hint copy (0.860824ms)
  ✔ template doc-p + isTemplateOnly=true does not mount (0.230023ms)
  ✔ legacy doc-001 does not mount (0.235583ms)
  ✔ unregistered doc-upload orphan does not mount (must register first) (0.270042ms)
  ✔ server-registered upload (doc-free) and freeform mount (0.33066ms)
  ✔ canonical doc_proj and generated non-template doc-p mount (0.199074ms)
✔ revisionToolbarMount (4.420588ms)
✔ useChatWindow: 所有 saveSessionWindowCache 调用必须传入 userId (1.060028ms)
✔ window fetch race: stale response ignored by generation (1.059468ms)
✔ mapRecordToMessage: 正确映射服务端消息记录为前端 ChatMessage (1.560494ms)
✔ refresh window: 空 messages 日桶不算有效窗口 (0.263342ms)
✔ mapRawBucket: 正确映射服务端按日分片桶 (0.288572ms)
✔ Category navigation: chip 选中后准确匹配目标分类最新轮次并触发归一化定位 (0.257992ms)
✔ turn runtime: session A stream survives session B switch (1.183235ms)
✔ abortAllSessions aborts controllers across all sessions (0.33573ms)
✔ syncAdminUserDirectories calls local reload then parent onRefreshUsers (1.384819ms)
✔ syncAdminUserDirectories fails closed when onRefreshUsers is a dead/missing prop (0.601742ms)
✔ syncAdminUserDirectories surfaces parent refresh errors (no silent swallow) (0.259902ms)
✔ afterProjectMemberPersisted syncs members then refreshes workflow docs (1.498676ms)
✔ afterProjectMemberPersisted does not refresh when member sync fails (0.549044ms)
▶ blockEditorDialogPolicy
  ✔ pins an accessible dialog label and exact save name (0.949511ms)
  ✔ rejects page-wide fuzzy /保存/ that would hit private-library buttons (0.383579ms)
✔ blockEditorDialogPolicy (2.562113ms)
▶ resolveSaveTargetBlock
  ✔ keeps the editor and does not fake success when the block id is gone (0.640411ms)
  ✔ never retargets another block that happens to share the same content (0.752827ms)
✔ resolveSaveTargetBlock (2.325531ms)
▶ editor session document binding
  ✔ fail-closes when activeDocId drifts away from the opened editor doc (0.229053ms)
  ✔ accepts a save only when the editor is still bound to the active doc (0.151646ms)
  ✔ blocks switching documents while the editor is open (0.164595ms)
✔ editor session document binding (0.895543ms)
▶ interpretBlockSaveError
  ✔ 409 keeps the draft in the editor (0.563334ms)
  ✔ other PATCH failures also keep the editor (2.113537ms)
✔ interpretBlockSaveError (3.085348ms)
▶ blockedGovernanceCopy
  ✔ recognizes blocked run status and fixed hint, not generation success (0.807416ms)
✔ blockedGovernanceCopy (1.814866ms)
▶ commentPolicy
  ✔ lets author/reviewer/approver annotate and keeps their comment role (0.833775ms)
  ✔ keeps viewer read-only: no add entry and no reviewer/approver cast (0.152925ms)
✔ commentPolicy (2.108627ms)
▶ controlledContentInvalidation
  ✔ hydrate success then late list_sync keeps cache/ready and does not bump resume (1.875694ms)
  ✔ post_task invalidation drops active cache and requires a new hydrate epoch (0.317201ms)
  ✔ editor open / save epoch keeps draft and rejects a stale GET after PATCH (0.552254ms)
  ✔ never drops the active doc without signaling rehydrate (0.468966ms)
  ✔ candidate helper keeps template / doc-001 / freeform / upload out of wipe lists (0.505365ms)
  ✔ dropRecordKeys is a no-op when ids are absent (0.141286ms)
✔ controlledContentInvalidation (6.685832ms)
▶ controlledDocHydrate
  ✔ shouldLoadControlledContent when non-template workflow doc (4.623543ms)
  ✔ shouldLoadControlledContent rejects local legacy/mock ids like doc-001 (4.355051ms)
  ✔ shouldLoadControlledContent keeps canonical, freeform-off, and template preview rules (0.33535ms)
  ✔ hydrateControlledDocumentContent never requests content/revision for doc-001 (0.371039ms)
  ✔ hydrateControlledDocumentContent never requests for template preview or registered freeform (0.530244ms)
  ✔ shouldLoadControlledContent stays inside toolbar server-backed eligibility (0.3313ms)
  ✔ resolveCanonicalDocId maps doc-p56-intake to doc_proj56_intake (0.515705ms)
  ✔ canonicalDocIdForTask maps doc-p56-research to doc_proj56_research (0.32603ms)
  ✔ hydrate treats projection missing as ledger content, not 404 (4.001802ms)
  ✔ attaches hydrate ETag as PATCH baseline and ignores a later GET (1.843485ms)
  ✔ rejects hydrate when revision-state network or 5xx fails (1.925553ms)
  ✔ aligns markdownToBlockAST random ids onto revision-state head_block_map (3.095228ms)
  ✔ leaves Math.random ids when head_block_map is omitted (why gate + fail-closed remain) (3.505966ms)
  ✔ rejects controlled hydrate on NOT_FOUND or NEEDS_CONTENT (0.479186ms)
  ✔ fingerprint stays stable when only object identity changes (0.182494ms)
  ✔ dedupes in-flight hydrate for the same doc fingerprint (0.315051ms)
  ✔ aligned late hydrate still cannot overwrite a PATCH-success baseline (0.519714ms)
✔ controlledDocHydrate (31.258232ms)
✔ createClientTurnId uses randomUUID when available (0.768398ms)
✔ createClientTurnId falls back to getRandomValues UUID v4 (0.452466ms)
✔ createClientTurnId throws when no secure random API exists (0.405498ms)
✔ selectNonCreatorInitialMembers skips creator only (1.519185ms)
✔ buildManagedMemberUpsertPayload sends document_duty on add/update/restore (0.294151ms)
✔ buildInitialMemberUpsertPayload maps reviewer UI role to member API role (0.285552ms)
✔ persistInitialProjectMembers awaits each add and stops on failure (2.529205ms)
✔ ensureCreatedProjectWithMembers skips recreate on bootstrap id and retries members (0.793066ms)
✔ beginCreateProjectSubmit rejects concurrent second entry until end (30.99431ms)
✔ resolveCreateProjectSubmitPhase uses bootstrap to choose syncing label (0.368889ms)
✔ createProjectSubmitButtonLabel and close block while submitting (0.197224ms)
✔ shouldCloneMedicalTemplates skips the 7-pack for software domain (0.125417ms)
▶ resolveCurrentDocRole
  ✔ resolves A as author by authoritative user id (1.071268ms)
  ✔ does not promote reviewer B or stranger to author (0.209004ms)
  ✔ resolves real USER_B id as reviewer and never name-promotes placeholder 2 (0.162735ms)
  ✔ fail-closes unknown identity to viewer even if projectPermission says author (0.151426ms)
  ✔ matches name only for legacy local docs without duty ids (0.116057ms)
  ✔ does not name-promote when server controlled duties are zero ids (0.128666ms)
✔ resolveCurrentDocRole (3.236863ms)
▶ currentProjectRestore
  ✔ rejects empty project names (1.107647ms)
  ✔ rejects page-wide project name when banner and sidebar both match (0.283262ms)
  ✔ scopes the visible entry to complementary exact title (0.898173ms)
  ✔ scopes the current project assertion to banner exact text (0.420938ms)
✔ currentProjectRestore (3.969582ms)
▶ deliverableLeaseSync
  ✔ returns the same array reference when leases are unchanged (0.907253ms)
  ✔ returns a new array only when a lease actually changes (0.212504ms)
✔ deliverableLeaseSync (2.162356ms)
▶ docGovActionVisibility
  ✔ hides all approval actions on unmanaged docs (0.794286ms)
  ✔ gates separated duties by user id, not folded role label (0.191454ms)
  ✔ author_only: same user holds all three duties and sees all actions (0.239592ms)
  ✔ author_only: non-duty user sees no actions (0.127156ms)
✔ docGovActionVisibility (2.670331ms)
▶ documentBlockDomAttrs
  ✔ marks a real DocumentBlock in pure mode without overlay kind (0.866665ms)
  ✔ keeps the same stable attrs when overlay is later attached separately (0.221383ms)
✔ documentBlockDomAttrs (2.152296ms)
▶ durableBodySnippet
  ✔ rejects empty persisted snippets (0.825675ms)
  ✔ lets a later successful revision replace the old snippet (0.155776ms)
  ✔ does not promote a conflict-failed draft to the expected body (0.080487ms)
✔ durableBodySnippet (1.778697ms)
▶ dutyCellAssertion
  ✔ parses author, reviewer, and viewer from select value or badge role (2.68939ms)
  ✔ must not infer author from a row whose option labels include 编制负责人 (2.749208ms)
  ✔ accepts only a disabled non-assignable reviewer select (0.192935ms)
  ✔ rejects an enabled reviewer select when the reviewer cannot assign leads (0.138596ms)
  ✔ rejects canAssignLead=true even if the reviewer select is disabled (0.104027ms)
  ✔ rejects viewer, author, approver, and unknown values for USER_B (0.147196ms)
✔ dutyCellAssertion (7.283944ms)
▶ decideHydrationApply
  ✔ applies only when gen, doc, save epoch match and editor is closed (1.169155ms)
  ✔ rejects a response for another document (0.202464ms)
  ✔ rejects a superseded generation (0.144535ms)
✔ decideHydrationApply (2.470667ms)
▶ createEditorHydrationGate
  ✔ does not start a new hydrate while the editor is open (UI-06 fill-window GET) (0.3481ms)
  ✔ deferred hydrate that resolves after the editor opens does not replace the session (0.179175ms)
  ✔ covers hydrate resolving between fill and save (2.726659ms)
  ✔ asks for a hydrate resume after editor_open blocked the first apply (0.298881ms)
  ✔ asks for a hydrate resume when beginHydration is skipped while editing (0.167885ms)
  ✔ requestHydrationResume is consumed once after a protected edit session (0.145506ms)
  ✔ late hydrate after a successful PATCH does not roll back the new baseline (0.199994ms)
✔ createEditorHydrationGate (4.561375ms)
✔ mergeSessionUser prefers session identity over stale catalog entry (1.34047ms)
▶ playwrightPhaseArtifacts
  ✔ defaults unknown or empty UI_PHASE to main (0.708309ms)
  ✔ keeps post-restart distinct from main so the second run cannot overwrite traces (0.219003ms)
  ✔ keeps main results at the historical filename and isolates post-restart recordPass (0.234473ms)
  ✔ shares phase-state and secrets across phases (0.114226ms)
✔ playwrightPhaseArtifacts (2.329371ms)
✔ resolvePostTaskActiveDocId prefers server doc_proj for taskKey (0.830936ms)
✔ resolvePostTaskActiveDocId honors preferred server doc id (0.183355ms)
✔ shouldSwitchTemplateSlotToServer when active is local template slot (0.126516ms)
✔ pollUntilPostTaskServerDoc retries until same taskKey server doc appears (0.317901ms)
✔ pollUntilPostTaskServerDoc returns null after maxAttempts without relying on setState (0.195934ms)
✔ mapServerProjectToProjectInfo maps creator and preserves local members (0.949132ms)
✔ mergeProjectLists drops local-only demo seed projects by default (0.375909ms)
✔ mergeProjectLists can retain local-only demo when explicitly opted in (0.191375ms)
✔ documentDutyFromMemberRole maps UI reviewer and creator (0.725779ms)
✔ exclusiveMemberRoleChange keeps a single reviewer (0.211814ms)
✔ memberRoleFromDocumentDuty does not invent reviewer from access role (0.142846ms)
✔ toApiProjectRole maps doc roles to member and creator to owner (0.839005ms)
✔ fromApiProjectRole maps owner to creator for project creator (0.247083ms)
✔ mapApiMemberToProjectMember builds UI record (0.200744ms)
▶ projectSettingsDuties
  ✔ toggles full to none by atomically clearing duties (1.334491ms)
  ✔ blocks partial saves and locates required/governance issue codes (0.474566ms)
  ✔ allows an all-none configurable draft without three members (0.207014ms)
  ✔ requires three members once any document is managed (0.099128ms)
  ✔ resolves author_only to A/A/A without three-member requirement (1.454897ms)
  ✔ rejects author_only without author or with conflicting reviewers (0.202334ms)
  ✔ mixed full + author_only still requires three members for the full doc (0.136956ms)
  ✔ toggleAuthorOnly clears review/approve slots and restores on disable (0.171035ms)
✔ projectSettingsDuties (5.255444ms)
▶ projectSettingsMode
  ✔ enters frozen when can_edit_plan is false or the project is active (0.787167ms)
  ✔ stays planning only for an editable draft (0.133746ms)
  ✔ lists enabled duties for the frozen snapshot and skips disabled tasks (0.733108ms)
  ✔ keeps the local draft after PLAN_FROZEN refresh and switches to frozen (0.189694ms)
✔ projectSettingsMode (2.730289ms)
▶ revisionEtag
  ✔ uses stale hydrate ETag for PATCH and never the latest GET (0.764917ms)
  ✔ does not invent 0:0 when controlled hydrate misses etag or errors (0.169775ms)
  ✔ refuses controlled save without a hydrate ETag (0.458676ms)
  ✔ allows freeform bootstrap 0:0 only (0.129586ms)
✔ revisionEtag (2.610083ms)
▶ saveControlledBlockEdit
  ✔ successful save calls PATCH once with bound docId, hydrate ETag, body and client_block_map (2.557825ms)
  ✔ does not PATCH when editorDocId and activeDocId diverge (0.179475ms)
  ✔ does not PATCH on stale block id and keeps the draft (0.191045ms)
  ✔ 409 does not close the editor or drop the draft (0.651871ms)
  ✔ network errors do not close the editor or drop the draft (0.230693ms)
✔ saveControlledBlockEdit (5.02899ms)
✔ parseProjectIdFromSessionId decodes sess-p{id}-u{user} (0.731609ms)
✔ resolveSessionProjectId prefers explicit id then session id encoding (0.132386ms)
✔ mapServerSessionToProjectSession fills project metadata (0.582313ms)
✔ mergeSessionLists keeps local stage while applying server counts (0.213144ms)
▶ squadCompletionObservation
  ✔ accepts a directly completed adjacent assistant without requiring inflight (0.984411ms)
  ✔ accepts a turn that passed through inflight then completed (0.189744ms)
  ✔ rejects error terminals, missing correspondence, and visible errors (0.173405ms)
  ✔ keeps waiting while still inflight and does not treat inflight as success (0.122086ms)
✔ squadCompletionObservation (2.565484ms)
✔ resolveReconnectRunId prefers explicit opts and ignores attempt without opts (0.712449ms)
✔ shouldSubscribeExistingRun only for in-flight statuses (0.135776ms)
✔ isRemoteTaskTerminal covers confirmation and quality_failed (0.147646ms)
✔ nextAttemptOpts carries retained runId for reconnect without new POST (0.145395ms)
▶ uploadFreeformRegister
  ✔ buildUploadClientKey prefers explicit hint then doc-upload stamp (0.714309ms)
  ✔ registerUploadAttachments hard-fails without creating orphan on API error (12.912846ms)
  ✔ registerUploadAttachments rejects local doc-upload id from server (0.35008ms)
  ✔ registerUploadAttachments returns server doc-free ids and freeform facts (0.477516ms)
  ✔ deliverableFromFreeformUpload maps server id and upload facts (0.204844ms)
✔ uploadFreeformRegister (15.81998ms)
▶ workflowCategoryNavigation
  ✔ private menu cannot see doc_proj* so it must switch to workflow before exact select (1.225724ms)
  ✔ fail-closes when the workflow menu is showing but the exact doc is missing (0.290642ms)
  ✔ label and taskKey opens always require the workflow category (0.143806ms)
✔ workflowCategoryNavigation (2.876514ms)
▶ no external Google Fonts on login shell
  ✔ index.html has no fonts.googleapis / fonts.gstatic (0.725838ms)
  ✔ styles reference self-hosted fonts.css (0.230633ms)
✔ no external Google Fonts on login shell (1.651031ms)
▶ 用户上传文档多格式在线预览体系与渲染分流测试
  ✔ 1. 上传附件时正确注入 sourceType: "uploaded_file" 与完整 fileMeta 元数据 (1.024029ms)
  ✔ 2. 扩展名分类规则准确分发至对应的高保真渲染器类型 (0.32923ms)
  ✔ 3. 受控工作流交付物严格隔离：绝不命中 FilePreviewPanel，保持 BlockRenderer 纯净 (0.223224ms)
  ✔ 4. 上传文档支持受控流转：从个人私密一键共享至项目参考库后，在线预览依然可用且权限标态正确 (0.195064ms)
✔ 用户上传文档多格式在线预览体系与渲染分流测试 (2.971082ms)
▶ 项目立项、成员职责分配与退出留痕治理测试套件
  ✔ 1. 默认项目库包含完整元数据与法定三权成员 (active 状态) (0.733548ms)
  ✔ 2. 跨用户会话可见性严格隔离：未加入成员完全不可见 (0.314491ms)
  ✔ 3. 创建者添加新成员并分配职责后，新成员即刻可见该项目会话 (0.246873ms)
  ✔ 4. 中途加入后期退出 (exited)：保留项目会话但标记已退出只读留痕 (0.207754ms)
  ✔ 5. 超级管理员 (ADMIN) 享有全量通配可见与管理兜底特权 (0.154515ms)
✔ 项目立项、成员职责分配与退出留痕治理测试套件 (3.121828ms)
▶ 新建项目工程文档模板质量与纯净性保障套件（对标官方参考系统）
  ✔ 1. 必须精确生成 7 份官方全流程受控工作流模板且标记纯净 (0.663741ms)
  ✔ 2. 杜绝旧项目 CUSA-NeuroPulse 串号泄露，动态注入新项目信息 (0.617142ms)
  ✔ 3. 严格对标参考系统模板规范要素，绝非 3 行残缺摘要 (0.458326ms)
  ✔ 4. 缓存丢失场景下即时自愈重建 AST 能力验证 (0.245863ms)
✔ 新建项目工程文档模板质量与纯净性保障套件（对标官方参考系统） (5.664852ms)
▶ 用户上传文档私密归档与共享流转测试
  ✔ 10 个评审项目均包含已共享的 URS 交付物与 AST，支持跨角色合规查阅且会话均以 assistant 闭环 (2.264823ms)
  ✔ 用户上传附件自动生成私密交付物并在 AST 中建立隔离，支持流转至项目参考库 (1.906043ms)
  ✔ 单轮对话支持一次上传多个文档(上限5个)，批量生成私密交付物并遵循数量约束 (0.720578ms)
✔ 用户上传文档私密归档与共享流转测试 (5.968453ms)
▶ 工作流切换与消息展示时序测试套件
  ✔ 1. 当存在历史 seed 消息且追加新实时消息时，新消息必须严格沉淀在末尾 (1.040629ms)
  ✔ 2. 切回项目时相同正文不应因 temp/server id 差异重复展示 (0.243113ms)
✔ 工作流切换与消息展示时序测试套件 (2.272152ms)
✔ DeliverableItem 必须包含 projectId 与 isTemplateOnly 属性 (0.750318ms)
ℹ tests 406
ℹ suites 36
ℹ pass 406
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1236.897492

 RUN  v5.0.0 /home/weichen/projects/Agent-System/web

(node:370484) ExperimentalWarning: localStorage is not available because --localstorage-file was not provided.
(Use `node --trace-warnings ...` to show where the warning was created)

 Test Files  3 passed (3)
      Tests  32 passed (32)
   Start at  03:44:36
   Duration  539ms (import 52%, transform 42%, tests 5%, worker 1%)

EXIT:0
