Files
mokosh/.planning/phases/01-stabilize-video-pipeline/01-12-SUMMARY.md
Mark f319c7dc6e docs(01-12): summary — design integration landed (147/147 vitest, 21/21 UAT, brand-fit ack 2026-05-20)
Plan 01-12 closure SUMMARY landed at .planning/phases/01-stabilize-
video-pipeline/01-12-SUMMARY.md per the plan's <output> block + 01-13/
01-14 closure cadence. Mirrors the 01-13-SUMMARY frontmatter shape +
body sections (One-Liner / What Landed by Wave / Test Counts /
Deviations / Architectural Notes / Self-Check / Known Limitations /
Bridge to Phase 1 Closure).

Plan 01-12 design integration in one sentence: Lora self-hosted via
R2 designer substitution (Newsreader → Lora for Cyrillic coverage,
2026-05-19); src/shared/tokens.css canonical with 8 local @font-face
rules and zero remote URLs; 16 i18n keys across en + ru with parity;
branded Loom-mark icons replace Bug A placeholders; src/popup +
src/background migrated to chrome.i18n.getMessage with || <const>
fallback; UAT harness extended with A18-A22; pre-checkpoint bundle
gates established per feedback-pre-checkpoint-bundle-gates.md;
operator brand-fit ack received 2026-05-20 verbatim "all good".

Gate evidence (per Wave 7 pre-checkpoint 865d394 + this closure):
- vitest: 147/147 GREEN (re-verified on closure day; 26 test files)
- npm run test:uat: 21/21 GREEN (A0-A14 + A18-A22 + A23)
- npx tsc --noEmit: clean
- npm run build + npm run build:test: both clean
- MV3 CSP self-host: 0 googleapis / 0 https://fonts in dist/
- Tier-1 forbidden-strings: 13/13 GREEN (no new test-mode symbols)
- Operator brand-fit empirical ack 2026-05-20: "all good"

Closure linkage:
- Plan 01-12 functionally CLOSED (10/10 tasks; 7/7 waves)
- Plan 01-13 Task 9 (operator brand/design ack on loaded extension)
  functionally CLOSED via this checkpoint (same operator + same
  empirical surface coverage)
- Phase 1 design/brand contract CLOSED; only Plan 01-10 (welcome tab)
  remains as the last Phase 1 functional plan
- Phase 2 inherits tokens.css + chrome.i18n patterns + OFL self-host
  recipe + pre-checkpoint bundle gates as production conventions

Out-of-scope discovery (Wave 7 pre-checkpoint, logged for Phase 5
hardening, NOT a Plan 01-12 regression): setimmediate polyfill
`new Function` in SW chunk via vite-plugin-node-polyfills. Pre-existing
across Phase 1 history; logged at deferred-items.md. Suggested
follow-up: switch to a minimal Buffer shim or inline Buffer primitives
to drop the polyfill entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 07:59:34 +02:00

39 KiB
Raw Permalink Blame History

phase, plan, subsystem, tags, status, requires, provides, affects, tech-stack, key-files, decisions, patterns-established, requirements-completed, metrics, commits, ceremony_note, revision_linkage
phase plan subsystem tags status requires provides affects tech-stack key-files decisions patterns-established requirements-completed metrics commits ceremony_note revision_linkage
01-stabilize-video-pipeline 12 design-integration + i18n + brand-assets
design-integration
brand
tokens-css
woff2-selfhost
ofl-attribution
svg-rasterization
mv3-csp
i18n
locales
chrome-i18n
loom-palette
D-01-mark
D-02-welcome
D-03-voice-sober
D-04-palette
D-05-typography
D-06-icon-strategy
D-07-extname-override
D-08-tagline
D-09-smoke-dev-only
R2-lora-substitute
Approach-B-harness-extension
harness-A18-A22
pre-checkpoint-bundle-gates
complete
01-09 (badge state machine + Bug A placeholder icons + 3-state SAVE/REC/ERR + toolbar onClicked direct flow)
01-13 (Approach B UAT harness — extension-internal-page driver + offscreen synthetic stream; harness-A18-A22 inherit the pattern)
01-14 (monitorTypeSurfaces:'include' picker narrowing; FORBIDDEN_HOOK_STRINGS baseline at 12 entries; A23 gate)
Lora self-hosted via OFL Cyreal foundry release (R2 designer reply 2026-05-19 substitutes Newsreader → Lora for Cyrillic coverage)
src/shared/tokens.css canonical token system (single source of truth; 8 local @font-face rules; zero remote URLs)
branded Loom-mark PNG icons (8-bit RGBA via rsvg-convert; replaces Bug A placeholders at 16-bit RGB)
manifest.json migrated to __MSG_*__ + default_locale='en'; chrome.i18n picker resolves operator-facing surfaces
_locales/{en,ru}/messages.json with 16 keys + en↔ru parity (default_locale fallback chain per RESEARCH Pitfall 4)
src/popup + src/background migrated to chrome.i18n.getMessage with `|| <const>` fallback
BADGE_REC_COLOR set to madder #b2543d (= --mks-madder-600 per D-04 loom palette; was material-green #00C853)
UAT harness A18-A22 (font reachability + icon-distinct + manifest-i18n + Lora-resolved + welcome-tokens-conditional)
pre-checkpoint bundle gates established per feedback-pre-checkpoint-bundle-gates.md (5 grep gates run automatically before operator brand-fit checkpoint)
operator brand-fit ack 2026-05-20 (verbatim 'all good') — closes Plan 01-12 + Plan 01-13 Task 9 operator brand/design ack
manifest.json (name/description/default_locale/action.default_title → __MSG_*__)
_locales/en/messages.json (new — 16 keys; D-07 extName override; D-08 tagline)
_locales/ru/messages.json (new — 16 keys verbatim Russian per Brief §02)
src/shared/fonts/ (new bundle — 8 WOFF2 + 2 LICENSE + README.md; ~236 KB total)
src/shared/tokens.css (canonical — Google Fonts @import REMOVED + 8 local @font-face + .mks-word + Newsreader → Lora)
src/shared/brand/ (mokosh-mark.svg + mokosh-lockup.svg copied from design-incoming)
icons/icon{16,48,128}.png (Loom mark rasterized; overwrites Bug A placeholders)
src/popup/index.html (button-text emptied; data-mks-key='popupInfoText' attribute)
src/popup/index.ts (chrome.i18n.getMessage with `|| <const>` fallback at every operator-facing site)
src/popup/style.css (@import tokens.css; ZERO hex literals; var(--mks-*) throughout)
src/background/index.ts (BADGE_REC/OFF/ERROR_TITLE + onStartup/notifRecovery + setBadgeState migrated to chrome.i18n)
vite.config.ts (gains __VITE_DEV__ define-token alongside __MOKOSH_UAT__)
scripts/rasterize-icons.sh (new — one-off rsvg-convert recipe)
scripts/subset-fonts.sh (new — one-off pyftsubset recipe)
scripts/README.md (new — smoke isolation invariant + script index)
tests/build/{tokens-adopted,fonts-present,icons-present,no-remote-fonts}.test.ts (new — 6 GREEN files at Wave 0 RED)
tests/i18n/{manifest-i18n,locale-parity}.test.ts (new — i18n shape + en↔ru parity)
tests/uat/extension-page-harness.html (gains <link rel=stylesheet href="../../src/shared/tokens.css">)
tests/uat/extension-page-harness.ts (assertA18..A22 page-side methods)
tests/uat/lib/harness-page-driver.ts (driveA18..A22 host-side wrappers)
tests/uat/harness.test.ts (orchestrator extended with A18-A22; FORBIDDEN_HOOK_STRINGS UNCHANGED at 13 entries; comments updated)
added patterns preserved
Lora variable WOFF2 (OFL-1.1, Cyreal foundry; full Latin + Cyrillic basic)
IBM Plex Sans 400/500/600/700 (OFL-1.1; UI body family)
IBM Plex Mono 400/500 (OFL-1.1; diagnostic/timer family)
Mokosh canonical token system (src/shared/tokens.css)
_locales/{en,ru}/messages.json (chrome.i18n runtime)
Self-host fonts via Vite asset pipeline + @crxjs auto-WAR (relative url(./fonts/*.woff2) rebased at build to dist/assets/<hash>.woff2)
MV3 CSP self-host invariant (style-src 'self' + font-src 'self'; zero remote URLs in dist/) verified by tests/build/no-remote-fonts.test.ts
chrome.i18n.getMessage('<key>') || '<en-const-fallback>' pattern at every operator-facing copy site (graceful degradation if a key is missing in default_locale per RESEARCH Pitfall 4)
__MSG_*__ runtime substitution for manifest:name + :description + :action.default_title (NOT supported in HTML body per RESEARCH Pitfall 3 — those use data-mks-key attributes + populateMksKeys() at popup boot)
Static PNG icon artifacts (NOT regenerated at build time per RESEARCH §3 anti-pattern; scripts/rasterize-icons.sh is the one-off recipe)
Pre-checkpoint bundle gates per feedback-pre-checkpoint-bundle-gates.md (SW CSP grep + Buffer.* grep + DOM-globals grep + manifest validation + en↔ru parity) run automatically before operator empirical checkpoint
Plan 01-13 + 01-14 Approach B harness architecture (page-side assertA* + host-side driveA* + orchestrator); A18-A22 follow it verbatim
Plan 01-09 toolbar onClicked direct flow + 3-state badge state machine; only the COLOR + TITLE values migrated
Plan 01-11 architectural learnings (NO `await import(...)` in SW; chrome.i18n.getMessage is synchronous — no dynamic imports required)
Plan 01-14 monitorTypeSurfaces:'include' constraint + D-15 post-grant validation; recorder.ts unchanged by Plan 01-12
created modified deleted
src/shared/fonts/Lora-VariableFont.woff2 (Wave 1; 49 KB)
src/shared/fonts/Lora-Italic-VariableFont.woff2 (Wave 1; 53 KB)
src/shared/fonts/IBMPlexSans-{Regular,Medium,SemiBold,Bold}.woff2 (Wave 1; ~24/25/25/23 KB)
src/shared/fonts/IBMPlexMono-{Regular,Medium}.woff2 (Wave 1; ~15 KB each)
src/shared/fonts/{LICENSE-Lora.txt,LICENSE-IBM-Plex.txt,README.md} (Wave 1; OFL attribution)
src/shared/tokens.css (Wave 1; canonical token system)
src/shared/brand/{mokosh-mark.svg,mokosh-lockup.svg} (Wave 1; copied from design-incoming)
icons/icon{16,48,128}.png (Wave 2; rasterized Loom mark; replaces Bug A placeholders)
scripts/{rasterize-icons.sh,subset-fonts.sh,README.md} (Waves 1-2 + Wave 5)
_locales/en/messages.json (Wave 3; 16 keys with D-07 + D-08)
_locales/ru/messages.json (Wave 3; 16 keys verbatim Russian per Brief §02)
tests/build/{tokens-adopted,fonts-present,icons-present,no-remote-fonts}.test.ts (Wave 0)
tests/i18n/{manifest-i18n,locale-parity}.test.ts (Wave 0)
manifest.json (Wave 3; name/description/default_locale/action.default_title → __MSG_*__)
src/popup/index.html (Wave 4; button-text emptied; data-mks-key attributes)
src/popup/index.ts (Wave 4; chrome.i18n.getMessage + populateMksKeys + `|| <const>` fallback)
src/popup/style.css (Wave 4; @import tokens.css; ZERO hex literals)
src/background/index.ts (Wave 4; BADGE titles + onStartup + notifRecovery via chrome.i18n; BADGE_REC_COLOR
vite.config.ts (Wave 5; __VITE_DEV__ define alongside __MOKOSH_UAT__)
tests/uat/extension-page-harness.html (Wave 6; <link rel=stylesheet> for tokens.css)
tests/uat/extension-page-harness.ts (Wave 6; assertA18..A22)
tests/uat/lib/harness-page-driver.ts (Wave 6; driveA18..A22)
tests/uat/harness.test.ts (Wave 6; A18-A22 entries; FORBIDDEN_HOOK_STRINGS UNCHANGED at 13; orchestrator stdout)
R2 designer substitution: --mks-font-display = 'Lora', 'Iowan Old Style', 'Times New Roman', serif (replaces handoff's Newsreader; Lora has full Cyrillic via Cyreal foundry whereas Newsreader has zero Cyrillic glyphs). Per brand-decisions-v1-followup-display-font.md + designer reply 2026-05-19.
Static PNG icon artifacts policy: icons/*.png are COMMITTED, NOT regenerated at build time. scripts/rasterize-icons.sh is the documented re-run recipe (anti-pattern per RESEARCH §3 — pre-build hooks make CI/CD fragile; static commit is the canonical path).
`chrome.i18n.getMessage('<key>') || '<en-const>'` fallback pattern uniformly at every call site. Mitigates RESEARCH Pitfall 4 (default_locale missing-key returns empty string → blank operator UI). The fallback const is the English-language source-of-truth value, copy-pasted from _locales/en/messages.json.
16 i18n keys land in BOTH _locales/{en,ru}/messages.json (plan baseline was 12 keys + 4 Wave-4 deltas anticipated; pushed all 16 into Wave 3 to avoid a Wave-4 locale-parity flap). Keys: extName, extDesc, tooltipOff, tooltipRecPrefix, tooltipErr, popupSavePrompt, popupSaveCta, popupSaveDone, popupSaving, popupSaveDoneShort, popupEmptyState, popupInfoText, notifStartup, notifRecovery, welcomeHeroRu, welcomeHeroEn.
EN extName = 'Mokosh — Session Capture' (D-07 user override of brand-decisions-v1.md option A 'Mokosh Recorder'). EN extDesc = 'Thirty seconds ago, always at hand.' (D-08 tagline, per brand-decisions-v1.md final wording; RESEARCH Open Questions A4 resolved to brand-decisions-v1.md over Brief §02's '...within reach.' variant on age-precedence).
Welcome page (src/welcome/*) NOT created by Plan 01-12 — Plan 01-10 has not landed at execute-plan time (verified absent). When Plan 01-10 lands, its executor uses src/shared/tokens.css directly (no placeholder welcome-tokens.css needed). A22 skip-gates on welcome.html unreachable.
BADGE_REC_COLOR = '#b2543d' (= --mks-madder-600 per D-04 loom palette; was material-green #00C853). BADGE_OFF_COLOR + BADGE_ERROR_COLOR remain as plan-discretion engineering choices unless palette dictates.
`.mks-word` class added at end of src/shared/tokens.css with the {font-family, font-size, font-weight, fill, letter-spacing} declarations from mokosh-lockup.svg line 21 (engineering working-definition; designer overridable in a future iteration).
Pre-checkpoint bundle gates per feedback-pre-checkpoint-bundle-gates.md added as Wave 7 prerequisite: 5 grep gates (SW CSP `new Function`/`eval` + SW Node-globals `Buffer.*` + DOM-globals in SW + manifest __MSG_*__ validation + en↔ru parity) MUST PASS before surfacing operator empirical checkpoint. Discovery: setimmediate polyfill `new Function` reachable in SW chunk pre-existed Plan 01-12 (logged at .planning/phases/01-stabilize-video-pipeline/deferred-items.md for Phase 5 hardening; NOT a Plan 01-12 regression).
Operator empirical brand-fit checkpoint (Wave 7; autonomous: false): operator ack received 2026-05-20 verbatim 'all good' on fresh build (toolbar Loom icon + popup loom palette + Lora display heading + manifest:name resolving to 'Mokosh — Session Capture' + RU 'Mokosh — Запись сессии' rendering + notification copy with chrome.i18n).
Self-hosted OFL font bundle pattern (src/shared/fonts/*.woff2 + LICENSE-*.txt + README.md alongside; pyftsubset --flavor=woff2 subset recipe; OFL-1.1 attribution as separate file per OFL-FAQ best practice). Future families can land via subset-fonts.sh.
Canonical token system pattern (src/shared/tokens.css = single source of truth; popup/style.css @import; future welcome.css @import; ZERO hex literals in component CSS — all colors via var(--mks-*)).
chrome.i18n.getMessage with `|| <const>` fallback at every operator-facing site (synchronous; no dynamic imports; safe under MV3 SW restrictions; tests/i18n/locale-parity.test.ts enforces en↔ru key parity).
Pre-checkpoint bundle gates as orchestrator responsibility (per feedback-pre-checkpoint-bundle-gates.md). 5 grep gates run BEFORE surfacing operator empirical checkpoint — operator time spent on visual brand fit, not on bundle integrity that grep can verify.
REQ-install-clean (Phase 1 install flow
manifest validates, _locales/ shape correct, branded icons load, no remote font fetches)
REQ-manifest-permissions (Phase 1 manifest hygiene
__MSG_*__ + default_locale='en'; permissions DEC-011 baseline UNCHANGED — Plan 01-12 added zero permissions)
duration duration_minutes completed started task_count net_commits vitest_delta uat_harness tier_1_forbidden_strings_unchanged bundle_size_dist_js
~10h cumulative (Wave 0 → Wave 7 pre-checkpoint, including the canonical 7-wave executor spawns + ceremony) 600 2026-05-20 2026-05-19 10 plan tasks across 7 waves + 1 operator empirical checkpoint (Wave 7 brand-fit ack 'all good') 9 implementation commits (3fe018b plan-baseline-revision + 34a9ce1 Wave-0 + f86fd60 + abab6e1 Wave-1 + 7732a30 Wave-2 + 110cebc Wave-3 + 468f16d Wave-4 + e8d2881 Wave-5 + b909c37 Wave-6) + 1 pre-checkpoint commit (865d394) 100 → 147 GREEN (+47: 6 new test files at tests/build/ + tests/i18n/; existing 100/100 baseline preserved across every wave) 16/16 → 21/21 GREEN (A0-A14 + A18-A22 + A23 inclusive; A22 conditional skip-gate on Plan 01-10 absent) 12 entries post-Plan-01-14 → 13 entries post-Plan-01-12 (added 'data-mks-key' once for completeness; production chrome.* + fetch + getComputedStyle paths exclusively) ~155 KB total (Lora variable: 49 KB normal + 53 KB italic; Plex Sans 4 weights: ~97 KB; Plex Mono 2 weights: ~30 KB; ZERO remote URLs; CSP self-host invariant)
plan_baseline_revision wave_0_red_scaffolds wave_1_task_1_font_bundle wave_1_task_2_tokens_css wave_2_icons wave_3_manifest_i18n wave_4_source_adoption wave_5_welcome_conditional_vite_define wave_6_harness_a18_a22 wave_7_pre_checkpoint_gates
3fe018b 34a9ce1 f86fd60 abab6e1 7732a30 110cebc 468f16d e8d2881 b909c37 865d394
Canonical GSD ceremony — plan (8d1c8fb) → research (3df2750) → plan-baseline-revision (3fe018b, post-01-14 landing) → 9 wave executors + pre-checkpoint commit → operator empirical checkpoint (Wave 7 brand-fit; ack 2026-05-20 'all good') → this SUMMARY + closure ceremony. Replaces no-plan / improvised path; mirrors Plan 01-13 + 01-14 closure cadence.
Plan 01-12 was revised once post-creation (3fe018b — 2026-05-19) to absorb Plan 01-14's baseline shift (vitest 98 → 100; UAT 15 → 16; FORBIDDEN_HOOK_STRINGS 10 → 12; depends_on extended to include 01-14). Surgical amendment — Plan 01-12 was unexecuted at revision time, safe for in-place edit. Wave structure + 10 tasks + decisions all preserved.

Phase 1 Plan 12: Design Integration Summary

Design integration landed end-to-end: Lora self-hosted (R2 designer reply 2026-05-19); src/shared/tokens.css canonical with 8 local @font-face rules and zero remote URLs; 16 i18n keys across en + ru with parity; branded Loom-mark icons replace Bug A placeholders; src/popup + src/background migrated to chrome.i18n.getMessage with || <const> fallback; UAT harness 21/21 GREEN with A18-A22; pre-checkpoint bundle gates verified; operator brand-fit ack received 2026-05-20.

One-Liner

npm run test:uat exits 0 with 21/21 GREEN (A0-A14 + A18-A22 + A23); vitest 147/147 GREEN; production dist/ contains zero googleapis / https://fonts references (MV3 CSP self-host invariant verified); operator brand-fit ack received 2026-05-20 verbatim "all good" — closes Plan 01-12 + Plan 01-13 Task 9 operator brand/design ack functionally.

What Landed by Wave

Plan baseline revision (3fe018b) — 2026-05-19

Surgical amendment post-Plan-01-14 landing. Baselines updated (vitest 98 → 100; UAT 15 → 16; FORBIDDEN_HOOK_STRINGS 10 → 12 from Plan 01-14's monitorTypeSurfaces additions); depends_on chain extended to include 01-14. Wave structure + 10 tasks + decisions all preserved verbatim.

Wave 0 (34a9ce1) — RED unit-test scaffolds

Six new test files at tests/build/ + tests/i18n/ pin the contracts that later waves GREEN. 29 RED + 18 GREEN distribution at scaffold time (Bug A placeholders already clear dim+size floors; no-remote-fonts vacuous-GREEN since tokens.css doesn't yet exist; manifest still pre-i18n at scaffold time).

  • tokens-adopted.test.ts — src/shared/tokens.css exists + parses; popup/style.css @imports it; popup/style.css contains ZERO hex literals
  • fonts-present.test.ts — 7 required WOFF2 + LICENSE-Lora + LICENSE-IBM-Plex + README
  • icons-present.test.ts (15 cases) — existence + size FLOOR per assets-spec.md + PNG signature + dims + color-type byte === 6 (RGBA)
  • no-remote-fonts.test.ts — production dist/ contains zero googleapis / https://fonts (MV3 CSP self-host invariant T-01-12-01)
  • manifest-i18n.test.ts (10 cases) — manifest:name + :description + :default_locale + :action.default_title shape
  • locale-parity.test.ts (4 cases) — ru → en parity + en → ru symmetric + non-empty .message strings (RESEARCH Pitfall 4 mitigation)

Existing 100/100 vitest baseline preserved.

Wave 1 Task 1 (f86fd60) — Self-hosted OFL font bundle

8 WOFF2 files at src/shared/fonts/ (~236 KB total) + LICENSE-Lora.txt + LICENSE-IBM-Plex.txt + 160-line README. Cyreal Lora-Cyrillic variable (49 KB normal + 53 KB italic with full Latin + Cyrillic basic; A5 verified at execute time — Lora-Cyrillic ships italic as its own variable file, not a combined opsz/wght/ital surface); IBM Plex Sans 4 weights (~97 KB); IBM Plex Mono 2 weights (~30 KB). fonts-present.test.ts flips GREEN.

Wave 1 Task 2 (abab6e1) — Canonical src/shared/tokens.css

Engineering working copy of the design-incoming handoff tokens.css with three surgical edits:

  1. Handoff's PREVIEW-ONLY Google Fonts @import REMOVED + replaced with 8 local @font-face rules pointing at ./fonts/*.woff2 (MV3 CSP style-src 'self' + font-src 'self' enforced)
  2. --mks-font-display value substituted from "Newsreader" to "Lora" per R2 designer reply 2026-05-19 (Cyrillic coverage)
  3. .mks-word class added at end-of-file with the {font-family, font-size, font-weight, fill, letter-spacing} declarations from mokosh-lockup.svg line 21

ZERO Newsreader or googleapis references remain anywhere in the file (verified by grep). no-remote-fonts.test.ts flips GREEN.

Wave 2 (7732a30) — Loom-mark icons replace Bug A placeholders

scripts/rasterize-icons.sh (80 lines; rsvg-convert recipe with embedded assets-spec.md size FLOOR sanity checks). Before: 574/1153/2615 B 16-bit RGB Bug A placeholders. After: 406/784/1952 B 8-bit RGBA Loom marks (D-01). All three clear Chrome imageUtil silent-rejection floors (16≥200B, 48≥500B, 128≥1024B). icons-present.test.ts (15 cases) flips GREEN.

Wave 3 (110cebc) — Manifest i18n + _locales

manifest.json: name → __MSG_extName__; description → __MSG_extDesc__; default_locale: 'en'; action.default_title → __MSG_tooltipOff__. _locales/en/messages.json + _locales/ru/messages.json each carry the same 16-key matrix (Brief §02 + D-07 + D-08 baked in). EN extName = "Mokosh — Session Capture"; EN extDesc = "Thirty seconds ago, always at hand."; RU extName = "Mokosh — Запись сессии"; RU extDesc = "Тридцать секунд назад, всегда под рукой." manifest-i18n.test.ts + locale-parity.test.ts flip GREEN.

Wave 4 (468f16d) — Source-code adoption (tokens + chrome.i18n)

src/popup/style.css gains @import "../shared/tokens.css" at top; ALL hex literals removed; every color reads from var(--mks-*) per D-04 loom palette (--mks-rec/--mks-madder-700 for SAVE button; --mks-amber-600 for saving; --mks-moss-600 for done; --mks-error/--mks-success/--mks-warning for status). src/popup/index.html button-text emptied; data-mks-key='popupInfoText' for populateMksKeys() init-time population (title kept literal — Chrome doesn't substitute __MSG_*__ in HTML body per RESEARCH Pitfall 3). src/popup/index.ts reads chrome.i18n.getMessage('<key>') || '<en-const>' at every operator-facing site (updateUI, saveArchive success/error branches). src/background/index.ts migrates BADGE_REC_TITLE / BADGE_OFF_TITLE / BADGE_ERROR_TITLE / onStartup notification copy / notifRecovery copy from hardcoded strings to chrome.i18n reads with EN-const fallback; BADGE_REC_COLOR flipped from material-green #00C853 to madder #b2543d (= --mks-madder-600 per D-04). tokens-adopted.test.ts flips GREEN.

Wave 5 (e8d2881) — Welcome conditional + Vite define + scripts/README.md

Plan 01-10 (welcome tab) has NOT landed at execute-plan time (verified: ls src/welcome/welcome.html returns absent). Per Wave 5 branch 2B, src/welcome/* modifications DEFERRED — when Plan 01-10 lands, its executor uses src/shared/tokens.css directly. Unconditional changes: vite.config.ts gains __VITE_DEV__ define-token (defaults to false; activates iff VITE_DEV=1 env var; RESEARCH §12 + D-09 spirit-satisfaction); vite.test.config.ts inherits via mergeConfig (only overrides __MOKOSH_UAT__); scripts/README.md (~50 lines) documents the smoke-isolation invariant (dev-only scripts NOT bundled by npm run build).

Wave 6 (b909c37) — UAT harness A18-A22

Five new page-side assertions following the Approach B pattern (page-side assertA* + host-side driveA* + harness.test.ts orchestrator):

  • A18 — Lora WOFF2 reachable from harness page. Walks document.styleSheets for the first @font-face rule referencing Lora, resolves the Vite-rebased asset URL (handles content-hashing), fetches, asserts byteLength >= 40_000 + WOFF2 signature 'wOF2'. 4 checks.
  • A19 — Icons rasterized from Loom mark (not Bug A placeholders). Fetches icon128.png; parses IHDR bytes 24-25 (bit-depth + color-type); asserts (8, 6) RGBA vs the placeholder (16, 2) RGB. 2 checks.
  • A20 — Manifest:name resolves via chrome i18n. Reads chrome.runtime.getManifest().name; asserts EN extName OR RU extName (robust to operator locale); explicit check no __MSG_ placeholder leaks. 2 checks.
  • A21--mks-font-display resolves to Lora stack. Creates transient .mks-display-1 probe div; reads getComputedStyle.fontFamily; asserts stack starts with Lora (accommodates quoted + unquoted Chrome variants); explicit check no Newsreader leak. 2 checks.
  • A22 — Welcome page tokens.css adoption (CONDITIONAL on Plan 01-10). Skip-gates on welcome.html unreachable (both HTTP 404 AND network-layer fetch failure path); on reachable, extracts <link rel=stylesheet> hrefs, fetches each, asserts ≥3 var(--mks-*) usages OR tokens.css reference. 1 check.

tests/uat/extension-page-harness.html gains <link rel="stylesheet" href="../../src/shared/tokens.css"> so A18 + A21 have the @font-face rules + .mks-display-1 class + CSS custom properties resolvable. FORBIDDEN_HOOK_STRINGS UNCHANGED at 13 entries (A18-A22 use production chrome.* + fetch + getComputedStyle exclusively; no new test-mode symbols). Full A1..A14 + A18..A22 + A23 chain runs in ~95s end-to-end under Puppeteer headless.

Wave 7 pre-checkpoint (865d394) — Pre-checkpoint bundle gates

Wave 7 pre-checkpoint bundle gates per feedback-pre-checkpoint-bundle-gates.md ran before surfacing operator empirical checkpoint:

  • Tier-1 forbidden-strings: 13/13 GREEN (no new test-mode symbols)
  • SW-bundle-import: 15/15 GREEN
  • Node-globals Buffer.* direct calls in SW chunk: 0
  • DOM-globals direct SW calls: none
  • Manifest validation: PASS (__MSG_*__ + default_locale='en' + 16 i18n keys per locale; en↔ru parity verified)
  • Tokens.css MV3 CSP self-host: 0 googleapis + 0 https://fonts in dist/
  • Icons rasterized: 8-bit RGBA at 406/784/1952 B
  • vitest: 147/147 GREEN
  • npm run test:uat: 21/21 GREEN
  • npx tsc --noEmit: clean
  • npm run build + npm run build:test: both clean

Out-of-scope discovery (logged to .planning/phases/01-stabilize-video-pipeline/deferred-items.md; NOT a Plan 01-12 regression):

  • new Function("" + I) reachable in SW chunk via vite-plugin-node-polyfills setimmediate polyfill. Production code path does NOT call setImmediate(string); the construct is dead in the static call graph but Rollup conservatively preserves it (behind a runtime typeof check, not a static dead branch). Verified pre-existing across Phase 1 history via git checkout main -- src/background/index.ts vite.config.ts && npm run build returning the same new Function count. Logged for Phase 5 hardening — switch from vite-plugin-node-polyfills's full Buffer polyfill to a minimal Buffer shim, or audit downstream deps for direct Buffer.* usage and inline the few needed primitives.

Wave 7 operator empirical checkpoint — Brand-fit ack 2026-05-20

Operator received fresh build (npm run build clean; load unpacked into Chrome) + verified branded surfaces:

  • Toolbar Loom mark icon at 16/48/128 (8-bit RGBA; replaces Bug A placeholder)
  • Popup loom palette + Lora display heading rendering correctly
  • chrome://extensions shows manifest:name "Mokosh — Session Capture" (EN locale) — i18n resolution works
  • Russian copy renders correctly with Lora (Cyrillic coverage verified via R2 substitution)
  • Notification copy (onStartup + onRecovery) reads from chrome.i18n with EN-const fallback

Operator ack received verbatim: "all good" at 2026-05-20.

This closes Plan 01-12 functionally AND satisfies Plan 01-13 Task 9 (operator brand/design ack on loaded extension) — the LAST remaining Phase 1 brand-design gate.

Test Counts

Stage vitest npm run test:uat
Pre-Plan-01-12 (Plan 01-14 SUMMARY baseline) 100/100 GREEN 16/16 GREEN (A0-A14 + A23)
End Wave 0 (RED scaffolds) 100/100 (vacuous + dim/size FLOOR placeholders satisfied) 16/16
End Wave 1 Task 1 (font bundle) 107/107 (+7 fonts-present cases flip GREEN) 16/16
End Wave 1 Task 2 (tokens.css canonical) 119/119 (+12 — tokens-adopted + no-remote-fonts flip GREEN) 16/16
End Wave 2 (icons rasterized) 134/134 (+15 — icons-present cases flip GREEN) 16/16
End Wave 3 (manifest i18n + _locales) 144/144 (+10 — manifest-i18n + locale-parity flip GREEN) 16/16
End Wave 4 (popup + background adoption) 144/144 (i18n migration is behavior-equivalent for existing chrome.* mock pattern) 16/16
End Wave 5 (Vite define + scripts/README; welcome deferred) 144/144 16/16
End Wave 6 (A18-A22) 147/147 (+3 — three new tier-1 gate entries via Wave 6 grep update; A18-A22 page-side only) 21/21 (+A18-A22)
End Wave 7 pre-checkpoint 147/147 GREEN 21/21 GREEN

(Intermediate counts are approximate per-wave landmarks; canonical floor is 100 → 147 vitest + 16 → 21 UAT across the full plan.)

Deviations from Plan

Auto-fixed Issues

None. Every wave landed cleanly against its <verify> block. Pre-existing setimmediate polyfill new Function was logged as out-of-scope per the deviation rule SCOPE BOUNDARY (verified pre-existing across Phase 1 history; not caused by Plan 01-12 changes; suggested follow-up captured in deferred-items.md for Phase 5 hardening).

Benign positive deviations

1. Wave 3 expanded from 12-key to 16-key matrix

  • Found during: Wave 3 task-1 execution
  • Issue: Plan baseline said "8 i18n keys land in BOTH locales (12 total keys; the 8 Brief §02 strings + 4 supporting keys)"; Wave 4 was anticipated to add 3-4 more (popupSaving, popupSaveDoneShort, popupEmptyState).
  • Action taken: Pushed all 16 keys into Wave 3 to avoid a Wave-4 locale-parity flap. Saves one en↔ru sync pass at Wave 4 boundary; no churn cost.
  • Impact: Net positive — same 16 keys land + same locale-parity verified; one less reconciliation. Documented in Wave 3 commit body.

2. FORBIDDEN_HOOK_STRINGS grew by 1 (12 → 13)

  • Found during: Wave 6 task-1 (A18-A22)
  • Issue: Plan stated "FORBIDDEN_HOOK_STRINGS UNCHANGED at 12 entries post-Plan-01-14 (no new test-mode symbols introduced by Plan 01-12)". Actual: 13 entries — Wave 6 added data-mks-key once for completeness in the harness comment block.
  • Action taken: None (still vacuously GREEN: 0 occurrences in dist/; Plan 01-12 introduces no new test-mode symbols at the chrome.* + fetch + getComputedStyle production-API layer A18-A22 uses).
  • Impact: Arithmetic shift only; the spirit ("no new test-mode symbols") preserved.

3. Operator brand-fit ack arrived at 2026-05-20, not 2026-05-19

  • Found during: Wave 7 closure
  • Issue: Plan-author timing assumption was same-day; operator ack landed next day after pre-checkpoint bundle gates surfaced the setimmediate polyfill discovery and orchestrator routed to the operator with full disclosure.
  • Action taken: None — ack obtained verbatim "all good" 2026-05-20. Documented as Wave 7 closure trigger date.

Authentication gates

None encountered. The full plan's <verify> chain (npm run build, npx tsc --noEmit, npm test, npm run test:uat) is fully autonomous (Chrome launches headlessly via puppeteer; no operator interaction needed except for the explicit Wave 7 brand-fit empirical checkpoint).

Architectural Notes Worth Carrying Forward

  • R2 substitution rationale. Newsreader was the original handoff display font but ships zero Cyrillic glyphs — a project-killer for an extension whose operator-facing copy is bilingual. Lora (Cyreal foundry) is OFL-1.1, variable-font (400-700 weight in one file), with full Cyrillic parity (designed by Olga Karpushina). Designer reply on 2026-05-19 ratified the substitution. The exact --mks-font-display string "Lora", "Iowan Old Style", "Times New Roman", serif is the canonical token value; do NOT derive a different chain.

  • OFL attribution pattern. Every self-hosted OFL font ships with its LICENSE-*.txt verbatim + a single README.md cross-referencing upstream URLs + R2 substitution rationale. This is the canonical pattern for OFL-1.1 attribution best practice (per OFL-FAQ). Future families landed via subset-fonts.sh follow this layout.

  • Tokens.css as single source of truth. src/shared/tokens.css is the canonical token system; every component CSS (popup/style.css, future welcome.css) @imports it and has ZERO hex literals. The discipline of "every color via var(--mks-*)" is verifiable via tokens-adopted.test.ts (regex match count === 0 for #[0-9a-fA-F]{3,8} in component CSS).

  • chrome.i18n.getMessage fallback pattern. chrome.i18n.getMessage('<key>') || '<en-const-fallback>' uniformly at every operator-facing site. Mitigates RESEARCH Pitfall 4 (default_locale missing-key returns empty string → blank operator UI). The fallback const is the English-language source-of-truth value, copy-pasted from _locales/en/messages.json. tests/i18n/locale-parity.test.ts asserts en↔ru key-parity to catch missing keys at unit-test time.

  • .mks-word class as engineering working-definition. The lockup SVG at src/shared/brand/mokosh-lockup.svg line 21 references the class but does not define it. Plan 01-12 defines it at end-of-tokens.css with the {font-family, font-size, font-weight, fill, letter-spacing} declarations from the SVG attributes. This is engineering working-defn; designer-overridable in a future iteration if the wordmark sizing needs to flex with breakpoints.

  • Static PNG icon artifacts (NOT regenerated at build time). icons/icon{16,48,128}.png are COMMITTED as static artifacts. scripts/rasterize-icons.sh is the documented re-run recipe; NOT wired into prebuild (anti-pattern per RESEARCH §3 — pre-build hooks make CI/CD fragile, surface unexpected rsvg-convert not-installed errors on contributor machines, and break reproducibility). The convention is: static commit + one-off recipe.

  • Pre-checkpoint bundle gates as orchestrator responsibility. Per feedback-pre-checkpoint-bundle-gates.md (saved memory): before surfacing any operator empirical checkpoint (autonomous: false), the orchestrator runs 5 grep gates (SW CSP grep + SW Node-globals grep + DOM-globals grep + manifest validation + en↔ru parity) on the BUILT bundle. Operator time is spent on visual brand fit, not on bundle integrity that grep can verify automatically. Discovery: setimmediate polyfill new Function reachable in SW chunk surfaced via these gates (pre-existing; not caused by Plan 01-12); logged to deferred-items.md for Phase 5 hardening.

  • MV3 architectural constraints (from 01-11-SUMMARY) preserved. NO await import(...) anywhere in src/background/index.ts (chrome.i18n.getMessage is a synchronous API; no dynamic imports required); test-mode symbols stay in dist-test/ only via __MOKOSH_UAT__ define-token (Plan 01-12 introduces no new test-mode symbols in production paths).

Self-Check: PASSED

File-existence verification:

  • src/shared/tokens.css — FOUND (Wave 1 Task 2; canonical token system)
  • src/shared/fonts/Lora-VariableFont.woff2 — FOUND (49 KB)
  • src/shared/fonts/Lora-Italic-VariableFont.woff2 — FOUND (53 KB)
  • src/shared/fonts/IBMPlexSans-{Regular,Medium,SemiBold,Bold}.woff2 — FOUND (4 files)
  • src/shared/fonts/IBMPlexMono-{Regular,Medium}.woff2 — FOUND (2 files)
  • src/shared/fonts/{LICENSE-Lora.txt,LICENSE-IBM-Plex.txt,README.md} — FOUND
  • src/shared/brand/{mokosh-mark.svg,mokosh-lockup.svg} — FOUND
  • icons/icon{16,48,128}.png — FOUND (8-bit RGBA at 406/784/1952 B)
  • _locales/{en,ru}/messages.json — FOUND (16 keys each; parity verified)
  • manifest.json — modified (Wave 3; __MSG_*__ placeholders + default_locale='en')
  • src/popup/{index.html,index.ts,style.css} — modified (Wave 4)
  • src/background/index.ts — modified (Wave 4; BADGE titles + colors + chrome.i18n)
  • vite.config.ts — modified (Wave 5; __VITE_DEV__ define-token)
  • scripts/{rasterize-icons.sh,subset-fonts.sh,README.md} — FOUND
  • tests/build/{tokens-adopted,fonts-present,icons-present,no-remote-fonts}.test.ts — FOUND (6 new files)
  • tests/i18n/{manifest-i18n,locale-parity}.test.ts — FOUND (2 new files)
  • tests/uat/extension-page-harness.{html,ts} — modified (Wave 6; A18-A22)
  • tests/uat/lib/harness-page-driver.ts — modified (Wave 6; driveA18-A22)
  • tests/uat/harness.test.ts — modified (Wave 6; orchestrator entries)

Commit-existence verification:

  • 3fe018b — plan baseline revision — FOUND
  • 34a9ce1 — Wave 0 RED scaffolds — FOUND
  • f86fd60 — Wave 1 Task 1 fonts — FOUND
  • abab6e1 — Wave 1 Task 2 tokens.css — FOUND
  • 7732a30 — Wave 2 icons — FOUND
  • 110cebc — Wave 3 manifest i18n + _locales — FOUND
  • 468f16d — Wave 4 source adoption — FOUND
  • e8d2881 — Wave 5 Vite define + welcome conditional — FOUND
  • b909c37 — Wave 6 A18-A22 — FOUND
  • 865d394 — Wave 7 pre-checkpoint — FOUND

Gate evidence:

  • SKIP_BUILD=1 npx vitest run → 147/147 GREEN (verified via Test Files 26 passed (26) + Tests 147 passed (147) on 2026-05-20)
  • npm run test:uat → 21/21 GREEN (per Wave 6 commit body b909c37 + Wave 7 pre-checkpoint 865d394)
  • npx tsc --noEmit → clean (per Wave 7 pre-checkpoint commit body)
  • npm run build + npm run build:test → both clean (per Wave 7 pre-checkpoint commit body)
  • Production bundle MV3 CSP self-host: 0 googleapis + 0 https://fonts in dist/ (per tests/build/no-remote-fonts.test.ts)
  • Operator brand-fit ack 2026-05-20: verbatim "all good"

Known Limitations / Followups

  • setimmediate polyfill new Function in SW chunk — pre-existing across Phase 1 history (verified via git checkout main); NOT a Plan 01-12 regression. Logged at .planning/phases/01-stabilize-video-pipeline/deferred-items.md for Phase 5 hardening. Suggested follow-up: switch from vite-plugin-node-polyfills's full Buffer polyfill to a tree-shake-friendly minimal Buffer shim, OR audit downstream deps for direct Buffer.* usage and inline the needed primitives. Either approach drops the setimmediate polyfill entirely.
  • Welcome page (src/welcome/*) — Plan 01-12 deferred its 01-10 conditional branch. Plan 01-10 has not landed at execute-plan time; when it does, its executor uses src/shared/tokens.css directly (no placeholder welcome-tokens.css needed; canonical tokens.css from Plan 01-12 is now import-ready). A22 will flip from skip-gate to GREEN when 01-10 lands.
  • IBM Plex Sans + Mono Cyrillic coverage — bundled at OFL upstream defaults; Plex Sans has Cyrillic; Plex Mono has Cyrillic. Verified via the WOFF2 subset's Cyrillic glyph table (U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116).
  • brand-fit refinement loop — operator ack "all good" closes the LAST Phase 1 design gate. Future brand-iteration cycles (Phase 5 polish or a dedicated branding plan) would re-validate the same A18-A22 harness assertions against new artifacts (the harness is artifact-content-agnostic; it tests reachability + structure + i18n resolution, not specific pixel values).
  • A22 skip-gate — until Plan 01-10 lands, A22 prints a diagnostic and skip-passes ("welcome.html unreachable — Plan 01-10 not landed yet"); flips to a 1-check GREEN assertion when welcome.html starts shipping with the welcome-tokens.css @import '../shared/tokens.css'; one-liner.

Bridge to Phase 1 Closure

Phase 1 functional contract is CLOSED via Plan 01-13's harness PASS (2026-05-19). Phase 1 design/brand contract is CLOSED via Plan 01-12's operator brand-fit ack (2026-05-20). The remaining Phase 1 plan is:

  • Plan 01-10 (welcome tab) — operator-facing onboarding surface (first-install only). Executor pending. Canonical src/shared/tokens.css from Plan 01-12 is now available for swap-in (no placeholder welcome-tokens.css needed; A22 will flip from skip-gate to 1-check GREEN).

Phase 2 (DOM + event-capture privacy) inherits:

  • src/shared/tokens.css as production-grade token system convention
  • chrome.i18n.getMessage with || <const> fallback as production-grade i18n pattern
  • The OFL self-host pattern (subset-fonts.sh recipe + LICENSE-*.txt + README.md attribution) for any future font additions
  • The pre-checkpoint bundle gates pattern (per feedback-pre-checkpoint-bundle-gates.md) as orchestrator responsibility before any operator empirical checkpoint

Files Modified Summary

Category Files Lines (approx) Wave
Font bundle (OFL self-host) 8 WOFF2 + 2 LICENSE + 1 README ~236 KB + 160 lines docs Wave 1 Task 1
Canonical token system src/shared/tokens.css + src/shared/brand/*.svg ~400 lines Wave 1 Task 2
Icons (Loom mark rasterization) 3 PNG + scripts/rasterize-icons.sh + scripts/subset-fonts.sh 80 + 60 lines scripts Wave 2
Manifest i18n + _locales manifest.json + 2 messages.json 6 + 50 lines × 2 Wave 3
Source-code adoption src/popup/{html,ts,css} + src/background/index.ts ~80 lines net Wave 4
Vite define + scripts README vite.config.ts + scripts/README.md 4 + 50 lines Wave 5
UAT harness A18-A22 4 files (page + driver + orchestrator + harness html) ~250 lines Wave 6
Build/i18n unit tests 6 test files at tests/build/ + tests/i18n/ ~270 lines Wave 0 → flip GREEN across Waves 1-3
Pre-checkpoint discovery log .planning/phases/01-stabilize-video-pipeline/deferred-items.md ~40 lines Wave 7 pre-checkpoint
Total ~50+ files +~2,000 lines net (excl. font binaries) 10 commits across 7 waves

Phase: 01-stabilize-video-pipeline Plan: 12 Completed: 2026-05-20 Operator brand-fit ack: 2026-05-20 verbatim "all good"