From 6a329d5987640c4f58879b926475fb3783a1954e Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Mon, 27 Jul 2026 01:22:54 +0000 Subject: [PATCH] fix: correlate redacted adaptive policy errors --- .../src/browser-adaptive-explorer.ts | 7 +++++- .../runtime-playground/src/browser-metrics.ts | 2 +- tests/browser-adaptive-exploration.test.ts | 25 ++++++++++++++++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/runtime-playground/src/browser-adaptive-explorer.ts b/packages/runtime-playground/src/browser-adaptive-explorer.ts index 697ad2f4..9bbf21b9 100644 --- a/packages/runtime-playground/src/browser-adaptive-explorer.ts +++ b/packages/runtime-playground/src/browser-adaptive-explorer.ts @@ -19,6 +19,7 @@ import { stableJson } from "@automattic/wp-codebox-core/internals" import type { Frame, Page } from "playwright" import { discoverBrowserActionCorpusDescriptors } from "./browser-action-discovery.js" +import { redactBrowserNetworkUrl } from "./browser-metrics.js" import { browserPreviewNetworkDecision, type BrowserPreviewNavigationScope, type BrowserPreviewNetworkPolicy } from "./browser-preview-routing.js" interface AdaptiveObservationSources { @@ -595,7 +596,7 @@ function adaptiveOracleEvidence(consoleRecords: Record[], netwo const message = recordMessage(record) const locationUrl = objectRecord(record.location).url const match = classifiedFailures.findIndex((failure, index) => unmatchedFailures.has(index) - && (typeof locationUrl === "string" && locationUrl ? failure.url === locationUrl && failureTokenMatches(message, failure.failure) : failureTokenMatches(message, failure.failure))) + && (typeof locationUrl === "string" && locationUrl ? networkUrlsMatch(failure.url, locationUrl) && failureTokenMatches(message, failure.failure) : failureTokenMatches(message, failure.failure))) if (match < 0) return [message] unmatchedFailures.delete(match) const failure = classifiedFailures[match]! @@ -643,6 +644,10 @@ function failureTokenMatches(message: string, failure: string | undefined): bool return Boolean(token && message.toUpperCase().includes(token.toUpperCase())) } +function networkUrlsMatch(networkUrl: string, consoleUrl: string): boolean { + return redactBrowserNetworkUrl(networkUrl) === redactBrowserNetworkUrl(consoleUrl) +} + function networkFailureOracleMessage(failure: BrowserAdaptiveNetworkFailure): string { return stableJson({ type: "requestfailed", url: failure.url, failure: failure.failure, urlClassification: failure.urlClassification, policyDecision: failure.policyDecision, policyReason: failure.policyReason }) } diff --git a/packages/runtime-playground/src/browser-metrics.ts b/packages/runtime-playground/src/browser-metrics.ts index e49fef2b..369bdc65 100644 --- a/packages/runtime-playground/src/browser-metrics.ts +++ b/packages/runtime-playground/src/browser-metrics.ts @@ -608,7 +608,7 @@ export function serializeBrowserRequestFailure(request: Request, timestamp = now } } -function redactBrowserNetworkUrl(url: string): string { +export function redactBrowserNetworkUrl(url: string): string { return redactString(url, { redactAllUrlQueryValues: true, redactUrlHash: true, redactQueryAssignments: true }) } diff --git a/tests/browser-adaptive-exploration.test.ts b/tests/browser-adaptive-exploration.test.ts index 365bc36f..b74be2fc 100644 --- a/tests/browser-adaptive-exploration.test.ts +++ b/tests/browser-adaptive-exploration.test.ts @@ -500,7 +500,7 @@ test("declared network-policy blocks remain structured evidence without becoming assert.equal(run.result.summary.errors, 0) assert(transition?.observations.consoleErrors.some((message) => message.includes("ERR_BLOCKED_BY_CLIENT")), "raw browser console evidence remains available") assert.deepEqual(transition?.observations.networkFailures, [{ - url: "http://assets.example.invalid/tile.png", + url: "http://assets.example.invalid/tile.png?cache=[redacted]", host: "assets.example.invalid", urlClassification: "external", policyDecision: "blocked", @@ -563,6 +563,21 @@ test("same-URL product errors require a matching failure token before policy cor assert.equal(finding.result.transitions[0]?.observations.networkFailureSummary?.policyBlocks, 1) }) +test("redacted policy-block URLs correlate without hiding independent console errors across browser contexts", async () => { + for (const environment of ["desktop", "mobile"] as const) { + const evidence = await runNetworkOracleFixture("block", "blocked", {}, false, false, environment) + assert.equal(evidence.result.findings.length, 0, environment) + assert.deepEqual(evidence.result.transitions[0]?.observations.oracleFingerprints, [], environment) + assert.equal(evidence.result.transitions[0]?.observations.networkFailureSummary?.policyBlocks, 1, environment) + + const independent = await runNetworkOracleFixture("block", "blocked", {}, false, true, environment) + const productFingerprint = browserAdaptiveDigest("oracle", { environmentDigest: independent.contract.environmentDigest, value: "same-URL product defect" }) + assert.deepEqual(independent.result.transitions[0]?.observations.oracleFingerprints, [productFingerprint], environment) + assert.equal(independent.result.findings[0]?.fingerprint, productFingerprint, environment) + assert.equal(independent.result.transitions[0]?.observations.networkFailureSummary?.oracleFindings, 0, environment) + } +}) + test("allow and record policies do not explain unexpected same-origin request failures", async () => { for (const mode of ["allow", "record"] as const) { const run = await runNetworkOracleFixture(mode, "unexpected") @@ -737,7 +752,7 @@ async function runRoutedFixture(topology: ReturnType = {}, urlLessConsole = false, sameUrlProductError = false) { +async function runNetworkOracleFixture(mode: "allow" | "block" | "record", behavior: "blocked" | "unexpected" | "mixed" | "exception", input: Record = {}, urlLessConsole = false, sameUrlProductError = false, environment: "desktop" | "mobile" = "desktop") { const server = createServer((request, response) => { const path = new URL(request.url ?? "/", "http://preview.invalid").pathname if (path === "/failed.png") { @@ -748,7 +763,7 @@ async function runNetworkOracleFixture(mode: "allow" | "block" | "record", behav response.end(`