Files
Mark f3baa3a9a8 docs(04-06): re-plan iter-2 — real inline-SVG coverage + corrected 184/184 baseline
Re-plan-checker iter-1 (commit deb68df) flagged 2 BLOCKERs against the
iter-1 re-plan (b59bd24). Both fixed below; 3 advisories fixed; iter-1
verified-correct items preserved. EVERY test-infrastructure claim
re-verified against actual code this session before being written into
the plan — extension-page-harness.ts, harness-page-driver.ts, launch.ts,
harness.test.ts, vitest.config.ts, vite.config.ts, vite.test.config.ts,
full vitest run. No third false premise.

BLOCKER 1 — fictitious A17.8 live-DOM delegation. The iter-1 re-plan
claimed live-DOM injection + currentColor cascade was "delegated to
A17.8 in real Chrome". Verified false: assertA17 reaches welcome.html
only via fetch + DETACHED DOMParser string-parse; A17.8 is 100%
string-grep on jsText; the harness opens exactly two pages (victimPage
file://, harnessPage extension-page-harness.html — launch.ts:473-542);
populateMark() never runs in the harness. Fixed: a NEW host-side
harness assertion A35 is added (Task 3, modeled on driveA32/33/34) —
opens welcome.html via browser.newPage() + page.goto, lets
populateMark() run at DOMContentLoaded, then querySelector
'.welcome-hero__mark svg' + getComputedStyle().stroke proves the
LIVE currentColor cascade. welcome.html is a real web-accessible
extension page (builds to dist-test/src/welcome/welcome.html);
launchHarnessBrowser returns browser + extensionId so the new tab is
cheaply reachable. A35 is genuine new harness work (new driver +
drivers-array entry + banner-string update + import). A17.8 is
narrowed honestly to a source-bundling check only. No fictitious
delegation.

BLOCKER 2 — DEFECT 3 named the wrong failing test. The iter-1 re-plan
claimed strict-meta-json-validation.test.ts "fails on a clean tree" and
hard-coded a Task 2 gate "failure set EXACTLY == {strict-meta-json}".
Verified false this session: strict-meta-json in isolation = 8/8 GREEN;
a full vitest run reproduced 183 passed / 1 failed where the RED was
tests/background/webm-remux.test.ts (ffprobe -count_frames, timeout) —
NOT strict-meta-json. webm-remux in isolation = 5/5 GREEN. The "1
failed" is a non-deterministic ffprobe/parallel-vitest timeout flake —
exactly 04-CONTEXT #9 + #10. Fixed: baseline corrected to 184/184 GREEN
when the flake doesn't fire; target after Plan 04-06 = 188/188 GREEN
(+4 new tests). Task 2 gate now: 188/188 -> pass; 1 RED that passes on
isolation re-run -> tolerate as the known flake; reproducible RED or
2+ RED -> regression. No test filename hard-coded. deferred-items.md
mis-diagnosis corrected (Task 3 Edit 5).

Advisories (all fixed):
- A1: Task 3 action and verify both use SKIP_PROD_REBUILD=0 (intentional
  — harness must rebuild dist-test against Task 2 source edits).
- A2: requirements:[] kept (Phase 4 has no new REQ-* per ROADMAP);
  charter linkage via the `charter-d-p4-03` tag — non-blocking.
- A3: Task 1 acceptance criterion reworded to grep only import
  statements + the @vitest-environment directive, so the file's header
  prose explaining "no DOM-emulation library" doesn't trip it.

Preserved (iter-1 verified-correct):
- DEFECT 2 back-patch line classification (22/47/82/135/205 flip;
  40/89/109/110 leave).
- welcome.css drop from files_modified (bare class selector matches
  <svg>; color is inherited).
- Thesis: currentColor Option A + cursor verification-only +
  operator-empirical Task 4 + PNG icons untouched.
- FORBIDDEN_HOOK_STRINGS stays at 12 (no new __MOKOSH_UAT__ symbols).
- Frontmatter shape (phase:04 / slug / plan:06 / type:execute / wave:5
  / autonomous:false / depends_on:[01..05]). files_modified extended by
  3 new entries (harness-page-driver.ts + harness.test.ts + the
  corrected deferred-items.md).

Validation:
- gsd-sdk frontmatter.validate --schema plan: valid:true (all 8
  required fields present).
- gsd-sdk verify.plan-structure: valid:true, 0 errors, 0 warnings,
  4 tasks each with Files+Action+Verify+Done; Task 4 is
  checkpoint:human-verify per autonomous:false.

Orchestrator: run the re-plan checker again on this iter-2 commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 17:24:17 +02:00

72 KiB

phase, slug, plan, type, wave, depends_on, files_modified, autonomous, requirements, tags, user_setup, revision_history, must_haves
phase slug plan type wave depends_on files_modified autonomous requirements tags user_setup revision_history must_haves
04 harden-clean-up-optional 06 execute 5
01
02
03
04
05
src/shared/brand/mokosh-mark.svg
src/welcome/welcome.ts
globals.d.ts
tests/uat/extension-page-harness.ts
tests/uat/lib/harness-page-driver.ts
tests/uat/harness.test.ts
tests/welcome/inline-svg.test.ts
tests/build/cursor-visibility.test.ts
.planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md
.planning/phases/04-harden-clean-up-optional/deferred-items.md
false
visual-polish
dark-logo-contrast
ui-spec
currentColor
inline-svg
cursor-visibility-verification
charter-d-p4-03
operator-empirical
revised reason defects_resolved
2026-05-22 Full re-plan via /gsd-plan-phase ceremony. The prior 04-06-PLAN.md hit a blocking checkpoint (plan-assumption defect). Three defects corrected; thesis preserved (dark-logo currentColor Option A + cursor verification-only + A17.8 + operator-empirical Task 4).
id was now
DEFECT 1 — false jsdom premise Prior Task 1 stated 'vitest jsdom environment (vitest.config.ts already configures this)'. FALSE — vitest.config.ts line 18 sets environment:'node'; no DOM-emulation library is in node_modules. Test strategy decided — STRATEGY (a): reframe inline-svg.test.ts for node-env source-contract. Full live-DOM injection delegated to the A17.8 harness sub-check (later corrected by iter-2 BLOCKER 1 — see below).
id was now
DEFECT 2 — stale back-patch line numbers Prior Task 3 cited 01-07-SUMMARY.md back-patch lines 47/82/109/135/205. Verified against the live file (grep 2026-05-22): the genuine stale 'deferred to Phase 5' framing is at lines 22, 47, 82, 135, 205. Lines 40, 89, 109, 110 are historical commit-description records and are LEFT unchanged. Task 3 flips 22/47/82/135/205 only.
id was now
DEFECT 3 — wrong vitest baseline Prior plan assumed a 184/184 GREEN vitest baseline and targeted '184 -> ~188 GREEN'. Baseline reframed (later corrected by iter-2 BLOCKER 2 — see below).
revised reason defects_resolved
2026-05-22 Re-plan iter-2 via /gsd-plan-phase. The iter-1 re-plan (commit b59bd24) introduced TWO new false premises; re-plan-checker iter-1 (commit deb68df) flagged both as BLOCKERs. Both fixed below. EVERY test-infrastructure claim re-verified against actual code this session (extension-page-harness.ts, harness-page-driver.ts, launch.ts, harness.test.ts, vitest.config.ts, vite.config.ts, full vitest run).
id was now
BLOCKER 1 — fictitious A17.8 live-DOM delegation The iter-1 re-plan justified the weak node-env source-contract unit test by 'delegating full live-DOM injection + currentColor cascade verification to the A17.8 harness sub-check in real Chrome'. VERIFIED FALSE this session: assertA17 (extension-page-harness.ts:2090-2308) reaches the welcome page ONLY via fetch(chrome.runtime.getURL('src/welcome/welcome.html')) + new DOMParser().parseFromString(htmlText,'text/html') — a DETACHED string parse. A17.8 (lines 2273-2298) is 100% string-grep on jsText. The harness opens exactly TWO pages — victimPage (file://) and harnessPage (extension-page-harness.html) — verified at launch.ts:473-542. populateMark() NEVER runs in the UAT harness. 'welcome-hero__mark' returns zero grep hits across the entire harness. So the iter-1 re-plan delegated to a target that does not do that work. Verified that a LIVE welcome-page tab IS cheaply reachable: launchHarnessBrowser returns { browser, extensionId, harnessPage, victimPage, ... } (launch.ts:534-542); welcome.html is a real web-accessible extension page that builds to dist-test/src/welcome/welcome.html (vite.test.config.ts:95) — exactly the path chrome.runtime.getURL('src/welcome/welcome.html') resolves to (the path A17 already fetches). A NEW host-side assertion A35 is added (Task 3): a host-side driver — pattern verified against driveA32/driveA33/driveA34 (host-side drivers that take Page + captured handles and build a CheckRecord[] directly, NOT page.evaluate(window.__mokoshHarness)) — that opens welcome.html in a fresh browser.newPage() tab, lets populateMark() run at DOMContentLoaded, then queries the LIVE injected .welcome-hero__mark svg element + getComputedStyle().stroke to prove the real currentColor cascade. This is genuine new harness work (a new driver + a new assertion + a new harness.test.ts driver-list entry), correctly scoped as such — NOT a result.checks.push inside assertA17. A17.8 itself is still updated to swap the data-URL grep for a raw-source grep (source-bundling check); A35 is the live-DOM behavior check. No fictitious delegation.
id was now
BLOCKER 2 — DEFECT 3 named the wrong failing test The iter-1 re-plan asserted 'baseline = 183 passed / 1 failed; the 1 failure is tests/build/strict-meta-json-validation.test.ts, a pre-existing red on a clean tree' and hard-coded a Task 2/Task 4 gate 'failure set EXACTLY == {strict-meta-json-validation.test.ts}'. VERIFIED FALSE this session: npx vitest run tests/build/strict-meta-json-validation.test.ts in isolation = 8/8 GREEN. A full npx vitest run this session reproduced 183 passed / 1 failed (184 total) — and the RED was tests/background/webm-remux.test.ts > 'ffprobe -count_frames reports between 905 and 912 frames' (Error: Test timed out in 5000ms), NOT strict-meta-json. webm-remux.test.ts in isolation = 5/5 GREEN. The 1 failure is a non-deterministic ffprobe/parallel-vitest timeout flake — exactly 04-CONTEXT.md in-scope items #9 (parallel-vitest Tier-1-build-step race, ~1/5 runs) and #10 (2 ffprobe/ffmpeg flakes). Baseline corrected to 184/184 GREEN when the parallel-vitest flake family (04-CONTEXT #9/#10) does not fire. Target after Plan 04-06: 188/188 GREEN (+4 new tests). The hard-coded named-test gate is REMOVED. Task 2's vitest gate logic: run the full suite; if 188/188 -> pass; if there is exactly 1 RED AND that RED test passes when re-run in isolation (npm test -- <thatfile>) -> tolerate it as the known 04-CONTEXT #9/#10 flake and pass; if there is a NEW/reproducible failure (RED persists in isolation, or 2+ RED) -> FAIL the gate (Plan 04-06 caused a regression). No test filename is hard-coded. The stale deferred-items.md entry that mis-named strict-meta-json is corrected in Task 3.
truths artifacts key_links
src/shared/brand/mokosh-mark.svg root <svg> element carries `stroke="currentColor"` (was `stroke="#181b2a"`); the 12 <line> + 1 <rect> children are unchanged
src/welcome/welcome.ts imports the mark via `import markSvg from '../shared/brand/mokosh-mark.svg?raw';` (was `?url`); populateMark uses DOMParser to inject an inline <svg> into the slot (NOT <img>, NEVER innerHTML)
globals.d.ts contains a `declare module '*.svg?raw'` ambient module declaration alongside the existing `*.svg?url` and `*.webm?url`
tests/welcome/inline-svg.test.ts (node-env, source-level) pins the SOURCE contract: mokosh-mark.svg source carries stroke='currentColor' + canonical viewBox; welcome.ts source uses the ?raw import + DOMParser + replaceChildren and does NOT use innerHTML; globals.d.ts carries the *.svg?raw ambient decl. It does NOT exercise live DOM (vitest is environment:'node' — verified vitest.config.ts:18 — and ships no DOM library)
A17.8 harness sub-check updated to assert the welcome chunk JS bundles the raw SVG SOURCE string (stroke='currentColor' + canonical viewBox), replacing the prior data:image/svg+xml data-URL grep
NEW harness assertion A35 (host-side driver) opens welcome.html as a real Puppeteer tab, lets populateMark() run, and verifies the LIVE injected `.welcome-hero__mark svg` element exists with stroke='currentColor' AND its getComputedStyle().stroke resolves to the parent .welcome-hero__mark wrapper color (the real currentColor cascade) AND no `.welcome-hero__mark img` exists. This is the genuine automated live-DOM coverage for the inline-SVG injection + cascade
Cursor visibility verified ALREADY SHIPPED at src/offscreen/recorder.ts:285 (`cursor: 'always'`) per RESEARCH Finding 4; tests/build/cursor-visibility.test.ts (node-env file-grep) regression-pins the literal
.planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md back-patched: the stale 'deferred to Phase 5' lines 22, 47, 82, 135, 205 flipped to 'shipped opportunistically Plan 01-09; verified Phase 4 Plan 04-06'; the historical commit-description lines 40, 89, 109, 110 left unchanged
Operator empirical checkpoint: dark-mode visual aesthetic judgment on welcome-hero from dark + light Puppeteer screenshots (the ONE genuine operator-empirical case in Phase 4 per UI-SPEC §'Acceptance Criteria #6')
PNG toolbar icons untouched (Chrome auto-inverts on dark toolbars; icons/icon{16,48,128}.png byte-identical)
path provides contains
src/shared/brand/mokosh-mark.svg Single-attribute change on root <svg>: stroke='#181b2a' -> stroke='currentColor'. 13 child elements unchanged. stroke="currentColor"
path provides contains
src/welcome/welcome.ts ?raw import + DOMParser-based inline SVG injection in populateMark (replaces <img> injection) mokosh-mark.svg?raw
path provides contains
globals.d.ts Ambient module declaration for *.svg?raw imports (mirror of the existing *.svg?url block) *.svg?raw
path provides contains min_lines
tests/welcome/inline-svg.test.ts Wave 0 RED -> GREEN — node-env source-level contract: SVG source recolor + welcome.ts ?raw/DOMParser/no-innerHTML + globals.d.ts ambient decl currentColor 50
path provides contains min_lines
tests/build/cursor-visibility.test.ts Wave 0 GREEN-on-arrival — node-env file-grep defensive pin for src/offscreen/recorder.ts:285 cursor: 'always' literal cursor: 'always' 15
path provides contains
tests/uat/extension-page-harness.ts A17.8 sub-check updated to assert raw SVG SOURCE bundling (replaces data:image/svg+xml data-URL grep) A17.8
path provides contains
tests/uat/lib/harness-page-driver.ts NEW host-side driveA35 — opens welcome.html as a real tab, runs populateMark(), queries the live injected <svg> + getComputedStyle().stroke for the currentColor cascade driveA35
path provides contains
tests/uat/harness.test.ts A35 wired into the orchestrator driver list (driveA35Wrapped closure capturing handles.browser + handles.extensionId); driver-count display string appended with A35 A35
path provides contains
.planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md Surgical back-patch — stale 'deferred to Phase 5' lines 22/47/82/135/205 flipped; historical commit-description lines 40/89/109/110 left Phase 4 Plan 04-06
path provides contains
.planning/phases/04-harden-clean-up-optional/deferred-items.md Correction of the mis-diagnosed 'strict-meta-json fails on clean tree' entry — the real flake is the 04-CONTEXT #9/#10 parallel-vitest ffprobe family, not a named test parallel-vitest
from to via pattern
src/welcome/welcome.ts populateMark src/shared/brand/mokosh-mark.svg?raw Vite ?raw import returns SVG source as a string; DOMParser parses; replaceChildren injects DOMParser
from to via pattern
Injected inline <svg> stroke='currentColor' .welcome-hero__mark wrapper color: var(--mks-fg-inverse) CSS color cascade (W3C SVG2 §13.3) — verified live in real Chrome by the NEW A35 host-side harness assertion (getComputedStyle().stroke on the injected <svg>) stroke="currentColor"
from to via pattern
tests/uat/lib/harness-page-driver.ts driveA35 a live welcome.html Puppeteer tab where populateMark() runs browser.newPage() + page.goto(chrome-extension://<id>/src/welcome/welcome.html) + querySelector('.welcome-hero__mark svg') + getComputedStyle driveA35
Land the UI-SPEC dark-surface logo contrast strategy (Option A — `currentColor` SVG + CSS `color` via the existing `.dark` block in `src/shared/tokens.css`). Per the UI-SPEC §"Implementation amendment", this requires a 2-part technique:
  1. SVG attribute change: stroke="#181b2a" to stroke="currentColor" on the root <svg> of src/shared/brand/mokosh-mark.svg.
  2. Inline-SVG injection in welcome.ts: an <img>-rendered SVG runs in an isolated SVG document context where currentColor resolves to the SVG's own root color (defaults to canvastext, near-black). To get the desired CSS cascade, the SVG must be inlined into the welcome page's DOM. Switch the import markUrl from '.../*.svg?url' to import markSvg from '.../*.svg?raw' plus rewrite populateMark to use DOMParser + replaceChildren.

Two additional polish items co-land:

  1. Cursor visibility verification (RESEARCH Finding 4): cursor: 'always' is ALREADY SHIPPED at src/offscreen/recorder.ts:285 (Plan 01-09 opportunistically lifted the original Phase 5 deferral). Plan 04-06 confirms via a defensive grep test (tests/build/cursor-visibility.test.ts) and back-patches the stale "deferred to Phase 5" lines in .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md.

  2. Operator empirical checkpoint (UI-SPEC Acceptance Criterion #6): the ONE Phase 4 genuine operator-empirical gate — dark-mode visual aesthetic judgment of the welcome hero. Per feedback-trust-harness-over-manual-uat.md, the operator judges from dark + light Puppeteer screenshots produced as the verification artifact, NOT a manual Chrome session.

Purpose: Closes the UI-SPEC dark-logo contrast strategy, RESEARCH Finding 4 cursor verification, the ROADMAP cursor visibility item, and the Plan 01-10 cycle-2 operator observation "also on dark surfaces probably either we need to place the logo on the light background or dunno".

Output: 3 source/test/spec file edits (SVG recolor + welcome.ts ?raw/DOMParser + globals.d.ts ambient decl) + a 3-part harness change (A17.8 sub-check update + NEW host-side A35 assertion + A35 orchestrator wiring) + 2 new test files (tests/welcome/inline-svg.test.ts + tests/build/cursor-visibility.test.ts) + 2 docs edits (01-07-SUMMARY back-patch + deferred-items.md correction) + 1 operator empirical UAT cycle. The plan is autonomous: false because of the operator-empirical checkpoint (the ONLY autonomous: false plan in Phase 4).

Test-strategy note (DEFECT 1 / iter-2 BLOCKER 1 resolution — VERIFIED this session). The automated coverage of the inline-SVG technique is split deliberately and HONESTLY across two layers:

  • Source-contract layer — tests/welcome/inline-svg.test.ts. This runs in vitest's environment: 'node' (the deliberate project default — verified at vitest.config.ts:18; there is NO jsdom/happy-dom/linkedom in node_modules). It pins the SOURCE-LEVEL contract — the SVG source carries currentColor, populateMark is rewritten correctly with a ?raw import + DOMParser + replaceChildren, and no innerHTML is used. It does NOT instantiate a DOM, does NOT call populateMark, does NOT use DOMParser at runtime. It proves the source TEXT; it cannot prove the runtime injection.

  • Live-DOM behavior layer — the NEW host-side harness assertion A35 (Task 3). Verified facts: the UAT harness opens exactly two pages (victimPage file://, harnessPage extension-page-harness.htmllaunch.ts:473-542), and populateMark() NEVER runs anywhere in the current harness — assertA17 reaches the welcome page only via fetch() + a DETACHED DOMParser string-parse, and A17.8 is 100% string-grep on the welcome JS chunk. So the prior iter-1 re-plan's claim "live-DOM injection is delegated to A17.8 in real Chrome" was FALSE — A17.8 cannot and does not do that. THIS plan fixes that gap with real new harness work: A35 is a host-side driver that opens welcome.html in a fresh browser.newPage() tab (welcome.html is a real web-accessible extension page; verified to build to dist-test/src/welcome/welcome.html via vite.test.config.ts:95), waits for populateMark() to run at DOMContentLoaded, then queries the LIVE injected .welcome-hero__mark svg element and reads getComputedStyle().stroke to prove the currentColor cascade actually resolves. A35 is the canonical automated proof of the runtime injection + cascade — NOT a fiction.

A17.8 is still updated (Task 3) but its honest scope is narrowed: it asserts the welcome chunk JS bundles the raw SVG SOURCE string (a source-bundling check — it confirms ?raw inlined the SVG; it does NOT prove injection). A35 carries the live-DOM behavior proof. The Task 4 operator screenshot is the additional human aesthetic gate, not a substitute for automated coverage.

Baseline note (DEFECT 3 / iter-2 BLOCKER 2 resolution — VERIFIED this session). The vitest baseline is 184/184 GREEN when the parallel-vitest flake family does NOT fire. A full npx vitest run this session produced 183 passed / 1 failed (184 total) — and the RED was tests/background/webm-remux.test.ts > 'ffprobe -count_frames reports between 905 and 912 frames' (Error: Test timed out in 5000ms). Both webm-remux.test.ts (5/5) and tests/build/strict-meta-json-validation.test.ts (8/8) pass deterministically when run in isolation. The "1 failed" is a non-deterministic ffprobe/parallel-worker timeout flake — exactly the pre-existing flake family 04-CONTEXT.md enumerates as in-scope items #9 (parallel-vitest Tier-1-build-step race, ~1/5 full-suite runs) and #10 (2 ffprobe/ffmpeg vitest flakes). It is NOT a real regression and NOT tied to one specific test name (the prior iter-1 re-plan wrongly named strict-meta-json-validation.test.ts as a "pre-existing red on a clean tree" — that test is GREEN on a clean tree). Plan 04-06 adds 2 new test files (4 new tests: 3 in inline-svg.test.ts + 1 in cursor-visibility.test.ts). Target after this plan: 188/188 GREEN. Task 2's vitest gate (below) tolerates a single isolation-passing flake from the 04-CONTEXT #9/#10 family but FAILS on any new or reproducible failure — it hard-codes NO test filename.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/04-harden-clean-up-optional/04-CONTEXT.md @.planning/phases/04-harden-clean-up-optional/04-RESEARCH.md @.planning/phases/04-harden-clean-up-optional/04-PATTERNS.md @.planning/phases/04-harden-clean-up-optional/04-UI-SPEC.md @.planning/phases/04-harden-clean-up-optional/deferred-items.md @.planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md

Source files — locus of the visual polish edits

@src/shared/brand/mokosh-mark.svg @src/welcome/welcome.ts @src/welcome/welcome.css @globals.d.ts @src/offscreen/recorder.ts

Harness files — A17.8 update + NEW A35 host-side assertion

@tests/uat/extension-page-harness.ts @tests/uat/lib/harness-page-driver.ts @tests/uat/harness.test.ts @tests/uat/lib/launch.ts @tests/uat/lib/assertions.ts

Analog test scaffolds — node-env file-read + string-assertion (NO DOM library)

@tests/i18n/manifest-i18n.test.ts @tests/build/no-remote-fonts.test.ts @vitest.config.ts

PROJECT TEST ENVIRONMENT (DEFECT 1 — verified this session, NON-NEGOTIABLE):

  • vitest.config.ts line 18 sets environment:'node'. There is NO jsdom / happy-dom / linkedom / @happy-dom/global-registrator in node_modules. No vitest unit test uses DOMParser. Do NOT grep for environment.*jsdom and do NOT assume a jsdom environment — there is none.
  • tests/welcome/inline-svg.test.ts uses the file-read + string-assert pattern (precedent: tests/i18n/manifest-i18n.test.ts). It does NOT instantiate a DOM, does NOT call populateMark, does NOT use DOMParser at runtime.
  • The LIVE-DOM behavior (populateMark injecting an inline ; the currentColor cascade) is verified by the NEW host-side harness assertion A35, NOT by the unit test and NOT by A17.8. See "NEW A35 host-side assertion" below.

UAT HARNESS ARCHITECTURE (BLOCKER 1 — verified this session, NON-NEGOTIABLE):

  • launchHarnessBrowser (tests/uat/lib/launch.ts) opens exactly TWO pages: victimPage (a file:// URL, lines 473-474) and harnessPage (chrome-extension:///tests/uat/extension-page-harness.html, lines 523-527). It returns { browser, extensionId, harnessPage, victimPage, downloadsDir, swConsole, offConsole } (lines 534-542).
  • NO welcome.html tab is ever opened. populateMark() NEVER runs in the current harness. assertA17 (extension-page-harness.ts:2090-2308) reaches the welcome page ONLY via fetch(chrome.runtime.getURL('src/welcome/welcome.html')) + new DOMParser().parseFromString(htmlText,'text/html') — a DETACHED string parse, not a live tab. A17.8 (lines 2273-2298) is 100% string-grep on the welcome JS chunk text (jsText). 'welcome-hero__mark' returns ZERO grep hits across the whole harness file.
  • Drivers A1..A22 are page.evaluate(() => window.__mokoshHarness.assertXX()) wrappers — they run INSIDE the single harness page. driveA32/driveA33/driveA34 are HOST-SIDE drivers: they take a Page (plus, for A33/A34, captured handles) and build a CheckRecord[] / AssertionRecord directly without page.evaluate(window.__mokoshHarness). A35 follows the driveA32/A33/A34 host-side pattern.
  • The orchestrator driver list is in harness.test.ts (the drivers array, lines 374-535). Each entry is { name: string, drive: (page) => Promise }. Wrapped closures capture extra handles, e.g. driveA33Wrapped = (page) => driveA33(page, handles.browser, handles.extensionId, handles.downloadsDir) (lines 367-368). The harness total is computed as total = drivers.length + 1 (line 580) — adding A35 to the array auto-increments the count; no hardcoded total to bump. The architecture banner string at harness.test.ts:283 lists driver names literally and must have ', A35' appended.

AssertionRecord / CheckRecord shape (tests/uat/lib/assertions.ts:25-44):

  • interface CheckRecord { readonly name: string; readonly expected: unknown; readonly actual: unknown; readonly passed: boolean; }
  • interface AssertionRecord { readonly passed: boolean; readonly name: string; readonly checks: ReadonlyArray; readonly diagnostics: ReadonlyArray; readonly error?: string; }

Canonical node-env file-read + string-assert scaffold (from tests/i18n/manifest-i18n.test.ts:27-33):

  • import { describe, expect, it } from 'vitest';
  • import { readFileSync } from 'node:fs';
  • import { resolve as resolvePath } from 'node:path';
  • const SOME_PATH = resolvePath(process.cwd(), 'relative/path');
  • inside it(): const text = readFileSync(SOME_PATH, 'utf8'); expect(text).toContain('...');

From src/shared/brand/mokosh-mark.svg (current — root + 13 children; line 2 is the root element):

  • root line 2:
  • children: 1 + 12 elements; they inherit stroke from the root.

After Plan 04-06 (1 attribute changed on the root ; 13 children UNCHANGED):

  • root line 2: stroke="#181b2a" becomes stroke="currentColor". Nothing else changes.

From src/welcome/welcome.ts:46 (current ?url import): import markUrl from '../shared/brand/mokosh-mark.svg?url';

After Plan 04-06 (swap to ?raw): import markSvg from '../shared/brand/mokosh-mark.svg?raw';

From src/welcome/welcome.ts:159-179 (current populateMark — injection): builds an HTMLImageElement, sets img.src = markUrl, img.alt = altText, img.width/height = 64, img.className = 'welcome-hero__mark-img', img.setAttribute('aria-hidden','true'), then slot.replaceChildren(img). Filter-pipeline form; empty-slot logger.warn fallback at the end. altText = COPY['welcome.hero.mark.alt'] ?? 'Знак Mokosh'.

After Plan 04-06 (DOMParser inline-SVG injection — the populateMark body becomes):

  • const parser = new DOMParser();
  • for each slot: const doc = parser.parseFromString(markSvg, 'image/svg+xml'); const svg = doc.documentElement;
  • svg.classList.add('welcome-hero__mark-img'); svg.setAttribute('aria-hidden','true'); svg.setAttribute('role','img'); svg.setAttribute('aria-label', altText);
  • slot.replaceChildren(svg);
  • preserve the function signature, the slots query, the altText resolution, the filter-pipeline form, and the empty-slot logger.warn fallback.

NEVER use innerHTML — DOMParser + replaceChildren ONLY (MV3 CSP discipline; T-04-06-01 mitigation). The DOMParser parse is safe because the input is a Vite-bundled compile-time literal (no runtime untrusted input).

From globals.d.ts (current — *.svg?url block at lines 34-37; a .webm?url block follows at 47-50): declare module '.svg?url' { const url: string; export default url; }

After Plan 04-06 (append a *.svg?raw block immediately after the .svg?url block): declare module '.svg?raw' { const raw: string; export default raw; } (with an explanatory comment block per project docstring convention; cite the UI-SPEC dark-logo strategy + Vite ?raw asset-as-string semantics.)

From src/offscreen/recorder.ts:284-291 (verification target — ALREADY shipped; do NOT modify): the getDisplayMedia constraints object carries video: { displaySurface: 'monitor', cursor: 'always' }. The cursor: 'always' literal is at line 285.

From src/welcome/welcome.css:64-73 + 91-95 (existing rules — NO change required): .welcome-hero__mark { ... color: var(--mks-fg-inverse); } (the wrapper sets an inherited color); .welcome-hero__mark-img { width: 60%; height: 60%; display: block; } is a BARE class selector (no img. tag qualifier) so it matches identically to . welcome.css is NOT in files_modified — the inline inherits color: var(--mks-fg-inverse) from the .welcome-hero__mark wrapper automatically (CSS color is an inherited property; CSS Color L3). stroke="currentColor" then resolves to that inherited color. No CSS edit is needed.

From tests/uat/extension-page-harness.ts:2249-2298 (current A17.8 — Plan 01-10 mark-bundling invariant): the A17 driver locates the welcome JS chunk via the parsed <script src>, fetches jsText, then computes hasInlineDataUrl = jsText.includes('data:image/svg+xml'), hasSvgFileUrl from a .svg-filename regex, and hasCanonicalViewBox from viewBox='0 0 32 32' / URL-percent-encoded variants. The A17.8 check is pushed via result.checks.push({ name: 'A17.8: ...', expected, actual, passed }). After Plan 04-06 the ?raw import inlines the SVG SOURCE as a string literal (no data URL): assert jsText contains the raw source signature stroke="currentColor" AND viewBox="0 0 32 32"; drop the data:image/svg+xml check. A17.8 stays a SOURCE-BUNDLING check — the live-DOM behavior moves to the NEW A35.

NEW A35 host-side assertion (driveA35 in tests/uat/lib/harness-page-driver.ts; wired in harness.test.ts):

  • Signature: export async function driveA35(page: Page, browser: Browser, extensionId: string): Promise. (The page param is the harness page — unused for navigation but kept for driver-list signature uniformity; A35 opens its OWN tab via browser.newPage(). Reference the driveA32 page-param-kept-for-uniformity precedent if page is genuinely unused, or use it only to read the harness console.)
  • Body: const welcomePage = await browser.newPage(); const welcomeUrl = chrome-extension://${extensionId}/src/welcome/welcome.html; await welcomePage.goto(welcomeUrl, { waitUntil: 'domcontentloaded' }); — welcome.ts init() runs populateMark() at DOMContentLoaded (welcome.ts:194-198). Optionally await welcomePage.waitForSelector('.welcome-hero__mark svg', { timeout: ... }) to be race-free against the readyState branch.
  • Then run welcomePage.evaluate(() => { ... }) to read the LIVE DOM: querySelector('.welcome-hero__mark svg') is non-null; that element's getAttribute('stroke') === 'currentColor'; getComputedStyle(svgEl).stroke is a resolved non-default color (NOT 'none', NOT empty — proves the currentColor cascade resolved through the .welcome-hero__mark wrapper's color: var(--mks-fg-inverse)); and querySelector('.welcome-hero__mark img') is null (the old path is gone).
  • Build a CheckRecord[] (e.g. A35.1 svg present, A35.2 stroke attribute === currentColor, A35.3 getComputedStyle().stroke resolved non-default, A35.4 no in the slot) and return an AssertionRecord. ALWAYS await welcomePage.close() in a finally block so the extra tab does not leak. Wrap in try/catch and set result.error on throw — mirror the driveA33/driveA34 host-side error handling.
  • Wiring in harness.test.ts: add a driveA35Wrapped closure — const driveA35Wrapped: (page: import('puppeteer').Page) => Promise = (page) => driveA35(page, handles.browser, handles.extensionId); — alongside driveA33Wrapped/driveA34Wrapped (lines 367-372). Add { name: 'A35', drive: driveA35Wrapped } as the LAST entry of the drivers array (after the A34 entry at line 534). Append ', A35' to the architecture banner string at line 283. driveA35 must be added to the import-from-'./lib/harness-page-driver' block (lines 81-116). The harness total auto-increments via total = drivers.length + 1 (line 580).

SW chunk canonical glob (inherited from Phase 4 REVISION iter-2): the Vite SW chunk is dist/assets/index.ts-.js (verified empirically; pinned by RESEARCH Q1). All Phase 4 bundle gates use the dist/assets/index.ts-*.js glob. Task 4 pre-checkpoint gates use this canonical glob.

Task 1: Wave 0 RED — inline-SVG source-contract unit test + cursor-visibility defensive pin tests/welcome/inline-svg.test.ts, tests/build/cursor-visibility.test.ts tests/i18n/manifest-i18n.test.ts (node-env file-read + string-assert scaffold — THE canonical analog), tests/build/no-remote-fonts.test.ts (single-file grep scaffold), vitest.config.ts (CONFIRM environment:'node' at line 18 — there is NO jsdom), src/shared/brand/mokosh-mark.svg (current state — stroke='#181b2a'), src/welcome/welcome.ts (current state — ?url import + populateMark), globals.d.ts (current state — no ?raw decl), .planning/phases/04-harden-clean-up-optional/04-PATTERNS.md sections "tests/welcome/inline-svg.test.ts" and "tests/build/cursor-visibility.test.ts" tests/welcome/inline-svg.test.ts — node-env, source-level, 3 tests in describe('UI-SPEC dark-logo currentColor strategy — source-level contract'): - Test A (mokosh-mark.svg recolor): the SVG source contains stroke="currentColor" AND viewBox="0 0 32 32" AND does NOT contain stroke="#181b2a". RED today (SVG still has #181b2a). - Test B (welcome.ts ?raw import + DOMParser injection): the welcome.ts source contains mokosh-mark.svg?raw AND DOMParser AND replaceChildren AND does NOT contain mokosh-mark.svg?url AND does NOT contain innerHTML. RED today (welcome.ts still uses ?url + ). - Test C (globals.d.ts ambient decl): the globals.d.ts source contains the *.svg?raw ambient module declaration. RED today (only *.svg?url + *.webm?url declared). tests/build/cursor-visibility.test.ts — node-env, 1 test: the src/offscreen/recorder.ts source contains cursor: 'always'. GREEN today (already shipped at recorder.ts:285). 1. Create the tests/welcome/ directory (NEW — mirrors src/welcome/ per the source-tree convention used by tests/background/, tests/i18n/).
2. Create tests/welcome/inline-svg.test.ts as a node-env source-contract test (NO DOM, NO runtime DOMParser, NO jsdom — this is the DEFECT 1 resolution). Mirror the tests/i18n/manifest-i18n.test.ts scaffold:
   - import { describe, expect, it } from 'vitest';
   - import { readFileSync } from 'node:fs'; and import { resolve as resolvePath } from 'node:path';
   - Define path constants via resolvePath(process.cwd(), ...): MARK_SVG_PATH for src/shared/brand/mokosh-mark.svg, WELCOME_TS_PATH for src/welcome/welcome.ts, GLOBALS_DTS_PATH for globals.d.ts.
   - describe('UI-SPEC dark-logo currentColor strategy — source-level contract', ...) with 3 it() blocks:
     - Test A: read MARK_SVG_PATH; assert the text contains stroke="currentColor"; assert it contains viewBox="0 0 32 32"; assert it does NOT contain stroke="#181b2a".
     - Test B: read WELCOME_TS_PATH; assert the text contains the substring mokosh-mark.svg?raw; assert it contains DOMParser; assert it contains replaceChildren; assert it does NOT contain mokosh-mark.svg?url; assert it does NOT contain innerHTML (the MV3-CSP discipline pin and the T-04-06-01 mitigation).
     - Test C: read GLOBALS_DTS_PATH; assert the text contains the *.svg?raw ambient module declaration string.
   - Add a header comment block (per the project docstring convention) explaining: this is a node-env source-contract test pinning source TEXT only; it does NOT exercise live DOM because vitest is environment:'node' (vitest.config.ts:18) and the project ships no DOM-emulation library; the live-DOM injection + currentColor cascade is verified by the harness A35 host-side assertion (Task 3), NOT here. Phrase the header so it states "no DOM-emulation library is used" WITHOUT relying on the bare token jsdom being absent — i.e. do not write the explanation in a way that an acceptance grep would trip on (advisory A3).

3. Create tests/build/cursor-visibility.test.ts per the PATTERNS.md cursor-visibility scaffold (node-env, single-it, file-grep):
   - import { describe, expect, it } from 'vitest'; import { readFileSync } from 'node:fs'; import { resolve as resolvePath } from 'node:path';
   - Define RECORDER_PATH via resolvePath(process.cwd(), 'src/offscreen/recorder.ts').
   - describe('cursor visibility constraint shipped (Plan 01-09 -> verified Plan 04-06)', ...).
   - One it() block: read RECORDER_PATH; assert the text contains the cursor: 'always' literal.

Filter-pipeline form where loops appear. Absolute imports per project rule. TypeScript-strict.

RED gate: run npm test against tests/welcome/ and tests/build/cursor-visibility.test.ts. inline-svg.test.ts shows 3 RED (SVG still #181b2a; welcome.ts still ?url/<img>; globals.d.ts has no ?raw decl). cursor-visibility.test.ts shows 1 GREEN (the literal already exists at recorder.ts:285).
npm test -- tests/welcome/ tests/build/cursor-visibility.test.ts --run 2>&1 | tail -25 - File tests/welcome/inline-svg.test.ts exists with 3 it() blocks in a describe('UI-SPEC dark-logo currentColor strategy ...') block. - File tests/build/cursor-visibility.test.ts exists with 1 it() block. - Inline-SVG tests: 3 RED today (SVG still #181b2a; welcome.ts still ?url/; globals.d.ts no ?raw). - Cursor-visibility test: 1 GREEN today (regression pin for the already-shipped literal). - grep -c 'currentColor' tests/welcome/inline-svg.test.ts returns at least 2. - grep -c "cursor: 'always'" tests/build/cursor-visibility.test.ts returns at least 1. - tests/welcome/inline-svg.test.ts has no `import` of any DOM-emulation library and no jsdom-environment directive (verify with: grep -E "^import .*jsdom|@vitest-environment jsdom" tests/welcome/inline-svg.test.ts returns 0 — this scopes the check to import statements + the environment directive, NOT prose, per advisory A3). 2 test files committed; 3 RED + 1 GREEN-on-arrival. Atomic commit: test(04-06): Wave 0 — inline-SVG source-contract RED + cursor-visibility regression pin. Task 2: Wave 1 GREEN — SVG stroke recolor + welcome.ts ?raw import + populateMark inline injection + globals.d.ts ambient decl src/shared/brand/mokosh-mark.svg, src/welcome/welcome.ts, globals.d.ts src/shared/brand/mokosh-mark.svg, src/welcome/welcome.ts (full; ~198 lines), globals.d.ts (full; 50 lines), .planning/phases/04-harden-clean-up-optional/04-UI-SPEC.md section "Implementation amendment", .planning/phases/04-harden-clean-up-optional/04-PATTERNS.md section "src/welcome/welcome.ts:46 + 159-179" Edit 1 — src/shared/brand/mokosh-mark.svg (1-attribute change on the root ): - Use the Edit tool to replace stroke="#181b2a" with stroke="currentColor" on the root element (line 2). The 12 + 1 children inherit stroke from the root and are UNCHANGED — do not touch them. - Verify: grep -c 'stroke="#181b2a"' src/shared/brand/mokosh-mark.svg returns 0 (was 1); grep -c 'stroke="currentColor"' src/shared/brand/mokosh-mark.svg returns 1.
Edit 2 — src/welcome/welcome.ts (?raw import + populateMark rewrite):
- Use the Edit tool to replace the line-46 import (import markUrl from '../shared/brand/mokosh-mark.svg?url';) with import markSvg from '../shared/brand/mokosh-mark.svg?raw';. Update the surrounding comment block (lines 36-45) to describe the ?raw strategy — cite the UI-SPEC implementation amendment and the currentColor cascade requirement (inline <svg> inherits parent CSS color; <img> does not) — instead of the ?url asset-URL strategy.
- Use the Edit tool to replace the populateMark function body (lines 159-179) with the DOMParser-based inline injection per the <interfaces> block. Preserve the function signature, the slots query, the altText resolution (COPY['welcome.hero.mark.alt'] ?? 'Знак Mokosh'), the filter-pipeline form, and the empty-slot logger.warn fallback. The new body parses markSvg via parser.parseFromString(markSvg, 'image/svg+xml'), takes doc.documentElement, applies classList.add('welcome-hero__mark-img') + setAttribute('aria-hidden','true') + setAttribute('role','img') + setAttribute('aria-label', altText), then slot.replaceChildren(svg).
- Update the populateMark docstring (lines 134-158) to describe inline-<svg> injection (was <img> injection). NEVER use innerHTML.

Edit 3 — globals.d.ts (append ambient decl):
- Use the Edit tool to APPEND the declare module '*.svg?raw' block immediately after the existing *.svg?url block (lines 34-37), with the explanatory comment per the <interfaces> block. The existing *.webm?url block (lines 47-50) is unrelated and stays.

Run gates:
- npx tsc --noEmit exits 0 (the ?raw ambient decl makes welcome.ts tsc-clean).
- npm test against tests/welcome/inline-svg.test.ts — Wave 0 RED flips to 3/3 GREEN.
- npm test against tests/build/cursor-visibility.test.ts — stays 1/1 GREEN.
- Full vitest (npm test --run). VITEST GATE LOGIC (DEFECT 3 / BLOCKER 2 resolution — do NOT hard-code any test filename):
    * If the suite is 188/188 GREEN -> PASS.
    * If the suite is 187 passed / 1 failed AND the single failing test PASSES when re-run in isolation (npm test -- <that-failing-file> --run) -> this is the known 04-CONTEXT #9/#10 non-deterministic parallel-vitest / ffprobe-timeout flake family; TOLERATE it and PASS. Record the flake test name + the isolation re-run result in the SUMMARY.
    * If the suite has 2+ failures, OR the single failing test STILL FAILS in isolation (i.e. it is reproducible, not a flake) -> FAIL the gate: Plan 04-06 caused a regression; fix it before commit.
  Note the true clean baseline is 184/184 GREEN; +4 new tests -> 188/188 target. The flake (when it fires) lands on ffprobe/parallel-race tests such as tests/background/webm-remux.test.ts — but the gate decision is by the isolation-re-run rule above, NOT by a name match.
- npm run build exits 0; verify the welcome chunk JS bundles the raw SVG source — at least one file under dist/assets/*.js contains the currentColor signature from the inlined SVG source.
npx tsc --noEmit && npm test -- tests/welcome/inline-svg.test.ts tests/build/cursor-visibility.test.ts --run 2>&1 | tail -20 - npx tsc --noEmit exits 0. - grep -c 'stroke="currentColor"' src/shared/brand/mokosh-mark.svg returns 1. - grep -c 'stroke="#181b2a"' src/shared/brand/mokosh-mark.svg returns 0. - grep -c 'svg?raw' src/welcome/welcome.ts returns at least 1. - grep -c 'svg?url' src/welcome/welcome.ts returns 0 (the old import is gone). - grep -c 'DOMParser' src/welcome/welcome.ts returns at least 1. - grep -c 'innerHTML' src/welcome/welcome.ts returns 0 (MV3 CSP discipline; T-04-06-01). - The *.svg?raw ambient module declaration is present in globals.d.ts. - npm test against tests/welcome/inline-svg.test.ts exits 0 with 3/3 GREEN (was 3-RED). - npm test against tests/build/cursor-visibility.test.ts exits 0 with 1/1 GREEN (preserved). - Full vitest passes the Task 2 VITEST GATE LOGIC: either 188/188 GREEN, or 187/1 where the single RED passes in isolation (the tolerated 04-CONTEXT #9/#10 flake). 2+ failures or a reproducible single failure FAILS the gate. SVG + welcome.ts + globals.d.ts edits landed; inline-SVG tests flip 3-RED to 3-GREEN; vitest gate passes (188/188 or a tolerated isolation-passing flake). Atomic commit: feat(04-06): Wave 1 — dark-logo currentColor strategy + inline-SVG injection. Task 3: A17.8 raw-source update + NEW A35 live-DOM harness assertion + 01-07-SUMMARY back-patch + deferred-items correction tests/uat/extension-page-harness.ts, tests/uat/lib/harness-page-driver.ts, tests/uat/harness.test.ts, .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md, .planning/phases/04-harden-clean-up-optional/deferred-items.md tests/uat/extension-page-harness.ts:2249-2308 (existing A17.8 region — the A17 driver Step 7 block), tests/uat/lib/harness-page-driver.ts:2425-2500 + 2622-2760 (driveA32 + driveA33/A34 host-side driver pattern — signature, browser.newPage usage, CheckRecord[] build, try/catch + error handling), tests/uat/harness.test.ts:81-116 (driver imports) + 360-535 (driveA33Wrapped/driveA34Wrapped closures + the `drivers` array) + 283 (architecture banner string) + 577-580 (total = drivers.length + 1), tests/uat/lib/launch.ts:473-542 (launchHarnessBrowser return shape — confirm handles.browser + handles.extensionId), tests/uat/lib/assertions.ts:25-44 (AssertionRecord/CheckRecord), src/welcome/welcome.ts:194-198 (init() runs populateMark at DOMContentLoaded), .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md (full; 244 lines), .planning/phases/04-harden-clean-up-optional/deferred-items.md (full), .planning/phases/04-harden-clean-up-optional/04-PATTERNS.md section "tests/uat/extension-page-harness.ts A17.8 sub-check update" and section "01-07-SUMMARY.md back-patch" Edit 1 — A17.8 sub-check (tests/uat/extension-page-harness.ts, the A17 driver Step 7 block at lines 2249-2298) — SOURCE-BUNDLING check only: - Read the existing A17.8 block. - The ?raw import bundles the SVG SOURCE as a string literal into the welcome chunk (no more data:image/svg+xml data URL). Update the sub-check: replace the hasInlineDataUrl computation (jsText.includes('data:image/svg+xml')) and the svgFileUrl regex with a raw-source check — assert jsText contains the canonical mark signature stroke="currentColor" AND viewBox="0 0 32 32" (the inlined raw SVG source). Keep the hasCanonicalViewBox check; it remains valid (the raw source carries the literal viewBox="0 0 32 32"). Update the diag() line and the result.checks.push({ name, expected, actual, passed }) object so the A17.8 name + expected describe RAW-SOURCE bundling. - Update the A17.8 explanatory comment block (lines ~2249-2272) to state honestly: A17.8 is a SOURCE-BUNDLING check (it confirms the ?raw import inlined the SVG source string); it does NOT prove the inline-SVG is injected into the live DOM or that the currentColor cascade resolves — that runtime behavior is verified by the NEW host-side assertion A35 (see driveA35). Do NOT claim A17.8 covers live-DOM injection. - Note the line range: A17.8 is at ~line 2294 — disjoint from the Plan 04-04/04-05 harness appends at ~line 3970+, which keeps Plan 04-06 land parallel-safe.
Edit 2 — NEW host-side A35 assertion (tests/uat/lib/harness-page-driver.ts) — the LIVE-DOM injection + currentColor cascade proof:
- Append a new driveA35 host-side driver function at the end of the harness-page-driver.ts driver section, modeled on the driveA32/driveA33/driveA34 host-side pattern (host-side: builds a CheckRecord[] + returns an AssertionRecord directly; NOT a page.evaluate(window.__mokoshHarness) wrapper).
- Signature: export async function driveA35(page: Page, browser: Browser, extensionId: string): Promise<AssertionRecord>. (Browser + Page are already imported at harness-page-driver.ts:43.) The `page` param is the harness page; A35 does not navigate it — A35 opens its OWN welcome tab. If `page` is genuinely unused, follow the driveA32 page-param-kept-for-signature-uniformity precedent (or annotate it).
- Body:
  - const checks: CheckRecord[] = []; const diagnostics: string[] = [];
  - Wrap the work in try/catch. In a finally block, await welcomePage.close() so the extra tab never leaks.
  - const welcomePage = await browser.newPage();
  - const welcomeUrl = `chrome-extension://${extensionId}/src/welcome/welcome.html`; (this is the canonical web-accessible welcome page path — the same path chrome.runtime.getURL('src/welcome/welcome.html') resolves to, which A17 already fetches; welcome.html builds to dist-test/src/welcome/welcome.html per vite.test.config.ts).
  - await welcomePage.goto(welcomeUrl, { waitUntil: 'domcontentloaded' }); — welcome.ts init() runs populateMark() at DOMContentLoaded (welcome.ts:194-198).
  - await welcomePage.waitForSelector('.welcome-hero__mark svg', { timeout: <a reasonable ms; reuse a HARNESS_*_TIMEOUT_MS-class constant or define an A35-local one> }) to be race-free against the welcome.ts readyState branch. If the selector never appears, the catch path records the failure.
  - Run a single welcomePage.evaluate(() => { ... }) that reads the LIVE DOM and returns a plain-object result: { svgPresent: querySelector('.welcome-hero__mark svg') !== null, strokeAttr: <that svg>.getAttribute('stroke'), computedStroke: getComputedStyle(<that svg>).stroke, imgPresent: querySelector('.welcome-hero__mark img') !== null }. Guard the getAttribute/getComputedStyle calls so a null element does not throw inside evaluate.
  - Push 4 CheckRecords:
      A35.1 — inline <svg> injected into the mark slot: expected non-null, actual svgPresent, passed === svgPresent.
      A35.2 — injected <svg> carries stroke="currentColor": expected 'currentColor', actual strokeAttr, passed === (strokeAttr === 'currentColor').
      A35.3 — getComputedStyle().stroke resolves to a non-default color (the currentColor cascade resolved through .welcome-hero__mark color: var(--mks-fg-inverse)): expected a non-empty, non-'none' resolved color, actual computedStroke, passed === (computedStroke is non-empty AND computedStroke !== 'none'). This is the real proof the cascade works.
      A35.4 — no legacy <img> in the mark slot: expected null/false, actual imgPresent, passed === !imgPresent.
  - result.passed = checks.every((c) => c.passed); return { passed, name: 'A35 — welcome-page inline-SVG injected at populateMark() runtime; currentColor stroke resolves via parent CSS color cascade (UI-SPEC dark-logo strategy live-DOM proof)', checks, diagnostics }.
  - On a thrown error, return an AssertionRecord with passed:false + error set (mirror driveA33/driveA34 host-side error handling). Always close welcomePage.
- Add a function docstring per project convention explaining: A35 is the LIVE-DOM counterpart to the source-only A17.8 + the source-only inline-svg.test.ts; it opens welcome.html as a real tab so populateMark() actually runs; it verifies the injected <svg> + the currentColor cascade — the runtime behavior the node-env unit test deliberately cannot cover. Cite the iter-2 BLOCKER 1 resolution.

Edit 3 — wire A35 into the orchestrator (tests/uat/harness.test.ts):
- Add driveA35 to the import block from './lib/harness-page-driver' (the block at lines 81-116, where driveA33/driveA34 are imported).
- Add a driveA35Wrapped closure alongside driveA33Wrapped/driveA34Wrapped (lines 367-372): const driveA35Wrapped: (page: import('puppeteer').Page) => Promise<AssertionRecord> = (page) => driveA35(page, handles.browser, handles.extensionId);
- Add { name: 'A35', drive: driveA35Wrapped } as the LAST entry of the `drivers` array (immediately after the A34 entry at line 534). The harness total auto-increments via `total = drivers.length + 1` (line 580) — no hardcoded count to bump.
- Append ', A35' to the architecture banner string at line 283 (the literal driver-name list).

Edit 4 — 01-07-SUMMARY.md back-patch (CORRECTED line set per DEFECT 2):
- Read .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md (full).
- Re-confirm the line set with: grep -nE 'Phase 5|deferred to Phase 5' .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md (the executor MUST verify the live file rather than trusting cited numbers).
- FLIP these 5 lines — the genuine stale "deferred to Phase 5" framing (cursor:'always' actually shipped opportunistically in Plan 01-09, so the deferral framing is false):
  - Line 22 (the affects: dependency-graph entry: "Phase 5 (P1/P2 hardening) — new entry: getDisplayMedia cursor visibility constraint"). Flip to note the constraint shipped in Plan 01-09 and was verified in Phase 4 Plan 04-06.
  - Line 47 (key-decisions: "Cursor visibility ... deferred to Phase 5, not back-patched into Phase 1 ..."). Flip to "Cursor visibility (cursor: 'always') was opportunistically shipped in Plan 01-09 at recorder.ts:285 and verified in Phase 4 Plan 04-06; the Phase 1 closure correctly did not back-patch it into Phase 1."
  - Line 82 (accomplishments: "Cursor-visibility refinement deferred to Phase 5 ..."). Flip to: "Cursor-visibility refinement opportunistically shipped in Plan 01-09 (recorder.ts:285 cursor: 'always'); verified in Phase 4 Plan 04-06 via tests/build/cursor-visibility.test.ts + operator-empirical SAVE flow showing the pointer visible in last_30sec.webm."
  - Line 135 (Decisions Made #5: "Cursor visibility refinement deferred to Phase 5 ..."). Flip the framing to reflect the Plan 01-09 opportunistic shipping while keeping the historical point that Phase 1 closure did not widen its own diff.
  - Line 205 (User Setup Required: "The cursor visibility refinement (Phase 5) will, when activated, add a cursor: 'always' constraint ..."). Flip to past tense: the constraint was added in Plan 01-09; no user action was required; Phase 4 Plan 04-06 verified it.
- LEAVE these 4 lines UNCHANGED — they are historical descriptions of what specific Plan 01-07-closure commits DID, not forward-looking deferrals:
  - Line 40 (key-files modified: describes the ROADMAP.md commit content "cursor-visibility refinement appended to Phase 5").
  - Line 89 (Task Commits: describes the 7df72aa commit "Phase 5 cursor-visibility appended").
  - Line 109 (Files Created/Modified: describes the ROADMAP.md modification "Phase 5 P1/P2 list appended ...").
  - Line 110 (Files Created/Modified: describes the STATE.md modification, including the [Phase 01-07-deferred-to-5] decision-log tag — a historical commit record).
- Each flip is surgical (single line or single bullet, with surrounding context). Do NOT rewrite the whole SUMMARY. After the flips, the SUMMARY narrative is internally consistent: the 5 flipped lines acknowledge Plan 01-09 + Phase 4; the 4 historical lines still accurately describe what the Phase-1-closure commits recorded at the time.

Edit 5 — deferred-items.md correction (DEFECT 3 / BLOCKER 2 — the prior entry mis-diagnosed the flake):
- Read .planning/phases/04-harden-clean-up-optional/deferred-items.md.
- The existing entry "tests/build/strict-meta-json-validation.test.ts failing on clean tree" is a MISDIAGNOSIS: that test is GREEN in isolation (8/8) AND GREEN on a clean tree; the actual full-suite RED observed this session was tests/background/webm-remux.test.ts (ffprobe -count_frames timeout), which is also GREEN in isolation (5/5). Correct the entry: re-title/rewrite it to describe the real root cause — a non-deterministic parallel-vitest / ffprobe-timeout flake family that is already 04-CONTEXT.md in-scope items #9 (parallel-vitest Tier-1-build-step race, ~1/5 runs) and #10 (2 ffprobe/ffmpeg flakes). State that the true clean baseline is 184/184 GREEN; the "1 failed" is the flake, which lands non-deterministically on whichever ffprobe/parallel-race test loses the worker race. Remove the false claim that strict-meta-json-validation.test.ts "fails on a clean tree". If a /gsd-debug route is noted, route it as "the 04-CONTEXT #9/#10 parallel-vitest ffprobe flake family", NOT as "strict-meta-json fails on a clean tree".

Verify gates:
- npx tsc --noEmit exits 0 (the new driveA35 + harness wiring is tsc-clean).
- npm run build:test exits 0.
- Run the UAT harness (HEADLESS=1 SKIP_PROD_REBUILD=0 SKIP_LONG_UAT=1 npm run test:uat). SKIP_PROD_REBUILD=0 is intentional: the harness must rebuild dist-test against the Task 2 source edits so A17.8 (raw-source grep) and the new A35 (live welcome tab) run against the updated welcome bundle — a stale dist-test would not carry the ?raw inlining (advisory A1: action and verify both use SKIP_PROD_REBUILD=0). Expected: the full harness driver set GREEN with the updated A17.8 AND the new A35. The dark-logo strategy land must not regress any other assertion.
- grep -c 'Phase 4 Plan 04-06' .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md returns at least 1 (the new back-patch citation appears in the flipped lines).
npx tsc --noEmit && npm run build:test 2>&1 | tail -5 && HEADLESS=1 SKIP_PROD_REBUILD=0 SKIP_LONG_UAT=1 npm run test:uat 2>&1 | tail -20 - npx tsc --noEmit exits 0. - npm run build:test exits 0. - The UAT harness driver set is GREEN with the updated A17.8 AND the new A35 (no harness regression from the dark-logo land); the harness total reported is the prior total + 1 (A35 added). - grep -c 'driveA35' tests/uat/lib/harness-page-driver.ts returns at least 1. - grep -c 'driveA35' tests/uat/harness.test.ts returns at least 2 (the import + the wrapped-closure entry). - grep -c "name: 'A35'" tests/uat/harness.test.ts returns at least 1 (the drivers-array entry). - grep -c 'getComputedStyle' tests/uat/lib/harness-page-driver.ts returns at least 1 (the A35 currentColor-cascade probe). - grep -c 'stroke="currentColor"' tests/uat/extension-page-harness.ts returns at least 1 (the new A17.8 raw-source grep target). - The data:image/svg+xml grep target is removed from the A17.8 block (the ?raw import no longer produces a data URL). - 01-07-SUMMARY.md lines 22, 47, 82, 135, 205 no longer carry the stale "deferred to Phase 5" framing. - 01-07-SUMMARY.md lines 40, 89, 109, 110 are unchanged (historical commit-description lines). - grep -c 'Phase 4 Plan 04-06' .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md returns at least 1. - deferred-items.md no longer claims strict-meta-json-validation.test.ts "fails on a clean tree"; the entry now describes the 04-CONTEXT #9/#10 parallel-vitest flake family. A17.8 updated to raw-source bundling check; NEW host-side A35 assertion opens a live welcome tab + verifies the injected + the currentColor cascade; A35 wired into the orchestrator; 01-07-SUMMARY.md back-patched (22/47/82/135/205); deferred-items.md flake mis-diagnosis corrected. Atomic commit: feat(04-06): A35 live-DOM inline-SVG harness check + A17.8 raw-source update + back-patch. Task 4: Operator empirical UAT — dark-mode aesthetic judgment on welcome hero (from screenshots) (no source files modified — verification-only checkpoint; gates against the existing dist/ + Puppeteer screenshots) Step 1 — Pre-checkpoint bundle gates (orchestrator-driven; per saved memory feedback-pre-checkpoint-bundle-gates.md; ALL MUST PASS before surfacing Step 3 to the operator):
Glob-existence pre-gate (run FIRST — guards against silent 0-hit passes on a mis-glob): ls dist/assets/index.ts-*.js must list at least one file. If 0, the build is broken (SW chunk missing) OR the canonical filename pattern shifted — fail loudly rather than 0-grep silently.

1. npm run build exits 0; dist/ populated.
2. SW CSP-safety grep (canonical SW chunk glob): grep for new Function( and eval( in dist/assets/index.ts-*.js returns 0 hits (Plan 04-02 effect preserved).
3. SW Node-globals grep (canonical SW chunk glob): grep for Buffer.from / Buffer.alloc / process. / require( in dist/assets/index.ts-*.js returns 0 hits.
4. DOM-globals grep (canonical SW chunk glob): grep for window. / document. in dist/assets/index.ts-*.js, excluding comment lines and globalThis idioms, returns 0 hits.
5. Tier-1 SW-bundle-import gate: vitest run tests/background/sw-bundle-import.test.ts is GREEN.
6. Tier-1 FORBIDDEN_HOOK_STRINGS gate: vitest run tests/background/no-test-hooks-in-prod-bundle.test.ts is GREEN (12 strings, 0 hits each — Plan 04-06 adds no new __MOKOSH_UAT__-gated symbols, so the inventory stays at 12).

Also confirm the vitest baseline per the Task 2 VITEST GATE LOGIC: the full suite is 188/188 GREEN, OR 187/1 where the single RED passes when re-run in isolation (the tolerated 04-CONTEXT #9/#10 non-deterministic parallel-vitest / ffprobe-timeout flake family — NOT a regression, NOT a named test). 2+ failures or a reproducible single failure is a regression. And the UAT harness driver set (now including the new A35) is GREEN.

Step 2 — Produce the verification artifact (light + dark Puppeteer screenshots; per feedback-trust-harness-over-manual-uat.md the operator judges from screenshots, NOT a manual Chrome session):
- Load dist/ as an unpacked extension and open the welcome page in a Puppeteer-driven Chrome.
- Capture a LIGHT-surface screenshot of the welcome hero (default OS appearance — the regression-baseline shot).
- Capture a DARK-surface screenshot of the welcome hero. Force dark via Puppeteer's emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]) (or the equivalent CDP Emulation.setEmulatedMedia) so the .dark / [data-theme="dark"] token overrides in src/shared/tokens.css lines 234-251 apply, then re-screenshot the welcome hero.
- Save both screenshots to a stable path (e.g. /tmp/04-06-welcome-hero-light.png and /tmp/04-06-welcome-hero-dark.png) and surface both paths to the operator in the checkpoint message.

Step 3 — Operator-driven empirical judgment: see the <how-to-verify> block below.

Step 4 — Resume signal handling: the orchestrator waits for the operator response per the <resume-signal> block below.
npm run build 2>&1 | tail -3 && ls dist/assets/index.ts-*.js UI-SPEC dark-logo contrast strategy: SVG stroke recolor (stroke="currentColor") + inline-SVG injection in welcome.ts (DOMParser + replaceChildren; no , no innerHTML, no eval) + globals.d.ts *.svg?raw ambient decl + A17.8 harness raw-source assertion + NEW A35 live-DOM harness assertion (opens a real welcome tab, verifies the injected + currentColor cascade) + cursor-visibility node-env regression pin + 01-07-SUMMARY.md back-patch (5 stale Phase-5 lines flipped) + deferred-items.md flake mis-diagnosis correction. Pre-checkpoint bundle gates 6/6 PASS: - Gate 1: npm run build exit 0. - Gate 2: new Function / eval count in dist/assets/index.ts-*.js returns 0 (Plan 04-02 effect preserved; canonical SW chunk glob). - Gate 3: SW Node-globals grep clean against dist/assets/index.ts-*.js. - Gate 4: DOM-globals grep clean against dist/assets/index.ts-*.js. - Gate 5: Tier-1 SW-bundle-import unit gate GREEN. - Gate 6: FORBIDDEN_HOOK_STRINGS at 12 (no change — Plan 04-06 adds no test-mode symbols). - Glob-existence pre-gate: ls dist/assets/index.ts-*.js lists at least one file (prevents silent 0-hit pass on a mis-glob). - Plus: vitest 188/188 GREEN (or a tolerated single isolation-passing 04-CONTEXT #9/#10 flake); UAT harness driver set GREEN including the new A35.
Auto-confirmed (no operator action needed):
- mokosh-mark.svg now uses stroke="currentColor" (1-attribute semantic change; 13 children unchanged).
- welcome.ts inline-injects the SVG via DOMParser + replaceChildren (no <img>, no innerHTML, no eval).
- The inline-SVG injection + the currentColor cascade are now verified AUTOMATICALLY in real Chrome by the new A35 harness assertion (a live welcome tab where populateMark() runs; A35 reads getComputedStyle().stroke on the injected <svg>).
- On the LIGHT surface the mark appears identical to the Plan 01-10 cycle-2 ack — color: var(--mks-fg-inverse) at .welcome-hero__mark cascades to the inline SVG's currentColor, resolving to linen-50 (off-white) stroke on the madder-orange wrapper background.
- PNG toolbar icons unchanged (Chrome auto-inverts dark icons on dark toolbars).
- cursor: 'always' already at recorder.ts:285 (Plan 01-09 opportunistic); pinned by tests/build/cursor-visibility.test.ts.
The orchestrator has produced two screenshots of the welcome hero: - /tmp/04-06-welcome-hero-light.png — LIGHT surface (default OS appearance). - /tmp/04-06-welcome-hero-dark.png — DARK surface (prefers-color-scheme: dark emulated).
1. Open /tmp/04-06-welcome-hero-light.png. LIGHT-surface regression check: the welcome hero mark renders inside the madder-600 circle with a linen-50 (off-white) stroke — visually identical to the Plan 01-10 cycle-2 operator ack 2026-05-20 "All good". Expected appearance unchanged.
2. Open /tmp/04-06-welcome-hero-dark.png. DARK-surface aesthetic judgment (the operator-empirical decision): on dark mode the .dark token block in src/shared/tokens.css lines 234-251 overrides --mks-fg-inverse to --mks-ink-900 (deep indigo); the wrapper background stays madder; the inline SVG's currentColor therefore resolves to deep indigo.
3. Judge the visual contrast: does the mark remain legible and aesthetically acceptable on the dark surface? The strategy aims to keep the mark crisp on EITHER a light or a dark surface by inverting the stroke when the surface flips.
4. (Optional, only if you want to also exercise the cursor path) Load dist/ as an unpacked extension, start a recording, click around, SAVE, then open video/last_30sec.webm and confirm the operator cursor is visible in playback (the cursor: 'always' verification for the ROADMAP cursor visibility item — this is already pinned automatically by tests/build/cursor-visibility.test.ts, so it is optional here).

Resume signals:
- "approved" — the dark-mode aesthetic is acceptable; the Phase 4 dark-logo strategy is closed.
- Otherwise describe the issue specifically (e.g. "stroke too thin on dark; needs heavier stroke-width", or "wrapper madder clashes with the dark BG; want a different accent"). Plan execution routes the issue via /gsd-debug per feedback-gsd-ceremony-for-fixes.md — no hot-edits to the UI-SPEC or the canonical design system.
Type "approved" or describe the issue (e.g. "stroke too thin", "need heavier weight on dark", "want a different accent"). Operator returns "approved" verbatim OR describes a specific issue; if an issue, route via /gsd-debug per feedback-gsd-ceremony-for-fixes.md.

<threat_model>

Trust Boundaries

Boundary Description
Vite ?raw import to compile-time string literal SVG source is bundled as a compile-time string; NO runtime untrusted input flows into DOMParser; the parser input is statically known at build time
DOMParser parse to live DOM parseFromString('image/svg+xml') is a CSP-safe operation per MDN — it does NOT execute scripts in the parsed SVG and runs in a sandboxed parser context; no innerHTML; no eval
Inline CSS color inheritance inline SVG (parsed + appended via DOMParser + replaceChildren) inherits parent CSS color per W3C SVG2 §13.3; currentColor on stroke resolves to the wrapper's color: var(--mks-fg-inverse) cascade
New A35 harness tab driveA35 opens an extra browser.newPage() against chrome-extension:///src/welcome/welcome.html; the tab is test-only (gated dist-test build), always closed in a finally block — no production surface, no leaked tab

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-04-06-01 Tampering a future developer might switch DOMParser to innerHTML for "simplicity" — innerHTML in an extension-page context is unsafe (CSP risk + script-execution surface) mitigate Inline code comment in populateMark + the executor instruction "NEVER use innerHTML — DOMParser + replaceChildren only (MV3 CSP discipline)"; tests/welcome/inline-svg.test.ts Test B asserts the welcome.ts source does NOT contain innerHTML; the NEW A35 harness assertion verifies the inline-SVG DOM shape live in real Chrome (defense in depth)
T-04-06-02 Information Disclosure the inline SVG carries no PII or secret — it is the canonical Mokosh brand mark accept Static brand asset; out-of-tree threat surface
T-04-06-03 Spoofing cursor visibility in captured frames could leak transient UI overlay state (e.g. a 2FA OTP digit the operator was about to type) — but this is a known and intended diagnostic feature per the Plan 01-07 observation; password masking is out of scope per the D-P3-02 charter accept Operator-side responsibility per the CONTEXT charter; v2 candidate per CONTEXT Deferred Ideas
T-04-06-04 Repudiation a mis-globbed dist/assets/index*-bg.js matches no files; grep -c new Function returns 0; Gate 2 spuriously PASSES even if a CSP regression slipped in mitigate Canonical SW chunk glob dist/assets/index.ts-.js (verified empirically; pinned by RESEARCH Q1); the Task 4 glob-existence pre-gate (ls dist/assets/index.ts-.js lists at least one file) runs BEFORE the grep gates and fails loudly if the glob matches nothing
T-04-06-05 Repudiation the parallel-vitest ffprobe-timeout flake (04-CONTEXT #9/#10) could mask a real Plan-04-06 regression — a hard-coded named-test gate would either falsely blame the plan or falsely pass mitigate Task 2 VITEST GATE LOGIC tolerates a single RED ONLY when that exact test passes on an isolation re-run (npm test -- ); a reproducible failure or 2+ failures FAILS the gate. No test filename is hard-coded — the gate distinguishes flake from regression by re-run behavior, not by name
T-04-06-SC Tampering npm/pip/cargo installs introducing a supply-chain risk accept Plan 04-06 introduces NO new package-manager installs — files_modified contains only existing source/test/spec/docs/harness files; no devDependency is added (the DEFECT 1 resolution explicitly rejected adding jsdom; the live-DOM coverage is the new in-repo A35 harness assertion, not a new dependency). Package legitimacy gate is therefore not triggered.
</threat_model>
- npx tsc --noEmit exits 0 (including the new driveA35 + harness wiring). - npm run build exits 0. - Full vitest per the Task 2 VITEST GATE LOGIC: 188/188 GREEN, OR 187/1 where the single RED passes when re-run in isolation (the tolerated 04-CONTEXT #9/#10 non-deterministic parallel-vitest / ffprobe-timeout flake family — NOT a regression, NOT a named test). +4 new tests over the 184/184 GREEN baseline (Task 1's 3 RED inline-svg tests flip GREEN in Task 2; Task 1's 1 cursor-visibility test is GREEN throughout). 2+ failures or a reproducible single failure FAILS. - grep -c 'stroke="currentColor"' src/shared/brand/mokosh-mark.svg returns 1. - grep -c 'svg?raw' src/welcome/welcome.ts returns at least 1; grep -c 'svg?url' src/welcome/welcome.ts returns 0. - grep -c 'innerHTML' src/welcome/welcome.ts returns 0. - The *.svg?raw ambient module declaration is present in globals.d.ts. - UAT harness driver set GREEN with the updated A17.8 (raw-source bundling check) AND the new host-side A35 (live-DOM inline-SVG injection + currentColor cascade proof); harness total = prior total + 1. - 01-07-SUMMARY.md back-patched: lines 22/47/82/135/205 flipped; lines 40/89/109/110 unchanged. - deferred-items.md flake entry corrected — no longer mis-names strict-meta-json-validation.test.ts; describes the 04-CONTEXT #9/#10 parallel-vitest flake family. - Operator empirical ack received (Task 4 resume signal "approved") from the dark + light screenshot artifact. - Pre-checkpoint bundle gates 6/6 PASS (canonical SW chunk glob dist/assets/index.ts-*.js across Gates 2/3/4; glob-existence pre-gate validates the glob first). - PNG toolbar icons byte-identical (no change to scripts/rasterize-icons.sh or icons/*.png).

<success_criteria>

  • UI-SPEC dark-logo strategy landed end-to-end (Tasks 1-3 automation + Task 4 operator ack).
  • Cursor visibility VERIFIED at recorder.ts:285 via the node-env regression-pin test + the 01-07-SUMMARY back-patch (RESEARCH Finding 4 closure).
  • Inline-SVG injection contract pinned at TWO honest layers: 3 node-env source-level unit tests (source TEXT contract) + the NEW A35 host-side harness assertion (live-DOM injection + currentColor cascade in real Chrome). A17.8 is a source-bundling check only — no claim of live-DOM coverage.
  • ROADMAP cursor visibility item GREEN.
  • ROADMAP dark-surface logo contrast item GREEN.
  • Operator empirical ack received on the dark-mode visual aesthetic, judged from the Puppeteer screenshot artifact.
  • Pre-checkpoint bundle gates 6/6 PASS preserved (canonical glob).
  • UAT harness driver set GREEN preserved, now +1 (A35).
  • Vitest: 188/188 GREEN (or a tolerated single isolation-passing 04-CONTEXT #9/#10 flake; no hard-coded named-test gate). </success_criteria>
After completion, create .planning/phases/04-harden-clean-up-optional/04-06-SUMMARY.md capturing: - mokosh-mark.svg diff (1-attribute change documented). - welcome.ts diff (?raw import + DOMParser + populateMark rewrite). - globals.d.ts diff (*.svg?raw ambient decl append). - A17.8 harness sub-check diff (old data-URL grep to new raw-source grep; A17.8 documented as source-bundling-only). - The NEW A35 host-side harness assertion (driveA35 — opens a live welcome tab, verifies the injected + getComputedStyle().stroke currentColor cascade) + the harness.test.ts wiring (driveA35Wrapped + drivers-array entry + banner string). - 01-07-SUMMARY.md back-patch (5 stale Phase-5 lines flipped — 22/47/82/135/205; 4 historical lines left — 40/89/109/110). - deferred-items.md correction (the strict-meta-json mis-diagnosis replaced with the 04-CONTEXT #9/#10 parallel-vitest flake-family description). - 2 new test files (inline-svg source-contract + cursor-visibility) with the RED-to-GREEN cycle commits. - The DEFECT 1 / BLOCKER 1 test-strategy decision recorded (node-env source-contract for source TEXT + the new A35 host-side harness assertion for live-DOM behavior; A17.8 is source-bundling only) so future plans understand the coverage split. - Operator empirical UAT verbatim ack (e.g. "approved", or the specific issue raised). - Pre-checkpoint bundle gates 6/6 PASS evidence (grep outputs against the canonical dist/assets/index.ts-*.js glob). - vitest before/after (184/184 GREEN baseline -> 188/188 GREEN; note the 04-CONTEXT #9/#10 parallel-vitest flake family may transiently land 1 RED that passes on an isolation re-run — that is tolerated, not a regression). - UAT harness driver-set GREEN preservation (now +1 with A35). - Commit refs (Tasks 1 + 2 + 3 + 4 ack).