feat(03-01): Task 2 — assertA29 + driveA29 + orchestrator wiring (A29 30/30 GREEN)

Page-side (tests/uat/extension-page-harness.ts):
- assertA29 dispatches probe-page DOM mutation (input value + modal
  toggle), settles 500ms for rrweb IncrementalSnapshot to enqueue,
  setupFreshRecording, 11s segment-settle, SAVE_ARCHIVE; pushes
  A29.1 SAVE ack check. Module-local constants:
  A29_SAVE_ARCHIVE_TIMEOUT_MS=15s, A29_SEGMENT_SETTLE_MS=11s,
  A29_MUTATION_SETTLE_MS=500ms.
- declare global interface + window.__mokoshHarness object literal
  extended with assertA29 (single-method-per-assertion contract).
- statusEl + console banner updated A28 → A29 + cite Plan 03-01.

Host-side (tests/uat/lib/harness-page-driver.ts):
- Add `import { EventType } from '@rrweb/types';`.
- driveA29 — 3-phase orchestration mirroring driveA26:
  Phase 1 page.evaluate harness.assertA29(); Phase 2 findLatestZip;
  Phase 3 JSZip.loadAsync rrweb/session.json + EventType grep.
  Appends A29.0a (rrweb/session.json present) + A29.2..A29.5
  (events.length>0 + Meta + FullSnapshot + IncrementalSnapshot).

Orchestrator (tests/uat/harness.test.ts):
- driveA29 imported after driveA28.
- driveA29Wrapped const captures handles.downloadsDir.
- drivers array push A29 entry with banner citing Plan 03-01 + Pitfall 1.
- Architecture banner string updated A28 → A29.

Empirical verification (HEADLESS=1 SKIP_PROD_REBUILD=0 npm run test:uat):
- UAT harness: 30/30 GREEN (29 prior + A29 NEW).
- A29 events.length=4; event types observed: 2, 3, 4 (FullSnapshot,
  IncrementalSnapshot, Meta — all three required types present).
- Pitfall 1 mitigation empirically verified — the pre-SAVE DOM
  mutation produced the IncrementalSnapshot.
- vitest 171/171 GREEN preserved (full suite).
- Tier-1 FORBIDDEN_HOOK_STRINGS unit gate 13/13 GREEN (12 strings × 0
  hits each) — A29 rides production rrweb wiring + GET_RRWEB_EVENTS
  bridge + sendMessageWithTimeout helper; NO new __MOKOSH_UAT__
  symbols.
- npx tsc --noEmit exit 0.
This commit is contained in:
2026-05-20 19:17:47 +02:00
parent c02914df86
commit cc13f319a1
3 changed files with 273 additions and 3 deletions

View File

@@ -97,6 +97,8 @@ import {
driveA26,
driveA27,
driveA28,
// Plan 03-01 — rrweb DOM verification (SPEC §10 #4 / REQ-rrweb-dom-buffer)
driveA29,
getManifestVersion,
} from './lib/harness-page-driver';
import {
@@ -265,7 +267,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)\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)\n');
process.stdout.write('='.repeat(72) + '\n');
// A0 pre-flight (no Chrome launch needed; runs against built dist/).
@@ -333,6 +335,10 @@ async function main(): Promise<number> {
(page) => driveA27(page, handles.downloadsDir);
const driveA28Wrapped: (page: import('puppeteer').Page) => Promise<AssertionRecord> =
(page) => driveA28(page, handles.downloadsDir);
// Plan 03-01 — driveA29 needs downloadsDir for host-side JSZip parse
// of rrweb/session.json from the just-produced zip.
const driveA29Wrapped: (page: import('puppeteer').Page) => Promise<AssertionRecord> =
(page) => driveA29(page, handles.downloadsDir);
const drivers: ReadonlyArray<{
readonly name: string;
@@ -428,6 +434,13 @@ async function main(): Promise<number> {
// and asserts EXACTLY 5 paths: video/last_30sec.webm, rrweb/session.json,
// logs/events.json, screenshot.png, meta.json (set-equality; no extras).
{ name: 'A28', drive: driveA28Wrapped },
// Plan 03-01 A29: rrweb DOM verification (SPEC §10 #4).
// A29 owns its SAVE because the probe-page DOM mutation must
// happen between page load and SAVE so rrweb's IncrementalSnapshot
// fires (RESEARCH Pitfall 1). Host-side driveA29 JSZip-parses
// rrweb/session.json and asserts the EventType enum surfaces
// (Meta=4, FullSnapshot=2, IncrementalSnapshot=3) are present.
{ name: 'A29', drive: driveA29Wrapped },
];
const buffers = { swConsole: handles.swConsole, offConsole: handles.offConsole };