fix(web-probe): keep controlled navigation hydration nonblocking

This commit is contained in:
Codex
2026-06-26 15:00:59 +00:00
parent 4e5249bb6a
commit 50f73978e6
2 changed files with 43 additions and 9 deletions
@@ -1387,7 +1387,7 @@ function sessionInvariantNavigationWindows(control) {
const started = new Map();
const windows = [];
for (const row of control || []) {
if (row?.type !== "switchAwayAndBack") continue;
if (row?.type !== "switchAwayAndBack" && row?.type !== "refreshCurrentSession") continue;
const commandId = stringOrNull(row.commandId) ?? String(row.seq ?? "");
if (row.phase === "started") {
started.set(commandId, row);
@@ -1435,6 +1435,35 @@ function sampleInControlledNavigationWindow(sample, windows) {
return (windows || []).some((window) => ms >= window.startMs && ms <= window.endMs);
}
function sampleRefInControlledNavigationSessionWindow(sample, windows) {
const ms = timestampMs(sample?.ts);
if (!Number.isFinite(ms)) return false;
const routeSessionId = stringOrNull(sample?.routeSessionId);
const activeSessionId = stringOrNull(sample?.activeSessionId);
return (windows || []).some((window) => {
if (ms < window.startMs || ms > window.endMs) return false;
const expected = [window.canarySessionId, window.alternateSessionId].filter(Boolean);
return expected.some((sessionId) => sessionId === routeSessionId || sessionId === activeSessionId);
});
}
function isBlankHydrationProjectionSample(sample) {
if (!sample) return false;
const messageCount = Array.isArray(sample.messages) ? sample.messages.length : Number(sample.messageCount ?? 0);
const traceRowCount = Array.isArray(sample.traceRows) ? sample.traceRows.length : Number(sample.traceRowCount ?? 0);
return !stringOrNull(sample.activeSessionId)
&& Number(messageCount) === 0
&& Number(traceRowCount) === 0;
}
function controlledNavigationHydrationCrossPageDiff(row, windows, sampleBySeq) {
if (row?.diffKind !== "projection") return false;
if (!sampleRefInControlledNavigationSessionWindow(row.control, windows) || !sampleRefInControlledNavigationSessionWindow(row.observer, windows)) return false;
const control = sampleBySeq.get(Number(row?.control?.seq));
const observer = sampleBySeq.get(Number(row?.observer?.seq));
return isBlankHydrationProjectionSample(control) || isBlankHydrationProjectionSample(observer);
}
function objectValue(value) {
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
}
@@ -1602,11 +1631,15 @@ function buildFindings(samples, control, network, errors, sampleMetrics, promptN
const crossPageProjectionDiffs = crossPageDiffs.filter((item) => item.diffKind !== "trace-visibility");
const crossPageTraceVisibilityDiffs = crossPageDiffs.filter((item) => item.diffKind === "trace-visibility");
const crossPageProjectionBudgetMs = alertThresholds.crossPageProjectionDivergenceRedMs;
const sampleBySeq = new Map(samples.map((item) => [Number(item?.seq), item]).filter(([seq]) => Number.isFinite(seq)));
const timedCrossPageProjectionDiffs = annotateCrossPageDiffTiming(crossPageProjectionDiffs);
const persistentCrossPageProjectionDiffs = timedCrossPageProjectionDiffs.filter((item) => Number(item.observedSpanMs ?? 0) > crossPageProjectionBudgetMs);
const transientCrossPageProjectionDiffs = timedCrossPageProjectionDiffs.filter((item) => Number(item.observedSpanMs ?? 0) <= crossPageProjectionBudgetMs);
const controlledNavigationHydrationProjectionDiffs = timedCrossPageProjectionDiffs.filter((item) => controlledNavigationHydrationCrossPageDiff(item, controlledNavigationWindows, sampleBySeq));
const evaluatedCrossPageProjectionDiffs = timedCrossPageProjectionDiffs.filter((item) => !controlledNavigationHydrationCrossPageDiff(item, controlledNavigationWindows, sampleBySeq));
const persistentCrossPageProjectionDiffs = evaluatedCrossPageProjectionDiffs.filter((item) => Number(item.observedSpanMs ?? 0) > crossPageProjectionBudgetMs);
const transientCrossPageProjectionDiffs = evaluatedCrossPageProjectionDiffs.filter((item) => Number(item.observedSpanMs ?? 0) <= crossPageProjectionBudgetMs);
if (persistentCrossPageProjectionDiffs.length > 0) findings.push({ id: "cross-page-projection-divergence", severity: "red", summary: "control and observer pages saw different projection state for the same sampled session beyond the configured budget", count: persistentCrossPageProjectionDiffs.length, budgetMs: crossPageProjectionBudgetMs, samples: persistentCrossPageProjectionDiffs.slice(0, 20) });
if (transientCrossPageProjectionDiffs.length > 0) findings.push({ id: "cross-page-projection-transient-divergence", severity: "info", summary: "control and observer pages briefly differed near a sampled transition; retained as transient evidence but not treated as persistent projection failure", count: transientCrossPageProjectionDiffs.length, budgetMs: crossPageProjectionBudgetMs, samples: transientCrossPageProjectionDiffs.slice(0, 20) });
if (controlledNavigationHydrationProjectionDiffs.length > 0) findings.push({ id: "cross-page-projection-controlled-navigation-hydration", severity: "info", summary: "control and observer pages differed while a non-blocking session-invariance navigation command still had an unhydrated blank page; retained as context but not treated as a red projection blocker", count: controlledNavigationHydrationProjectionDiffs.length, budgetMs: crossPageProjectionBudgetMs, samples: controlledNavigationHydrationProjectionDiffs.slice(0, 20) });
if (crossPageTraceVisibilityDiffs.length > 0) findings.push({ id: "cross-page-trace-visibility-divergence", severity: "info", summary: "control and observer pages differed only in visible trace row count; this is local disclosure/hydration visibility, not session/message projection divergence", count: crossPageTraceVisibilityDiffs.length, samples: crossPageTraceVisibilityDiffs.slice(0, 20) });
const traceMessageDuplicates = detectTraceMessageDuplication(samples);
if (traceMessageDuplicates.length > 0) findings.push({ id: "trace-assistant-message-duplicates-final-response", severity: "amber", summary: "trace-frame rendered duplicate visible assistant final rows; the fixed Final Response renderer summary block is excluded", count: traceMessageDuplicates.length, finalResponseSummaryBlockCounted: false, traceFrameSource: "traceRows-only", samples: traceMessageDuplicates.slice(0, 20) });