fix: surface Workbench navigation root cause

This commit is contained in:
Codex
2026-06-27 03:07:51 +00:00
parent 61d9249e50
commit 873bb16d0c
@@ -1400,6 +1400,115 @@ function buildSessionInvariantFindings(control, manifest = {}) {
return findings;
}
function buildControlledNavigationRootCauseFindings(control, manifest = {}) {
const commands = [];
for (const row of control || []) {
if (row?.phase !== "completed") continue;
if (row?.type !== "refreshCurrentSession" && row?.type !== "switchAwayAndBack") continue;
const detail = objectValue(row.detail);
const navigation = objectValue(detail.navigation);
const readiness = objectValue(navigation.readiness);
const snapshot = objectValue(readiness.snapshot);
const pageProvenance = objectValue(navigation.pageProvenance);
const blankShell = snapshot.workbenchShellVisible === false
&& snapshot.sessionRailPresent === false
&& snapshot.commandInputPresent === false
&& snapshot.bodyTextHash === "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
const shellOrComposerMissing = snapshot.workbenchShellVisible === false
|| snapshot.sessionRailPresent === false
|| snapshot.commandInputPresent === false;
const degraded = navigation.degraded === true
|| readiness.ok === false
|| detail.routeOk === false
|| blankShell
|| (detail.activeOk === false && shellOrComposerMissing)
|| (detail.composerReady === false && snapshot.commandInputPresent === false);
if (!degraded) continue;
const rootCause = stringOrNull(navigation.degradedReason)
?? (readiness.ok === false ? stringOrNull(readiness.reason) : null)
?? (detail.routeOk === false ? "route-session-not-hydrated" : null)
?? (blankShell ? "workbench-blank-shell-after-navigation" : null)
?? (detail.activeOk === false && shellOrComposerMissing ? "active-session-not-hydrated" : null)
?? (detail.composerReady === false && snapshot.commandInputPresent === false ? "composer-not-ready" : null)
?? "controlled-navigation-degraded";
commands.push({
commandId: stringOrNull(row.commandId),
type: stringOrNull(row.type),
commandTs: stringOrNull(row.ts),
afterRound: numberOrNull(detail.afterRound ?? row.input?.afterRound),
rootCause,
blocking: true,
canarySessionId: stringOrNull(detail.canarySessionId),
routeSessionId: stringOrNull(detail.routeSessionId),
activeSessionId: stringOrNull(detail.activeSessionId),
routeOk: detail.routeOk === true,
activeOk: detail.activeOk === true,
composerReady: detail.composerReady === true,
navigation: {
httpStatus: numberOrNull(navigation.httpStatus),
degraded: navigation.degraded === true,
degradedReason: stringOrNull(navigation.degradedReason),
beforePath: urlPath(navigation.beforeUrl),
afterPath: urlPath(navigation.afterUrl),
valuesRedacted: true,
},
readiness: {
ok: readiness.ok === true,
reason: stringOrNull(readiness.reason),
durationMs: numberOrNull(readiness.durationMs),
path: stringOrNull(snapshot.path),
readyState: stringOrNull(snapshot.readyState),
workbenchShellVisible: snapshot.workbenchShellVisible === true,
sessionCreatePresent: snapshot.sessionCreatePresent === true,
sessionRailPresent: snapshot.sessionRailPresent === true,
commandInputPresent: snapshot.commandInputPresent === true,
activeTabPresent: snapshot.activeTabPresent === true,
loginVisible: snapshot.loginVisible === true,
blankShell,
bodyTextHash: stringOrNull(snapshot.bodyTextHash),
valuesRedacted: true,
},
pageProvenance: {
pageLoadSeq: numberOrNull(pageProvenance.pageLoadSeq),
reason: stringOrNull(pageProvenance.reason),
observedAt: stringOrNull(pageProvenance.observedAt),
urlPath: stringOrNull(pageProvenance.urlPath),
documentReadyState: stringOrNull(pageProvenance.documentReadyState),
timeOrigin: numberOrNull(pageProvenance.timeOrigin),
httpStatus: numberOrNull(pageProvenance.httpStatus),
assetFingerprint: stringOrNull(pageProvenance.assetFingerprint),
scriptCount: numberOrNull(pageProvenance.scriptCount),
stylesheetCount: numberOrNull(pageProvenance.stylesheetCount),
scripts: arrayStrings(pageProvenance.scripts).slice(0, 8),
stylesheets: arrayStrings(pageProvenance.stylesheets).slice(0, 8),
valuesRedacted: true,
},
observer: {
ok: detail.observer?.ok === true,
pageRole: stringOrNull(detail.observer?.pageRole),
pageId: stringOrNull(detail.observer?.pageId),
changed: detail.observer?.changed === true,
valuesRedacted: true,
},
observerId: stringOrNull(manifest.jobId),
stateDir: stringOrNull(manifest.stateDir),
valuesRedacted: true,
});
}
if (commands.length === 0) return [];
return [{
id: "workbench-controlled-navigation-degraded-root-cause",
severity: "red",
summary: "controlled Workbench refresh/switch completed degraded; route may be correct but app shell, active session, or composer was not ready, so later Code Agent turns cannot continue",
count: commands.length,
blocking: true,
rootCauses: Array.from(new Set(commands.map((item) => item.rootCause))).slice(0, 12),
commands: commands.slice(0, 20),
next: "Investigate the first degraded command, then correlate browser requestfailed/static asset failures and Workbench hydration state before changing Code Agent/provider logic.",
valuesRedacted: true,
}];
}
function sessionInvariantNavigationWindows(control) {
const started = new Map();
const windows = [];
@@ -1941,6 +2050,7 @@ function buildFindings(samples, control, network, errors, sampleMetrics, promptN
const findings = [];
const effectiveApiDomLag = apiDomLag || buildApiDomLagReport(samples, network);
if (commandFailures.length > 0) findings.push({ id: "observer-command-failed", severity: "red", summary: "observer control commands failed; analyze must surface command failure instead of hiding it in command artifacts", count: commandFailures.length, commands: commandFailures.slice(0, 20) });
findings.push(...buildControlledNavigationRootCauseFindings(control, manifest));
findings.push(...buildSessionInvariantFindings(control, manifest));
const commandTimes = control
.filter((item) => item.phase === "completed" || item.phase === "started" || item.type === "observer-periodic-refresh")