feat(03-04): Task 1 — driveA32 host-side Page.metrics scaffolding + orchestrator wiring
A32 ships ~90 lines of best-effort RAM scaffolding per D-P3-04 + RESEARCH Open Question 3 (recommended SHIP). Calls puppeteer.Page.metrics() against the harness page and asserts JSHeapUsedSize is below the SPEC §10 #9 50 MB ceiling. Page-realm scope is the load-bearing caveat (RESEARCH Pitfall 2): the MV3 service worker is a separate Puppeteer target with its own V8 isolate, so Page.metrics() under-reports the operator-facing "extension background RAM" measurement that §10 #9 actually requires. The binding §10 #9 gate stays operator-driven (chrome://memory-internals OR chrome://extensions service-worker memory display) and is recorded in Plan 03-05 VERIFICATION.md human_verification block. Mandatory diagnostic line emitted on EVERY run regardless of pass/fail: "NOTE: page-realm only; SW context measurement requires chrome://memory-internals operator verification per D-P3-04." printAssertionResult prints diagnostics to stdout so the operator sees the caveat in the live UAT trace, never confusing automation GREEN with full §10 #9 closure (T-03-04-01 Repudiation mitigation). Host-side only — no page-side assertA32, no setupFreshRecording, no SAVE, no archive parse. driveA32 takes only `page` (no downloadsDir), so the orchestrator pushes it bare in the drivers array without a wrapped const. Tier-1 FORBIDDEN_HOOK_STRINGS inventory unchanged at 12 entries (Page.metrics is host-side puppeteer; not bundled). Empirical: UAT harness 32/32 → 33/33 GREEN; A32.1 PASS (JSHeapUsedSize= 1909924 bytes); A32.2 PASS (1.82 MB << 50 MB). Tier-1 unit-gate 13/13 sub-tests GREEN; 12 strings × 0 hits each in dist/. vitest 171/171 GREEN. Closes: - Plan 03-04 must_have 'puppeteer.Page.metrics() returns a JSHeapUsedSize value (>= 0) for the harness page realm' (A32.1) - Plan 03-04 must_have 'JSHeapUsedSize for the harness page realm is below 50 MB' (A32.2) - Plan 03-04 must_have 'Driver emits an explicit diagnostic line: NOTE: page-realm only' (Pitfall 2 gate — leads diagnostics array) - Plan 03-04 must_have 'UAT harness exits 0 with 32 + 1 = 33/33 assertions GREEN' (empirical 33/33)
This commit is contained in:
@@ -2314,3 +2314,93 @@ export async function driveA31(
|
||||
error: pageResult.error,
|
||||
};
|
||||
}
|
||||
|
||||
/* ─── Plan 03-04 — driveA32 (RAM scaffolding best-effort) ──────────── */
|
||||
|
||||
/** RAM ceiling per SPEC §10 #9 + CON-ram-ceiling. */
|
||||
const A32_RAM_CEILING_BYTES = 50 * 1024 * 1024;
|
||||
/** Bytes-per-MB factor for diagnostic copy. */
|
||||
const A32_BYTES_PER_MB = 1024 * 1024;
|
||||
|
||||
/**
|
||||
* Drive A32 (Plan 03-04 — SPEC §10 #9 RAM best-effort per D-P3-04).
|
||||
*
|
||||
* Reads puppeteer.Page.metrics() against the harness page and asserts
|
||||
* JSHeapUsedSize is below the 50 MB ceiling. This is informational
|
||||
* scaffolding ONLY:
|
||||
*
|
||||
* - RESEARCH Pitfall 2: Page.metrics is page-realm only. The MV3
|
||||
* service worker is a separate Puppeteer target with its own V8
|
||||
* isolate; page.metrics() does not aggregate across workers/iframes.
|
||||
* - The page-realm value reported here is NOT the operator-facing
|
||||
* "extension background RAM" measurement that SPEC §10 #9 requires.
|
||||
* - The binding §10 #9 gate lives in Plan 03-05 VERIFICATION.md
|
||||
* `human_verification` block (operator runs chrome://memory-internals
|
||||
* OR chrome://extensions service-worker memory display).
|
||||
*
|
||||
* Why ship this anyway (per RESEARCH Open Question 3):
|
||||
* - Low cost (~30 lines; single API call; no new bundle surface).
|
||||
* - Exercises the Page.metrics API end-to-end so Phase 4 (programmatic
|
||||
* RAM measurement upgrade) inherits a working scaffold.
|
||||
* - Provides a sanity floor — if the harness page-realm heap ever
|
||||
* blows past 50 MB, something has gone catastrophically wrong in
|
||||
* the test infrastructure itself (not necessarily a §10 #9 regression
|
||||
* in production).
|
||||
*
|
||||
* The diagnostic line about page-realm scope MUST be emitted regardless
|
||||
* of pass/fail per Pitfall 2.
|
||||
*
|
||||
* @param page - The harness page from `launchHarnessBrowser`.
|
||||
* @returns AssertionRecord with 2 checks (heap returned + heap < 50 MB)
|
||||
* + explicit page-realm-only diagnostic.
|
||||
*/
|
||||
export async function driveA32(page: Page): Promise<AssertionRecord> {
|
||||
const checks: CheckRecord[] = [];
|
||||
const diagnostics: string[] = [];
|
||||
|
||||
// Pitfall 2 gate: emit the page-realm caveat BEFORE any other diagnostic
|
||||
// so it leads in the structured output (the operator sees it first).
|
||||
diagnostics.push(
|
||||
'NOTE: page-realm only; SW context measurement requires chrome://memory-internals operator verification per D-P3-04.',
|
||||
);
|
||||
|
||||
let metricsErr: string | null = null;
|
||||
let jsHeapBytes = -1;
|
||||
let jsHeapTotal = -1;
|
||||
try {
|
||||
const metrics = await page.metrics();
|
||||
jsHeapBytes = metrics.JSHeapUsedSize ?? -1;
|
||||
jsHeapTotal = metrics.JSHeapTotalSize ?? -1;
|
||||
} catch (err) {
|
||||
metricsErr = err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
|
||||
const jsHeapMB = jsHeapBytes >= 0 ? jsHeapBytes / A32_BYTES_PER_MB : -1;
|
||||
diagnostics.push(`A32 JSHeapUsedSize=${jsHeapBytes} bytes (${jsHeapMB.toFixed(2)} MB)`);
|
||||
diagnostics.push(`A32 JSHeapTotalSize=${jsHeapTotal} bytes`);
|
||||
if (metricsErr !== null) {
|
||||
diagnostics.push(`A32 Page.metrics threw: ${metricsErr}`);
|
||||
}
|
||||
|
||||
checks.push({
|
||||
name: 'A32.1: Page.metrics returned a JSHeapUsedSize value >= 0',
|
||||
expected: '>= 0',
|
||||
actual: jsHeapBytes,
|
||||
passed: jsHeapBytes >= 0,
|
||||
});
|
||||
checks.push({
|
||||
name: `A32.2: Page-realm JS heap < ${A32_RAM_CEILING_BYTES / A32_BYTES_PER_MB} MB (NOTE: scaffolding only; SW context excluded per D-P3-04)`,
|
||||
expected: `< ${A32_RAM_CEILING_BYTES / A32_BYTES_PER_MB} MB`,
|
||||
actual: jsHeapMB >= 0 ? `${jsHeapMB.toFixed(2)} MB` : 'unavailable',
|
||||
passed: jsHeapBytes >= 0 && jsHeapBytes < A32_RAM_CEILING_BYTES,
|
||||
});
|
||||
|
||||
const passed = checks.every((c) => c.passed);
|
||||
return {
|
||||
passed,
|
||||
name: 'A32 — RAM scaffolding (best-effort; page-realm only per D-P3-04 / SPEC §10 #9)',
|
||||
checks,
|
||||
diagnostics,
|
||||
error: metricsErr ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user