27 KiB
27 KiB
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.md 和 PJ2026-01060505-workbench-performance.md;本技能只规定如何开发、采集、复现和验收。
P0 防分叉原则
- 单一权威入口:先按 issue/CLI 明确的 node + lane 解析 workspace、public origin、namespace、sourceRef 和目标分支。没有明确目标时才读取受控 YAML;不得把 D601、G14、v0.2、v0.3、旧端口或本地 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 ?? B、if 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、最后一条 eventcompleted、message fallback、session fallback、elapsed timeout 或 UI heuristic 补造事实。 - 无多路径、无 fallback:这是本技能的核心原则。Web、CLI、fake-server 和线上 web-probe 必须复用同一套 API 契约、同一 route/session/conversation/trace authority 和同一状态投影;不得为了让测试通过增加第二套 dispatcher、localStorage 真相、workspace snapshot 真相、内部 manager 调用、旧 lane 端口、raw request、临时兼容路径或“测试专用后门”。
- 严禁事后 repair / 0repair:Web、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。投影滞后必须显式暴露projectionStatus、lastProjectedSeq、sourceRunId、blocker或等价诊断字段,并由后台 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 mutation;Web reducer/selectors、route hydrate、GET/list/detail/messages/SSE consumer、fake-server 和测试 helper 都不能由读侧失败、404、空列表、网络瞬断或 late response 触发这些 mutation。只有用户显式 mutation 成功,或后端 canonical lifecycle projection,能改变 session lifecycle。需求真相见 UniDesk OAPJ2026-010401 Web工作台的“破坏性投影权”。 - fake-server 不是第二后端:它只按正式 API 契约重放脱敏 fixture 和必要边界变形。未 mock 的
/auth/*、/v1/*、/health*请求应失败并暴露 path;不得访问 live Cloud API、AgentRun、HWPOD、数据库或 Kubernetes 作为通过条件。 - 真实数据优先:fixture seed 优先从目标 node/lane 的受控真实样本采集。合成 fixture 只补真实样本难以稳定覆盖的边界,并标明
derivedFrom与syntheticReason。 - 原入口闭环:fake-server Playwright 用例负责可重复红灯和源码回归;线上
hwlab nodes 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。
工作流
- 定位目标:确认 repo、node、lane、workspace、public origin 和目标 SPEC。HWLAB D601 v0.3 例子是
/home/ubuntu/workspace/hwlab-v03+https://hwlab.pikapython.com,但只能在 issue/CLI 指向该目标时使用。 - 读规则:进入目标 workspace 前读取目标
AGENTS.md;涉及规格或测试设计时读取 UniDesk OA 对应 SPEC。 - 线上复现:用
hwlab nodes web-probe run|script在目标 public origin 复现用户现象,保存scriptSha256、runDir、截图名、截图 SHA、URL、DOM/API 摘要。 - 建红灯:修 Workbench/Performance 用户可见 bug 前,在目标 HWLAB workspace 的
web/hwlab-cloud-webfake-server Playwright 套件中补确定性用例;fixture 从真实采集样本脱敏产生。 - 修源码:保持状态读写单一路径。状态投影类修复优先收敛 server-state/reducer/projection,不在 UI 组件、trace polling、result polling 或 localStorage 中新增竞争事实。
- 验证:先跑 fake-server Playwright 目标用例,再回到同一 node/lane public origin 用 web-probe 复测;截图和报告作为证据回传,不进入源码仓库。
- 写 issue/closeout:问题登记和收口必须写明目标合并分支、node/lane、fixture 来源、Playwright fake-server 用例、线上 web-probe 命令/脚本 SHA、截图 SHA 和剩余边界。
HWLAB Web Probe
线上 Cloud Web DOM 验收优先使用受控入口:
bun scripts/cli.ts hwlab nodes web-probe run --node D601 --lane v03
需要 Playwright route/intercept、延迟 API、读取 in-flight DOM 或截图时使用:
bun scripts/cli.ts hwlab nodes 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
约束:
web-probe script不运行默认探针,必须通过 stdin heredoc 或--script-file <path>提供脚本;只需要 repo-owned 标准 DOM probe 时使用web-probe run。- stdin heredoc 与
--script-file都按 ES module 加载,脚本必须导出export default async ({ page, gotoStable, recordStep, ... }) => { ... };不要在模块顶层直接写return。失败为Illegal return statement、does not provide an export named default或 finalUrl 仍是about:blank且 stepCount=0 时,先按 probe 脚本入口误用处理,不要归因成 Cloud Web 行为失败。 - web-probe 由 UniDesk CLI 从 YAML 声明的 bootstrap admin sourceRef 读取凭据并建立同源
hwlab_session;脚本不得自行读取、打印或复制 Web 登录凭据、cookie、token 或完整 API key。 - 脚本构造 URL 时使用
new URL(path, baseUrl).toString();不要拼出//v1/...。 - 先通过
gotoStable、waitWorkbenchReady或等价导航进入目标 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 的通过条件。 - HWLAB v0.3
fa2ad4845a111e0f9e86d473eb4204ed1b2b0a3c后,repo-ownedscripts/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 jobweb-live-dom-probe-1781842424721-44066:freshSessionAligned=true、messageCount=0、report SHAd34c6765943e14bbd639b91bfc17139d582f670ed5cf409a957acd40fae7871f、screenshot SHA8d341b7c30293baa9be8f1e63e147ea0fdafbdbcfc43f0b05e4fb9f316ef996c。- 若带
--message的 fresh-session 路径已经达到freshSessionAligned=true、promptSubmitted=true、messageCount>0和 session API 200,但随后报trace-id-missing、Workbench 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 上下文,浏览器全局window、document、location、CSS只在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.origin、CSS.escape(...),也不要用没有 baseURL 的page.goto('/relative/path')。若失败为location is not defined、CSS is not defined或相对 URL invalid,先按脚本误用处理;工具提示改进跟踪见 pikasTech/unidesk#479。- 脚本中用
recordStep(name, data)保存关键 DOM/API partial evidence;API 批量探测优先用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.1HTML、公网原始 HTML、浏览器 DOM。不要只凭一次 web-probe DOM 缺字段就判定 rollout 失败;先确认是运行面未渲染、Pod 未滚动、边缘缓存,还是脚本读取层级错误。 - web-probe 只能观察、截图和断言,不得用
sessionRepair、realignFreshSession、自动点击 session、reload 循环或 workspace selection repair 作为通过条件。发现routeSessionId、activeSessionId、activeConversationId、message session 或 trace session 不一致时,必须记录 mismatch 并失败;截图和 API 摘要是证据,不是修复动作。 - 失败证据至少保留
failureKind、errorMessage、scriptSha256、runDir、lastUrl、lastScreenshot、probe.summary和reportPath/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一致性; - Trace 阅读按事件顺序渲染可读 row,正确处理分页、终态、失败、自动展开和终态折叠;
- deep link 与普通点击 session 走同一 authority path;
- Performance 页的摘要、错误态、刷新、移动端表格可达性和低基数脱敏展示。
Fixture 采集与脱敏
- 采集范围至少包括 session list/detail/messages、session/turn snapshot、trace event page、Workbench event stream 和 Web performance summary;workspace selection/config 只有在当前 API 契约仍声明该读模型时才采集。
- 产物必须记录
capturedFrom、capturedAt、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.status、message.status、session.running、trace terminal、finalResponse、projectionStatus只能来自唯一 durable projection;trace event row 的completed只表示该 event/tool row 完成,不能终结 turn;message 文本为空只表示无可展示正文,不能生成占位 final response;list summary、session detail、turn snapshot、trace page 之间的差异只能作为 diagnostic,不得用优先级函数在读侧“选一个看起来合理的状态”。 - 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 是 Workbench 投影禁令的固定判例:AgentRun 已 terminal 但 Workbench 停在旧 seq 时,不得用 GET/read-side 补 result;turn/card completed 但 TraceEventPage seq/range 不合法时,不得用 completed 状态压过 trace 不可读事实。合法修复是后台 projector/resumer 补 durable projection,或在同一 trace event 快照内修正分页输出契约;不得推断 lifecycle、补写 GET、切 session/reload 修页面或添加多来源优先级。
- Session rail 会话集合只消费
/v1/workbench/sessions;当前 session detail 只消费/v1/workbench/sessions/{sessionId};消息本体只消费/v1/workbench/sessions/{sessionId}/messages;turn 状态只消费/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 authority;
POST /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/blocker,final response 展示区必须直接显示,不能只放在 trace rows 或详情面板中。
- 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、切走再切回、
sessionRepair或realignFreshSession修正页面后再判通过。旧 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.push、sessions.value =、previousMessages、previousSessionId、restorePrevious、restoreMessagesTraceAuthority、repairWorkbenchMessagePage、findMessageTextFallback、projectionCatchup、PROJECTION_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 汇总;不得泄露conversationId、sessionId、traceId、runId、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,按锁文件和目标执行面补依赖后继续。
跨 Host Playwright
非 HWLAB 或确实需要把截图/PDF 自动回传到本机时,使用 trans <route> playwright:
trans D601 playwright --local-dir /tmp <<'PW'
playwright-cli screenshot https://example.com "$UNIDESK_PLAYWRIGHT_SCREENSHOT" --full-page
PW
多步交互必须写在同一个 heredoc,并显式等待关键 HTTP response 和稳定 selector。该入口只负责短生命周期浏览器执行和 artifact 回传,不提供长驻 browser daemon;HWLAB node/lane Cloud Web 验收仍优先使用 hwlab nodes web-probe script。