feat(spec): let the runner install state.logs in the page

Claude-Session: https://claude.ai/code/session_01ShuAy8q8ZfPi8KHxwc8JpQ
This commit is contained in:
pj committed 2026-08-16 01:37:52 +05:30
1 parent 36caf6916f
commit 226f5805aa
1 file changed
+15 -1
+15 -1
View File
@@ -445,6 +445,15 @@ if (typeof globalThis.addEventListener === "function") {
// that reads state.lastAction vacuously true on web. // that reads state.lastAction vacuously true on web.
let lastAction: unknown = null; let lastAction: unknown = null;
// logs is what the driver captured between the previous step and this one,
// pushed in by the Go runner (via __sanderlingSetLogs__) before each extractor
// evaluation, in the shape internal/verifier/marshal.go builds for goja. The
// page cannot derive it: console output reaches the runner over CDP and nothing
// in the page reads it back. Hardcoding [] here, as this file used to, makes
// every spec property that reads state.logs vacuously true on web, the default
// noLogcatErrors included, because the page's reading is the one that wins.
let logs: unknown[] = [];
function buildState(): unknown { function buildState(): unknown {
return { return {
snapshots: {}, snapshots: {},
@@ -453,7 +462,7 @@ function buildState(): unknown {
window, window,
lastAction, lastAction,
time: 0, time: 0,
logs: [], logs,
exceptions: capturedExceptions.slice(), exceptions: capturedExceptions.slice(),
}; };
} }
@@ -502,6 +511,11 @@ defineLockedGlobal("__sanderlingSetLastAction__", (value: unknown) => {
lastAction = value ?? null; lastAction = value ?? null;
}); });
// The host calls this once per step too, alongside __sanderlingSetLastAction__.
defineLockedGlobal("__sanderlingSetLogs__", (value: unknown) => {
logs = Array.isArray(value) ? value : [];
});
// writable:false stops a page script from shadowing the runtime via plain // writable:false stops a page script from shadowing the runtime via plain
// assignment (the realistic in-page threat). configurable:true is required so // assignment (the realistic in-page threat). configurable:true is required so
// unit tests sharing one process can reinstall a fake via defineProperty; a // unit tests sharing one process can reinstall a fake via defineProperty; a