import fs from "node:fs"; import net from "node:net"; import path from "node:path"; import { createHash } from "node:crypto"; const exactUrl = "https://legacy-parity.mbn.local/index.html"; const requiredSelector = Object.freeze({ searchText: "삼성전자", marketText: "코스피", stockName: "삼성전자", cutLabel: "1열판기본_현재가", graphicType: "1열판기본", subtype: "현재가", preparedCode: "5001", pageNumberOneBased: 1 }); const acceptedArguments = new Set([ "port", "plan", "plan-sha256", "authorization", "authorization-sha256", "output", "screenshot", "capability-sha256", "permit-pipe", "timeout-ms" ]); const forbiddenCdpMethods = new Set([ "Browser.close", "Page.close", "Runtime.terminateExecution", "Target.closeTarget" ]); class GateFailure extends Error { constructor(category, message) { super(`${category}: ${message}`); this.name = "GateFailure"; this.category = category; } } const known = message => { throw new GateFailure("KNOWN_FAILURE", message); }; const unknown = message => { throw new GateFailure("OUTCOME_UNKNOWN", message); }; const sha256 = bytes => createHash("sha256").update(bytes).digest("hex").toUpperCase(); const isSha256 = value => /^[0-9A-F]{64}$/u.test(String(value || "")); const isSafeId = value => /^[A-Za-z0-9._:-]{1,128}$/u.test(String(value || "")); function parseArguments(argv) { if (argv.length === 0 || argv.length % 2 !== 0) known("Arguments must be --name value pairs."); const values = new Map(); for (let index = 0; index < argv.length; index += 2) { const raw = argv[index]; const value = argv[index + 1]; if (!raw?.startsWith("--") || !value) known("Every argument requires a value."); const name = raw.slice(2); if (!acceptedArguments.has(name) || values.has(name)) known(`Invalid argument --${name}.`); values.set(name, value); } for (const name of [ "port", "plan", "plan-sha256", "authorization", "authorization-sha256", "output", "screenshot", "capability-sha256", "permit-pipe" ]) { if (!values.has(name)) known(`--${name} is required.`); } const port = Number(values.get("port")); if (!Number.isInteger(port) || port < 1 || port > 65535) known("--port is invalid."); const timeoutMilliseconds = values.has("timeout-ms") ? Number(values.get("timeout-ms")) : 90000; if (!Number.isInteger(timeoutMilliseconds) || timeoutMilliseconds < 15000 || timeoutMilliseconds > 180000) known("--timeout-ms must be 15000 through 180000."); const result = { port, timeoutMilliseconds, planPath: path.resolve(values.get("plan")), planSha256: String(values.get("plan-sha256")).toUpperCase(), authorizationPath: path.resolve(values.get("authorization")), authorizationSha256: String(values.get("authorization-sha256")).toUpperCase(), outputPath: path.resolve(values.get("output")), screenshotPath: path.resolve(values.get("screenshot")), capabilitySha256: String(values.get("capability-sha256")).toUpperCase(), permitPipeName: String(values.get("permit-pipe")) }; for (const [name, candidate, extension] of [ ["plan", result.planPath, ".json"], ["authorization", result.authorizationPath, ".json"], ["output", result.outputPath, ".json"], ["screenshot", result.screenshotPath, ".png"] ]) { if (!path.isAbsolute(values.get(name)) || path.extname(candidate).toLowerCase() !== extension) { known(`--${name} must be an absolute ${extension} path.`); } } if (!isSha256(result.planSha256) || !isSha256(result.authorizationSha256) || !isSha256(result.capabilitySha256)) { known("A supplied SHA-256 is invalid."); } if (!/^MBN_STOCK_WEBVIEW\.GateA\.Node\.[0-9A-F]{32}$/u.test(result.permitPipeName)) { known("The parent-owned JIT permit pipe name is invalid."); } if (new Set([result.planPath, result.authorizationPath, result.outputPath, result.screenshotPath] .map(value => value.toLowerCase())).size !== 4) known("Evidence paths must be distinct."); if (fs.existsSync(result.outputPath) || fs.existsSync(result.screenshotPath)) { known("Output evidence is never overwritten."); } return result; } function readFrozenJson(filePath, label, expectedHash = null) { const bytes = fs.readFileSync(filePath); const actualHash = sha256(bytes); if (expectedHash && actualHash !== expectedHash) known(`${label} SHA-256 changed.`); let value; try { value = JSON.parse(bytes.toString("utf8")); } catch { known(`${label} is not strict JSON.`); } return { bytes, hash: actualHash, value }; } const configuration = parseArguments(process.argv.slice(2)); if (Object.keys(process.env).some(name => name.startsWith("MBN_LEGACY_PGM_GATE_A_"))) { known("Gate A bearer material must not be inherited through the Node environment."); } const startedAtUtc = new Date().toISOString(); const hardDeadline = Date.now() + configuration.timeoutMilliseconds; const evidence = { schemaVersion: 1, result: "RUNNING", startedAtUtc, completedAtUtc: null, planSha256: configuration.planSha256, roundId: null, target: { expectedUrl: exactUrl, port: configuration.port, id: null }, commandBudget: { connect: 1, prepare: 1, takeIn: 0, next: 0, pageNext: 0, takeOut: 0, databaseWrite: 0, appClose: 0, retry: 0 }, observed: { prepareDispatchPossible: false, prepareIssued: false, busyObserved: false, jitPermitRequested: false, jitPermitReceived: false, outboundTypes: [], blocked: [] }, checkpoints: [], screenshot: null, finalState: null, error: null }; let socket = null; let nextRpcId = 1; const pending = new Map(); let prepareDispatchPossible = false; let prepareIssued = false; function assertDeadline(label) { if (Date.now() >= hardDeadline) unknown(`Global Gate A deadline expired ${label}; no retry.`); } async function sleep(milliseconds) { assertDeadline("before wait"); await new Promise(resolve => setTimeout(resolve, Math.min(milliseconds, hardDeadline - Date.now()))); assertDeadline("after wait"); } function validateFrozenContract() { const planFile = readFrozenJson(configuration.planPath, "plan", configuration.planSha256); const plan = planFile.value; if (plan?.schemaVersion !== 1 || plan?.kind !== "LegacyPgmPrepareGatePlan" || !isSafeId(plan.roundId) || plan?.webView?.url !== exactUrl || plan?.webView?.address !== "127.0.0.1" || plan?.webView?.port !== configuration.port || plan?.safety?.nodeHelperInvocationMaximum !== 1 || plan?.safety?.nodeHelperFailStopRequired !== true || plan?.safety?.packageWrapperFailStopRequired !== true || plan?.safety?.forceCloseForbidden !== true || plan?.safety?.automaticSessionCleanupForbiddenAfterLaunch !== true) { known("Plan identity or target contract is invalid."); } const databasePin = plan?.configuration?.database; if (typeof databasePin?.path !== "string" || !path.isAbsolute(databasePin.path) || !Number.isSafeInteger(databasePin?.length) || databasePin.length <= 0 || !isSha256(databasePin?.sha256)) { known("Plan database configuration pin is invalid."); } const selectorMap = { marketText: requiredSelector.marketText, stockName: requiredSelector.stockName, cutLabel: requiredSelector.cutLabel, graphicType: requiredSelector.graphicType, subtype: requiredSelector.subtype, sceneAlias: requiredSelector.preparedCode }; for (const [name, value] of Object.entries(selectorMap)) { if (plan?.selector?.[name] !== value) known(`Plan selector ${name} is not exact.`); } if (plan?.selector?.groupCode !== "KOSPI" || plan?.selector?.stockCode !== "005930" || plan?.selector?.normalizedSubtype !== "CURRENT" || plan?.cut?.sceneCode !== "5001" || plan?.cut?.pageNumberOneBased !== requiredSelector.pageNumberOneBased) { known("Plan selector identity is incomplete."); } const limits = plan?.budgets; if (limits?.connect !== 1 || limits?.prepare !== 1 || limits?.takeIn !== 0 || limits?.next !== 0 || limits?.pageNext !== 0 || limits?.takeOut !== 0 || limits?.databaseWrite !== 0 || limits?.appClose !== 0 || limits?.retry !== 0) { known("Plan command budget is not exact Gate A."); } const authorizationFile = readFrozenJson( configuration.authorizationPath, "authorization", configuration.authorizationSha256); const authorization = authorizationFile.value; const approvedAt = Date.parse(authorization?.authorizedAtUtc || ""); const expiresAt = Date.parse(authorization?.expiresAtUtc || ""); if (authorization?.schemaVersion !== 1 || authorization?.kind !== "LegacyPgmPrepareGateAuthorization" || authorization?.roundId !== plan.roundId || String(authorization?.planSha256 || "").toUpperCase() !== configuration.planSha256 || authorization?.authorizationStatement !== "I_AUTHORIZE_CURRENT_PGM_LIVE_CONNECT_ONCE_AND_PREPARE_5001_PAGE_1_ONCE" || authorization?.currentK3dLicenseValid !== true || authorization?.runningTornadoIsLicensedMainProgram !== true || authorization?.currentPgmApproved !== true || !Number.isFinite(approvedAt) || !Number.isFinite(expiresAt) || expiresAt <= approvedAt || expiresAt - approvedAt > 15 * 60 * 1000 || Date.now() < approvedAt - 5000 || Date.now() >= expiresAt - 5000) { known("Gate A authorization is invalid, expired, or too near expiry."); } const authorizationBudget = authorization?.budgets; if (authorizationBudget?.connect !== 1 || authorizationBudget?.prepare !== 1 || authorizationBudget?.takeIn !== 0 || authorizationBudget?.next !== 0 || authorizationBudget?.pageNext !== 0 || authorizationBudget?.takeOut !== 0 || authorizationBudget?.databaseWrite !== 0 || authorizationBudget?.appClose !== 0 || authorizationBudget?.retry !== 0) { known("Authorization command budget is not exact Gate A."); } evidence.roundId = plan.roundId; return { plan, authorization, authorizationHash: authorizationFile.hash, expiresAt }; } async function discoverTarget() { let lastError = null; while (Date.now() < hardDeadline) { try { const response = await fetch(`http://127.0.0.1:${configuration.port}/json/list`, { redirect: "error", signal: AbortSignal.timeout(1000) }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const targets = await response.json(); const exact = Array.isArray(targets) ? targets.filter(target => target?.type === "page" && target.url === exactUrl) : []; if (exact.length > 1) known("More than one exact WebView target exists."); if (exact.length === 1) return exact[0]; } catch (error) { lastError = String(error?.message || error); } await sleep(100); } known(`Exact WebView target was not found${lastError ? `: ${lastError}` : "."}`); } function validateEndpoint(target) { if (!target?.id || !target.webSocketDebuggerUrl) known("Target has no CDP endpoint."); const endpoint = new URL(target.webSocketDebuggerUrl); if (endpoint.protocol !== "ws:" || endpoint.hostname !== "127.0.0.1" || Number(endpoint.port) !== configuration.port || endpoint.pathname !== `/devtools/page/${target.id}`) known("CDP endpoint is not exact loopback."); evidence.target.id = target.id; return endpoint; } async function connect(endpoint) { if (typeof WebSocket !== "function") known("Node WebSocket API is unavailable."); socket = new WebSocket(endpoint.href); await new Promise((resolve, reject) => { const timer = setTimeout(() => reject(new GateFailure("OUTCOME_UNKNOWN", "CDP open timed out.")), 5000); socket.addEventListener("open", () => { clearTimeout(timer); resolve(); }, { once: true }); socket.addEventListener("error", () => { clearTimeout(timer); reject(new GateFailure("OUTCOME_UNKNOWN", "CDP open failed.")); }, { once: true }); }); socket.addEventListener("message", event => { let message; try { message = JSON.parse(String(event.data)); } catch { return; } if (!Object.hasOwn(message, "id")) return; const request = pending.get(message.id); if (!request) return; pending.delete(message.id); clearTimeout(request.timer); if (message.error) request.reject(new GateFailure("KNOWN_FAILURE", `${request.method}: ${message.error.message}`)); else request.resolve(message.result); }); socket.addEventListener("close", () => { for (const request of pending.values()) { clearTimeout(request.timer); request.reject(new GateFailure("OUTCOME_UNKNOWN", `${request.method} interrupted by CDP close.`)); } pending.clear(); }); } function rpc(method, params = {}, timeoutMilliseconds = 10000) { assertDeadline(`before ${method}`); if (forbiddenCdpMethods.has(method)) known(`Forbidden CDP method ${method}.`); if (!socket || socket.readyState !== WebSocket.OPEN) unknown(`CDP is unavailable for ${method}.`); const id = nextRpcId++; return new Promise((resolve, reject) => { const timer = setTimeout(() => { pending.delete(id); reject(new GateFailure("OUTCOME_UNKNOWN", `${method} timed out; no retry.`)); }, Math.min(timeoutMilliseconds, hardDeadline - Date.now())); pending.set(id, { method, resolve, reject, timer }); socket.send(JSON.stringify({ id, method, params })); }); } async function evaluate(expression) { const response = await rpc("Runtime.evaluate", { expression, awaitPromise: true, returnByValue: true, userGesture: false }); if (response.exceptionDetails) known(response.exceptionDetails.exception?.description || response.exceptionDetails.text || "Runtime evaluation failed."); return response.result?.value; } async function installGate(planSha256, capabilitySha256) { const token = `legacy-pgm-prepare-${Date.now()}`; const result = await evaluate(`(() => { if (!window.chrome?.webview) throw new Error("WebView bridge unavailable"); if (globalThis.__legacyPgmPrepareGate) throw new Error("Gate already installed"); const allowedBeforePrepare = new Set([ "ready", "search-stocks", "select-stock", "cut-pointer-down", "drop-selected-cuts" ]); const gate = { version: 1, token: ${JSON.stringify(token)}, planSha256: ${JSON.stringify(planSha256)}, capabilityHash: ${JSON.stringify(capabilitySha256)}, original: window.chrome.webview.postMessage, wrapper: null, listener: null, states: [], outbound: [], blocked: [], armed: false, prepareCapability: null, prepareCount: 0, prepareIssuedAtUtc: null, stateCountAtPrepare: null, expectedPreRevision: null, busyObservedAtPreRevision: false }; const hashText = async value => { const bytes = new TextEncoder().encode(value); const digest = await crypto.subtle.digest("SHA-256", bytes); return Array.from(new Uint8Array(digest), b => b.toString(16).padStart(2, "0")) .join("").toUpperCase(); }; gate.listener = event => { if (event.data?.type !== "state" || !event.data.payload) return; const state = structuredClone(event.data.payload); gate.states.push(state); if (gate.states.length > 500) gate.states.shift(); if (gate.prepareCount === 1 && state?.isBusy === true && state?.revision === gate.expectedPreRevision) { gate.busyObservedAtPreRevision = true; } }; gate.wrapper = message => { const type = typeof message?.type === "string" ? message.type : null; const payload = message?.payload; const record = { type, atUtc: new Date().toISOString() }; gate.outbound.push(record); let allowed = false; if (type === "gate-a-prepare") { const empty = payload && typeof payload === "object" && !Array.isArray(payload) && Object.keys(payload).length === 1 && typeof payload.capability === "string" && payload.capability === gate.prepareCapability; allowed = gate.armed && gate.prepareCount === 0 && empty; if (allowed) { gate.armed = false; gate.prepareCapability = null; gate.prepareCount = 1; gate.prepareIssuedAtUtc = record.atUtc; gate.stateCountAtPrepare = gate.states.length; } } else { allowed = !gate.armed && gate.prepareCount === 0 && allowedBeforePrepare.has(type); } if (!allowed) { if (gate.armed) { gate.armed = false; gate.prepareCapability = null; } gate.blocked.push(record); return; } return gate.original.call(window.chrome.webview, message); }; gate.arm = async (supplied, expectedPreRevision) => { if (gate.armed || gate.prepareCount !== 0 || gate.blocked.length !== 0 || !Number.isSafeInteger(expectedPreRevision) || expectedPreRevision < 0 || await hashText(String(supplied || "")) !== gate.capabilityHash) { throw new Error("One-shot PREPARE capability rejected"); } gate.expectedPreRevision = expectedPreRevision; gate.prepareCapability = String(supplied); gate.armed = true; return { armed: true, stateCount: gate.states.length }; }; gate.inspect = () => ({ version: gate.version, token: gate.token, planSha256: gate.planSha256, wrapperCurrent: window.chrome.webview.postMessage === gate.wrapper, stateCount: gate.states.length, states: gate.states.slice(), outbound: gate.outbound.slice(), blocked: gate.blocked.slice(), armed: gate.armed, prepareCount: gate.prepareCount, prepareIssuedAtUtc: gate.prepareIssuedAtUtc, stateCountAtPrepare: gate.stateCountAtPrepare, expectedPreRevision: gate.expectedPreRevision, busyObservedAtPreRevision: gate.busyObservedAtPreRevision }); window.chrome.webview.postMessage = gate.wrapper; if (window.chrome.webview.postMessage !== gate.wrapper) throw new Error("Gate identity failed"); window.chrome.webview.addEventListener("message", gate.listener); globalThis.__legacyPgmPrepareGate = Object.freeze({ arm: gate.arm, inspect: gate.inspect }); window.chrome.webview.postMessage({ type: "ready", payload: {} }); return { token: gate.token, wrapperCurrent: window.chrome.webview.postMessage === gate.wrapper }; })()`); if (result?.token !== token || result.wrapperCurrent !== true) unknown("Page gate did not install exactly."); } function projectedState(state) { if (!state) return null; const playout = state.playout || {}; return { revision: state.revision, isBusy: state.isBusy, statusMessage: state.statusMessage, statusKind: state.statusKind, playlist: (state.playlist || []).map(row => ({ rowId: row.rowId, isEnabled: row.isEnabled, isActive: row.isActive, marketText: row.marketText, stockName: row.stockName, graphicType: row.graphicType, subtype: row.subtype, pageText: row.pageText })), playout: { mode: playout.mode, connectionState: playout.connectionState, phase: playout.phase, isConnected: playout.isConnected, isCommandAvailable: playout.isCommandAvailable, liveTakeInAllowed: playout.liveTakeInAllowed, isPlayCompletionPending: playout.isPlayCompletionPending, isTakeOutCompletionPending: playout.isTakeOutCompletionPending, outcomeUnknown: playout.outcomeUnknown, preparedCode: playout.preparedCode, onAirCode: playout.onAirCode, currentEntryId: playout.currentEntryId, pageIndexZeroBased: playout.pageIndexZeroBased, pageCount: playout.pageCount, pageSize: playout.pageSize, itemCount: playout.itemCount, currentPageItemCount: playout.currentPageItemCount, isLastPage: playout.isLastPage, nextKind: playout.nextKind, isBusy: playout.isBusy, refreshActive: playout.refreshActive, refreshCompletedCount: playout.refreshCompletedCount, refreshMaximumCount: playout.refreshMaximumCount, refreshLimitReached: playout.refreshLimitReached, message: playout.message } }; } async function snapshot() { return await evaluate(`(() => { const gate = globalThis.__legacyPgmPrepareGate; if (!gate || typeof gate.inspect !== "function") return null; const audit = gate.inspect(); const state = audit.states.at(-1) || null; return { audit, state, dom: { readyState: document.readyState, url: location.href, connection: (document.getElementById("playout-connection-state")?.textContent || "").trim(), status: (document.getElementById("playout-status")?.textContent || "").trim(), dialogHidden: document.getElementById("legacy-dialog")?.hidden === true, dialogText: (document.getElementById("legacy-dialog-message")?.textContent || "").trim() } }; })()`); } function assertCommon(value, label) { if (!value?.state?.playout || value.dom?.url !== exactUrl || value.dom.readyState !== "complete" || value.audit?.wrapperCurrent !== true) { unknown(`Authoritative state or gate missing at ${label}.`); } if (value.audit.blocked.length !== 0) unknown(`An unapproved message was blocked at ${label}.`); if (value.state.playout.outcomeUnknown === true) unknown(`Native outcome is unknown at ${label}.`); if (value.state.playout.onAirCode != null || value.state.playout.phase === "program") { unknown(`PROGRAM output was observed at ${label}.`); } if (value.dom.dialogHidden !== true) known(`Legacy dialog is visible at ${label}: ${value.dom.dialogText}`); } async function waitFor(label, predicate, timeoutMilliseconds = null) { const deadline = Math.min(hardDeadline, Date.now() + (timeoutMilliseconds || configuration.timeoutMilliseconds)); let last = null; while (Date.now() < deadline) { last = await snapshot(); if (last?.state?.playout) assertCommon(last, label); if (predicate(last)) return last; await sleep(100); } unknown(`Timed out waiting for ${label}; no retry. Last=${JSON.stringify(projectedState(last?.state))}`); } function isConnectedIdle(value) { const p = value?.state?.playout; return p?.mode === "live" && p.connectionState === "connected" && p.phase === "idle" && p.isConnected === true && p.isCommandAvailable === true && p.liveTakeInAllowed === false && p.outcomeUnknown !== true && p.preparedCode == null && p.onAirCode == null && p.isBusy !== true && p.isPlayCompletionPending !== true && p.isTakeOutCompletionPending !== true && p.refreshActive !== true && value.state.isBusy !== true; } function exactPlaylist(state) { const rows = state?.playlist || []; return rows.length === 1 && rows[0].isEnabled === true && rows[0].isActive === true && rows[0].marketText === requiredSelector.marketText && rows[0].stockName === requiredSelector.stockName && rows[0].graphicType === requiredSelector.graphicType && rows[0].subtype === requiredSelector.subtype && rows[0].pageText === "1/1"; } function assertExactOutbound(audit, expectPrepare) { const types = audit?.outbound?.map(item => item.type) || []; const count = type => types.filter(value => value === type).length; const selectedCount = count("select-stock"); if (count("ready") !== 1 || count("search-stocks") !== 1 || selectedCount > 1 || count("cut-pointer-down") !== 1 || count("drop-selected-cuts") !== 1 || count("gate-a-prepare") !== (expectPrepare ? 1 : 0) || audit?.blocked?.length !== 0 || audit?.prepareCount !== (expectPrepare ? 1 : 0)) { unknown("Gate A outbound ledger counts are not exact."); } const expected = ["ready", "search-stocks"]; if (selectedCount === 1) expected.push("select-stock"); expected.push("cut-pointer-down", "drop-selected-cuts"); if (expectPrepare) expected.push("gate-a-prepare"); if (types.length !== expected.length || types.some((type, index) => type !== expected[index])) { unknown(`Gate A outbound ledger order is not exact: ${JSON.stringify(types)}`); } } function isPrepared5001(value) { const p = value?.state?.playout; const row = value?.state?.playlist?.[0]; return exactPlaylist(value?.state) && p?.mode === "live" && p.connectionState === "connected" && p.phase === "prepared" && p.isConnected === true && p.isCommandAvailable === true && p.liveTakeInAllowed === false && p.outcomeUnknown !== true && p.preparedCode === "5001" && p.onAirCode == null && p.currentEntryId === row?.rowId && p.pageIndexZeroBased === 0 && p.pageCount === 1 && p.itemCount === 1 && p.currentPageItemCount === 1 && p.isLastPage === true && String(p.nextKind).toLowerCase() === "endofplaylist" && p.isBusy !== true && p.isPlayCompletionPending !== true && p.isTakeOutCompletionPending !== true && p.refreshActive !== true && value.state.isBusy !== true; } async function click(expression, label) { const geometry = await evaluate(`(() => { const element = ${expression}; if (!element || element.disabled || element.getAttribute("aria-disabled") === "true") return null; const r = element.getBoundingClientRect(); if (r.width <= 0 || r.height <= 0) return null; return { x: r.left + r.width / 2, y: r.top + r.height / 2 }; })()`); if (!geometry) known(`${label} is unavailable.`); await rpc("Input.dispatchMouseEvent", { type: "mouseMoved", ...geometry }); await rpc("Input.dispatchMouseEvent", { type: "mousePressed", ...geometry, button: "left", buttons: 1, clickCount: 1 }); await rpc("Input.dispatchMouseEvent", { type: "mouseReleased", ...geometry, button: "left", buttons: 0, clickCount: 1 }); } async function configurePlaylist() { await evaluate(`(() => { const input = document.getElementById("stock-search"); if (!input) throw new Error("stock search unavailable"); input.value = ${JSON.stringify(requiredSelector.searchText)}; })()`); await click('document.getElementById("stock-search-button")', "stock search button"); let current = await waitFor("exact stock search", value => { const state = value?.state; return state?.isBusy === false && state.searchText === requiredSelector.searchText && (state.searchResults || []).filter(row => row.displayName === requiredSelector.stockName).length === 1; }, 60000); const exact = current.state.searchResults.filter(row => row.displayName === requiredSelector.stockName)[0]; if (current.state.selectedStockIndex !== exact.index) { await click(`document.querySelector('#stock-results button[data-result-index="${exact.index}"]')`, "exact stock result"); current = await waitFor("exact stock selection", value => value?.state?.selectedStockIndex === exact.index && value.state.isBusy === false, 15000); } const geometry = await evaluate(`(() => { const state = globalThis.__legacyPgmPrepareGate.inspect().states.at(-1); const cut = (state?.cutRows || []).find(row => row.rawLabel === ${JSON.stringify(requiredSelector.cutLabel)} && row.isSeparator !== true); if (!cut) return null; const source = document.querySelector('#cut-list .cut-row[data-physical-index="' + String(cut.physicalIndex) + '"]'); const target = document.getElementById("playlist-drop-zone"); if (!source || !target) return null; const a = source.getBoundingClientRect(); const b = target.getBoundingClientRect(); return { physicalIndex: cut.physicalIndex, source: { x: a.left + a.width / 2, y: a.top + a.height / 2 }, threshold: { x: a.left + a.width / 2 + 20, y: a.top + a.height / 2 + 20 }, target: { x: b.left + b.width / 2, y: b.top + Math.min(80, b.height / 2) } }; })()`); if (!geometry) known("Exact 5001 cut row or drop target is unavailable."); await rpc("Input.dispatchMouseEvent", { type: "mouseMoved", ...geometry.source }); await rpc("Input.dispatchMouseEvent", { type: "mousePressed", ...geometry.source, button: "left", buttons: 1, clickCount: 1 }); await rpc("Input.dispatchMouseEvent", { type: "mouseMoved", ...geometry.threshold, button: "left", buttons: 1 }); await rpc("Input.dispatchMouseEvent", { type: "mouseMoved", ...geometry.target, button: "left", buttons: 1 }); await rpc("Input.dispatchMouseEvent", { type: "mouseReleased", ...geometry.target, button: "left", buttons: 0, clickCount: 1 }); current = await waitFor("exact 5001 playlist", value => value?.state?.isBusy === false && exactPlaylist(value.state), 30000); assertExactOutbound(current.audit, false); evidence.checkpoints.push({ name: "playlist-5001", state: projectedState(current.state) }); return current; } async function receiveJitCapability(expiresAt) { if (Date.now() >= expiresAt - 5000) known("Authorization is too near expiry before JIT permit."); evidence.observed.jitPermitRequested = true; const remaining = Math.min(15000, hardDeadline - Date.now(), expiresAt - 5000 - Date.now()); if (remaining <= 0) known("No safe time remains for the JIT permit."); const pipePath = `\\\\.\\pipe\\${configuration.permitPipeName}`; const capability = await new Promise((resolve, reject) => { let settled = false; let total = 0; const chunks = []; const client = net.createConnection(pipePath); const finish = (error, value = null) => { if (settled) return; settled = true; clearTimeout(timer); client.destroy(); if (error) reject(error); else resolve(value); }; const timer = setTimeout(() => finish(new GateFailure( "KNOWN_FAILURE", "The parent did not grant the one-shot JIT permit.")), remaining); client.on("data", chunk => { total += chunk.length; if (total > 64) { finish(new GateFailure("KNOWN_FAILURE", "The JIT permit payload length is invalid.")); return; } chunks.push(chunk); }); client.on("end", () => { const bytes = Buffer.concat(chunks, total); try { const value = bytes.toString("ascii"); if (bytes.length !== 64 || !/^[0-9A-F]{64}$/u.test(value) || sha256(bytes) !== configuration.capabilitySha256) { finish(new GateFailure("KNOWN_FAILURE", "The JIT permit did not match the sealed capability hash.")); return; } finish(null, value); } finally { bytes.fill(0); for (const chunk of chunks) chunk.fill(0); } }); client.on("error", () => finish(new GateFailure( "KNOWN_FAILURE", "The parent-owned JIT permit pipe closed without authority."))); }); evidence.observed.jitPermitReceived = true; return capability; } async function prepareOnce(expiresAt) { if (Date.now() >= expiresAt - 5000) known("Authorization is too near expiry before PREPARE."); let before = await snapshot(); assertCommon(before, "PREPARE boundary"); if (!isConnectedIdle(before) || !exactPlaylist(before.state)) known("PREPARE boundary is not exact IDLE 5001."); const preRevision = before.state.revision; let capability = await receiveJitCapability(expiresAt); before = await snapshot(); assertCommon(before, "post-permit PREPARE boundary"); if (before.state.revision !== preRevision || !isConnectedIdle(before) || !exactPlaylist(before.state)) { capability = null; known("The exact PREPARE boundary changed while the parent granted the JIT permit."); } const armed = await evaluate(`globalThis.__legacyPgmPrepareGate.arm( ${JSON.stringify(capability)}, ${JSON.stringify(preRevision)})`); if (armed?.armed !== true) unknown("PREPARE permit did not arm."); if (Date.now() >= expiresAt - 5000) known("Authorization expired at PREPARE boundary."); prepareDispatchPossible = true; evidence.observed.prepareDispatchPossible = true; const dispatched = await evaluate(`(() => { if (!globalThis.__legacyPgmPrepareGate) throw new Error("PREPARE gate unavailable"); window.chrome.webview.postMessage({ type: "gate-a-prepare", payload: { capability: ${JSON.stringify(capability)} } }); return true; })()`); capability = null; if (dispatched !== true) unknown("PREPARE bridge dispatch did not return exactly."); prepareIssued = true; evidence.observed.prepareIssued = true; let current; let busyObserved = false; while (Date.now() < hardDeadline) { current = await snapshot(); assertCommon(current, "PREPARE observation"); if (current.audit.prepareCount !== 1) unknown("PREPARE one-shot ledger changed."); if (current.audit.busyObservedAtPreRevision === true) { busyObserved = true; evidence.observed.busyObserved = true; } if (busyObserved && isPrepared5001(current) && current.state.revision > preRevision) { evidence.checkpoints.push({ name: "prepared-5001", state: projectedState(current.state) }); return current; } const p = current.state.playout; if (busyObserved && current.state.isBusy === false && current.state.revision > preRevision && p.phase === "idle" && p.preparedCode == null && p.onAirCode == null && p.outcomeUnknown !== true && String(current.state.statusKind).toLowerCase() === "error" && String(current.state.statusMessage || "").length > 0) { throw new GateFailure("KNOWN_FAILURE", `PREPARE rejected: ${current.state.statusMessage}`); } await sleep(100); } unknown("PREPARE outcome timed out; no retry or cleanup command was sent."); } async function captureScreenshot() { const response = await rpc("Page.captureScreenshot", { format: "png", fromSurface: true, captureBeyondViewport: false }, 15000); if (!response?.data) known("Screenshot data is unavailable."); const bytes = Buffer.from(response.data, "base64"); const pngSignature = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]); if (bytes.length < 1024 || !bytes.subarray(0, pngSignature.length).equals(pngSignature)) { unknown("Screenshot is not a nontrivial PNG image."); } fs.mkdirSync(path.dirname(configuration.screenshotPath), { recursive: true }); fs.writeFileSync(configuration.screenshotPath, bytes, { flag: "wx" }); evidence.screenshot = { path: configuration.screenshotPath, bytes: bytes.length, sha256: sha256(bytes) }; } async function execute() { const contract = validateFrozenContract(); evidence.authorizationSha256 = contract.authorizationHash; const target = await discoverTarget(); await connect(validateEndpoint(target)); await rpc("Runtime.enable"); await rpc("Page.enable"); await installGate(configuration.planSha256, configuration.capabilitySha256); const connected = await waitFor("Live connected IDLE", value => isConnectedIdle(value), 60000); if ((connected.state.playlist || []).length !== 0) known("Gate A requires an empty playlist."); evidence.checkpoints.push({ name: "connected-idle", state: projectedState(connected.state) }); await configurePlaylist(); const prepared = await prepareOnce(contract.expiresAt); assertExactOutbound(prepared.audit, true); await captureScreenshot(); const final = await snapshot(); assertCommon(final, "post-screenshot final verification"); assertExactOutbound(final.audit, true); if (final.audit.busyObservedAtPreRevision !== true || !isPrepared5001(final)) { unknown("Post-screenshot state is not the exact prepared 5001 result."); } evidence.finalState = projectedState(final.state); evidence.observed.outboundTypes = final.audit.outbound.map(item => item.type); evidence.observed.blocked = final.audit.blocked; evidence.result = "PASS_PREPARED"; } try { await execute(); } catch (error) { let category = error instanceof GateFailure ? error.category : "HARNESS_ERROR"; if (socket?.readyState === WebSocket.OPEN) { try { const final = await snapshot(); evidence.finalState = projectedState(final?.state); evidence.observed.outboundTypes = final?.audit?.outbound?.map(item => item.type) || []; evidence.observed.blocked = final?.audit?.blocked || []; if (final?.audit?.prepareCount === 1) { prepareIssued = true; evidence.observed.prepareIssued = true; } if (!fs.existsSync(configuration.screenshotPath)) await captureScreenshot(); } catch (captureError) { evidence.captureError = String(captureError?.message || captureError); } } const isExactKnownRejection = prepareIssued && category === "KNOWN_FAILURE" && String(error?.message || "").includes("PREPARE rejected:"); if (prepareDispatchPossible && !isExactKnownRejection) category = "OUTCOME_UNKNOWN"; evidence.result = category; evidence.error = { name: error?.name || "Error", message: String(error?.message || error) }; process.exitCode = category === "KNOWN_FAILURE" ? 2 : 3; } finally { evidence.completedAtUtc = new Date().toISOString(); fs.mkdirSync(path.dirname(configuration.outputPath), { recursive: true }); fs.writeFileSync(configuration.outputPath, JSON.stringify(evidence, null, 2) + "\n", { encoding: "utf8", flag: "wx" }); try { socket?.close(); } catch { /* The page and its installed guard stay open. */ } }