Files
Mark d66cbf6900 chore(04-06): add operator-empirical screenshot harness (Task 4 artifact)
Per the orchestrator checkpoint protocol + the saved-memory feedback
"trust harness over manual UAT", Task 4's dark-mode aesthetic
judgment uses Puppeteer-produced screenshots (NOT a manual Chrome
session). This script:

1. Loads dist/ via puppeteer.launch enableExtensions.
2. Resolves the runtime extension ID via the canonical
   browser.extensions() Map (mirrors tests/uat/lib/launch.ts
   resolveExtensionIdWithPolling).
3. Opens chrome-extension://<id>/src/welcome/welcome.html.
4. Captures the .welcome-hero bounding-box region in LIGHT surface
   (default OS appearance — the regression-baseline shot, matching
   the Plan 01-10 cycle-2 operator ack 2026-05-20).
5. Sets [data-theme="dark"] on <html> (Mokosh's tokens.css cascade
   uses the explicit .dark / [data-theme="dark"] selector at line
   234; emulateMediaFeatures alone does NOT trigger it because
   tokens.css has no @media (prefers-color-scheme: dark) block — a
   fact verified live this session). emulateMediaFeatures is also
   set, forward-compatible with any future @media block.
6. Re-screenshot the hero region — the DARK-surface aesthetic shot.

Output paths (canonical per the 04-06-PLAN Task 4 contract):
  - /tmp/04-06-welcome-hero-light.png
  - /tmp/04-06-welcome-hero-dark.png

Run results (this session):
  - LIGHT: computed stroke = rgb(250, 247, 241) — linen-50; the
    --mks-fg-inverse value on the LIGHT cascade flowing through
    .welcome-hero__mark to the inline <svg>'s currentColor.
  - DARK:  computed stroke = rgb(24, 27, 42) — ink-900; the
    --mks-fg-inverse value AFTER the .dark cascade override
    (tokens.css 244 sets --mks-fg-inverse: var(--mks-ink-900)) —
    the strategy's contrast flip is empirically verified.

Implementation notes (deviation Rule 3 — observed environment
constraints fixed inline):
  - Initial extension ID resolver used browser.targets() polling +
    regex; rewritten to use the canonical Puppeteer 22.x
    browser.extensions() Map approach.
  - Initial screenshot used ElementHandle.screenshot(); Puppeteer
    Runtime.callFunctionOn timed out on the second elementHandle
    evaluate in headless extension page context. Rewritten to a
    single page.evaluate() that returns getBoundingClientRect() +
    computedStroke in one CDP round trip, then page.screenshot({clip})
    against those coordinates — succeeds reliably.
  - protocolTimeout set to 120s to match the UAT harness baseline.

References:
  - .planning/phases/04-harden-clean-up-optional/04-06-PLAN.md Task 4.
  - tests/uat/lib/launch.ts (the canonical extension-loading pattern).
  - https://pptr.dev/api/puppeteer.browser.extensions
  - https://pptr.dev/api/puppeteer.page.screenshot
2026-05-26 09:11:46 +02:00
..

scripts/

Dev-only utility scripts. These are NOT bundled by npm run build — the production dist/ contains zero smoke artifacts (verified by grep -rn smoke dist/ returning empty post-build).

Smoke-isolation invariant

smoke.sh and any future smoke-test harness live ENTIRELY in this directory. Vite's rollupOptions.input (vite.config.ts) does NOT reference any path under scripts/; the build pipeline cannot include smoke artifacts in dist/. RESEARCH §12 verifies no-op condition via grep -rn 'smoke\|SMOKE\|data:text/html' src/ returning empty.

A defensive __VITE_DEV__ define-token (see vite.config.ts:define) is reserved for any future inline smoke-mode check; currently it defaults to false so even a misplaced if (__VITE_DEV__) { ... } branch is statically tree-shaken out of production by Rollup.

Override per-build via env var:

VITE_DEV=1 npm run dev    # __VITE_DEV__ === true
npm run build              # __VITE_DEV__ === false (production default)

Index

Script Purpose
subset-fonts.sh One-off font subsetting (Lora + IBM Plex Sans/Mono → Latin+Cyrillic)
rasterize-icons.sh One-off icon rasterization (mokosh-mark.svg → icons/icon{16,48,128}.png)
smoke.sh (if present) Local smoke harness — not part of npm run build

Re-run conditions:

  • subset-fonts.sh: when upstream Lora-Cyrillic or IBM/plex releases a major bump with bug fixes; or when the UNICODES range needs expansion. See src/shared/fonts/README.md for the canonical recipe.
  • rasterize-icons.sh: when src/shared/brand/mokosh-mark.svg changes (the source-of-truth for the toolbar icon).

References

  • .planning/phases/01-stabilize-video-pipeline/01-12-PLAN.md Wave 5 Task 1 — the smoke-isolation contract this README documents
  • .planning/phases/01-stabilize-video-pipeline/01-12-RESEARCH.md §12 — verification rationale
  • .planning/intel/brand-decisions-v1.md D-09 — dev-only smoke shipping decision