fix: surface web probe target readiness blockers

This commit is contained in:
Codex
2026-07-02 07:37:54 +00:00
parent acb60dc60d
commit 457cbd1e38
5 changed files with 146 additions and 7 deletions
@@ -68,6 +68,22 @@ async function readCommandBucket(dir, bucket) {
function buildToolFindings({ manifest, heartbeat, commandState }) {
const findings = [];
const diagnostics = heartbeatDiagnostics(manifest, heartbeat);
const startupReadiness = toolStartupReadiness(manifest, heartbeat);
if (startupReadiness !== null) {
findings.push({
id: "tool-target-page-not-ready",
severity: "red",
summary: "web-probe observe target page did not reach the expected Workbench app shell; treat this as probe setup/runtime access blocker before interpreting business turns or frontend hotspots",
count: 1,
reason: startupReadiness.reason,
rootCause: startupReadiness.reason === "nav-access-denied" ? "web_probe_target_nav_access_denied" : startupReadiness.reason === "workbench-blank-document" ? "web_probe_target_blank_workbench_document" : "web_probe_target_page_not_ready",
rootCauseStatus: "confirmed-from-startup-readiness",
rootCauseConfidence: "high",
nextAction: "Fix the selected node/lane Web access or Workbench shell loading first, then rerun observe start and performanceCapture; do not treat an empty performance report from this run as a business performance result.",
readiness: startupReadiness,
valuesRedacted: true
});
}
if (diagnostics.heartbeatStale) {
findings.push({
id: "tool-runner-heartbeat-stale",
@@ -112,6 +128,44 @@ function buildToolFindings({ manifest, heartbeat, commandState }) {
return findings;
}
function toolStartupReadiness(manifest, heartbeat) {
const candidates = [
heartbeat?.error?.navigationReadiness,
heartbeat?.error?.details?.readiness,
heartbeat?.error?.details?.readinessAfterWait,
heartbeat?.error?.details?.readinessBeforeClick,
manifest?.error?.navigationReadiness,
manifest?.error?.details?.readiness,
manifest?.error?.details?.readinessAfterWait,
manifest?.error?.details?.readinessBeforeClick,
];
for (const candidate of candidates) {
const readiness = candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : null;
if (!readiness) continue;
const snapshot = readiness.snapshot && typeof readiness.snapshot === "object" && !Array.isArray(readiness.snapshot) ? readiness.snapshot : readiness;
const reason = typeof readiness.reason === "string" && readiness.reason ? readiness.reason : typeof snapshot.reason === "string" && snapshot.reason ? snapshot.reason : null;
if (reason === null) continue;
return {
reason,
path: typeof snapshot.path === "string" ? snapshot.path : null,
search: typeof snapshot.search === "string" ? snapshot.search : null,
blockedReason: typeof snapshot.blockedReason === "string" ? snapshot.blockedReason : null,
readyState: typeof snapshot.readyState === "string" ? snapshot.readyState : null,
workbenchShellVisible: snapshot.workbenchShellVisible === true,
sessionCreatePresent: snapshot.sessionCreatePresent === true,
sessionCreateVisible: snapshot.sessionCreateVisible === true,
sessionRailPresent: snapshot.sessionRailPresent === true,
commandInputPresent: snapshot.commandInputPresent === true,
activeTabPresent: snapshot.activeTabPresent === true,
loginVisible: snapshot.loginVisible === true,
bodyTextBytes: Number.isFinite(Number(snapshot.bodyTextBytes)) ? Number(snapshot.bodyTextBytes) : null,
bodyTextHash: typeof snapshot.bodyTextHash === "string" ? snapshot.bodyTextHash : null,
valuesRedacted: true
};
}
return null;
}
function heartbeatDiagnostics(manifest, heartbeat) {
const status = String(heartbeat?.status || manifest?.status || "");
const terminal = /^(completed|failed|force-stopped|stopped|abandoned)$/u.test(status);