Milestone v1 (v2.0.0): Mokosh — Session Capture #1
@@ -103,6 +103,8 @@ import {
|
|||||||
driveA30,
|
driveA30,
|
||||||
// Plan 03-03 — password-filter PARTIAL (SPEC §10 #8 PARTIAL per D-P3-02)
|
// Plan 03-03 — password-filter PARTIAL (SPEC §10 #8 PARTIAL per D-P3-02)
|
||||||
driveA31,
|
driveA31,
|
||||||
|
// Plan 03-04 — RAM scaffolding best-effort (SPEC §10 #9 per D-P3-04)
|
||||||
|
driveA32,
|
||||||
getManifestVersion,
|
getManifestVersion,
|
||||||
} from './lib/harness-page-driver';
|
} from './lib/harness-page-driver';
|
||||||
import {
|
import {
|
||||||
@@ -271,7 +273,7 @@ async function assertA0_GrepGate(): Promise<{
|
|||||||
*/
|
*/
|
||||||
async function main(): Promise<number> {
|
async function main(): Promise<number> {
|
||||||
process.stdout.write('\nMokosh Plan 01-13 + 01-14 + 02-04 — UAT harness orchestrator\n');
|
process.stdout.write('\nMokosh Plan 01-13 + 01-14 + 02-04 — UAT harness orchestrator\n');
|
||||||
process.stdout.write('Architecture: A0 pre-flight + extension-internal page driver (A1..A14, A15..A17, A18..A22, A23, A24, A25, A26, A27, A28, A29, A30, A31)\n');
|
process.stdout.write('Architecture: A0 pre-flight + extension-internal page driver (A1..A14, A15..A17, A18..A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32)\n');
|
||||||
process.stdout.write('='.repeat(72) + '\n');
|
process.stdout.write('='.repeat(72) + '\n');
|
||||||
|
|
||||||
// A0 pre-flight (no Chrome launch needed; runs against built dist/).
|
// A0 pre-flight (no Chrome launch needed; runs against built dist/).
|
||||||
@@ -475,6 +477,13 @@ async function main(): Promise<number> {
|
|||||||
// mean the filter actually fired rather than the trivial "no
|
// mean the filter actually fired rather than the trivial "no
|
||||||
// events at all" tautology).
|
// events at all" tautology).
|
||||||
{ name: 'A31', drive: driveA31Wrapped },
|
{ name: 'A31', drive: driveA31Wrapped },
|
||||||
|
// Plan 03-04 A32: RAM scaffolding (SPEC §10 #9 best-effort per D-P3-04).
|
||||||
|
// NOTE — Page.metrics is page-realm only; SW context is a separate
|
||||||
|
// Puppeteer target (RESEARCH Pitfall 2). A32 is informational
|
||||||
|
// scaffolding; the binding §10 #9 gate lives in Plan 03-05
|
||||||
|
// VERIFICATION.md `human_verification` block. No wrapped const
|
||||||
|
// needed — driveA32 takes only `page`.
|
||||||
|
{ name: 'A32', drive: driveA32 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const buffers = { swConsole: handles.swConsole, offConsole: handles.offConsole };
|
const buffers = { swConsole: handles.swConsole, offConsole: handles.offConsole };
|
||||||
|
|||||||
@@ -2314,3 +2314,93 @@ export async function driveA31(
|
|||||||
error: pageResult.error,
|
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