docs: record hwlab mirror and web probe lessons

This commit is contained in:
Codex
2026-06-17 17:05:46 +00:00
parent 6db0d228c0
commit 1e84af7441
4 changed files with 11 additions and 9 deletions
+3 -3
View File
@@ -129,11 +129,11 @@ bun scripts/cli.ts hwlab nodes git-mirror flush --node D601 --lane v03 --confirm
PipelineRun `gitops-promote` 如果报 git mirror 控制面漂移、refs 不一致或 flush/publish 未完成,优先按当前 `devops-infra/git-mirror.yaml` 收敛:先 `git-mirror apply --confirm`,再 `git-mirror sync --confirm --wait`,然后用 `control-plane cleanup-runs --pipeline-run <failed-run> --confirm` 受控清理失败 PipelineRun 后重试。旧 branch/path allowlist gate 已删除,不要恢复旧 hook、直接 `kubectl delete`、手工 patch pod 内 hook 或绕过 `flush`
手动 trigger closeout 不能只看 PipelineRun `Completed`。必须继续查 `control-plane status --pipeline-run <name>``git-mirror status` `pendingFlush=true`,执行 `git-mirror flush --confirm --wait``githubInSync=true`
手动 trigger closeout 不能只看 PipelineRun `Completed`。必须继续查 `control-plane status --pipeline-run <name>``git-mirror status`node-scoped `trigger-current --confirm --wait` 会自动做必要的 mirror pre/post flush,但 closeout 仍要确认最终 `pendingFlush=false``githubInSync=true`。如果 lower-level 手工路径或旧 job 留下 `pendingFlush=true`,执行 `git-mirror flush --confirm --wait``githubInSync=true`
D601 `v0.3` 固定 worktree 的 fetch remote 是 node-local git mirror。GitHub PR 合并后,如果 `D601:/home/ubuntu/workspace/hwlab-v03``git fetch origin v0.3` 仍看不到最新 merge commit,先执行 `hwlab nodes git-mirror sync --node D601 --lane v03 --confirm --wait`,再在固定 worktree `git fetch origin v0.3 && git pull --ff-only origin v0.3``trigger-current --lane v03` 会为 PipelineRun 做 mirror pre-sync,但不替代固定 worktree 的 fetch hygiene。promotion 后若 node-local `git-mirror status` 显示 `pendingFlush=true`,执行 node-local flush 并等到 `pendingFlush=false``githubInSync=true`
D601 `v0.3` 固定 worktree 的 fetch remote 是 node-local git mirror。GitHub PR 合并后,如果 `D601:/home/ubuntu/workspace/hwlab-v03``git fetch origin v0.3` 仍看不到最新 merge commit,先执行 `hwlab nodes git-mirror sync --node D601 --lane v03 --confirm --wait`,再在固定 worktree `git fetch origin v0.3 && git pull --ff-only origin v0.3``sync` 遇到 GitHub SSH transient 时应走 target workspace fallback,把 GitHub source/gitops 通过 `ssh.github.com:443` 拉回并写入 node-local mirror;输出只披露 commit、mirror URL 和 fallback 状态。`trigger-current --lane v03` 会为 PipelineRun 做 mirror pre-sync,但不替代固定 worktree 的 fetch hygiene。promotion 后若 node-local `git-mirror status` 显示 `pendingFlush=true`,执行 node-local flush 并等到 `pendingFlush=false``githubInSync=true`
D601/node-scoped mirror status 的 `githubGitops` 来自本地 mirror cache 的 `refs/mirror-stage/...``status` 输出应通过 `refSources.githubFieldsAreMirrorStageCache=true` 显示这一点。`hwlab nodes git-mirror flush --node D601 --lane v03 --confirm --wait` 如果已经显示 `v0.3-gitops -> v0.3-gitops` 推送成功,但随后因 GitHub SSH `kex_exchange_identification` 或 fetch 确认失败导致命令非零退出,会标记 `partialSuccess=push-succeeded-fetch-failed`把下一步指向 `hwlab nodes git-mirror sync --node D601 --lane v03 --confirm --wait`。不要连续盲目 flush;先刷新 mirror-stage,再用 status 确认 `localGitops=githubGitops``pendingFlush=false``githubInSync=true`
D601/node-scoped mirror status 的 `githubGitops` 来自本地 mirror cache 的 `refs/mirror-stage/...``status` 输出应通过 `refSources.githubFieldsAreMirrorStageCache=true` 显示这一点。`hwlab nodes git-mirror flush --node D601 --lane v03 --confirm --wait` 如果已经显示 `v0.3-gitops -> v0.3-gitops` 推送成功,但随后因 GitHub SSH `kex_exchange_identification` 或 fetch 确认失败导致命令非零退出,会标记 `partialSuccess=push-succeeded-fetch-failed`。当前 CLI 会自动做一次受控 sync/recheck;恢复后输出 `partialSuccessRecovered=true``postPushRecovery` 且整体 `ok=true`,未恢复时才把下一步指向 `hwlab nodes git-mirror sync --node D601 --lane v03 --confirm --wait`。不要连续盲目 flush;先刷新 mirror-stage,再用 status 确认 `localGitops=githubGitops``pendingFlush=false``githubInSync=true`
---
+4 -4
View File
@@ -22,15 +22,15 @@ CI/CD、GitOps、rollout、artifact 发布、PR 合并后的 runtime lane 滚动
G14/D601 v03 的 bootstrap admin password 是 HWLAB runtime Secret 生命周期的一部分,必须收敛到 `config/hwlab-node-lanes.yaml``bootstrapAdmin` 声明与受控 `hwlab nodes secret status|ensure --node <node> --lane v03 --name hwlab-v03-bootstrap-admin` CLI。明文只能存在于 Git 忽略、owner-only 的 `.state/secrets/...` sourceRef 文件;CLI 在本地把明文转换为 HWLAB 兼容 password hash,只向运行面同步 `password-hash`,并在输出中只披露 sourceRef、sourceKey、target Secret/key、presence、byte count、fingerprint、mutation 与后续命令。`secret ensure --force` 只用于明确需要按 YAML sourceRef 重灌 bootstrap admin hash 并重启 Cloud API 的受控恢复场景,默认 ensure 不做强制重灌;不要把人工生成 hash、手工写 k8s Secret 或原生 `kubectl rollout` 沉淀为长期入口。
`hwlab nodes web-probe run --node <node> --lane <lane> [--url <public-origin>]` 是 HWLAB Cloud Web DOM probe 的受控指挥入口。它从 `config/hwlab-node-lanes.yaml` 解析目标 workspace、public URL 和 bootstrap admin sourceRef,在 UniDesk 指挥侧读取 owner-only 明文后只通过一次性 stdin/env 注入目标 workspace 的 `scripts/web-live-dom-probe.mjs`stdout 只披露 sourceRef、sourceKey、presence、fingerprint、注入方式、DOM 摘要和 artifact hash,不打印密码。缺少 sourceRef 或 source 文件时应结构化返回 `web_login_secret_missing`,不能回退历史默认密码或要求把 secret 复制到 D601/G14 目标 host。Code Agent Trace 实时性验收使用 `--trace-sample-count <N>``--trace-sample-interval-ms <ms>` 透传到目标 helper,输出每次采样的 agent status、trace presence/status、row count、empty label 和最新 row preview,用于证明运行中渐进拉取;这类采样不能由终态截图替代。CLI 默认按 trace 采样窗口、terminal wait 和页面 timeout 自动扩展短连接 `commandTimeout`,显式 `--command-timeout-seconds` 只允许延长该预算,不应把 90-180s 采样压回 60s。需要自定义 Playwright route/intercept、in-flight DOM 读取或专用截图时,使用 `hwlab nodes web-probe script --node <node> --lane <lane> <<'JS' ... JS`,由 CLI 负责同一 sourceRef 凭据解析、`/auth/login` 建立 `hwlab_session`、已认证 `browser/context/page/baseUrl` 注入和 artifact path/hash 摘要;自定义脚本不得自行读取或打印 Web 登录凭据。`web-probe script` 托管登录先对同源 `/auth/login` 做短重试;仍未拿到 `hwlab_session` 时自动回到当前 Cloud Web 登录表单,以浏览器方式提交同一凭据。`probe.auth` 只输出 method、origin、loginPath、status、attempts、retryCount、fallbackUsed、fallback、retryable、transientObserved、fingerprint、commanderAction 和 redacted errorSummary,不打印密码、cookie 或可复制 session 值。
`hwlab nodes web-probe run --node <node> --lane <lane> [--url <public-origin>]` 是 HWLAB Cloud Web DOM probe 的受控指挥入口。它从 `config/hwlab-node-lanes.yaml` 解析目标 workspace、public URL 和 bootstrap admin sourceRef,在 UniDesk 指挥侧读取 owner-only 明文后只通过一次性 stdin/env 注入目标 workspace 的 `scripts/web-live-dom-probe.mjs`stdout 只披露 sourceRef、sourceKey、presence、fingerprint、注入方式、DOM 摘要和 artifact hash,不打印密码。缺少 sourceRef 或 source 文件时应结构化返回 `web_login_secret_missing`,不能回退历史默认密码或要求把 secret 复制到 D601/G14 目标 host。Code Agent Trace 实时性验收使用 `--trace-sample-count <N>``--trace-sample-interval-ms <ms>` 透传到目标 helper,输出每次采样的 agent status、trace presence/status、row count、empty label 和最新 row preview,用于证明运行中渐进拉取;这类采样不能由终态截图替代。CLI 默认按 trace 采样窗口、terminal wait 和页面 timeout 自动扩展短连接 `commandTimeout`,显式 `--command-timeout-seconds` 只允许延长该预算,不应把 90-180s 采样压回 60s;当自动预算超过短连接安全窗口时,`run` 必须切到 helper `start/status` 异步轮询并在输出中标记 `transportMode=async-start-status`、job id、poll count、timedOut 和最终 report。需要自定义 Playwright route/intercept、in-flight DOM 读取或专用截图时,使用 `hwlab nodes web-probe script --node <node> --lane <lane> <<'JS' ... JS`,由 CLI 负责同一 sourceRef 凭据解析、`/auth/login` 建立 `hwlab_session`、已认证 `browser/context/page/baseUrl` 注入和 artifact path/hash 摘要;自定义脚本不得自行读取或打印 Web 登录凭据。`web-probe script` 托管登录先对同源 `/auth/login` 做短重试;仍未拿到 `hwlab_session` 时自动回到当前 Cloud Web 登录表单,以浏览器方式提交同一凭据。`probe.auth` 只输出 method、origin、loginPath、status、attempts、retryCount、fallbackUsed、fallback、retryable、transientObserved、fingerprint、commanderAction 和 redacted errorSummary,不打印密码、cookie 或可复制 session 值。
`web-probe script` 的默认 `goto('/workbench')` 是稳定导航边界:它会先复用当前 page,失败后有限次切 fresh page 重试,并等待 workbench 基础 DOM(默认 `#workspace``#command-input`)可见;需要显式控制时使用注入的 `gotoStable(target, { selectors, activeSelector, attempts, readinessTimeoutMs })``waitWorkbenchReady({ selectors })``waitForReady({ selectors })``gotoRaw()``getPage()`。稳定化失败必须在 `probe.readiness` 中低噪声披露 attempt、阶段、selector、是否观察到 `/v1` API request、API failure 摘要和失败截图 artifact;分类值固定为 `browser-load-jitter``selector-timeout``api-not-sent``api-response-failed`,避免把“页面没准备好/请求未发出”和“后端响应失败”混成同一种 selector timeout。runner 不在用户脚本执行前抢先导航同一 page,保证脚本仍可先安装 `page.route` 或 context route;如重试切换 fresh page,后续脚本应通过 `gotoStable()` 返回值或 `getPage()` 取得当前 page。
`web-probe script` 的调试 helper 必须覆盖常见 Workbench 探针动作:`fetchJson(path)` 在已登录页面上下文里按同源 cookie 请求 JSON,失败返回 `{ ok:false, path, status, error }` 而不是吞掉证据;`collectText(selector)` 返回 selector 命中数量和文本摘要;`safeEvaluate(fn, arg)` 固定使用 Playwright 单参数规则;`screenshotOnError(name, fn)` 在用户断言抛错时落 `failure.png``summarizeWorkspace()``summarizeConversation()` 只输出会话/消息摘要,不打印 cookie、密码或 token。可复用脚本优先用 `--script-file <path>`,一次性探针才用 stdin heredoc。Playwright `page.evaluate` 只能传一个可序列化参数;需要多个值时必须写成 `page.evaluate(({ a, b }) => ..., { a, b })` 或使用 `safeEvaluate(fn, { a, b })`。脚本抛错或返回 `{ ok:false }` 时,`probe` 顶层必须保留 `failureKind=script-api-misuse|assertion-failed|navigation-failed|auth-failed|browser-failed``errorMessage``scriptSha256``runDir``lastUrl``lastScreenshot`;默认失败截图文件名是 `failure.png`,调用方脚本源码保存在同一 `runDir` 以便复查。
`web-probe script` 的调试 helper 必须覆盖常见 Workbench 探针动作:`fetchJson(path)` 在已登录页面上下文里按同源 cookie 请求 JSON,失败返回 `{ ok:false, path, status, error }` 而不是吞掉证据;`collectText(selector)` 返回 selector 命中数量和文本摘要;`safeEvaluate(fn, arg)` 固定使用 Playwright 单参数规则;`screenshotOnError(name, fn)` 在用户断言抛错时落 `failure.png``summarizeWorkspace()``summarizeConversation()` 只输出会话/消息摘要,不打印 cookie、密码或 token。workspace/conversation/trace 采样必须保留 project authority:摘要中输出 projectIdtrace 请求优先使用 conversation/workspace projectId;遇到 `trace_project_mismatch` 时输出 `requestProjectId``requestScoped``errorCode`、HTTP status/bodyPreview/degradedReason,并允许降级尝试无 projectId 查询,不能退化成无上下文的 `Failed to fetch`可复用脚本优先用 `--script-file <path>`,一次性探针才用 stdin heredoc。Playwright `page.evaluate` 只能传一个可序列化参数;需要多个值时必须写成 `page.evaluate(({ a, b }) => ..., { a, b })` 或使用 `safeEvaluate(fn, { a, b })`。脚本抛错或返回 `{ ok:false }` 时,`probe` 顶层必须保留 `failureKind=script-api-misuse|assertion-failed|navigation-failed|auth-failed|browser-failed``errorMessage``scriptSha256``runDir``lastUrl``lastScreenshot`;默认失败截图文件名是 `failure.png`,调用方脚本源码保存在同一 `runDir` 以便复查。
`hwlab nodes control-plane infra plan|status|apply --node D601 --lane v03` 是 D601 HWLAB v03 节点本地 CI/CD 与 git-mirror 前置控制面的 YAML 驱动入口,配置真相源是 `config/hwlab-node-control-plane.yaml``plan` 只读展示 YAML target 和将渲染的 control-plane 对象;`status` 只读观察 D601 Tekton、CI namespace、git-mirror、Argo、node-local registry 和 tools image readiness`apply --dry-run` 只输出 manifest 摘要;`apply --confirm` 只收敛 D601 control-plane bootstrap 对象,不触发 HWLAB runtime rollout,不创建 PK01 DB,也不修改 Caddy/FRP。tools image 的 node-local registry 地址只能作为输出 artifact;输入 base image 必须由 YAML 声明为公开 registry 来源,缺少 output image 时应在 `status.next.blockers` 中体现,而不是把现有 node-local image 当成输入基础镜像。
`hwlab nodes git-mirror status|sync|flush --node <node> --lane <lane>` 是 node-scoped runtime lane 的 Git mirror 维护入口。`status``githubSource` / `githubGitops` 来自本地 mirror cache 的 `refs/mirror-stage/...`,不是实时 GitHub API;输出中的 `refSources.githubFieldsAreMirrorStageCache=true``refSources.cacheRefresh` 给出这一来源和刷新命令。`flush --confirm --wait` 如果已经把 GitOps ref push 到 GitHub,但 post-push fetch/recheck 因 transient SSH 失败而无法刷新 mirror-stage,会返回 `partialSuccess=push-succeeded-fetch-failed``degradedReason=node-runtime-git-mirror-flush-post-push-fetch-failed`,并把下一步指向 `sync --confirm --wait` 后再查 `status`不要把这种 partial success 解读为需要连续盲目 flush。`hwlab nodes control-plane trigger-current --node <node> --lane <lane> --confirm --wait` 会在 source sync 后自动执行必要的 pre-flush,在 PipelineRun terminal 后自动执行必要的 post-flushprogress 事件必须显式输出 `git-mirror-pre-flush` / `git-mirror-post-flush` 的 executed/skipped、jobName、local/github source、local/github GitOps、`pendingFlush``githubInSync``control-plane status` 仍是只读入口,只暴露 compact `gitMirror` 摘要和下一步 flush 命令,不隐式执行写操作。
`hwlab nodes git-mirror status|sync|flush --node <node> --lane <lane>` 是 node-scoped runtime lane 的 Git mirror 维护入口。`status``githubSource` / `githubGitops` 来自本地 mirror cache 的 `refs/mirror-stage/...`,不是实时 GitHub API;输出中的 `refSources.githubFieldsAreMirrorStageCache=true``refSources.cacheRefresh` 给出这一来源和刷新命令。`sync --confirm --wait` 的 k3s Job 遇到 GitHub SSH transient 时,应通过目标 workspace fallback 拉取 GitHub source/gitops 并写回 node-local mirror,输出只披露 commit、mirror write URL 和 fallback 状态。`flush --confirm --wait` 如果已经把 GitOps ref push 到 GitHub,但 post-push fetch/recheck 因 transient SSH 失败而无法刷新 mirror-stage,会标记 `partialSuccess=push-succeeded-fetch-failed`;CLI 应自动执行一次受控 sync 刷新 mirror-stage,若恢复后 `pendingFlush=false``githubInSync=true`,结果应为 `ok=true` 并输出 `partialSuccessRecovered` / `postPushRecovery`,否则才保留 `degradedReason=node-runtime-git-mirror-flush-post-push-fetch-failed`下一步 `sync --confirm --wait`不要把这种 partial success 解读为需要连续盲目 flush。`hwlab nodes control-plane trigger-current --node <node> --lane <lane> --confirm --wait` 会在 source sync 后自动执行必要的 pre-flush,在 PipelineRun terminal 后自动执行必要的 post-flushprogress 事件必须显式输出 `git-mirror-pre-flush` / `git-mirror-post-flush` 的 executed/skipped、jobName、local/github source、local/github GitOps、`pendingFlush``githubInSync`,且已恢复的 partial success 不能让顶层 trigger-current false-fail`control-plane status` 仍是只读入口,只暴露 compact `gitMirror` 摘要和下一步 flush 命令,不隐式执行写操作。
`hwlab nodes control-plane infra tools-image status|build|logs --node D601 --lane v03` 是 D601 tools image 的受控入口。Dockerfile 必须由 `config/hwlab-node-control-plane.yaml``tekton.toolsImage.dockerfileInline` 声明,输入镜像必须列在 `publicBaseImages`,构建参数和网络模式也来自 YAMLconfirmed build 只在 D601 后台异步构建并推送到 node-local registry,返回 status/logs 轮询命令。`hwlab nodes control-plane infra argo status|apply|logs --node D601 --lane v03` 是 D601 Argo CD 的声明式安装入口。Argo 版本、官方 manifest URL、镜像 rewrite/preload、field manager、imagePullPolicy、CRD 列表、期望 Deployment/StatefulSet 以及生成的 AppProject/Application 都必须来自同一个 YAML`argo apply --confirm` 只执行可重复 server-side apply 和后台轮询,不把原生 `kubectl apply`、手工 Argo CLI 或临时 manifest 作为正式安装路径。
@@ -167,7 +167,7 @@ PW
长时操作采用 Fire-and-Forget 模式:CLI 创建 `.state/jobs/{jobId}.json`,后台进程执行真实命令,并将 stdout、stderr 分别写入 `.state/jobs/{jobId}.stdout.log``.state/jobs/{jobId}.stderr.log`。调用者通过 `bun scripts/cli.ts job status <jobId>` 查询进度和尾部输出。
异步 job 的返回值只表示控制动作已经排入后台执行,不表示目标运行面对象已经创建或收敛。所有带 `statusCommand` 的返回都必须先用 `job status <jobId>` 查看 `progress.stage``progress.stageStatus`、关键对象名和 `nextCommand`;只有 progress 已进入对应创建/完成阶段后,才进入更重的运行面 status。对于 `hwlab g14 control-plane trigger-current --lane v02 --confirm``progress.pipelineRun` 在 refresh 或 mirror pre-sync 阶段可能只是预期 PipelineRun 名称;在 `progress.stage=create-pipelinerun``progress.pipelineCreated=true` 前,`control-plane status --pipeline-run <name>` 返回 not found 只能说明 PipelineRun 尚未创建,不能当作 CI/CD 失败。对于 `git-mirror sync|flush --confirm`,先看 job progress 和 timing 摘要,再用对应 `git-mirror status` 确认 `pendingFlush`、local/github refs 和 `githubInSync`node-scoped `flush` 的 progress 若出现 `partialSuccess=push-succeeded-fetch-failed``nextCommand` 会直接指向同 node/lane 的 `sync --confirm --wait` 刷新 mirror-stage cache。
异步 job 的返回值只表示控制动作已经排入后台执行,不表示目标运行面对象已经创建或收敛。所有带 `statusCommand` 的返回都必须先用 `job status <jobId>` 查看 `progress.stage``progress.stageStatus`、关键对象名和 `nextCommand`;只有 progress 已进入对应创建/完成阶段后,才进入更重的运行面 status。对于 `hwlab g14 control-plane trigger-current --lane v02 --confirm``progress.pipelineRun` 在 refresh 或 mirror pre-sync 阶段可能只是预期 PipelineRun 名称;在 `progress.stage=create-pipelinerun``progress.pipelineCreated=true` 前,`control-plane status --pipeline-run <name>` 返回 not found 只能说明 PipelineRun 尚未创建,不能当作 CI/CD 失败。对于 `git-mirror sync|flush --confirm`,先看 job progress 和 timing 摘要,再用对应 `git-mirror status` 确认 `pendingFlush`、local/github refs 和 `githubInSync`node-scoped `flush` 的 progress 若出现 `partialSuccess=push-succeeded-fetch-failed`先看是否同时有 `partialSuccessRecovered=true``postPushRecovery`,未恢复时再按 `nextCommand` 执行同 node/lane 的 `sync --confirm --wait` 刷新 mirror-stage cache。
定点状态查询优先使用后台 job 输出的稳定对象名:PipelineRun 用 `hwlab g14 control-plane status --lane v02 --pipeline-run <name>`,已知 source commit 用 `--source-commit <full-sha>`。不要在 source branch 可能继续推进时用默认最新 head status 判定历史 run 成败;默认最新 head 口径只适合判断当前 lane 是否整体最新。`control-plane status` 会汇总 source、mirror、Tekton、Argo、runtime workload 和公网探针,可能比普通只读命令慢;高频轮询应先用 `job status` 或更窄的 status,完整 status 留给阶段收口和异常定位。
+1 -1
View File
@@ -81,7 +81,7 @@ The `devops-infra` git mirror/relay remains manual and CLI-controlled, not CronJ
After a `v0.2` PipelineRun completes, treat runtime rollout and remote GitOps persistence as two separate checks. `hwlab g14 control-plane status --lane v02` is the runtime check: it must show the expected source commit, PipelineRun completed, Argo `Synced/Healthy`, public 19666/19667 probes passing, and Cloud Web asset probes such as `/app.js` readable. `hwlab g14 git-mirror status` is the persistence check: `cache.summary.pendingFlush` must be false and `cache.summary.githubInSync` true before declaring GitOps fully flushed back to GitHub. The PR monitor performs this flush automatically for its own merged PRs and records the result in the PR comment. Manual operators should run `bun scripts/cli.ts hwlab g14 git-mirror flush --confirm` and poll the returned job with `bun scripts/cli.ts job status <jobId> --tail-bytes 12000` only when they used lower-level manual trigger/status paths or when the monitor reports a flush failure; do not replace this with raw `kubectl`, native `git push`, or a long SSH wait.
For D601/node-scoped runtime lanes, `hwlab nodes git-mirror status --node <node> --lane <lane>` reports GitHub refs from the mirror cache's `refs/mirror-stage/...`, not from a live GitHub API request. The status output must keep that source visible through `refSources.githubFieldsAreMirrorStageCache=true`. A `flush --wait` run can push the GitOps ref successfully and still exit non-zero if the follow-up fetch/verification hits a transient GitHub SSH error such as `kex_exchange_identification`; this condition is reported as `partialSuccess=push-succeeded-fetch-failed` with the next step set to the corresponding controlled `hwlab nodes git-mirror sync --node <node> --lane <lane> --confirm --wait`. Do not keep repeating blind flush attempts; refresh `refs/mirror-stage/...` with `sync --wait`, then recheck status for `localGitops=githubGitops`, `pendingFlush=false`, and `githubInSync=true`.
For D601/node-scoped runtime lanes, `hwlab nodes git-mirror status --node <node> --lane <lane>` reports GitHub refs from the mirror cache's `refs/mirror-stage/...`, not from a live GitHub API request. The status output must keep that source visible through `refSources.githubFieldsAreMirrorStageCache=true`. A `flush --wait` run can push the GitOps ref successfully and still hit a transient GitHub SSH error such as `kex_exchange_identification` during follow-up fetch/verification; this condition is reported as `partialSuccess=push-succeeded-fetch-failed`. Current CLI should first perform a controlled sync/recheck and mark `partialSuccessRecovered=true` when `pendingFlush=false` and `githubInSync=true`; only unrecovered cases should point operators at `hwlab nodes git-mirror sync --node <node> --lane <lane> --confirm --wait`. Do not keep repeating blind flush attempts; refresh `refs/mirror-stage/...` with `sync --wait`, then recheck status for `localGitops=githubGitops`, `pendingFlush=false`, and `githubInSync=true`.
If `gitops-promote` fails because the git mirror control plane drifted, refs are inconsistent, or publish/flush did not complete, recover through the controlled mirror path: `hwlab g14 git-mirror apply --confirm` to reinstall the current hook/ConfigMap, `hwlab g14 git-mirror sync --confirm --wait` to realign source and GitOps refs, then a targeted `control-plane cleanup-runs --pipeline-run <failed-run> --confirm` before retriggering the same lane. The old branch/path allowlist gate has been removed; do not restore it, patch the hook inside the pod, delete PipelineRuns with raw kubectl, or bypass `git-mirror flush`. Closeout still requires the target PipelineRun status, Argo health, public probes, and `git-mirror status` with `pendingFlush=false`.
+3 -1
View File
@@ -100,11 +100,13 @@ fixture seed 优先来自目标 node/lane 的受控真实样本;采集脚本
`web-probe script` 注入的 `baseUrl` 是 public origin,并且可以带尾随 `/`。自定义脚本构造 API 或页面 URL 时必须使用 `new URL(path, baseUrl).toString()`;不要用 `` `${baseUrl}${path}` `` 直接拼接以 `/` 开头的 path,否则会生成 `//health`、`//v1/...` 这类双斜杠路径,可能被 edge-proxy 当成上游绝对 URL/异常代理路径处理,造成与真实浏览器页面不同的 502 或误判。
Workbench 历史会话 deep link 可能属于非默认 project。打开 `/workbench/sessions/<conversationId>` 时如果默认 project 返回 `conversation_project_mismatch`、页面提示 conversation 不可见,不能立即判定原 issue 失效;应先从 workspace/conversation 摘要确认该会话 projectId,再用等价 URL `/workbench/sessions/<conversationId>?projectId=<projectId>` 做 DOM 断言。closeout 证据应写明实际 projectId、finalUrl、terminal agent card 数量和负向文本断言,避免用默认 project 的 404 掩盖真实页面状态。
Web 登录凭据必须从目标 node/lane 的受控 source 解析并作为一次性进程环境注入,例如先用 `bun scripts/cli.ts hwlab nodes secret status|ensure --node <node> --lane <lane> --name hwlab-v03-bootstrap-admin` 确认 bootstrap admin sourceRef,再运行受控 `hwlab nodes web-probe run` / `hwlab nodes web-probe script`。目标 host 没有 owner-only source 文件时,受控入口应快速返回 `web_login_secret_missing`;不要依赖脚本历史默认密码,不要把凭据复制到目标 host、shell 启动文件、issue、日志或 Git 文档。若 sourceRef/fingerprint 已确认但 public `/auth/login` 仍不接受 source 密码,应先区分 API rollout、user-billing 回退和用户表状态;只有明确需要按 YAML source 重灌 bootstrap admin hash 时,才使用受控 `secret ensure --confirm --force`
排查 probe 登录误报时,优先看 JSON 里的 `actions``dom.authState``finalUrl``failureDom``dom.requiredSelectors`。新版登录页 fallback 必须先等待真实登录 surface(`#workspace`、legacy id 或 `.login-card input`)再判断 input count;提交前还要确认表单值已经落到 DOM,例如 `actions.login.valuesReady=true`。只在 `authState=login` 的瞬间立即 `count()`,或在 Vue 尚未更新 input value 时 submit,都可能把前端填表时序误判成凭据错误。关闭 Workbench 登录/DOM helper 问题时,证据至少包含原命令、目标 URL/lane、登录 `selectorMode``valuesReady``finalUrl``workspace`/`commandInput` 等关键 selector 结果。
Trace 实时性问题必须使用间隔采样,而不是只看静态截图或终态 DOM。`hwlab nodes web-probe run` 可用 `--trace-sample-count``--trace-sample-interval-ms` 采集运行中样本;自定义场景使用 `hwlab nodes web-probe script` 在同一 public origin 上读取 `.message-card[data-role="agent"]``.trace-timeline``.trace-render-row``data-status``.trace-empty`。采样判断要区分“加载中”和“思考中”:加载中表示页面仍在拉取已有 trace 或 trace 资源未就绪;思考中表示 trace 容器已挂载、turn 正在运行,但还没有第一条可读 Code Agent 事件。通过证据应包含连续样本里的 `agentStatus``tracePresent``traceStatus``rowCount``emptyLabel` 和最后一行预览;至少要看到 running 期间 trace 容器存在,并在上游写入后逐步出现 rows
Trace 实时性问题必须使用间隔采样,而不是只看静态截图或终态 DOM。`hwlab nodes web-probe run` 可用 `--trace-sample-count``--trace-sample-interval-ms` 采集运行中样本;自定义场景使用 `hwlab nodes web-probe script` 在同一 public origin 上读取 `.message-card[data-role="agent"]``.trace-timeline``.trace-render-row``data-status``.trace-empty`。采样判断要区分“加载中”和“思考中”:加载中表示页面仍在拉取已有 trace 或 trace 资源未就绪;思考中表示 trace 容器已挂载、turn 正在运行,但还没有第一条可读 Code Agent 事件。终态 message cardcompleted/failed/blocked/timeout/canceled)不得继续保留“思考中”空态;若 full trace 为空,应显示与终态一致的空 trace 文案,并且该 article 的可读 `textContent` 不应包含“思考中”。通过证据应包含连续样本里的 `agentStatus``tracePresent``traceStatus``rowCount``emptyLabel` 和最后一行预览;终态空 trace 类 issue 还应统计 terminal agent card、terminalWithThinking 和 terminal trace-empty label
浏览器控制台中的随机文件名脚本、扩展注入脚本或浏览器实验功能警告不得直接归因到 HWLAB Cloud Web。遇到 `Permissions policy violation``unload is not allowed` 或类似 console 噪声时,先用 `hwlab nodes web-probe script` 在干净 Playwright 上记录 `document.scripts`、同源响应 header 和相关 console 过滤结果;只有脚本实际来自 HWLAB public origin、部署产物或响应 header 明确由 HWLAB 设置时,才把它登记为 HWLAB Web bug。Edge/Copilot、浏览器扩展或用户侧注入脚本产生的随机 bundle 名称,应作为浏览器环境噪声记录,不阻塞已通过的 Web 功能验收。