Milestone v1 (v2.0.0): Mokosh — Session Capture #1

Merged
strategy155 merged 297 commits from gsd/phase-04-harden-clean-up-optional into main 2026-05-31 15:34:17 +00:00
2 changed files with 100 additions and 1 deletions
Showing only changes of commit 8c94bd515d - Show all commits

View File

@@ -103,6 +103,8 @@ import {
driveA30,
// Plan 03-03 — password-filter PARTIAL (SPEC §10 #8 PARTIAL per D-P3-02)
driveA31,
// Plan 03-04 — RAM scaffolding best-effort (SPEC §10 #9 per D-P3-04)
driveA32,
getManifestVersion,
} from './lib/harness-page-driver';
import {
@@ -271,7 +273,7 @@ async function assertA0_GrepGate(): Promise<{
*/
async function main(): Promise<number> {
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');
// 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
// events at all" tautology).
{ 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 };

View File

@@ -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,
};
}