feat(02-04): harness A25 — empirical <5s SAVE→zip latency (REQ-archive-export-latency, SPEC §10 #6)
Wire A25 into the UAT harness as the binding empirical gate for REQ-archive-export-latency / SPEC §10 #6 (5000ms hard ceiling end-to-end from SAVE_ARCHIVE dispatch to zip-on-disk). Architecture: - Page-side assertA25 records t0 (performance.now) + t0Wall (Date.now) + tAck bookends around the chrome.runtime.sendMessage(SAVE_ARCHIVE) call. Returns A25Result extending AssertionRecord with the 3 timing fields + ackSuccess flag. - Host-side driveA25(page, downloadsDir) snapshots zip dir BEFORE page.evaluate dispatch, polls for new-or-overwritten .zip via mtime delta (mirrors A12/A13 overwrite-aware pattern), uses page-supplied t0Wall as the host anchor for the dispatch→file-on-disk latency check (NOT a host-side Date.now captured before page.evaluate, which would include setupFreshRecording + 11s segment-settle wall time and always fail the 5s budget). [Rule 1 - Bug] Initial implementation used host-side Date.now() captured before page.evaluate as the latency anchor — this incorrectly included the 11s segment-settle window in the budget. First run observed A25.3=11188ms (FAIL). Fix: page-side captures Date.now() at the SAVE_ARCHIVE dispatch instant (AFTER setupFreshRecording + segment-settle complete) and returns it as t0Wall in A25Result; the driver uses this as the canonical host anchor. Result on re-run: A25.3=61ms (GREEN, well under 5s SLO). Documented per T-02-04-02 disposition (bracket only the SAVE dispatch, not the broader test orchestration). Files modified: - tests/uat/extension-page-harness.ts (+~115 lines): assertA25 + A25_* constants + A25Result interface - tests/uat/lib/harness-page-driver.ts (+~95 lines): driveA25 + A25_HOST_POLL_TIMEOUT_MS const + A25_LATENCY_CEILING_MS const - tests/uat/harness.test.ts (+~15 lines): import driveA25, wrap with downloadsDir, append to drivers list Verification: - HEADLESS=1 npm run test:uat → 26/26 GREEN - elapsedAck=60ms, host-side delta=61ms (both well under 5000ms SLO) - npx vitest run tests/background/no-test-hooks-in-prod-bundle.test.ts → 13/13 GREEN (Tier-1 FORBIDDEN_HOOK_STRINGS unchanged at 12) - npx tsc --noEmit → clean Plan 02-04 scope: 2/3 tasks landed (A24 + A25); Task 3 adds A26 (meta.json 8-field) + A27 (multi-tab strict) + A28 (archive-layout strict).
This commit is contained in:
@@ -91,6 +91,8 @@ import {
|
||||
driveA23,
|
||||
// Plan 02-04 Task 1 — D-P2-01 empirical Blob URL verification
|
||||
driveA24,
|
||||
// Plan 02-04 Task 2 — REQ-archive-export-latency (5s ceiling)
|
||||
driveA25,
|
||||
getManifestVersion,
|
||||
} from './lib/harness-page-driver';
|
||||
import {
|
||||
@@ -259,7 +261,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)\n');
|
||||
process.stdout.write('Architecture: A0 pre-flight + extension-internal page driver (A1..A14, A15..A17, A18..A22, A23, A24, A25)\n');
|
||||
process.stdout.write('='.repeat(72) + '\n');
|
||||
|
||||
// A0 pre-flight (no Chrome launch needed; runs against built dist/).
|
||||
@@ -313,6 +315,10 @@ async function main(): Promise<number> {
|
||||
(page) => driveA12(page, handles.downloadsDir);
|
||||
const driveA13Wrapped: (page: import('puppeteer').Page) => Promise<AssertionRecord> =
|
||||
(page) => driveA13(page, handles.downloadsDir, expectedManifestVersion);
|
||||
// Plan 02-04 Task 2 — driveA25 needs downloadsDir for the host-side
|
||||
// dispatch→file-on-disk latency check (mirrors A5/A12/A13 wrapping).
|
||||
const driveA25Wrapped: (page: import('puppeteer').Page) => Promise<AssertionRecord> =
|
||||
(page) => driveA25(page, handles.downloadsDir);
|
||||
|
||||
const drivers: ReadonlyArray<{
|
||||
readonly name: string;
|
||||
@@ -384,6 +390,14 @@ async function main(): Promise<number> {
|
||||
// must be installed pre-dispatch. After A24 the recording stays alive
|
||||
// for any chained Plan 02-04 Tasks 2-3 assertions (Phase 2 closure).
|
||||
{ name: 'A24', drive: driveA24 },
|
||||
// Plan 02-04 Task 2 A25: REQ-archive-export-latency / SPEC §10 #6.
|
||||
// Page-side measures SAVE→ack via performance.now() bookends; host-side
|
||||
// adds the dispatch→file-on-disk latency check via downloadsDir
|
||||
// polling + mtime delta. Hard ceiling: 5000ms end-to-end. A25 owns
|
||||
// its setupFreshRecording (clean latency measurement; not compounded
|
||||
// with A24's still-pending state). The 11s segment-settle is NOT
|
||||
// counted toward the 5s budget — only the SAVE dispatch.
|
||||
{ name: 'A25', drive: driveA25Wrapped },
|
||||
];
|
||||
|
||||
const buffers = { swConsole: handles.swConsole, offConsole: handles.offConsole };
|
||||
|
||||
Reference in New Issue
Block a user