Files
pikasTech-unidesk/.agents/skills/unidesk-webdev/references/full.md
T

55 KiB
Raw Blame History

name, description
name description
unidesk-webdev UniDesk Web 开发与浏览器验证技能。用户处理 UniDesk/HWLAB Cloud Web、Workbench、Performance 页、前端状态投影、Playwright、fake-server、web-probe、截图、响应式布局、Web E2E 回归或线上 Web bug 复测/提 issue 时使用。

UniDesk WebDev

本技能是 UniDesk/HWLAB Web 开发、浏览器复测和 Playwright 回归的唯一操作面。需求真相源仍是 UniDesk OA 规格,例如 project-management/PJ2026-01/specs/PJ2026-010401-web-workbench.mdPJ2026-01060505-workbench-performance.md;本技能只规定如何开发、采集、复现和验收。

P0 防分叉原则

  • 单一权威入口:先按 issue/CLI 明确的 node + lane 解析 workspace、web-probe origin、public origin、namespace、sourceRef 和目标分支。没有明确目标时才读取受控 YAML;不得把 D601、G14、v0.2、v0.3、旧端口、ClusterIP 或本地 dev server 写成隐藏默认。
  • 防分叉原则:Web/Workbench 修复必须先确定唯一 authority、唯一 API 契约和唯一状态投影入口;不得写成“当字段缺失/请求失败/状态不符/超时/刷新后,再改走另一个 endpoint、旧 workspace/conversation 模型、localStorage、trace polling、result polling、GET read-through repair、内部 manager、legacy route 或测试专用后门”。字段缺失、状态滞后或投影不完整时,修 schema、projector、read model 或正式 mutation 源头;代码里只能保留单一路径内的输入规范化、校验和错误暴露,不能用 A ?? Bif missing then fallback、兼容分支或双写双读把缺口遮住。
  • 禁止状态竞争行为:不得在代码、API、reducer、read model、fake-server 或测试中保留两个事实源,再用“覆盖、压过、override、优先级、优先采用、以 A 为准否则 B、A 赢过 B”等仲裁规则决定展示状态;这就是条件分叉和竞争投影。必须先定义唯一投影对象、唯一归属字段和唯一生成时机,让 UI/API 只消费该投影对象的单一状态;其他原始字段只能作为审计输入、诊断字段或待收敛数据,不能参与展示状态仲裁。
  • 严禁读侧推理:REST GET、SSE consumer、compat wrapper、CLI renderer、Web reducer/selectors、Trace renderer、fake-server 和测试断言都不能从 trace tail、message text、tool event、result cache、session summary、list row、workspace snapshot 或 localStorage 推断 turn/session/message 的 lifecycle、terminal、final response 或 running 状态。读侧只能读取唯一投影对象已经写好的字段;字段缺失、投影滞后或多字段矛盾时必须暴露 diagnostic/blocker 并修 projection writer/finalizer/schema,不得用 result?.status ?? trace?.status、最后一条 event completed、message fallback、session fallback、elapsed timeout 或 UI heuristic 补造事实。
  • Sealed final response 不可被读侧诊断覆盖:assistant final response 一旦由唯一 durable projection 写入 terminal/sealed 字段,主消息正文、finalResponse、message status 和 turn terminal 就是 sealed 用户结果;turn polling、trace hydration、SSE gap、realtime timeout、transport close、compat wrapper error 或 read model lag 只能进入 trace detail、transport diagnostics、projection diagnostics、session health 或消息详情入口,不能替换主 timeline 正文。
  • 无多路径、无 fallback:这是本技能的核心原则。Web、CLI、fake-server 和线上 web-probe 必须复用同一套 API 契约、同一 route/session/conversation/trace authority 和同一状态投影;不得为了让测试通过增加第二套 dispatcher、localStorage 真相、workspace snapshot 真相、内部 manager 调用、旧 lane 端口、raw request、临时兼容路径或“测试专用后门”。
  • 严禁事后 repair / 0repairWeb、Workbench、fake-server 和 web-probe 不得通过 reload、切换 session、realign、sessionRepair、workspace selection repair、active tab repair、GET read-through、SSE gap repair、localStorage truth 或测试 helper 自动点击,把已经分裂的 route/session/message/trace 状态补成看起来正确。合法页面必须在首次进入、刷新、deep link、session 切换和 SSE 重连时按同一权威自然收敛;不一致必须暴露为 blocker/diagnostic,并修 schema、projector、read model、reducer 或 route authority 源头。允许 session-bound hydrate/gap-fill 只写目标 session 自己的 cache/read model,不得改变 active selection、URL 或当前消息区。
  • Workbench GET 纯读投影:GET /v1/workbench/* 只能读取已持久化的 Workbench 投影事实并组装摘要;不得在 GET 中调用 AgentRun、Code Agent 或其他上游执行面做同步、补事件、修 trace、finalize terminal、改 running/completed 或写 message/session。投影滞后必须显式暴露 projectionStatuslastProjectedSeqsourceRunIdblocker 或等价诊断字段,并由后台 projector/finalizer 或显式受控 mutation 处理;刷新页面、切换 session 或打开详情不能成为事实推进入口。
  • Workbench session lifecycle:空消息/无活动 session 的回收只能由后端 lifecycle GC、后台 finalizer 或显式受控 mutation 完成,TTL 和开关从选中 node/lane 的受控配置进入运行面;Web、fake-server 和 web-probe 不得靠隐藏 tab、前端 DELETE timer、GET read-through 或 deep link repair 清理。归档/删除后的 session deep link 必须观察同一 authority 的 404/archived diagnostic,不能补建或复活 session。
  • Workbench 前端无破坏性投影权:删除 session、清空 active session、清空当前消息页、清空 tabs、把 composer 降成 session_required,或把 route session 标记为 not-found/archived/deleted,都是 lifecycle mutationWeb reducer/selectors、route hydrate、GET/list/detail/messages/SSE consumer、fake-server 和测试 helper 都不能由读侧失败、404、空列表、网络瞬断或 late response 触发这些 mutation。只有用户显式 mutation 成功,或后端 canonical lifecycle projection,能改变 session lifecycle。需求真相见 UniDesk OA PJ2026-010401 Web工作台 的“破坏性投影权”。
  • fake-server 不是第二后端:它只按正式 API 契约重放脱敏 fixture 和必要边界变形。未 mock 的 /auth/*/v1/*/health* 请求应失败并暴露 path;不得访问 live Cloud API、AgentRun、HWPOD、数据库或 Kubernetes 作为通过条件。
  • 真实数据优先:fixture seed 优先从目标 node/lane 的受控真实样本采集。合成 fixture 只补真实样本难以稳定覆盖的边界,并标明 derivedFromsyntheticReason
  • 原入口闭环:fake-server Playwright 用例负责可重复红灯和源码回归;线上 web-probe 负责同一 node/lane public origin 的 P4 原入口验收。二者不能互相替代。
  • Master server 禁重型验证:不要在 master server 跑仓库级 check、Web build、Playwright/browser smoke 或镜像构建。HWLAB Web 验证走目标 node/lane workspace、k3s/Tekton、D601 runner 或受控 web-probe。
  • 禁止裸写 PlaywrightUniDesk/HWLAB Web 复现、截图、DOM/API 采样、长程 Workbench 观测和线上 closeout 默认必须走 web-probe run|script|observe;不得直接写 trans <route> playwright heredoc、playwright-cli、临时 Node Playwright 脚本或本地 browser daemon 作为正式证据入口。确有非 HWLAB 外站截图/PDF 等 web-probe 不覆盖的短生命周期需求时,必须说明例外原因,且可复用动作要回收进 web-probe。

工作流

  1. 定位目标:确认 repo、node、lane、workspace、public origin 和目标 SPEC。HWLAB D601 v0.3 例子是 /home/ubuntu/workspace/hwlab-v03 + https://hwlab.pikapython.com,但只能在 issue/CLI 指向该目标时使用。
  2. 读规则:进入目标 workspace 前读取目标 AGENTS.md;涉及规格或测试设计时读取 UniDesk OA 对应 SPEC。
  3. 线上复现:短动作用 web-probe run|script,长程 Workbench/session 观测用 web-probe observe start|command|status|stop|analyze;保存 scriptSha256runDir、observer id、stateDir、截图名、截图 SHA、URL、DOM/API 摘要、prompt hash、trace/session/run id。
  4. 建红灯:修 Workbench/Performance 用户可见 bug 前,在目标 HWLAB workspace 的 web/hwlab-cloud-web fake-server Playwright 套件中补确定性用例;fixture 从真实采集样本脱敏产生。
  5. 修源码:保持状态读写单一路径。状态投影类修复优先收敛 server-state/reducer/projection,不在 UI 组件、trace polling、result polling 或 localStorage 中新增竞争事实。
  6. 验证:先跑 fake-server Playwright 目标用例,再回到同一 node/lane public origin 用 web-probe 复测;多轮任务必须用同一个 observer/session 采样到终态。截图、report hash 和 analyze finding 作为证据回传,不进入源码仓库。
  7. 写 issue/closeout:问题登记和收口必须写明目标合并分支、node/lane、fixture 来源、Playwright fake-server 用例、线上 web-probe 命令/脚本 SHA、截图 SHA 和剩余边界。

HWLAB Web Probe

线上 Cloud Web DOM 验收优先使用受控入口:

bun scripts/cli.ts web-probe run --node D601 --lane v03

web-probe 入口分三类:

  • runrepo-owned 标准 DOM probe,适合固定 P4 验收和已有脚本。
  • script:受控 Playwright 托管脚本,适合一轮 55 秒内完成的 DOM/API 断言、截图、route/intercept 和边界采样。
  • observe:纯客户端长程观测,适合同一 Workbench session 多轮任务、realtime/projection 问题、长时间 trace/DOM/network 采样和无副作用报告生成。长程 Workbench 观测默认同时打开两个浏览器页面:control 页面只执行显式 observe command 用户动作,observer 页面只打开同一个 session 做被动观察,并默认每 3 分钟整页刷新一次同一 session,模拟用户离开后返回,用来抓多用户/多页面下同一 session 的投影差异、历史 trace 丢失、耗时跳变和 loading 差异。

工测优先级:Workbench trace 乱序、完成行位置、耗时不一致、时间跳变、final response flicker、session 不刷新、性能慢路径和多轮可靠性问题,默认先用 observe 采样并跑 observe analyze;不要把临时 Playwright spec、裸 DOM 调试脚本或单次 script 结果当作主要工测证据。script/run 只作为短路径断言、截图/API 摘要或 observe/analyze 后的补充复核。

需要 Playwright route/intercept、延迟 API、读取 in-flight DOM 或截图时仍使用受控 web-probe script,不要裸写 Playwright

bun scripts/cli.ts web-probe script --node D601 --lane v03 <<'JS'
export default async ({ gotoStable, screenshot, fetchJson, fetchApiMatrix, recordStep }) => {
  await gotoStable('/workbench');
  const sessionsResponse = await fetchJson('/v1/workbench/sessions?limit=5');
  const firstSession = sessionsResponse.body?.sessions?.[0] ?? sessionsResponse.body?.items?.[0] ?? null;
  const sessionId = firstSession?.sessionId ?? firstSession?.id ?? null;
  const apiMatrix = await fetchApiMatrix([
    '/v1/workbench/sessions?limit=5',
    ...(sessionId ? [
      `/v1/workbench/sessions/${encodeURIComponent(sessionId)}`,
      `/v1/workbench/sessions/${encodeURIComponent(sessionId)}/messages`
    ] : []),
    '/auth/session'
  ]);
  recordStep('workbench-ready', { sessionsOk: sessionsResponse.ok, sessionId, apiMatrixOk: apiMatrix.ok });
  return {
    sessionsOk: sessionsResponse.ok,
    sessionCount: sessionsResponse.body?.sessions?.length ?? sessionsResponse.body?.items?.length ?? null,
    sessionId,
    screenshot: await screenshot('workbench.png')
  };
};
JS

长程 Workbench 观测使用 observe 命令组:

bun scripts/cli.ts web-probe observe start --node D601 --lane v03 --target-path /workbench --sample-interval-ms 5000 --screenshot-interval-ms 60000 --command-timeout-seconds 55
bun scripts/cli.ts web-probe observe command webobs-xxxx --type newSession
bun scripts/cli.ts web-probe observe command webobs-xxxx --type selectProvider --provider codex-api
bun scripts/cli.ts web-probe observe command webobs-xxxx --type sendPrompt --text 'ping'
bun scripts/cli.ts web-probe observe command webobs-xxxx --type steer --text '继续观察当前 trace'
bun scripts/cli.ts web-probe observe command webobs-xxxx --type cancel
bun scripts/cli.ts web-probe observe command webobs-xxxx --type sendPrompt --text-stdin <<'EOF'
long prompt
EOF
bun scripts/cli.ts web-probe observe status webobs-xxxx --tail-lines 6
bun scripts/cli.ts web-probe observe collect webobs-xxxx --view turn-summary
bun scripts/cli.ts web-probe observe collect webobs-xxxx --view timeline --command-id cmd-xxxx
bun scripts/cli.ts web-probe observe collect webobs-xxxx --view trace-frame --trace-id trc_xxx --sample-seq 42
bun scripts/cli.ts web-probe observe stop webobs-xxxx
bun scripts/cli.ts web-probe observe analyze webobs-xxxx
bun scripts/cli.ts web-probe sentinel plan --node D601 --lane v03 --dry-run
bun scripts/cli.ts web-probe sentinel status --node D601 --lane v03
bun scripts/cli.ts web-probe sentinel image status --node D601 --lane v03
bun scripts/cli.ts web-probe sentinel image build --node D601 --lane v03 --dry-run
bun scripts/cli.ts web-probe sentinel control-plane plan --node D601 --lane v03 --dry-run
bun scripts/cli.ts web-probe sentinel control-plane status --node D601 --lane v03
bun scripts/cli.ts web-probe sentinel control-plane trigger-current --node D601 --lane v03 --dry-run
bun scripts/web-probe-sentinel-service.ts --node D601 --lane v03 --state-root .state/web-probe-sentinel-smoke --scheduler-disabled --once

observe analyze 的 duplicate final response 判定必须以 trace-frame 可见行事实为准。observe collect --view trace-frame 固定渲染的 Final Response 区块是 summary,不是第二条业务 assistant message;只有同一 trace-frame 中出现两个可见 assistant final rows 且内容重复时,才应报告 duplicate finding,并在证据中写明 finalResponseSummaryBlockCounted=false

observe collect --view timeline 用于 issue closeout 前的 artifact drill-down:它只读取现有 control.jsonlsamples.jsonlcommands/{pending,processing,done,failed,abandoned}/*.json,默认输出 bounded timeline、关键 metadata、脱敏 disclosure 和下一步命令。按 --command-id--turn--trace-id--sample-seq--timestamp--window-ms 缩小窗口;需要完整原始内容时必须显式使用 --raw--view files --file ...

项目管理 / MDTODO 页面同样优先使用 observe,不要退回一次性 Playwright 脚本。MDTODO 主动编辑验收必须把常见动作沉淀成 observe command,同一 observer 串联 source 配置、HWPOD probe/reindex、文件/任务选择、Rxx 树操作、编辑写回和 Workbench launch

bun scripts/cli.ts web-probe observe start --node D601 --lane v03 --target-path /projects/mdtodo --sample-interval-ms 5000 --screenshot-interval-ms 60000 --command-timeout-seconds 55
bun scripts/cli.ts web-probe observe command webobs-xxxx --type gotoProjectMdtodo
bun scripts/cli.ts web-probe observe command webobs-xxxx --type configureMdtodoHwpodSource --hwpod-id d601-f103-v2 --node-id node-d601-f103-v2 --root docs/MDTODO/
bun scripts/cli.ts web-probe observe command webobs-xxxx --type probeMdtodoSource
bun scripts/cli.ts web-probe observe command webobs-xxxx --type reindexMdtodoSource
bun scripts/cli.ts web-probe observe command webobs-xxxx --type closeMdtodoSourceConfig
bun scripts/cli.ts web-probe observe command webobs-xxxx --type selectMdtodoSource --source-id <opaque-source-id>
bun scripts/cli.ts web-probe observe command webobs-xxxx --type selectMdtodoFile --file-ref <opaque-file-ref>
bun scripts/cli.ts web-probe observe command webobs-xxxx --type selectMdtodoFile --filename <direct-mdtodo-file-name.md>
bun scripts/cli.ts web-probe observe command webobs-xxxx --type selectMdtodoTask --task-ref <opaque-task-ref-or-rxx>
bun scripts/cli.ts web-probe observe command webobs-xxxx --type openMdtodoReportPreview --task <rxx-or-task-ref> --link <report-label-or-path-fragment>
bun scripts/cli.ts web-probe observe command webobs-xxxx --type toggleMdtodoReportFullscreen --text toggle
bun scripts/cli.ts web-probe observe command webobs-xxxx --type editMdtodoTaskInline --task <rxx-or-task-ref> --field title --text 'web-probe interactive edit acceptance'
bun scripts/cli.ts web-probe observe command webobs-xxxx --type editMdtodoTaskInline --task <rxx-or-task-ref> --field body --text 'body updated through web-probe command'
bun scripts/cli.ts web-probe observe command webobs-xxxx --type editMdtodoTaskTitle --task <rxx-or-task-ref> --text 'web-probe interactive edit acceptance'
bun scripts/cli.ts web-probe observe command webobs-xxxx --type editMdtodoTaskBody --task <rxx-or-task-ref> --text 'body updated through web-probe command'
bun scripts/cli.ts web-probe observe command webobs-xxxx --type toggleMdtodoTaskStatus --task <rxx-or-task-ref> --status completed
bun scripts/cli.ts web-probe observe command webobs-xxxx --type addMdtodoSubTask --parent <rxx-or-task-ref> --title 'web-probe command subtask'
bun scripts/cli.ts web-probe observe command webobs-xxxx --type continueMdtodoTask --task <rxx-or-task-ref> --title 'web-probe sibling task'
bun scripts/cli.ts web-probe observe command webobs-xxxx --type deleteMdtodoTask --task <rxx-or-task-ref>
bun scripts/cli.ts web-probe observe command webobs-xxxx --type launchWorkbenchFromMdtodo --task <rxx-or-task-ref>
bun scripts/cli.ts web-probe observe collect webobs-xxxx --view project-mdtodo-summary
bun scripts/cli.ts web-probe observe analyze webobs-xxxx

MDTODO 或 Project Management 的 Web 重写/布局 closeout 不能只引用组件 diff、PipelineRun 成功或一张默认截图。最小证据应按 SPEC 覆盖:默认深链任务正文可见、Source/File 下拉显示 direct MDTODO 文件名、Rxx 任务树为 outline 辅助视图、右侧报告栏可打开且不挤爆主工作区、报告全屏可读并可关闭。涉及报告渲染时,先用有 reportLinkCount > 0 的任务执行 openMdtodoReportPreview,再执行 toggleMdtodoReportFullscreen,并在 closeout 中记录 command id、reportPreviewVisiblereportFullscreenVisible、报告 deep link、截图 SHA 和 analyze report SHA。

observe 的 Project Management 采样可能同时包含 control 页和 observer 页。control 页是显式用户动作所在页面;observer 页用于被动对照和周期刷新。若 project-mdtodo-summaryobserve analyze 的最新汇总被 observer 周期刷新、stop 命令或根路由样本带成 SRC=0/FILES=0/TASKS=0,不得直接推翻已完成 command result 和 control 页面截图;必须按 pageRole、command JSON、control URL、screenshot path/SHA 和相邻 samples 解释。反过来,若 control command 失败、command backlog 未清空或截图 URL 不在目标 source/file/task/report 深链上,也不能用 observer 的健康样本替代用户入口证据。

observe command --type newSession 是显式用户/control action:它通过当前 Workbench UI 点击 #session-create 创建新 session,等待 active session id 改变和 composer ready,并把前后 snapshot 写入 control log。它只能用于采样开始时建立目标 session,或作为用户明确的新建会话动作;不得在 route/session mismatch 后当作 repair 手段。

约束:

  • web-probe script 不运行默认探针,必须通过 stdin heredoc 或 --script-file <path> 提供脚本;只需要 repo-owned 标准 DOM probe 时使用 web-probe run
  • web-probe run|script|observe start 的默认 URL、browser proxy mode、observe/analyze 报警阈值和 project-management 采样/命令 allowlist 必须来自 config/hwlab-node-lanes.yamlwebProbe;需要排除公网/FRP/跨国 proxy 抖动时,在 YAML 里把目标 node/lane 的 webProbe.defaultOrigin 配成内部 Service ClusterIP origin,不要在命令行长期手写 --url 或裸 Playwright。
  • web-probe observe start 默认是被动观测:记录 DOM 摘要、自然页面 request/response/requestfailed、截图和 performance 样本,不主动 fetch Workbench API、不切换 control session、不拦截路由、不调用 repair helper。长程 Workbench 观测必须保留 control/observer 双页面模型:control 页面执行显式 commandobserver 页面只同步到同一 session URL 后被动采样,并按默认 180000ms 周期整页刷新同一 session 来模拟用户往返;周期刷新只作用于 observer,不得改变 control active session 或作为通过条件。两页的 pageRolepageIdsampleGroupSeq 必须进入样本和 analyzer 报表。任何 newSessionselectProvidersendPromptsteercancelgotoscreenshotmarkstop 都必须通过 observe command 显式下发,并进入 control.jsonl;长 prompt 必须优先用 sendPrompt --text-stdinsteer --text-stdin,不要为了绕开 shell quoting 退回裸 Playwright 或临时脚本。MDTODO 高频操作也必须优先沉淀为 observe command;同类动作第二次出现时不要继续写临时 web-probe script
  • observe command --type steer--type cancel 是显式用户/control actionsteer 复用当前 Workbench composer 的运行中 turn 引导路径,cancel 复用同一 composer 主按钮的取消路径。二者必须进入 control.jsonl,不能用后端私有 API、AgentRun direct cancel 或测试后门替代。configureMdtodoHwpodSourceprobeMdtodoSourcereindexMdtodoSourcecloseMdtodoSourceConfigselectMdtodoSourceselectMdtodoFileselectMdtodoTaskeditMdtodoTaskTitleeditMdtodoTaskBodytoggleMdtodoTaskStatusaddMdtodoSubTaskcontinueMdtodoTaskdeleteMdtodoTasklaunchWorkbenchFromMdtodo 也是显式用户/control action,只能使用页面公开 data-* id、正式按钮和 YAML 允许的自然 API;它们通过 public source/file/task id 与 Workbench 关联,不能读取内部 store、私有后端或把 MDTODO 页面包含进 Workbench。
  • observe collect --view turn-summary 是第一层 CLI 阅读视图:只从 samples.jsonlcontrol.jsonl 和已有 analysis/report.json 按需渲染同一 session 的多 turn 摘要,包含用户消息 preview/hash、traceId、状态、耗时/最近更新时间、steer/cancel 标记和 Final Response 摘要。observe collect --view trace-frame --trace-id <id> --sample-seq <n> 是第二层 CLI 阅读视图:从同一采样帧渲染单帧 trace 文字截图,并固定输出 Final Response 区块。observe collect --view project-summary|project-mdtodo-summary 从同一 artifact 渲染项目管理 / MDTODO DOM 采样、Source/File/Task 计数、command/mutation 结果、Workbench launch、捕获到的 x-hwlab-otel-trace-id 和 OTel/Tempo drill-down 线索;project collect 的远端 payload 必须保持 bounded compact rows,由本地 renderer 生成表格,避免 trans stdout 截断后 JSON parse 失败。collect 视图不是采样器新增保存物,不构成第二事实源。
  • observe start/status/command/collect/analyze 默认输出包含 Wrapper contract 区块;该区块证明 Web 哨兵只能 wrap 现有 observe CLI verb、现有 runner/analyzer 和既有 artifact contract,不新增第二套 Playwright runner、analyzer、状态机或私有 web-probe API。
  • web-probe sentinel plan|status 只读取 observability.webProbe.sentinel.enabled/configRefs 和 owning YAML,渲染 redacted 配置引用图、文件 hash、缺失字段和跨 ref 冲突;web-probe sentinel image|control-plane 继续从 owning YAML 渲染 image、GitOps、Argo 和 manifest 计划,并在远端 publish job 接通前拒绝报告部署 mutation。它不启动浏览器、不读取 Secret 值、不保存采样结果,也不是第二套 runner/analyzer。真正的采样和判定仍以 observe start|command|collect|analyze artifacts 为准。
  • Web 哨兵 public dashboard/origin 必须以 issue/SPEC/YAML 既定计划为准;当前 P6 计划沿用 monitor.pikapython.com,不要未经明确变更改成 hwlab-monitor.pikapython.com 或其他新域名。验证 report 时记录 publicOrigin,但不要把域名硬编码到 runner/analyzer 逻辑里。
  • 验证 sentinel public dashboard 页面 DOM/截图(区别于 CI/CD sentinel status|plan|image|control-plane)时,web-probe script 的默认 origin 是 lane 的 HWLAB Cloud WebgotoStable('/') 进入 hwlab workbench),不是 sentinel dashboard origin;必须用显式 page.goto('<sentinel publicBaseUrl>/')publicBaseUrl 来自 config/hwlab-web-probe-sentinel/public-exposure.*.yaml#sentinel.publicExposure.publicBaseUrl,如 https://monitor.pikapython.com)进入 dashboard 页面,再用 safeEvaluate/screenshot 采样,不能用 gotoStable('/') 期望落到 sentinel dashboard。这是 web-probe 缺少 sentinel dashboard DOM 验证受控入口的临时绕过,根因见 pikasTech/unidesk#1030dashboard DOM 验证脚本不要复用 hwlab workbench 的 waitWorkbenchReady/session helper 作为通过条件。
  • scripts/web-probe-sentinel-service.ts 是 Web 哨兵 Pod entrypoint--once 只做 config/PVC/SQLite/scheduler/analyzer-command health 快照,--scheduler-disabled 仅用于本地服务健康冒烟,不能作为生产运行参数。HTTP 服务只提供 /api/health/api/status/api/runs/api/maintenance/metrics 和 redacted dashboard 外壳,底层采样仍只能经 observe CLI adapter。
  • trace-frame 出现 (无 trace rows;这是 blocker...) 时,必须先看同一输出中的 TRACE DIAGNOSTIC:记录 pageRole/pageId、traceRows/turns/messages 数量、sampleTraceIds、尾部 traceRow/turn/message 归属。若目标 trace 的 turn/message/final 存在但 traceRows 全部属于旧 trace,应按 Workbench read model authority 分裂登记到架构/业务 issue(例:HWLAB #2124),不得把旧 traceRows 当作新 turn 通过证据,也不得让 analyzer 的聚合计数压过 CLI trace 视图。
  • analyzer finding 不得压过 CLI trace-frame 人工视图。尤其 trace-assistant-message-duplicates-final-response 只有在 trace-frame 中同一 completed turn 可见多条相同 assistant final rows 时才按业务 bug 处理;如果 trace-frame 只有一条 assistant final row、后面固定 Final Response 区块正确且 API messages/turns 对齐,该 amber 归类为 analyzer 精度问题,应登记/修工具,不得阻止业务 closeout。
  • observe status 显示 PID still alive 但 heartbeat/sample 不推进、commands/pending/*.json 不被消费,或 observe stop --force 只是继续排队 stop command,应先按 web-probe runner 工具缺陷处理(例:UniDesk #874),用 route 只读确认 PID/heartbeat 后清理进程;不要把 pending command、未触发的 cancel 或 runner stale 混入 Workbench 业务结论。
  • web-probe observe 的 issue evidence 优先记录 observer id、stateDir、report JSON/Markdown SHA、samples/control/network/artifact 计数、routeSessionId、activeSessionId、prompt hash/textBytes、traceId、AgentRun runId/commandId、最终 status 和必要摘要;不要把 prompt 原文、assistant 大段正文、完整 stdout/stderr 或 provider payload 粘贴到 issue。
  • 多轮 Workbench 采样必须证明同一个 sessionId 连续承载所有轮次;每轮至少记录 prompt hash、traceId、终态、最终回答摘要和性能/产物表。若 Web UI 投影卡住但 Code Agent/AgentRun result 已 terminal,应同时登记“执行终态”和“Workbench 投影未收敛”,不得用 goto、reload、切 session 或 result polling 把 UI 失败伪装成通过。
  • observe command --type sendPrompt 是普通新 turn 路径,composer 主按钮应处于 data-action=turn;如果仍是 steercancel,必须作为工具/页面状态不一致失败暴露,不能点击后再等待错误接口。空输入状态下 submit disabled 可以为 true,不能把 disabled 当作新 turn 不可用的唯一依据;应先看 input present/enabled、warning absent 和 action=turn,再由正式填入 prompt 后提交。
  • observe analyze 是离线分析,只读取 artifact JSONL 并写 analysis/report.mdanalysis/report.json,不访问 Workbench API、不驱动浏览器。observe start 每次启动必须先把同一 stateDir 中已有的根目录 JSONL 轮转到带时间戳的 archive/ 文件;observe analyze 默认只分析当前根目录 JSONL,不扫描历史 archive,只有显式指定 archive prefix 时才分析历史轮转窗口。报告必须输出采样点 vs 每个 turn 的总耗时/最近更新时间表、trace row 视觉顺序异常、terminal/轮次完成 row 是否最后、Code Agent 卡片耗时与 trace/轮次完成总耗时一致性、可见“加载中”的数量/归属/并发 owner/连续出现区间、DOM diagnostic/HTTP/console/requestfailed/runtime execution error 分组、page asset provenance segment、同源 API Resource Timing 分位表和超过 YAML webProbe.alertThresholds budget 的慢路径 finding;项目管理页还必须输出 DOM readiness、source/file/task 计数、缺失 public task ref、Workbench launch success/failure、captured OTel trace header、自然 project-management API 分组和超过 YAML webProbe.projectManagement.slowApiBudgetMs 的慢路径 finding。页面/API 加载、可见“加载中”、长连接打开耗时、turn timing 跳变、trace row 顺序、卡片耗时/轮次完成耗时一致性、session fallback 标题比例和项目管理 API 慢路径阈值只能改 YAML,不能在 analyzer/renderer 中写死。修复必须降低真实请求、投影、渲染或后端路径耗时,禁止为了减少“加载中”出现时间而提前展示未加载完的内容,也不能靠下游 retry/reload/fallback 掩盖。报告里的 trace-row-order-nonmonotonictrace-completion-row-not-lastround-completion-elapsed-mismatchcode-agent-card-duration-underreportedfinal-response-flickeruncommanded-visible-state-changemdtodo-workbench-launch-otel-trace-missingproject-management-api-slow、session changed、network 503 等 finding 是排障线索;用于 closeout 时必须结合原始 session/trace/DOM 证据解释,避免把采样噪声直接当作业务结论。
  • sentinel validate --quick-verify 超过 120s 是严重超时,必须保持 warning/red 并优先从 envreuse、git mirror、warm runner 复用、first tool execution、Workbench 投影和 observe/analyze 开销排查;不要通过提高 budget、减少轮数、放宽 analyzer 或绕过 CLI trace 视图来让场景变绿。quick-verify 等待每轮终态时应读取既有 sampler artifacts 和 bounded collect 视图,不能反复启动完整 collect 或新增第二份“trace 截图”保存来源。
  • 自定义 web-probe script 仍运行在 UniDesk trans 60s 最外层短连接约束内;能在一轮内完成的 P4 验收优先把 --command-timeout-seconds 控制在 55 秒以内,并减少无界 selector/network 等待。确需等待更久时,改用 web-probe run 的异步 job/status 语义,或把动作拆成“提交/采样/截图/状态读取”多次短 probe。若输出出现 UNIDESK_SSH_RUNTIME_TIMEOUT 但同时恢复了 reportPathreportSha256、screenshots 或 DOM steps,先按远端报告判断脚本/页面实际状态;最终关闭证据仍优先用一次未触发短连接超时的 bounded rerun。
  • issue closeout 优先引用 web-probe script 输出的顶层 issueEvidencesummary.issueEvidence;只有需要展开调查时才粘贴 probe.script.resultprobe.steps 或完整 reportPath,避免 stdout、summary 和 report 多层重复同一证据。
  • stdin heredoc 与 --script-file 都按 ES module 加载,脚本必须导出 export default async ({ page, gotoStable, recordStep, ... }) => { ... };不要在模块顶层直接写 return。失败为 Illegal return statementdoes not provide an export named default 或 finalUrl 仍是 about:blank 且 stepCount=0 时,先按 probe 脚本入口误用处理,不要归因成 Cloud Web 行为失败。
  • 自定义脚本需要主动失败时,优先返回 { ok: false, failedCondition: "..." } 或抛出错误;兼容返回 { pass: false }{ success: false },且 { ok: true, pass: false } 仍按失败处理。failedConditionerrorMessagemessageerrorreasonsummary 会进入失败摘要;不要只把失败埋在普通业务字段里。
  • web-probe 由 UniDesk CLI 从 YAML 声明的 bootstrap admin sourceRef 读取凭据并建立同源 hwlab_session;脚本不得自行读取、打印或复制 Web 登录凭据、cookie、token 或完整 API key。
  • 需要禁用 EventSource、mock Date/clock、注入 preload hook 或修改浏览器启动前全局对象时,page.addInitScript() 必须在目标页面整页加载前注册,并用 page.goto(new URL(path, origin).toString(), { waitUntil: "domcontentloaded" }) 进入目标 deep link;不要依赖 gotoStable() 复用当前 SPA 页面后再期待 init script 生效。若只在已加载页面上 route/block 请求,既有 SSE 或 store 状态可能继续更新,不能作为“无后端刷新依赖”的验收。
  • 脚本构造 URL 时使用 new URL(path, baseUrl).toString();不要拼出 //v1/...
  • 先通过 gotoStablewaitWorkbenchReady 或等价导航进入目标 origin,再用 fetchJson 读同源 API;不要在 about:blank 上请求 /v1/...fetchJson 返回包装对象 { ok, status, body, failureKind, ... },业务字段必须从 .body 读取,并同时记录 ok/status/failureKind;如果返回 status=0 且页面还不是目标 origin,先按 probe 脚本误用处理,不要归因成 Cloud API 或 Workbench 投影失败。
  • Workbench 有 SSE/长轮询时不要用 networkidle 判断通过;用明确 DOM/API 条件,如 final URL、route sessionId、active tab、message card、trace row 或 durable session detail/messages。
  • 当前 HWLAB v0.3 Workbench durable read model 的验收端点是 /v1/workbench/sessions/v1/workbench/sessions/{sessionId}/v1/workbench/sessions/{sessionId}/messages/v1/workbench/turns/{traceId}/v1/workbench/traces/{traceId}/events;提交 mutation 可用正式 /v1/agent/chat 产生真实 turn。/v1/workbench/workspace 只在当前 API 契约声明为选择/config 快照时采集,不作为消息或 trace authority/v1/agent/conversations 属于旧模型,不得作为 v0.3 Workbench durable projection 的通过条件。
  • 需要稳定 running message、timing、SSE 或 projection 样本时,优先通过正式同源 mutation 创建样本:POST /v1/agent/sessions 建 session,再按前端同一路径提交 /v1/agent/chat,轮询 /v1/workbench/sessions/{sessionId}/messages 等待 durable projection。不要把历史 session 是否仍 running 当作验收前提,也不要用旧 conversation/workspace 端点造样本。验收结束后能取消的 turn 必须调用 /v1/agent/chat/cancel 清理,并在 issue evidence 只记录 trace/session、status、script/report SHA 和必要摘要,避免粘贴完整 provider payload。
  • HWLAB v0.3 fa2ad4845a111e0f9e86d473eb4204ed1b2b0a3c 后,repo-owned scripts/web-live-dom-probe.mjs 的默认 web-probe run --fresh-session 已使用 durable Workbench session 端点,不应再依赖 /v1/workbench/workspace/v1/agent/conversations 作为消息/trace authority。若 session-not-selected 复现,先确认目标 workspace 已包含该提交,再对 helper 做旧端点扫描;只有扫描仍命中旧端点时才按工具链回归处理。
  • web-probe run --fresh-session 空消息路径的基线证据是 D601 v0.3 job web-live-dom-probe-1781842424721-44066freshSessionAligned=truemessageCount=0、report SHA d34c6765943e14bbd639b91bfc17139d582f670ed5cf409a957acd40fae7871f、screenshot SHA 8d341b7c30293baa9be8f1e63e147ea0fdafbdbcfc43f0b05e4fb9f316ef996c
  • 若带 --message 的 fresh-session 路径已经达到 freshSessionAligned=truepromptSubmitted=truemessageCount>0 和 session API 200,但随后报 trace-id-missingWorkbench turn is not visible to the current actor 或 trace 面板同类不可见文案,应登记为 Workbench turn/trace actor visibility 问题,不再归因到 fresh-session 选择 helper 或旧端点。
  • Playwright page.evaluate 只能传一个可序列化参数;多个值包成对象,或用 safeEvaluate(fn, { a, b })
  • safeEvaluate 返回结构化包装对象;脚本断言前必须解包,例如 const evaluated = await safeEvaluate(...); const dom = evaluated?.value ?? evaluated;recordStep 可以记录包装对象用于诊断,但行为断言不要直接读包装对象的业务字段,避免把已通过的 DOM 误判成 undefined
  • 脚本用 page.evaluate 模拟滚动、resize、click 或派发 DOM event 后,若断言 Vue/React 绑定出的 data-*、ARIA、按钮状态或 scroll-follow 状态,必须先等待一次浏览器/框架更新,例如 await wait(300)page.waitForFunction(...) 或下一次明确 DOM 条件;不要在同一个 evaluate 内写完事件就立刻读取状态,否则会把尚未 flush 的响应式状态误判为业务失败。验证用户滚动暂停/恢复时优先记录操作前后 scroll metrics 和 data-following 的延迟稳定值。
  • web-probe script 顶层/default export 运行在 Node 上下文,浏览器全局 windowdocumentlocationCSS 只在 safeEvaluate/page.evaluate 回调内可用。Node 侧 deep link 用 const origin = new URL(page.url()).origin; await page.goto(new URL('/workbench/sessions/' + encodeURIComponent(id), origin).toString()),或直接用 gotoStable('/workbench/sessions/<id>');不要在 Node 侧写 location.originCSS.escape(...),也不要用没有 baseURL 的 page.goto('/relative/path')。若失败为 location is not definedCSS is not defined 或相对 URL invalid,先按脚本误用处理;工具提示改进跟踪见 pikasTech/unidesk#479
  • 脚本中用 recordStep(name, data) 保存关键 DOM/API partial evidenceAPI 批量探测优先用 fetchApiMatrix(paths),单个 API 失败不应让后续证据丢失。
  • deleted/archived/not-found session deep link 验收用 web-probe script 直接 gotoStable('/workbench/sessions/<id>'),再用同源 fetchJson('/v1/workbench/sessions/<id>')、messages 和 list API 断言 404/不在列表;不要调用要求 active session selection、composer readiness 或 workspace repair 的 helper 作为通过条件。
  • 验证 Cloud Web runtime config 或 HTML 注入时,优先加 cache-busting query 和 cache-control: no-cache,并按层拆开判断:Deployment env、Pod 内 127.0.0.1 HTML、公网原始 HTML、浏览器 DOM。不要只凭一次 web-probe DOM 缺字段就判定 rollout 失败;先确认是运行面未渲染、Pod 未滚动、边缘缓存,还是脚本读取层级错误。
  • web-probe 只能观察、截图和断言,不得用 sessionRepairrealignFreshSession、自动点击 session、reload 循环或 workspace selection repair 作为通过条件。发现 routeSessionIdactiveSessionIdactiveConversationId、message session 或 trace session 不一致时,必须记录 mismatch 并失败;截图和 API 摘要是证据,不是修复动作。
  • 失败证据至少保留 failureKinderrorMessagescriptSha256runDirlastUrllastScreenshotprobe.summaryreportPath/reportSha256;默认失败截图是 failure.png

Fake-Server Playwright

Workbench 回归入口在目标 HWLAB repo 的 web/hwlab-cloud-web

bun run e2e:workbench -- --project=chromium

运行面要求:

  • 在 issue/CLI 选中的 node/lane workspace 或其独立 worktree 上运行,不在 master server 本地运行。
  • 同源 fake-server 只提供正式 API 契约,覆盖 /auth/*、session list/detail/messages、turn snapshot、trace event page、Workbench event stream、Performance summary 等当前用例所需端点。
  • 测试断言优先使用用户可见文本、ARIA role 和稳定 DOM 标识;不要通过内部 store、localStorage、数据库或 live API 直接判定通过。
  • 非终态瞬时不变量必须用立即 DOM 快照断言:例如 running/pending 阶段要求 final response 为空时,先定位当前 agent card,再用 locator.evaluate / page.evaluate 直接读取 .message-markdown.message-text 数组并立刻判断;不要用会自动等待的 expect(locator).toHaveCount(0)not.toContainText 或类似负向 locator 断言,否则测试可能等到 terminal DOM 替换后误通过,掩盖 running 阶段污染。
  • 失败必须保留截图、Playwright trace 或等价 artifact;关键路径可生成命名截图。

Workbench 至少覆盖:

  • session 切换后主工作区 loading 和目标 conversation 恢复;
  • 刷新页面后以同一 message/turn/trace 标识还原 timeline
  • SSE 断线、丢事件或重连后通过 REST snapshot 与 trace page 补洞;
  • session tab、workspace card、message card、composer 主按钮、Trace detail 的 running/completed/failed/canceled 一致性;
  • completed assistant 已 sealed 后,turn snapshot、trace event page、SSE 或 realtime diagnostic 失败不覆盖主消息正文,诊断只进入详情/感叹号/transport health
  • Trace 阅读按事件顺序渲染可读 row,正确处理分页、终态、失败、自动展开和终态折叠;
  • deep link 与普通点击 session 走同一 authority path
  • Performance 页的摘要、错误态、刷新、移动端表格可达性和低基数脱敏展示。

Fixture 采集与脱敏

  • 采集范围至少包括 session list/detail/messages、session/turn snapshot、trace event page、Workbench event stream 和 Web performance summaryworkspace selection/config 只有在当前 API 契约仍声明该读模型时才采集。
  • 产物必须记录 capturedFromcapturedAt、schema/redaction 版本和 valuesPrinted=false
  • 使用稳定伪 ID 映射保留 conversation、session、thread、turn、trace、message、sourceSeq 的关系。
  • 删除或替换 HWLAB_API_KEY、cookie、Authorization header、DB DSN、provider token、真实用户身份、非公开 prompt、stdout/stderr 大段原文和完整 provider payload。
  • 真实样本难以覆盖的延迟响应、SSE 断线、分页缺口、列表缺少当前选中项、可选字段异常、空集合和特定 HTTP 错误可以合成,但必须说明来源和原因。

Workbench 判定口径

  • Workbench API 的 GET 路径不是修复入口。若 session/messages/turn/trace 出现状态不一致,应登记为投影唯一性或投影延迟问题,修 backend projector/read model;不得用前端轮询、session 切换、reload、read-through sync 或 GET 内部修复把问题掩盖。
  • Workbench 读侧不得推理生命周期。turn.statusmessage.statussession.runningtrace terminalfinalResponseprojectionStatus 只能来自唯一 durable projectiontrace event row 的 completed 只表示该 event/tool row 完成,不能终结 turn;message 文本为空只表示无可展示正文,不能生成占位 final responselist summary、session detail、turn snapshot、trace page 之间的差异只能作为 diagnostic,不得用优先级函数在读侧“选一个看起来合理的状态”。
  • Workbench sealed final response 必须与读侧诊断分仓。messageProjection 承载 role/status/text/finalResponse/sealedAttraceDetail 承载 events/page hydration/trace diagnosticssessionStatus 承载 rail/card 运行摘要,transportDiagnostics 承载 SSE/poll/hydration timeout 等可见性诊断;等价结构可以使用不同命名,但主消息投影和 diagnostic 不能竞争同一字段。showMessageText()、message diagnostic selector 和组件模板不得让 diagnostic 压过 sealed final response。
  • Workbench trace 视觉顺序的唯一权威是 durable projection 分配的 projectedSeqprojectedSeq 必须由持久化 runtime store 在 trace 内全局递增分配,并按 traceId + sourceEventId 幂等复用;本地 event.seqsourceSeq、事件到达顺序、时间戳、DOM 顺序和 renderer 输入顺序只能作为审计输入或源游标,不能直接派生视觉位置或参与仲裁。重复源事件不能分配新 projectedSeq;不同源事件即使局部 event.seq 重置为 1 也必须分配新的全局 projectedSeq,这个幂等性需要有最小单元测试覆盖。
  • Workbench trace 时间字段的 source truth 是后端和 trace event page 暴露的 ISO/UTC 时间戳;后端 projector、durable read model 和共享 renderer 默认行为不得改成本地时区字符串。Web 展示北京时间或其他用户时区时,只能在 Vue/Web 渲染层从 runtime displayTime 注入 formatterCLI、CaseRun 和原始 trace API 仍显示/返回 UTC,不通过多字段仲裁、默认 fallback 或后端补写时区字符串修显示。
  • Trace event page 检测到同一 trace 内历史 projectedSeq collision 时必须暴露 projectionStatus=blockedprojectionHealth=degraded 和稳定 blocker code,不能把损坏序列交给 CLI/Web renderer 继续展示。CLI/Web trace renderer 只能按 projection 已给定的位置一次渲染;不得通过 assistant 文本相等/包含、final response 匹配、尾部排序、terminal row 合并或 completion row 追加来事后修正视觉顺序。
  • Workbench durable projection 验收必须覆盖同一 session/trace 的 list、detail、messages、turn、trace events 和 DOM session tab/message card;尤其要用 fresh browser 或 runtime 重启后的历史 terminal 样本证明 read model 能从 durable trace events 恢复终态。若内存 trace 仍显示 running 而 durable trace 已 terminal,应修唯一 read model 的投影对象,不得在 GET handler、前端 reducer 或 probe 脚本里做临时状态仲裁。
  • HWLAB #1585/#1596/#1690 是 Workbench 投影禁令的固定判例:AgentRun 已 terminal 但 Workbench 停在旧 seq 时,不得用 GET/read-side 补 resultturn/card completed 但 TraceEventPage seq/range 不合法时,不得用 completed 状态压过 trace 不可读事实;Trace timeline 乱序或 terminal row 重排时,不得让 sourceSeq、局部 event.seq、输入顺序和 renderer 文本匹配多来源仲裁。合法修复是后台 projector/resumer 补 durable projection,在同一 trace event 快照内修正分页/顺序契约,或暴露 historical projection blocker;不得推断 lifecycle、补写 GET、切 session/reload 修页面、添加多来源优先级或在 renderer 做事后 repair。
  • Session rail 会话集合只消费 /v1/workbench/sessions;当前 session detail 只消费 /v1/workbench/sessions/{sessionId};消息本体只消费 /v1/workbench/sessions/{sessionId}/messagesturn 状态只消费 /v1/workbench/turns/{traceId}trace 阅读只消费 /v1/workbench/traces/{traceId}/events 或正式 trace event page。不要让 workspace snapshot、列表摘要、localStorage、trace polling 或 result polling 互相覆盖。
  • 空消息 session 回收验收必须同时证明:未超过 TTL 的空 session 保留,有消息、running/admitting、terminal result 或 active trace 的 session 不被回收;超过 TTL 的空 idle session 由后端 GC 归档/删除后,rail/list/detail/messages/deep link 都按同一 canonical lifecycle 状态表现。
  • UI transient state 只保存 route、显式选择、composer draft、scroll、展开状态和临时交互状态;服务端事实进入 server-state/reducer/projection。
  • running turn 必须同时反映在主任务区、composer 主按钮、session tab 和可取消入口;清空、切换、刷新不得把 running trace 隐藏成空态。
  • 显式新建或选择 session 是 active selection 的 mutation authorityPOST /v1/agent/sessions 返回 201 或用户点击目标 session 后,URL、active tab、当前消息区和 composer 必须立即归属目标 session。目标 session detail/messages 慢只能表现为该目标 session 的 loading/empty 态;旧 session 的 list refresh、detail、turn、trace、SSE 迟到事件只能更新旧 session 自己的 cache/status,不得继续占据或夺回 active route、message area、composer/cancel 状态。
  • 读侧没有破坏性投影权。GET /v1/workbench/sessions、session detail、messages、SSE、route hydrate 或 refreshSessions 的失败、404、空列表、网络错误和迟到响应,只能显示 loading/degraded/unknown/blocker 或保留上一份成功投影;不得 forgetSession()replaceActiveSessionSelection(null)、清空 messages/tabs,或把 composer 改成 session_required。deleted/archived/not-found 必须来自后端 canonical lifecycle projection,或来自用户显式 DELETE mutation 成功后的展示更新。
  • terminal failure、blocked、canceled 都是最终结果;若 API 返回可读 error/blockerfinal response 展示区必须直接显示,不能只放在 trace rows 或详情面板中。
  • completed、failed、canceled、blocked 的 sealed final result 一旦显示,后续 polling/hydration/SSE/realtime 的 timeout、500、gap、close 和 lag 只能改变诊断区,不得把已显示 final response 闪回 Code Agent 代理暂时无法连接上游turn 超时无新活动projection-resume:sync-failed 或同类读侧错误态。
  • session 切换验收必须覆盖点击态和持久化恢复态:选择目标 session、确认 route/session list/detail/messages 归属同一 sessionId、刷新后同一 session 仍 active。
  • completed turn / Trace 重放 / deep link 验收必须用 fresh browser context 或等价 fresh login 直接打开 /workbench/sessions/<sessionId>,不能只用同页 reload。
  • 0repair 验收必须用 fresh context 直达 session/deep link,或从当前 session 显式切换到目标 session;不得依赖测试 helper 选择、reload、切走再切回、sessionRepairrealignFreshSession 修正页面后再判通过。旧 session 的延迟 detail、turn、trace、SSE 或 refreshSessions 晚到,只能更新该 session cache/list,不能改变 active URL、active tab、current messages 或 composer。
  • Workbench reducer/selectors/0repair 收敛类 closeout 必须做负向源码扫描并在 issue/PR 证据里写明结果;至少覆盖直接写服务端事实和旧 repair 名称,例如 messages.value =messages.value.pushsessions.value =previousMessagespreviousSessionIdrestorePreviousrestoreMessagesTraceAuthorityrepairWorkbenchMessagePagefindMessageTextFallbackprojectionCatchupPROJECTION_CATCHUP 和组件侧 workbench.messages。这些扫描是辅助证据,不能替代 fake-server Playwright 与 public web-probe。
  • Trace 实时性要用间隔采样,区分“加载中”和“思考中”;终态卡片不得继续保留“思考中”空态。
  • 用户反馈“当前 session 不刷新、切走再切回才刷新”时,证据必须成对采集:直达目标 URL、原地等待、切到其他 session、切回目标 session 的 DOM 截图;同时记录 session list、session detail、messages、turn snapshot 和 trace event page 的状态。issue 正文要明确这是事件投影/重放问题,不能只登记成普通 deep link 或单接口 404。

Performance 页判定口径

  • /performance 只展示低基数、脱敏的 Workbench/RUM/API/long task 汇总;不得泄露 conversationIdsessionIdtraceIdrunId、prompt、assistant 正文、tool 参数、stdout/stderr、Secret 或用户身份。
  • 单位以 API unit 为准;后端若以 seconds 存储,前端显示 ms 时必须只做一次换算。
  • 移动端和窄屏断言要检查目标表格/按钮是否可见、可点击、layout rect 非零且可触达;不要只用 desktop selector readiness 代表所有 viewport。
  • 刷新按钮应有明确 loading/error/empty 状态,重复点击不能制造 stuck loading、旧数据冒充新数据或未捕获 console/page error。

UniDesk Frontend E2E

UniDesk 主前端交付门禁仍由 bun scripts/cli.ts e2e run 承担;本技能规定浏览器侧如何选取和解释验证。

  • 先跑最小相关选择集,例如 bun scripts/cli.ts e2e run --only frontend:pipeline;目标检查通过后再跑完整 bun scripts/cli.ts e2e run。选择集是真执行,不是输出过滤。
  • 浏览器必须打开 config.json / publicHost 派生的公开 frontend 或 dev frontend proxy;不要用 localhost、Docker internal URL 或后端 API 直调替代用户入口。
  • 前端断言优先使用用户可见文本、ARIA role、稳定 DOM 标识和 React 控件状态;禁止用 raw JSON、内部 store、localStorage 或后端数据库绕过 UI。
  • 高信息密度区域如 Pipeline 右侧栏、Trace timeline、详情抽屉、甘特图坐标、资源监控表和 Performance 面板,必须显式检查总高度、横向滚动条、关键控件可见可点、文本不重叠。
  • 用户服务页必须等待真实后端数据,而不是只看页面骨架;Todo Note、OA Event Flow、Code Queue、FindJob、Pipeline、MET Nonlinear、ClaudeQQ 等页面的通过条件以当前 E2E check 名称和 issue scope 为准,不在文档里复制所有字段清单。
  • raw JSON 只能在用户显式点击 查看原始JSON 后出现;默认页面必须把 JSON 渲染为表格、卡片、徽章、树、图或其他可读控件。
  • 任何 frontend E2E 失败都应保留截图路径、resultPath、failedChecks 和关键 console/page error 摘要;不要把 missing browser/deps 当作 skip,按锁文件和目标执行面补依赖后继续。

受控 web-probe 代替裸 Playwright

UniDesk/HWLAB Web 工作不再把裸 Playwright 当作默认操作面。需要截图、DOM 断言、API matrix、route/intercept、SSE 降级、长程 session 采样、性能页面复测或 Workbench 多轮任务时,统一选择 web-probe run|script|observe

web-probe observe analyze 必须把 Workbench session 列表标题纳入默认采样与报告:可见列表中 Session ses_... fallback 标题超过一半时输出红灯 finding。修复方向必须让上游 session list projection 直接携带名称;点击详情后的下游补名、reload repair 或多来源仲裁不能作为修复。

trans <route> playwrightplaywright-cli 和临时 Node Playwright 脚本只允许作为非 HWLAB 外站短生命周期截图/PDF、或 web-probe 尚未覆盖且一次性不可复用的诊断例外。例外使用前必须写明为什么 web-probe scriptweb-probe observe 不适用;同类动作出现第二次就应补进 web-probe CLI 或 repo-owned probe。

需要把截图回传到本机时,优先用 web-probe scriptscreenshot(name),或长程观测中使用 observe command --type screenshot --label <label>,并在 issue 中引用截图 SHA、report SHA、observer id 和 stateDir。不要把本地 Playwright artifact 当作 HWLAB node/lane 原入口验收替代品。