Task 1 of Plan 01-11 (Puppeteer UAT harness).
- npm install --save-dev puppeteer@^25.0.2 tsx@^4 @types/node
resolved: puppeteer@25.x, tsx@4.22.1, @types/node@25.8.0
pulls ~150MB Chromium binary at install time (T-1-11-03 — accepted,
package-lock pins resolved hashes via @puppeteer/browsers).
- package.json scripts: add build:test + test:uat (per RESEARCH §10
two-bundle orchestration); existing dev/build/preview/test untouched.
- vite.test.config.ts: extends ./vite.config.ts via mergeConfig with
mode:'test' + build.outDir:'dist-test' + emptyOutDir:true. Verified
npm run build:test produces dist-test/ in 7.93s; npm run build keeps
producing dist/ in 7.67s (no clobber).
- tsconfig.json `include: ["src"]` already covers src/test-hooks/**/*
via wildcard — no edit needed.
- tests/background/no-test-hooks-in-prod-bundle.test.ts: Tier-1 gate
mirroring sw-bundle-import.test.ts's execFile pattern. Greps the
BUILT dist/ tree for 5 forbidden hook surfaces (one `it` per surface
for granular failure isolation): __mokoshTest, simulateUserStop,
getSegmentCount, setCurrentStream, setSegmentCountGetter. All 5
surfaces absent today (RED-then-GREEN polarity inverted — the gate
is GREEN now and MUST stay GREEN after Task 2 lands the hooks).
SKIP_BUILD=1 escape hatch for developer iteration.
- .gitignore: add dist-test/ (no point versioning generated test bundle).
Verification:
- npx tsc --noEmit: exit 0
- npm run build: exit 0; dist/ populated (375.37 kB SW chunk)
- npm run build:test: exit 0; dist-test/ populated (identical chunk sizes —
the gated dynamic imports do not land until Task 2; this commit only
proves the two-bundle plumbing)
- SKIP_BUILD=1 npx vitest run tests/background/no-test-hooks-in-prod-bundle.test.ts:
6/6 GREEN (1 build-sanity + 5 forbidden-surface)
- SKIP_BUILD=1 npx vitest run (full suite): 89/89 GREEN
(83 baseline + 6 new Tier-1 surfaces = 89)
Working-tree cleanup: a stale 5.4 MB tests/fixtures/last_30sec.webm
(unrelated operator smoke regen present at session spawn) was stashed
before running the baseline — it caused the webm-playback test to time
out at 5s. After stashing back to HEAD's 1.9 MB fixture, baseline passes
cleanly. Not committing the fixture restoration here (pre-existing
working-tree state, not part of Task 1).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Layer 2 of the extended SW-bundle-import gate caught a runtime
ReferenceError: Buffer is not defined at EBMLDecoder.constructor
(this._buffer = Buffer.alloc(0)). Reached from remuxSegments via
extractFramesFromSegment for every input segment — would crash
the SW on every SAVE_ARCHIVE click in real Chrome.
ts-ebml has a 5-year-old open issue (legokichi/ts-ebml#37,
"Can't use Buffer in browser") acknowledging the incompatibility
with no maintainer fix. The canonical Vite workaround is
vite-plugin-node-polyfills with a narrow Buffer-only config (per
the plugin author's official docs).
Changes:
- vite-plugin-node-polyfills@0.27.0 added as devDependency
- vite.config.ts adds nodePolyfills plugin with narrow config:
include: ['buffer'], globals.Buffer: true, globals.global: false,
globals.process: false, protocolImports: false (Buffer only, no
stdlib pull-in)
- bundle delta: SW chunk 373.05 kB (-0.49 kB vs C-config alone);
+27.48 kB shared polyfill chunk (index-CgqXENQe.js, used by SW
and offscreen). Net cost ~26.3 kB for full Buffer support.
Bundle verification:
- bundled EBMLDecoder.js now reads `this._buffer = me.alloc(0)`
where `me` is the imported polyfill Buffer (was `Buffer.alloc(0)`
against undefined globalThis.Buffer). Same rewrite applied to
all 3 Buffer.alloc/Buffer.concat/Buffer.from sites in ts-ebml.
- bundle does NOT depend on globalThis.Buffer (the polyfill
rewrites references as imports, not as global assignments) —
Layer 1 of the gate still strips Buffer from globalThis and
passes, confirming this.
Layer 2 gate: RED → GREEN. resolve.alias.ebml fix from commit
52c7636 preserved — still required for ebml CJS-interop;
the polyfill addresses an orthogonal runtime concern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add ts-ebml ^3.0.2 (parse half) and webm-muxer ^5.1.4 (write half) per
CONTEXT.md amendment D-14-remux; both MIT, both verified SW-compatible
in the d13 debug-session library survey.
- tests/background/webm-remux-deps.test.ts pins two contracts:
(a) named exports surface (Muxer + ArrayBufferTarget + Decoder).
(b) both libraries import cleanly when window/document are absent on
globalThis — guards the published dist against accidentally
acquiring DOM globals on the hot path that would crash the
Chrome service-worker runtime.
- Note: webm-muxer 5.1.4 upstream-deprecated in favor of Mediabunny; the
pinned version still meets the d13 architectural requirement
(single-EBML output via addVideoChunkRaw). Migration to Mediabunny is
out of scope for Plan 01-08 and would require a new ADR.
- Baseline 53 GREEN + 2 new GREEN; tsc clean; 2 webm-playback duration
RED still pending (drive to GREEN in Tasks 3-5).
- Add vitest@^4 to devDependencies (4.1.6 latest stable; 5.x still beta)
- Add "test": "vitest run" npm script
- Run npm install to refresh node_modules and lock file
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>