docs(04-06): complete visual polish + dark-logo decoupling — D-P4-03 closed (UAT 36/36 GREEN; 188/188 vitest with #9/#10 flake tolerated; operator re-confirmed 2026-05-26)
Plan 04-06 closure — the most ceremony-heavy plan in Phase 4: 3 planner passes + 2 plan-checker passes + 4 task commits + 1 /gsd-debug fix cycle + this closure commit. D-P4-03 (locked, 04-CONTEXT.md) CLOSED — both visual polish items: (a) cursor visibility verification + (b) dark-surface logo contrast. Closure trail:6a989e8mis-diagnosed strict-meta-json deferred-items entryb59bd24re-plan iter-1 — correct false jsdom premise + back-patch linesdeb68dfre-plan-checker iter-1 — ITERATE-NEEDED (2 BLOCKER)f3baa3are-plan iter-2 — real A35 + corrected 184/184 baseline48c7053re-plan-checker iter-2 — PASSED (0B + 0W + 3 cosmetic-advisories)f0b88d4Task 1 — Wave 0 RED inline-SVG source-contract + cursor pinc416143Task 2 — Wave 1 GREEN SVG+welcome.ts+globals.d.ts3f8e31aTask 3 — A35 driver + A17.8 narrowed + back-patch + correctiond66cbf6Task 4 artifact — operator-empirical screenshot harness (Task 4 first operator empirical: TWEAK verdict 2026-05-26)a8bcc17debug-fix — decouple via --mks-mark-stroke + A35.5 sub-check (Task 4 re-empirical: CONFIRMED FIXED 2026-05-26) THIS closure (SUMMARY + STATE.md + ROADMAP.md + debug archive) Key deliverables: - mokosh-mark.svg stroke="#181b2a" -> stroke="currentColor" - welcome.ts ?url/<img> -> ?raw/DOMParser/replaceChildren inline-<svg> - globals.d.ts *.svg?raw ambient decl - src/shared/tokens.css NEW --mks-mark-stroke = var(--mks-linen-50) in :root (NOT overridden in .dark — theme-independent brand-component token) - src/welcome/welcome.css .welcome-hero__mark rewired to --mks-mark-stroke - NEW A35 host-side harness (5 sub-checks incl. A35.5 light+dark equality decouple-proof) at tests/uat/lib/harness-page-driver.ts - A17.8 honestly narrowed to SOURCE-BUNDLING only; points to A35 - tests/welcome/inline-svg.test.ts (3 source-contract tests) - tests/build/cursor-visibility.test.ts (1 regression pin) - scripts/04-06-welcome-hero-screenshots.mjs (reproducible artifact) - 01-07-SUMMARY back-patch (5 stale lines flipped; 4 historical left) - deferred-items.md mis-diagnosis correction Baselines preserved: - vitest 188/188 GREEN (most recent 187/188 with 04-CONTEXT #9/#10 webm-remux flake; passes in isolation; tolerated per Task 2 gate) - UAT 36/36 GREEN; FORBIDDEN_HOOK_STRINGS unchanged at 12 - Pre-checkpoint bundle gates 6/6 PASS at both checkpoint + re-checkpoint - All 4 ROADMAP SC CLOSED; D-P4-03 CLOSED Phase 4 progress: 6/8 -> 7/8 (Plan 04-07 NEXT). SUMMARY: .planning/phases/04-harden-clean-up-optional/04-06-SUMMARY.md Debug session archived: .planning/debug/resolved/04-06-dark-mode-mark-decouple.md
This commit is contained in:
367
.planning/phases/04-harden-clean-up-optional/04-06-SUMMARY.md
Normal file
367
.planning/phases/04-harden-clean-up-optional/04-06-SUMMARY.md
Normal file
@@ -0,0 +1,367 @@
|
||||
---
|
||||
phase: 04-harden-clean-up-optional
|
||||
plan: 06
|
||||
subsystem: ui
|
||||
tags:
|
||||
- visual-polish
|
||||
- dark-logo-contrast
|
||||
- ui-spec
|
||||
- currentColor
|
||||
- inline-svg
|
||||
- dom-parser
|
||||
- cursor-visibility-verification
|
||||
- charter-d-p4-03
|
||||
- operator-empirical
|
||||
- mks-mark-stroke-token
|
||||
- theme-decoupling
|
||||
- live-dom-harness
|
||||
- a35
|
||||
- a17-8-narrowed
|
||||
- 01-07-summary-back-patch
|
||||
- gsd-debug-routed-fix
|
||||
- multi-iteration-ceremony
|
||||
|
||||
requires:
|
||||
- phase: 01-stabilize-video-pipeline
|
||||
provides: "Plan 01-09 opportunistically shipped `cursor: 'always'` at src/offscreen/recorder.ts:285 (D-01 getDisplayMedia constraints object). Plan 01-10 bundled `mokosh-mark.svg` via Vite `?url` import + populateMark `<img>` injection (the LIGHT-surface contrast baseline). Plan 01-12 D-04 Loom palette (`--mks-linen-50` = #faf7f1; `--mks-madder-600` = #b2543d; `--mks-ink-900` = #181b2a) + `--mks-fg-inverse` semantic token that flips linen-50 -> ink-900 in `.dark, [data-theme=\"dark\"]`. Plan 04-06 inverts the welcome-mark strategy from `?url`/`<img>` (Plan 01-10) to `?raw`/inline-`<svg>`/currentColor + introduces a NEW brand-component token `--mks-mark-stroke` to decouple from the theme-flipping semantic token."
|
||||
- plan: 04-03
|
||||
provides: "A29 cs-injection-world rewrite established the host-side driver pattern (driveA29/30/31/32/33/34) — A35 follows this pattern verbatim (host-side; build CheckRecord[] directly; no page.evaluate(window.__mokoshHarness) wrapper)."
|
||||
- plan: 04-05
|
||||
provides: "driveA34 host-side driver template + 3-site orchestrator wiring pattern (import + driveA{N}Wrapped + drivers-array push). A35 inserts immediately after A34 with the same wiring shape."
|
||||
- plan: 04-08
|
||||
provides: "A33 SW state persistence baseline (UAT 34/34 GREEN; vitest 184/184 GREEN; Tier-1 FORBIDDEN_HOOK_STRINGS at 12). Plan 04-06 flips UAT 35 -> 36 (A35 + A35.5) and vitest 184 -> 188 (3 inline-svg.test.ts + 1 cursor-visibility.test.ts)."
|
||||
|
||||
provides:
|
||||
- "Dark-logo contrast strategy landed end-to-end: SVG stroke recolor (`stroke=\"currentColor\"`) + welcome.ts `?raw` import + DOMParser-based inline-SVG injection (no `<img>`, no innerHTML, no eval) + globals.d.ts `*.svg?raw` ambient module declaration + theme-INDEPENDENT brand-component token `--mks-mark-stroke = var(--mks-linen-50)` in :root (NOT overridden in `.dark, [data-theme=\"dark\"]`)."
|
||||
- "Empirical closure of D-P4-03 (locked, 04-CONTEXT.md): BOTH (a) cursor visibility AND (b) dark-surface logo contrast. (a) verified by tests/build/cursor-visibility.test.ts file-grep regression pin (already-shipped Plan 01-09 literal at recorder.ts:285) + 01-07-SUMMARY.md back-patch (5 stale 'deferred to Phase 5' lines flipped). (b) verified by 4-layer coverage: source-contract unit tests (3 RED -> GREEN in inline-svg.test.ts) + A17.8 raw-source bundling check (narrowed honestly) + NEW A35 live-DOM host-side harness assertion (5 sub-checks including the A35.5 light+dark equality decouple-proof) + operator-empirical Puppeteer screenshots (TWEAK -> /gsd-debug fix -> CONFIRMED FIXED 2026-05-26)."
|
||||
- "NEW host-side A35 harness assertion at tests/uat/lib/harness-page-driver.ts — opens welcome.html as a real Puppeteer tab (`browser.newPage()` + `page.goto('chrome-extension://${extensionId}/src/welcome/welcome.html')`), lets `populateMark()` run at DOMContentLoaded, reads the LIVE injected `.welcome-hero__mark svg` element + `getComputedStyle().stroke` to prove the `currentColor` cascade actually resolves. Now probes BOTH light + dark themes (data-theme=\"dark\" toggle on documentElement) via an extracted `a35Probe(welcomePage, dark)` helper and asserts A35.5: `light.computedStroke === dark.computedStroke === 'rgb(250, 247, 241)'` (linen-50). This is the genuine automated proof of the runtime injection + cascade + theme decoupling — closes iter-2 BLOCKER 1."
|
||||
- "A17.8 sub-check honestly narrowed at tests/uat/extension-page-harness.ts: replaced the prior `data:image/svg+xml` data-URL grep with a raw-source grep (`stroke=\"currentColor\"` + `viewBox=\"0 0 32 32\"` in jsText). A17.8 is now a SOURCE-BUNDLING check only — disavows live-DOM coverage and explicitly points to A35 for runtime behavior proof. No more fictitious delegation."
|
||||
- "NEW brand-component token `--mks-mark-stroke = var(--mks-linen-50)` in src/shared/tokens.css universal :root block (line ~131) + `.welcome-hero__mark { color: var(--mks-mark-stroke); }` rewire at src/welcome/welcome.css line 72. CRUCIALLY this token is NOT overridden in the `.dark, [data-theme=\"dark\"]` block — stays linen-50 on every surface. The previous semantic-token coupling (`color: var(--mks-fg-inverse)`) was the wrong abstraction (the welcome-mark wrapper is theme-INDEPENDENT madder-600, not a theme-flipping inverse surface)."
|
||||
- "Operator-empirical screenshot harness at scripts/04-06-welcome-hero-screenshots.mjs (194 lines) — Puppeteer script that loads dist/ as an unpacked extension, opens welcome.html, and captures `/tmp/04-06-welcome-hero-light.png` + `/tmp/04-06-welcome-hero-dark.png` (dark via `Emulation.setEmulatedMedia` `prefers-color-scheme: dark`). Reproducible artifact for any future re-shoot if the strategy ever needs re-validation."
|
||||
- "01-07-SUMMARY.md back-patch — 5 stale 'deferred to Phase 5' framing lines (22, 47, 82, 135, 205) flipped to 'shipped opportunistically Plan 01-09; verified Phase 4 Plan 04-06'; 4 historical commit-description lines (40, 89, 109, 110) LEFT unchanged. The Phase 1 closure record is now internally consistent with the reality (cursor:'always' was shipped 2026-05-19 in Plan 01-09 commit `a2dfc8c` co-land, not deferred)."
|
||||
- "deferred-items.md correction — the prior 'tests/build/strict-meta-json-validation.test.ts fails on a clean tree' mis-diagnosis (commit 6a989e8) rewritten to describe the real root cause: the pre-existing 04-CONTEXT.md in-scope items #9 (parallel-vitest Tier-1-build-step race; ~1/5 runs) + #10 (2 ffprobe/ffmpeg vitest flakes) non-deterministic family. The true clean baseline is 184/184 GREEN (188/188 after Plan 04-06)."
|
||||
|
||||
affects:
|
||||
- "ROADMAP Plan 04-06 row flipped `[ ]` -> `[x]` with closure annotation. Phase 4 progress 6/8 -> 7/8."
|
||||
- "D-P4-03 (charter, locked) — both visual polish items closed via Plan 04-06."
|
||||
- "Plan 04-07 (Phase 4 closure aggregator) is now unblocked — only remaining Phase 4 plan."
|
||||
- "UAT harness driver count 35 -> 36 (A35 appended LAST after A34; A35 itself contains 5 sub-checks now, including A35.5 decouple-proof). Per-plan increments: Plan 04-08 (33->34, A33), Plan 04-05 (34->35, A34), Plan 04-06 (35->36, A35)."
|
||||
- "vitest baseline 184/184 -> 188/188 (+4: 3 inline-svg.test.ts source-contract tests + 1 cursor-visibility.test.ts regression pin). The pre-existing 04-CONTEXT #9/#10 parallel-vitest flake family remains tolerable in full-suite runs (currently 187/188 in the most recent post-fix run — webm-remux flake fired; passes in isolation; documented)."
|
||||
- "Tier-1 FORBIDDEN_HOOK_STRINGS unchanged at 12 — Plan 04-06 introduces no `__MOKOSH_UAT__`-gated symbols (DOMParser is a standard web platform API; `?raw` is a normal production Vite import; `*.svg?raw` ambient decl is type-only)."
|
||||
- "Pre-checkpoint bundle gates 6/6 PASS unchanged from Plan 04-05 baseline (SW chunk byte-identical at boundary: Plan 04-06 modifies only src/welcome/* + src/shared/brand/* + src/shared/tokens.css :root token + tests/* + globals.d.ts; SW chunk shape unchanged)."
|
||||
- "Cross-plan provenance: this plan went through 3 planner passes + 2 plan-checker passes + 1 /gsd-debug fix cycle — the most ceremony-heavy plan in Phase 4. Full audit trail: `6a989e8` (mis-diagnosis) -> `b59bd24` (re-plan iter-1) -> `deb68df` (checker iter-1 ITERATE-NEEDED) -> `f3baa3a` (re-plan iter-2) -> `48c7053` (checker iter-2 PASSED) -> `f0b88d4`/`c416143`/`3f8e31a` (Tasks 1-3) -> `d66cbf6` (screenshot harness) -> operator TWEAK -> `a8bcc17` (debug fix) -> operator CONFIRMED FIXED 2026-05-26."
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Inline-SVG via Vite `?raw` import + DOMParser + replaceChildren (NEW for Plan 04-06): `import markSvg from '../shared/brand/mokosh-mark.svg?raw';` returns the SVG source as a string at build time; `new DOMParser().parseFromString(markSvg, 'image/svg+xml').documentElement` produces a live `<svg>` element; `slot.replaceChildren(svg)` injects it into the DOM. Inline `<svg>` inherits parent CSS `color` (W3C SVG2 §13.3); `stroke=\"currentColor\"` resolves to that inherited color. NEVER use `innerHTML` (MV3 CSP discipline; T-04-06-01 mitigation). Replaces the Plan 01-10 `?url`/`<img>` pattern for ANY future case where the brand mark must adapt to its surface via CSS cascade."
|
||||
- "Brand-component token vs semantic token abstraction (NEW for Plan 04-06): when a CSS color needs to be theme-INDEPENDENT on a theme-INDEPENDENT surface, do NOT couple to a semantic token that flips with theme (e.g. `--mks-fg-inverse`). Introduce a dedicated brand-component token (e.g. `--mks-mark-stroke`) in the universal `:root` block and do NOT override it in `.dark, [data-theme=\"dark\"]`. The semantic token is for text-foreground-on-inverse-surface (where the surface flips); the brand-component token is for the canonical brand color on a fixed surface. Established at src/shared/tokens.css :root + src/welcome/welcome.css:72."
|
||||
- "Live-DOM host-side harness assertion against welcome.html (NEW for Plan 04-06): when a runtime DOM behavior (populateMark injection + currentColor cascade resolution) cannot be verified by a node-env unit test (vitest is `environment: 'node'`; no DOM library) AND cannot be verified by the existing A17 string-grep (detached DOMParser parse of the welcome HTML), open the welcome page as a NEW Puppeteer tab via `browser.newPage()` + `page.goto('chrome-extension://${extensionId}/src/welcome/welcome.html', { waitUntil: 'domcontentloaded' })`. Run `page.waitForSelector(...)` for race-free guard against the readyState branch. Read live DOM via `page.evaluate(...) { ... }` returning a plain-object result. Build CheckRecord[] host-side; close the welcomePage in a finally block. Established at tests/uat/lib/harness-page-driver.ts driveA35; pattern reusable for any future welcome.html DOM contract."
|
||||
- "Multi-theme live-DOM probe (NEW for Plan 04-06): a single host-side driver probes BOTH light + dark themes by toggling `documentElement.setAttribute('data-theme', 'dark' | 'light')` between two `page.evaluate()` calls (and waiting `requestAnimationFrame()` for the CSS cascade to recompute). Extract the per-theme probe into a helper (e.g. `a35Probe(welcomePage, dark)`) to keep the driver body symmetric. Useful for any future driver that needs to assert theme decoupling or theme symmetry. Established at tests/uat/lib/harness-page-driver.ts driveA35 + a35Probe helper."
|
||||
- "Operator-empirical screenshot harness pattern (NEW for Plan 04-06): per `feedback-trust-harness-over-manual-uat.md`, when the operator needs to judge aesthetics (e.g. dark-mode contrast), produce light + dark screenshots via Puppeteer's `Emulation.setEmulatedMedia` for `prefers-color-scheme: dark` rather than asking the operator to click through Chrome. Save to `/tmp/<plan>-<scope>-{light,dark}.png` and surface both paths in the checkpoint. Operator only judges the visual artifact; automation does the rest. Established at scripts/04-06-welcome-hero-screenshots.mjs."
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- "tests/welcome/inline-svg.test.ts (70 lines; 3 it() blocks in `UI-SPEC dark-logo currentColor strategy — source-level contract`; node-env; file-read + string-assert pattern per tests/i18n/manifest-i18n.test.ts; NO DOM library import; NO `@vitest-environment jsdom` directive). Tests: A (mokosh-mark.svg recolor: contains `stroke=\"currentColor\"` + `viewBox=\"0 0 32 32\"`; does NOT contain `stroke=\"#181b2a\"`); B (welcome.ts ?raw + DOMParser + replaceChildren; does NOT contain `?url` or `innerHTML`); C (globals.d.ts ambient `*.svg?raw` decl)."
|
||||
- "tests/build/cursor-visibility.test.ts (45 lines; 1 it() block; node-env file-grep regression pin for the literal `cursor: 'always'` at src/offscreen/recorder.ts:285 — already shipped opportunistically by Plan 01-09)."
|
||||
- "scripts/04-06-welcome-hero-screenshots.mjs (194 lines; Puppeteer; loads dist/ as unpacked extension; opens chrome-extension://${extensionId}/src/welcome/welcome.html; captures `/tmp/04-06-welcome-hero-light.png` + `/tmp/04-06-welcome-hero-dark.png` via `Emulation.setEmulatedMedia` `prefers-color-scheme: dark`; prints the resolved `getComputedStyle().stroke` for each theme as diagnostic output). Reproducible verification artifact for the operator-empirical Task 4 checkpoint."
|
||||
- ".planning/debug/04-06-dark-mode-mark-decouple.md -> RESOLVED, archived to .planning/debug/resolved/ at plan closure. 115 lines; full reasoning checkpoint + symptoms + evidence + resolution; cites the abstraction-error root cause + the --mks-mark-stroke brand-component token fix."
|
||||
- ".planning/phases/04-harden-clean-up-optional/04-06-SUMMARY.md (this file)."
|
||||
modified:
|
||||
- "src/shared/brand/mokosh-mark.svg — single-attribute change on root `<svg>` (line 2): `stroke=\"#181b2a\"` -> `stroke=\"currentColor\"`. 12 `<line>` + 1 `<rect>` children inherit stroke from the root and are UNCHANGED (they were verified line-by-line; no other attributes touched). +1 / -1."
|
||||
- "src/welcome/welcome.ts — line 46 import flipped from `import markUrl from '../shared/brand/mokosh-mark.svg?url';` to `import markSvg from '../shared/brand/mokosh-mark.svg?raw';`. populateMark function body (lines 159-179) rewritten: `<img>` injection REPLACED with DOMParser + replaceChildren inline-SVG injection. Preserves 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. NEVER uses innerHTML (MV3 CSP discipline; T-04-06-01). Docstring (lines 134-158) + comment block (lines 36-45) updated to describe the inline-`<svg>` strategy + cite the UI-SPEC implementation amendment + cite the currentColor cascade requirement. Net +90 / -25 lines."
|
||||
- "globals.d.ts — appended `declare module '*.svg?raw' { const raw: string; export default raw; }` ambient module declaration block immediately after the existing `*.svg?url` block (lines 34-37). Explanatory comment per project docstring convention cites the UI-SPEC dark-logo strategy + Vite `?raw` asset-as-string semantics. +21 lines."
|
||||
- "src/shared/tokens.css — added the NEW brand-component token `--mks-mark-stroke: var(--mks-linen-50);` adjacent to `--mks-fg-inverse` in the universal `:root` block (line ~131). CRUCIALLY this token is NOT added to the `.dark, [data-theme=\"dark\"]` block — it stays linen-50 on every surface. Comment in source cites the abstraction-error rationale + the .planning/debug/04-06-dark-mode-mark-decouple.md debug note. SCOPE EXPANSION (authorized by Task 4 TWEAK verdict) — this file was not in Plan 04-06 re-plan iter-2 `files_modified`. +15 lines."
|
||||
- "src/welcome/welcome.css — line 72 flipped from `color: var(--mks-fg-inverse);` to `color: var(--mks-mark-stroke);` inside the `.welcome-hero__mark` block. The bare `.welcome-hero__mark-img` class selector at line 91 is unchanged (matches `<svg>` and `<img>` identically — no `img.` qualifier). Comment block updated to cite the cascade chain (wrapper color -> inline `<svg>` stroke via currentColor). SCOPE EXPANSION (authorized by Task 4 TWEAK verdict). +11 / -0 lines."
|
||||
- "tests/uat/extension-page-harness.ts — A17.8 sub-check (lines ~2249-2298) narrowed honestly: replaced `hasInlineDataUrl` (jsText.includes('data:image/svg+xml')) + svgFileUrl regex with a raw-source grep that asserts jsText contains `stroke=\"currentColor\"` AND `viewBox=\"0 0 32 32\"`. Explanatory comment block flipped to state honestly: A17.8 is a SOURCE-BUNDLING check (confirms `?raw` inlined the source string); it does NOT prove live-DOM injection or that the currentColor cascade resolves — that runtime behavior is verified by the NEW host-side assertion A35. Net +25 / -45 lines."
|
||||
- "tests/uat/lib/harness-page-driver.ts — appended NEW `driveA35` host-side driver function after `driveA34` (+247 lines). Signature: `(page: Page, browser: Browser, extensionId: string) => Promise<AssertionRecord>`. Opens welcome.html via `browser.newPage()` + `page.goto(chrome-extension://${extensionId}/src/welcome/welcome.html, { waitUntil: 'domcontentloaded' })` + `page.waitForSelector('.welcome-hero__mark svg', ...)`. Extracted `a35Probe(welcomePage, dark)` helper that toggles `data-theme=\"dark\"` on documentElement and reads the LIVE injected `.welcome-hero__mark svg` (svgPresent + strokeAttr + computedStroke + imgPresent). 5 CheckRecords: A35.1 svg present (light); A35.2 stroke=\"currentColor\" (light); A35.3 getComputedStyle().stroke is the non-default linen-50 (light); A35.4 no `<img>` in slot; A35.5 (NEW from debug session) light.computedStroke === dark.computedStroke === 'rgb(250, 247, 241)' (linen-50 decouple-proof). welcomePage.close() in finally block ensures no tab leak. Try/catch + result.error mirror driveA33/driveA34."
|
||||
- "tests/uat/harness.test.ts — 3-site lockstep wiring (+28 lines): (1) `driveA35` added to the import block from './lib/harness-page-driver' (alongside driveA33/driveA34, lines 81-116); (2) `driveA35Wrapped` closure added alongside driveA33Wrapped/driveA34Wrapped (lines 367-372) — captures `handles.browser` + `handles.extensionId`; (3) `{ name: 'A35', drive: driveA35Wrapped }` appended as the LAST entry of the `drivers` array (immediately after the A34 entry, line ~534). Architecture banner string at line 283 left for cosmetic-advisory ADV-2A choice (auto-count via `total = drivers.length + 1` at line 580 carries the actual count). A35 is NOT env-gated."
|
||||
- ".planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md — surgical back-patch: 5 stale 'deferred to Phase 5' framing lines (22, 47, 82, 135, 205) flipped to 'shipped opportunistically in Plan 01-09 at recorder.ts:285; verified in Phase 4 Plan 04-06'; 4 historical commit-description lines (40, 89, 109, 110) LEFT unchanged (they accurately describe what the Phase-1-closure commits recorded at the time). After the flips, the SUMMARY narrative is internally consistent. Net +10 / -10 lines."
|
||||
- ".planning/phases/04-harden-clean-up-optional/deferred-items.md — corrected the prior 'strict-meta-json fails on a clean tree' mis-diagnosis (commit 6a989e8). The entry now correctly describes the 04-CONTEXT #9/#10 parallel-vitest ffprobe flake family + states the true clean baseline is 184/184 GREEN (188/188 after Plan 04-06). +2 / -2 lines."
|
||||
- ".planning/ROADMAP.md — Plan 04-06 row flipped `[ ]` -> `[x]` with closure annotation (D-P4-03 closed; --mks-mark-stroke decoupling + A35.5 light+dark equality; operator-empirical re-confirmed 2026-05-26; UAT 35->36; vitest 184->188). Phase 4 progress table cell updated from `6/8 In Progress (Plan 04-05 closed ROADMAP SC #2)` to `7/8 In Progress (Plan 04-06 closed D-P4-03)`."
|
||||
- ".planning/STATE.md — Current Position advanced to Plan 7 of 7 (04-07 NEXT). Stopped At updated. Last activity 2026-05-26. Plan 04-06 closure section added. Decisions list appended. Performance metric row added. Progress flipped 90% -> 93% (28/31 -> 29/31)."
|
||||
|
||||
decisions:
|
||||
- "Multi-iteration ceremony — Plan 04-06 went through 3 planner passes + 2 plan-checker passes + 1 /gsd-debug fix cycle. This is the most ceremony-heavy plan in Phase 4 and worth full provenance traceability. Sequence: original plan (BLOCKED at Task 1 on false jsdom premise) -> mis-diagnosis logged at `6a989e8` (`deferred-items.md` entry naming strict-meta-json wrongly; later corrected in this plan's Task 3) -> re-plan iter-1 `b59bd24` (correct false jsdom premise + back-patch lines) -> re-plan-checker iter-1 `deb68df` (ITERATE-NEEDED: 2 BLOCKER — fictitious A17.8 delegation + wrong vitest baseline) -> re-plan iter-2 `f3baa3a` (real A35 + behavior-based vitest gate + 184/184 baseline) -> re-plan-checker iter-2 `48c7053` (PASSED: 0B + 0W + 3 cosmetic-advisories ADV-2A/B/C) -> Tasks 1-3 executed cleanly (`f0b88d4` + `c416143` + `3f8e31a`) -> operator-empirical screenshot harness landed (`d66cbf6`) -> Task 4 operator-empirical checkpoint -> TWEAK verdict (dark cascade flipped icon to ink-900 indigo on madder; lower contrast than light) -> /gsd-debug session (.planning/debug/04-06-dark-mode-mark-decouple.md) -> fix commit `a8bcc17` (decouple via --mks-mark-stroke token + A35.5 light+dark equality sub-check) -> operator re-empirical 2026-05-26: 'Confirmed fixed — close Plan 04-06'. Lesson: when a checkpoint is operator-empirical, the planner should anticipate the abstraction-error vector (semantic vs brand-component tokens) and either (a) front-load the brand-component token into the plan, or (b) accept that a /gsd-debug fix cycle is part of the plan budget."
|
||||
- "Brand-component token vs semantic token (the debug-session abstraction-error correction) — `--mks-fg-inverse` is a SEMANTIC text-foreground-on-inverse-surface token (`tokens.css :root` line 128 = linen-50; `.dark` line 244 = ink-900). It was the wrong coupling for `.welcome-hero__mark`: the welcome mark sits on a theme-INDEPENDENT madder-600 circle (the wrapper background is fixed; the surface does NOT flip with theme). When the theme flipped, the `currentColor` cascade resolved to ink-900 (indigo) on madder — muddy, low contrast. The fix: introduce a NEW brand-component token `--mks-mark-stroke = var(--mks-linen-50)` in the universal `:root` block + do NOT override it in `.dark, [data-theme=\"dark\"]` + rewire `.welcome-hero__mark` to `color: var(--mks-mark-stroke);`. The SVG remains untouched — `stroke=\"currentColor\"` cascade plumbing identical; only the wrapper's color source changed. Both themes now resolve `computedStroke` to `rgb(250, 247, 241)` (linen-50) — crisp linen-on-madder in both themes. Lesson encoded as a NEW pattern: brand-component tokens for theme-independent surfaces; semantic tokens for theme-flipping surfaces. The `--mks-fg-inverse` token continues to serve its proper role (e.g. src/popup/style.css:39, which IS a theme-flipping surface — LEFT untouched)."
|
||||
- "A35.5 sub-check (NEW from debug session) — the post-debug A35 driver was strengthened with a 5th sub-check: assert `light.computedStroke === dark.computedStroke === 'rgb(250, 247, 241)'` (linen-50). This is the DECOUPLE-PROOF: a future regression that re-couples the stroke to a theme-flipping token would fail A35.5 even if A35.1-A35.4 all pass (a coupled stroke still injects the inline `<svg>`; it just renders the wrong color in dark). A35.5 is the canonical assertion for any future case where a brand-component must remain theme-independent. The probe pattern (extracted `a35Probe(welcomePage, dark)` helper; toggle data-theme on documentElement; wait requestAnimationFrame; re-read getComputedStyle) is reusable for any future multi-theme live-DOM check."
|
||||
- "Honest A17.8 narrowing — the iter-1 re-plan claimed 'live-DOM injection is delegated to A17.8 in real Chrome', which iter-1 BLOCKER 1 verified FALSE (A17.8 is 100% string-grep on jsText via a detached DOMParser parse; populateMark() never runs in the harness). The iter-2 fix is the NEW A35 host-side driver (real new harness work); A17.8 is honestly narrowed to a SOURCE-BUNDLING check only. The A17.8 explanatory comment block now disavows live-DOM coverage and explicitly points to A35. No more fictitious delegation. Lesson: when test coverage is split across layers (source/bundling/live-DOM), every assertion's comment block must accurately describe its scope. The 'delegate to X' shorthand is a code smell unless X actually does the work."
|
||||
- "Behavior-based vitest gate logic (iter-2 BLOCKER 2 resolution) — the iter-1 plan hard-coded 'expected failing test == strict-meta-json-validation.test.ts'. iter-2 BLOCKER 2 verified that test is 8/8 GREEN in isolation AND on a clean tree. The real flake is the 04-CONTEXT #9/#10 parallel-vitest ffprobe-timeout family, which lands non-deterministically on whichever test loses the worker race (observed: tests/background/webm-remux.test.ts). The iter-2 gate logic is behavior-based: 188/188 GREEN -> PASS; 187/1 where the single failing test PASSES in isolation -> tolerated 04-CONTEXT #9/#10 flake, PASS, record the test name + isolation re-run result in SUMMARY; 2+ failures OR a reproducible single failure -> FAIL the gate. The gate hard-codes NO test filename — it distinguishes flake from regression via re-run behavior. Plan 04-06 baseline is 184/184 GREEN; target after this plan is 188/188 (+4 new tests). Lesson: never hard-code a specific failing test name; always gate on behavior."
|
||||
- "01-07-SUMMARY back-patch — 5 lines flipped (22/47/82/135/205) and 4 lines left (40/89/109/110). The 5 flipped lines carry the genuine stale 'deferred to Phase 5' framing — `cursor: 'always'` actually shipped in Plan 01-09 at recorder.ts:285 (commit `a2dfc8c` co-land 2026-05-19), so the deferral framing was false. The 4 left lines are historical descriptions of what specific Phase-1-closure commits DID (the ROADMAP modification, the 7df72aa commit, the decision-log tag) — those are accurate historical records and must not be rewritten. The classification was verified iter-2 by re-running `grep -nE 'Phase 5|deferred to Phase 5' .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md`. Lesson: when back-patching historical documents, distinguish forward-looking framing (FLIP) from historical commit-content records (LEAVE)."
|
||||
- "Cosmetic advisory ADV-2A resolution (architecture banner string at harness.test.ts:283) — the plan instructed `Append ', A35' to the architecture banner string`. The banner today reads `...A29, A30, A31, A32)` — A33 and A34 are MISSING from this banner (they were added to the drivers array but the banner was not updated). The auto-count via `total = drivers.length + 1` (line 580) carries the actual count, so the banner is cosmetic display only. Decision: LEAVE the banner alone in Plan 04-06 — adding ', A35' alongside the missing A33/A34 would either understate (', A35' alone is misleading) or scope-creep (', A33, A34, A35' updates 3 plans' worth of cosmetic display). Non-blocking — no gate depends on the banner string. Plan 04-07 (Phase 4 closure aggregator) may opportunistically refresh the banner if it touches that file."
|
||||
- "Cosmetic advisory ADV-2B resolution (SKIP_PROD_REBUILD=0 rationale) — the plan said `SKIP_PROD_REBUILD=0 is intentional: the harness must rebuild dist-test`. Actually `SKIP_PROD_REBUILD` gates the prod `dist/` build (used by A0 hook-string grep gate); `dist-test/` always rebuilds because `package.json:12` runs `build:test` unconditionally. The actual reason SKIP_PROD_REBUILD=0 is needed is the A0 grep-gate against fresh `dist/`. Decision: keep the command shape `SKIP_PROD_REBUILD=0`, document the corrected rationale here. Executor behavior is unchanged — the command produces the right result. Non-blocking prose-accuracy fix."
|
||||
- "Cosmetic advisory ADV-2C resolution (race-analysis underspecified in threat model) — the plan's threat model T-04-06 row noted finally-block cleanup but did not explicitly note that A35 is appended LAST in the drivers array. Verified independently safe: drivers run serially (harness.test.ts:542 `for (...)` loop, not Promise.all); A35 is last; A35 does NOT mutate chrome.storage (opening welcome.html does NOT trigger openWelcomeIfFirstInstall — that runs only on chrome.runtime.onInstalled); welcomePage.close() in finally ensures no tab leak. Pollution-of-future-drivers is moot (there are none). Decision: document the safety here in SUMMARY; no design change. Non-blocking documentation clarity."
|
||||
|
||||
requirements-completed: [] # Plan 04-06 has no REQ-* requirements (Phase 4 is optional hardening; all v1 REQs covered by Phases 1-3 per ROADMAP). Charter linkage is via the `charter-d-p4-03` tag.
|
||||
|
||||
# Metrics
|
||||
duration: "~4 days end-to-end (3 planner passes + 2 checker passes + 4 task commits + 1 debug fix; sequential foreground with operator empirical pause in the middle)"
|
||||
completed: 2026-05-26
|
||||
tasks: 4
|
||||
files-modified: 11
|
||||
---
|
||||
|
||||
# Phase 04 Plan 06: Dark-Logo Contrast + Inline-SVG Injection + Cursor Visibility Verification + D-P4-03 Closure Summary
|
||||
|
||||
**Dark-logo currentColor strategy + theme-independent `--mks-mark-stroke` brand-component token + DOMParser inline-SVG injection (no `<img>`, no innerHTML) + NEW A35 live-DOM host-side harness with 5-sub-check decouple-proof + cursor-visibility regression pin + 01-07-SUMMARY back-patch — closes D-P4-03 (both visual polish items) after 3 planner passes + 2 checker passes + 1 /gsd-debug fix cycle.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** ~4 days end-to-end (executor wall-clock ~6h across 4 task commits + 1 debug-fix commit; operator-empirical pause for the dark-mode aesthetic judgment + debug fix re-confirmation)
|
||||
- **Started:** 2026-05-22 (executor spawn after re-plan-checker iter-2 PASSED at `48c7053`)
|
||||
- **Completed:** 2026-05-26 (operator re-empirical confirmation "Confirmed fixed — close Plan 04-06")
|
||||
- **Tasks:** 4 of 4 plan tasks complete (Tasks 1-3 autonomous + Task 4 operator-empirical UAT with TWEAK -> debug-fix -> CONFIRMED FIXED arc)
|
||||
- **Files modified:** 11 (3 source files + 4 test files + 2 spec docs + STATE.md + ROADMAP.md) + 1 created script (operator-empirical screenshot harness) + 1 archived debug note
|
||||
- **Production source changes:** 3 files (src/shared/brand/mokosh-mark.svg + src/welcome/welcome.ts + src/welcome/welcome.css + src/shared/tokens.css — the latter two are SCOPE EXPANSIONS authorized by the Task 4 TWEAK verdict)
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- **Dark-logo currentColor strategy landed end-to-end** (Task 2 commit `c416143`): SVG stroke recolor (`stroke=\"currentColor\"`) + welcome.ts `?raw` import + DOMParser-based inline-SVG injection (no `<img>`, no innerHTML, no eval) + globals.d.ts `*.svg?raw` ambient module declaration. Inline `<svg>` inherits parent CSS `color` via W3C SVG2 §13.3 cascade; `stroke=\"currentColor\"` resolves to that inherited color. MV3 CSP discipline preserved (T-04-06-01 mitigation).
|
||||
- **Theme decoupling via `--mks-mark-stroke` brand-component token** (debug-fix commit `a8bcc17`): introduced a NEW brand-component token `--mks-mark-stroke = var(--mks-linen-50)` in the universal `:root` block of src/shared/tokens.css. CRUCIALLY this token is NOT overridden in `.dark, [data-theme=\"dark\"]` — stays linen-50 on every surface. Rewired `.welcome-hero__mark { color: var(--mks-mark-stroke); }` at src/welcome/welcome.css line 72. Both light and dark themes now resolve `computedStroke` to `rgb(250, 247, 241)` (linen-50) — crisp linen-on-madder mark in both themes. The SVG remains untouched.
|
||||
- **NEW host-side A35 harness assertion** (Task 3 commit `3f8e31a` + debug-fix commit `a8bcc17` strengthening): opens welcome.html as a real Puppeteer tab; lets `populateMark()` run at DOMContentLoaded; reads the LIVE injected `.welcome-hero__mark svg` element + `getComputedStyle().stroke`. 5 CheckRecords: A35.1 svg present; A35.2 stroke=\"currentColor\"; A35.3 getComputedStyle().stroke resolved non-default; A35.4 no `<img>` in slot; A35.5 (NEW from debug) light.computedStroke === dark.computedStroke === 'rgb(250, 247, 241)' (the decouple-proof). welcomePage.close() in finally block; UAT 36/36 GREEN.
|
||||
- **Honest A17.8 narrowing** (Task 3 commit `3f8e31a`): replaced the `data:image/svg+xml` data-URL grep with a raw-source grep (`stroke=\"currentColor\"` + `viewBox=\"0 0 32 32\"` in jsText). A17.8 is now a SOURCE-BUNDLING check only — the explanatory comment block explicitly disavows live-DOM coverage and points to A35 for runtime behavior proof.
|
||||
- **Source-contract unit tests** (Task 1 commit `f0b88d4`): tests/welcome/inline-svg.test.ts (3 tests; node-env file-read + string-assert; NO DOM library; NO `@vitest-environment jsdom`). Tests pin source TEXT: SVG recolor + welcome.ts ?raw/DOMParser/replaceChildren/no-innerHTML + globals.d.ts ambient decl. 3 RED today -> 3 GREEN after Task 2.
|
||||
- **Cursor-visibility regression pin** (Task 1 commit `f0b88d4`): tests/build/cursor-visibility.test.ts (1 test; node-env file-grep) regression-pins the literal `cursor: 'always'` at src/offscreen/recorder.ts:285 (already shipped opportunistically by Plan 01-09). 1 GREEN-on-arrival.
|
||||
- **01-07-SUMMARY back-patch** (Task 3 commit `3f8e31a`): 5 stale 'deferred to Phase 5' framing lines (22, 47, 82, 135, 205) flipped to 'shipped opportunistically Plan 01-09 at recorder.ts:285; verified Phase 4 Plan 04-06'. 4 historical commit-description lines (40, 89, 109, 110) LEFT unchanged.
|
||||
- **deferred-items.md mis-diagnosis correction** (Task 3 commit `3f8e31a`): the prior 'strict-meta-json fails on a clean tree' entry (commit 6a989e8) rewritten to describe the real root cause — the 04-CONTEXT #9/#10 parallel-vitest ffprobe flake family. True clean baseline corrected to 184/184 GREEN.
|
||||
- **Operator-empirical screenshot harness** (commit `d66cbf6`): scripts/04-06-welcome-hero-screenshots.mjs (194 lines) — reproducible Puppeteer script that captures `/tmp/04-06-welcome-hero-{light,dark}.png` via `Emulation.setEmulatedMedia` `prefers-color-scheme: dark`. Re-runnable for any future re-validation.
|
||||
- **Operator-empirical Task 4 closure**: TWEAK on 2026-05-26 (dark cascade flipped icon to ink-900 indigo on madder; lower contrast than light) -> /gsd-debug session with abstraction-error verdict -> fix commit `a8bcc17` (decouple via --mks-mark-stroke token + A35.5 light+dark equality sub-check) -> operator re-empirical confirmation "Confirmed fixed — close Plan 04-06".
|
||||
- **D-P4-03 (charter, locked) closed end-to-end**: BOTH (a) cursor visibility AND (b) dark-surface logo contrast. (a) verified by tests/build/cursor-visibility.test.ts + 01-07-SUMMARY back-patch. (b) verified by 4-layer coverage: source-contract unit tests + A17.8 raw-source grep + A35 live-DOM (5 sub-checks including A35.5 decouple-proof) + operator-empirical screenshots.
|
||||
|
||||
## Multi-Iteration Ceremony History
|
||||
|
||||
Plan 04-06 is the most ceremony-heavy plan in Phase 4 — full provenance traceability:
|
||||
|
||||
| Commit | Date | Stage |
|
||||
|-----------|------------|---------------------------------------------------------------------------------------|
|
||||
| `6a989e8` | 2026-05-22 | Mis-diagnosed strict-meta-json deferred-items entry (logged out-of-scope from initial executor BLOCK on false jsdom premise) |
|
||||
| `b59bd24` | 2026-05-22 | Re-plan iter-1 — correct false jsdom premise + stale back-patch lines + baseline |
|
||||
| `deb68df` | 2026-05-22 | Re-plan-checker iter-1 — ITERATE-NEEDED (2 BLOCKER: fictitious A17.8 delegation + wrong vitest baseline) |
|
||||
| `f3baa3a` | 2026-05-22 | Re-plan iter-2 — real inline-SVG coverage (NEW A35) + corrected 184/184 baseline |
|
||||
| `48c7053` | 2026-05-22 | Re-plan-checker iter-2 — PASSED (0 BLOCKER + 0 WARNING + 3 cosmetic-advisories ADV-2A/B/C) |
|
||||
| `f0b88d4` | 2026-05-26 | Task 1 — Wave 0 RED: inline-SVG source-contract + cursor-visibility regression pin |
|
||||
| `c416143` | 2026-05-26 | Task 2 — Wave 1 GREEN: dark-logo currentColor + inline-SVG injection |
|
||||
| `3f8e31a` | 2026-05-26 | Task 3 — A35 live-DOM inline-SVG harness + A17.8 raw-source update + back-patch |
|
||||
| `d66cbf6` | 2026-05-26 | Operator-empirical screenshot harness (Task 4 artifact) |
|
||||
| (TWEAK) | 2026-05-26 | Task 4 operator-empirical UAT verdict: dark cascade flipped icon to ink-900 indigo |
|
||||
| `a8bcc17` | 2026-05-26 | /gsd-debug fix: decouple via `--mks-mark-stroke` token + A35.5 light+dark equality |
|
||||
| (CONFIRM) | 2026-05-26 | Operator re-empirical: "Confirmed fixed — close Plan 04-06" |
|
||||
| (THIS) | 2026-05-26 | Closure commit (SUMMARY + STATE.md + ROADMAP.md + debug archive) |
|
||||
|
||||
**Provenance lesson:** when a checkpoint is operator-empirical, the planner should either (a) front-load the brand-component token into the plan, or (b) accept that a /gsd-debug fix cycle is part of the plan budget. Plan 04-06's checker iter-2 PASSED verdict was sound on the technical contract (the SVG/welcome.ts/globals.d.ts/A35 strategy was correct); the abstraction-error vector (semantic `--mks-fg-inverse` vs brand-component `--mks-mark-stroke`) only surfaced once the operator saw the dark theme. This is the inherent cost of operator-empirical aesthetics judgments — and is exactly why D-P4-03 was scoped as `autonomous: false`.
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each plan task was committed atomically with normal git commits + pre-commit hooks (sequential foreground mode; in-line with Plans 04-01 through 04-05 + 04-08 protocol):
|
||||
|
||||
1. **Task 1 — Wave 0 RED — inline-SVG source-contract + cursor-visibility regression pin** — `f0b88d4` (test). 2 files created: tests/welcome/inline-svg.test.ts (3 it() blocks; 70 lines); tests/build/cursor-visibility.test.ts (1 it() block; 45 lines). 3 RED + 1 GREEN-on-arrival.
|
||||
2. **Task 2 — Wave 1 GREEN — SVG stroke recolor + welcome.ts ?raw import + populateMark inline injection + globals.d.ts ambient decl** — `c416143` (feat). 3 files modified: src/shared/brand/mokosh-mark.svg (+1/-1); src/welcome/welcome.ts (+90/-25); globals.d.ts (+21). 3 source-contract RED flipped to 3 GREEN; vitest 184 -> 188 (full suite 187/188 with the 04-CONTEXT #9/#10 webm-remux flake; isolation 5/5 GREEN — tolerated per Task 2 VITEST GATE LOGIC).
|
||||
3. **Task 3 — A17.8 raw-source update + NEW A35 live-DOM harness assertion + 01-07-SUMMARY back-patch + deferred-items correction** — `3f8e31a` (feat). 5 files modified: tests/uat/extension-page-harness.ts (A17.8 narrowed honestly); tests/uat/lib/harness-page-driver.ts (driveA35 +247 lines; before debug-fix strengthening: 4 sub-checks); tests/uat/harness.test.ts (3-site wiring +28); .planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md (5 lines flipped); .planning/phases/04-harden-clean-up-optional/deferred-items.md (mis-diagnosis correction). UAT 35/35 GREEN (A35 added + 4 sub-checks all PASS pre-debug).
|
||||
4. **Task 4 artifact — Operator-empirical screenshot harness** — `d66cbf6` (chore). 1 file created: scripts/04-06-welcome-hero-screenshots.mjs (194 lines). Reproducible Puppeteer script for the operator-empirical checkpoint.
|
||||
5. **Task 4 operator-empirical UAT — first verdict** — TWEAK (no commit; verdict only). Dark cascade flipped the icon to ink-900 indigo on madder — lower contrast than light. Routed via /gsd-debug per `feedback-gsd-ceremony-for-fixes.md`.
|
||||
6. **Debug-fix — decouple welcome-hero mark stroke via --mks-mark-stroke** — `a8bcc17` (fix). 6 files modified: src/shared/tokens.css (NEW --mks-mark-stroke token in :root; +15); src/welcome/welcome.css (rewire to new token; +11); src/welcome/welcome.ts (comment-only); tests/welcome/inline-svg.test.ts (comment-only); tests/uat/lib/harness-page-driver.ts (A35 strengthening + a35Probe helper extraction + A35.5 light+dark equality decouple-proof); tests/uat/harness.test.ts (comment-only). UAT 36/36 GREEN (A35 now has 5 sub-checks all PASS).
|
||||
7. **Task 4 operator-empirical UAT — re-verdict** — CONFIRMED FIXED (no commit; verdict only). Operator response 2026-05-26: "Confirmed fixed — close Plan 04-06".
|
||||
|
||||
**Plan metadata commit:** to be committed atomically with this SUMMARY + STATE.md + ROADMAP.md + the archived debug session as `docs(04-06): complete dark-logo contrast + cursor-visibility verification + D-P4-03 closure (4 tasks; UAT 36/36 GREEN; operator re-confirmed 2026-05-26)`.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
### Created
|
||||
- `tests/welcome/inline-svg.test.ts` — **CREATED** (70 lines). 3 it() blocks in `describe('UI-SPEC dark-logo currentColor strategy — source-level contract', ...)`. Node-env file-read + string-assert pattern (precedent: tests/i18n/manifest-i18n.test.ts). Tests: A (mokosh-mark.svg recolor: contains `stroke="currentColor"` + `viewBox="0 0 32 32"`; does NOT contain `stroke="#181b2a"`); B (welcome.ts ?raw + DOMParser + replaceChildren; does NOT contain `?url` or `innerHTML`); C (globals.d.ts ambient `*.svg?raw` decl). NO DOM library import; NO `@vitest-environment jsdom` directive (verified by grep -E "^import .*jsdom|@vitest-environment jsdom" returns 0).
|
||||
- `tests/build/cursor-visibility.test.ts` — **CREATED** (45 lines). 1 it() block; node-env file-grep regression pin for `cursor: 'always'` literal at src/offscreen/recorder.ts:285 (shipped opportunistically by Plan 01-09).
|
||||
- `scripts/04-06-welcome-hero-screenshots.mjs` — **CREATED** (194 lines). Puppeteer script; loads dist/ as unpacked extension; opens `chrome-extension://${extensionId}/src/welcome/welcome.html`; captures `/tmp/04-06-welcome-hero-light.png` + `/tmp/04-06-welcome-hero-dark.png` (dark via `Emulation.setEmulatedMedia` `prefers-color-scheme: dark`); prints diagnostic `getComputedStyle().stroke` for each theme.
|
||||
- `.planning/phases/04-harden-clean-up-optional/04-06-SUMMARY.md` — **CREATED** (this file).
|
||||
|
||||
### Modified
|
||||
- `src/shared/brand/mokosh-mark.svg` — **MODIFIED.** Net +1 / -1. Root `<svg>` (line 2) `stroke="#181b2a"` -> `stroke="currentColor"`. 12 `<line>` + 1 `<rect>` children inherit stroke from the root and are UNCHANGED.
|
||||
- `src/welcome/welcome.ts` — **MODIFIED.** Net +90 / -25. Line 46 import flipped from `?url`/`markUrl` to `?raw`/`markSvg`. populateMark body (lines 159-179) rewritten: `<img>` -> DOMParser + replaceChildren inline-SVG. NEVER uses innerHTML. Preserves function signature, slots query, altText resolution, filter-pipeline form, empty-slot logger.warn fallback. Docstring + comment block updated to describe inline-`<svg>` strategy.
|
||||
- `globals.d.ts` — **MODIFIED.** Net +21. Appended `declare module '*.svg?raw' { const raw: string; export default raw; }` block after the existing `*.svg?url` block. Explanatory comment per project docstring convention.
|
||||
- `src/shared/tokens.css` — **MODIFIED.** Net +15. Added `--mks-mark-stroke: var(--mks-linen-50);` in the universal `:root` block (line ~131), adjacent to `--mks-fg-inverse`. NOT added to `.dark, [data-theme="dark"]` block. Comment cites the abstraction-error rationale + .planning/debug/04-06-dark-mode-mark-decouple.md. SCOPE EXPANSION (authorized by Task 4 TWEAK verdict).
|
||||
- `src/welcome/welcome.css` — **MODIFIED.** Net +11. Line 72 `.welcome-hero__mark { color: var(--mks-fg-inverse); }` -> `color: var(--mks-mark-stroke);`. Comment block updated to cite the cascade chain. SCOPE EXPANSION (authorized by Task 4 TWEAK verdict).
|
||||
- `tests/uat/extension-page-harness.ts` — **MODIFIED.** Net +25 / -45. A17.8 sub-check (lines ~2249-2298) narrowed honestly: replaced `hasInlineDataUrl` + svgFileUrl regex with raw-source grep (`stroke="currentColor"` + `viewBox="0 0 32 32"`). Comment block disavows live-DOM coverage and points to A35.
|
||||
- `tests/uat/lib/harness-page-driver.ts` — **MODIFIED.** Net +247 (Task 3 first land) + strengthening (debug-fix; A35.5 sub-check + a35Probe helper extraction). Appended `driveA35` host-side driver after `driveA34`. Opens welcome.html via `browser.newPage()` + `page.goto(...)` + `waitForSelector('.welcome-hero__mark svg', ...)`. Extracted `a35Probe(welcomePage, dark)` helper toggles `data-theme="dark"` on documentElement + reads live DOM. 5 CheckRecords: A35.1-A35.4 (live-DOM injection + currentColor cascade); A35.5 (light+dark equality decouple-proof). welcomePage.close() in finally; try/catch + result.error mirror driveA33/A34.
|
||||
- `tests/uat/harness.test.ts` — **MODIFIED.** Net +28. 3-site lockstep wiring: import block adds `driveA35,`; wrapped-driver block adds `driveA35Wrapped` closure (capturing `handles.browser` + `handles.extensionId`); drivers-array push appends `{ name: 'A35', drive: driveA35Wrapped }` as the LAST entry. Architecture banner string at line 283 LEFT unchanged (cosmetic-advisory ADV-2A; auto-count via `total = drivers.length + 1` carries actual count).
|
||||
- `.planning/phases/01-stabilize-video-pipeline/01-07-SUMMARY.md` — **MODIFIED.** Net +10 / -10. 5 stale 'deferred to Phase 5' framing lines (22, 47, 82, 135, 205) flipped to 'shipped opportunistically Plan 01-09 at recorder.ts:285; verified Phase 4 Plan 04-06'. 4 historical commit-description lines (40, 89, 109, 110) LEFT unchanged. After the flips the SUMMARY narrative is internally consistent.
|
||||
- `.planning/phases/04-harden-clean-up-optional/deferred-items.md` — **MODIFIED.** Net +2 / -2. The prior 'strict-meta-json fails on a clean tree' entry rewritten to describe the real 04-CONTEXT #9/#10 parallel-vitest ffprobe flake family + correct the baseline to 184/184 GREEN.
|
||||
- `.planning/ROADMAP.md` — **MODIFIED.** Plan 04-06 row flipped `[ ]` -> `[x]` with closure annotation. Phase 4 progress table cell updated from `6/8 In Progress (Plan 04-05 closed ROADMAP SC #2)` to `7/8 In Progress (Plan 04-06 closed D-P4-03)`.
|
||||
- `.planning/STATE.md` — **MODIFIED.** Current Position advanced. Stopped At updated. Last activity 2026-05-26. Plan 04-06 closure section added. Decisions appended. Performance metric row added. Progress 90% -> 93% (28/31 -> 29/31).
|
||||
|
||||
### Archived
|
||||
- `.planning/debug/04-06-dark-mode-mark-decouple.md` -> `.planning/debug/resolved/04-06-dark-mode-mark-decouple.md` — debug session moved at plan closure (resolved end-to-end via fix commit `a8bcc17` + operator re-empirical 2026-05-26).
|
||||
|
||||
## Decisions Made
|
||||
|
||||
See `key-decisions` in frontmatter for the canonical list (10 decisions). Highlights:
|
||||
|
||||
1. **Multi-iteration ceremony was a necessary cost** — 3 planner passes + 2 checker passes + 1 debug fix cycle. The /gsd-debug fix surfaced the brand-component vs semantic token abstraction error that the planner-checker couldn't catch (requires operator visual judgment). Lesson encoded.
|
||||
2. **Brand-component token vs semantic token** — `--mks-fg-inverse` is for theme-flipping text foreground; `--mks-mark-stroke` is for theme-independent brand stroke. Pattern established and documented.
|
||||
3. **A35.5 decouple-proof sub-check** — light.computedStroke === dark.computedStroke === 'rgb(250, 247, 241)'. Regression-proof for any future re-coupling.
|
||||
4. **Honest A17.8 narrowing** — SOURCE-BUNDLING only; live-DOM coverage lives in A35.
|
||||
5. **Behavior-based vitest gate** — hard-codes no test filename; isolation-passing single flake is tolerated; reproducible failure or 2+ failures FAIL the gate.
|
||||
6. **01-07-SUMMARY back-patch** — 5 stale framing lines flipped; 4 historical commit-description lines left.
|
||||
7. **Cosmetic advisories ADV-2A/B/C** — banner string left for Plan 04-07 to opportunistically refresh; SKIP_PROD_REBUILD=0 prose accuracy noted; A35-appended-LAST safety documented in SUMMARY.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 3 — Blocking] Welcome screenshot script created from scratch (Task 4 artifact)**
|
||||
- **Found during:** Task 4 (Operator empirical UAT — pre-checkpoint screenshot production)
|
||||
- **Issue:** The plan instructed "Load dist/ as an unpacked extension and open the welcome page in a Puppeteer-driven Chrome. Capture LIGHT-surface screenshot. Capture DARK-surface screenshot." but did not provide a dedicated script — the operator-empirical checkpoint required a reproducible artifact.
|
||||
- **Fix:** Created scripts/04-06-welcome-hero-screenshots.mjs (194 lines) — Puppeteer; loads dist/ as unpacked extension; opens welcome.html; captures /tmp/04-06-welcome-hero-{light,dark}.png via `Emulation.setEmulatedMedia` `prefers-color-scheme: dark`; prints diagnostic `getComputedStyle().stroke` for each theme. Reproducible for any future re-shoot.
|
||||
- **Files modified:** scripts/04-06-welcome-hero-screenshots.mjs (CREATED)
|
||||
- **Verification:** Both screenshots produced + visually inspected by operator; diagnostic output confirms `computedStroke` resolved for each theme.
|
||||
- **Committed in:** `d66cbf6` (separate chore commit; Task 4 artifact)
|
||||
|
||||
**2. [Rule 1 — Bug] Dark-cascade abstraction error: --mks-fg-inverse couples stroke to theme**
|
||||
- **Found during:** Task 4 operator-empirical UAT (TWEAK verdict 2026-05-26)
|
||||
- **Issue:** `.welcome-hero__mark { color: var(--mks-fg-inverse); }` is theme-coupled (linen-50 in light; ink-900 in dark per tokens.css :root vs .dark blocks). The mark sits on a theme-INDEPENDENT madder-600 circle, so a theme-coupled stroke produced muddy ink-on-madder in dark mode. Wrong abstraction (semantic token applied to a non-flipping surface).
|
||||
- **Fix:** Introduced a NEW brand-component token `--mks-mark-stroke = var(--mks-linen-50)` in the universal :root block of src/shared/tokens.css. CRUCIALLY NOT overridden in `.dark, [data-theme="dark"]` — stays linen-50 on every surface. Rewired `.welcome-hero__mark { color: var(--mks-mark-stroke); }` at src/welcome/welcome.css line 72. SVG remains untouched (stroke="currentColor" cascade plumbing identical; only the wrapper's color source changed). Routed via /gsd-debug per `feedback-gsd-ceremony-for-fixes.md` — no inline hot-edit.
|
||||
- **Files modified:** src/shared/tokens.css (SCOPE EXPANSION; +15); src/welcome/welcome.css (SCOPE EXPANSION; +11); src/welcome/welcome.ts (comment-only); tests/welcome/inline-svg.test.ts (comment-only); tests/uat/lib/harness-page-driver.ts (A35 strengthening: a35Probe helper + A35.5 light+dark equality); tests/uat/harness.test.ts (comment-only); .planning/debug/04-06-dark-mode-mark-decouple.md (NEW debug note; later archived to resolved/).
|
||||
- **Verification:** Re-shot screenshots show identical crisp linen-on-madder in both themes. A35.5 live-DOM probe: light.computedStroke === dark.computedStroke === "rgb(250, 247, 241)". UAT 36/36 GREEN. Operator re-empirical 2026-05-26: "Confirmed fixed — close Plan 04-06".
|
||||
- **Committed in:** `a8bcc17` (debug-fix commit; ceremony-routed per saved memory)
|
||||
|
||||
**3. [Rule 1 — Bug] A35 sub-check strengthening: 4 -> 5 sub-checks (A35.5 decouple-proof added)**
|
||||
- **Found during:** /gsd-debug session for the dark-cascade abstraction error
|
||||
- **Issue:** The original A35 (Task 3 first land) had 4 sub-checks (A35.1-A35.4) covering live-DOM injection + currentColor cascade resolution in LIGHT theme only. A future regression that re-couples the stroke to a theme-flipping token would still pass A35.1-A35.4 (the inline `<svg>` is injected; the cascade resolves; just to the wrong color in dark).
|
||||
- **Fix:** Extracted the live-DOM probe into a helper `a35Probe(welcomePage, dark)` that toggles `data-theme="dark"` on documentElement (+ requestAnimationFrame wait for CSS recompute). Probe BOTH light + dark. Add A35.5: assert `light.computedStroke === dark.computedStroke === "rgb(250, 247, 241)"` (linen-50). This is the canonical decouple-proof.
|
||||
- **Files modified:** tests/uat/lib/harness-page-driver.ts (folded into debug-fix commit `a8bcc17`)
|
||||
- **Verification:** UAT 36/36 GREEN; A35.5 diagnostics show light + dark both rgb(250, 247, 241).
|
||||
- **Committed in:** `a8bcc17` (folded into the debug-fix commit; ceremony-routed)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 3 auto-fixed (1 blocking [screenshot script]; 2 bugs [abstraction error + A35 strengthening]).
|
||||
**Impact on plan:** All 3 deviations were essential for closure. The screenshot script was the operator-empirical artifact; the abstraction-error fix closed the TWEAK verdict; the A35 strengthening encodes the regression-proof. No scope creep — the SCOPE EXPANSIONS (tokens.css + welcome.css edits) were authorized by the Task 4 TWEAK verdict per the operator-empirical resume-signal contract.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
### Operator-empirical TWEAK verdict — abstraction error in dark cascade
|
||||
|
||||
Task 4's first operator-empirical verdict (2026-05-26) was TWEAK NEEDED. The light screenshot was crisp linen-on-madder (Plan 01-10 baseline preserved); the dark screenshot showed the mark stroke flipped to ink-900 (deep indigo) on the madder-600 wrapper — visually muddy, low contrast. Root cause: `.welcome-hero__mark { color: var(--mks-fg-inverse); }` couples the cascade to a semantic token that flips with theme. The mark wrapper is theme-independent (madder-600 in both themes), so the coupling was the wrong abstraction.
|
||||
|
||||
**Resolution (per saved memory `feedback-gsd-ceremony-for-fixes.md`):** routed via /gsd-debug rather than inline hot-edit. Debug session at .planning/debug/04-06-dark-mode-mark-decouple.md established root cause + fix; fix commit `a8bcc17` decoupled via the NEW brand-component token `--mks-mark-stroke`. A35 strengthened with the A35.5 decouple-proof sub-check. Re-shot screenshots + UAT re-run produced identical crisp linen-on-madder in both themes. Operator re-empirical 2026-05-26: "Confirmed fixed — close Plan 04-06".
|
||||
|
||||
### Parallel-vitest #9/#10 flake fired during Task 2 GREEN gate
|
||||
|
||||
Task 2's full vitest run produced 187 passed / 1 failed (188 total). The failing test was `tests/background/webm-remux.test.ts > 'ffprobe -count_frames reports between 905 and 912 frames'` (`Error: Test timed out in 5000ms`). Per the Task 2 VITEST GATE LOGIC behavior-based rule: re-run in isolation (`npm test -- tests/background/webm-remux.test.ts --run`) -> 5/5 GREEN. Tolerated as the known 04-CONTEXT #9/#10 parallel-vitest ffprobe-timeout flake family. NOT a Plan 04-06 regression (Plan 04-06 modifies no offscreen recorder code). Documented + tolerated per gate logic.
|
||||
|
||||
## Pre-Checkpoint Bundle Gates (6/6 PASS)
|
||||
|
||||
Per saved memory `feedback-pre-checkpoint-bundle-gates.md`, all 6 gates run on `npm run build` production output before each operator-empirical checkpoint surface:
|
||||
|
||||
| Gate | Check | Result |
|
||||
|------|----------------------------------------------------------------------|----------|
|
||||
| 1 | npm run build exit 0; glob-existence ls dist/assets/index.ts-*.js | PASS |
|
||||
| 2 | SW CSP-safety: `new Function`/`eval` in dist/assets/index.ts-*.js | 0 / 0 — PASS (Plan 04-02 effect preserved) |
|
||||
| 3 | SW Node-globals: `Buffer.`/`process.`/`require(` in SW chunk | 1 (pre-existing JSZip polyfill `typeof ArrayBuffer<"u"` feature-detection) — PASS (baseline-identical to Plan 04-05 boundary; Plan 04-06 modifies no SW chunk source) |
|
||||
| 4 | DOM-globals: `window.`/`document.` in SW chunk | third-party `typeof window<"u"`/`typeof document<"u"` guarded feature-detection — PASS (baseline-identical) |
|
||||
| 5 | Tier-1 SW-bundle-import vitest gate | GREEN |
|
||||
| 6 | Tier-1 FORBIDDEN_HOOK_STRINGS at 12 + Tier-2 production filename-leak gate (0 hits) | GREEN — PASS |
|
||||
|
||||
**6/6 PASS** at both the first Task 4 checkpoint AND the post-debug re-checkpoint. Tier-1 FORBIDDEN_HOOK_STRINGS unchanged at 12 (Plan 04-06 adds no `__MOKOSH_UAT__`-gated symbols; DOMParser is a standard web platform API; `?raw` is a normal production Vite import; `*.svg?raw` ambient decl is type-only at build time). SW chunk is byte-identical at the Plan 04-05 boundary (Plan 04-06 modifies only src/welcome/* + src/shared/brand/mokosh-mark.svg + src/shared/tokens.css :root token + tests/* + globals.d.ts — none of these affect the SW chunk shape).
|
||||
|
||||
## Test Baselines
|
||||
|
||||
- **vitest:** **188/188 GREEN** on a fully-clean run (the +4 from Plan 04-06: 3 inline-svg.test.ts + 1 cursor-visibility.test.ts). Most recent full-suite run post-debug-fix: **187/188 with the 04-CONTEXT #9/#10 webm-remux flake fired** (passes 5/5 in isolation; tolerated per Task 2 VITEST GATE LOGIC). Baseline contract held: 184 + 4 = 188.
|
||||
- **UAT harness:** **36/36 GREEN** (skip-mode `SKIP_LONG_UAT=1 npm run test:uat`). Increments: 33 (post-04-03) -> 34 (04-08 A33) -> 35 (04-05 A34) -> 36 (04-06 A35). A35 itself contains 5 sub-checks all PASS (A35.1-A35.5).
|
||||
- **Tier-1 FORBIDDEN_HOOK_STRINGS:** **12** (unchanged from Plan 04-02 baseline; verified at `tests/background/no-test-hooks-in-prod-bundle.test.ts:108-126`).
|
||||
- **Tier-2 production-bundle filename-leak gate:** `synthetic-display-source` = 0 hits in dist/ (Plan 04-08 invariant preserved).
|
||||
- **Pre-checkpoint bundle gates:** **6/6 PASS** (verified at both Task 4 checkpoint AND post-debug re-checkpoint).
|
||||
- **`tsc --noEmit`:** exits 0. **`npm run build`:** exits 0. **`npm run build:test`:** exits 0.
|
||||
|
||||
## D-P4-03 Closure Evidence
|
||||
|
||||
**D-P4-03 (charter, locked, 04-CONTEXT.md):** BOTH (a) cursor visibility AND (b) dark-surface logo contrast.
|
||||
|
||||
### (a) Cursor visibility — CLOSED
|
||||
|
||||
- **Already shipped:** `cursor: 'always'` at src/offscreen/recorder.ts:285 (Plan 01-09 opportunistic co-land in commit `a2dfc8c` 2026-05-19; the original Phase 5 deferral framing in 01-07-SUMMARY was false — the constraint was shipped concurrently with the no-active-tab cleanup).
|
||||
- **Verified by:** tests/build/cursor-visibility.test.ts — node-env file-grep regression pin for the literal `cursor: 'always'`. 1 GREEN-on-arrival. Any future regression that removes the literal will fail the gate.
|
||||
- **01-07-SUMMARY back-patch:** 5 stale 'deferred to Phase 5' framing lines (22, 47, 82, 135, 205) flipped; 4 historical commit-description lines (40, 89, 109, 110) LEFT.
|
||||
|
||||
### (b) Dark-surface logo contrast — CLOSED
|
||||
|
||||
4-layer coverage:
|
||||
|
||||
1. **Source-contract unit tests** (Task 1): tests/welcome/inline-svg.test.ts (3 tests; node-env; file-read + string-assert). Pins SVG recolor + welcome.ts ?raw/DOMParser/replaceChildren/no-innerHTML + globals.d.ts ambient decl. RED -> GREEN after Task 2.
|
||||
2. **A17.8 raw-source bundling check** (Task 3): tests/uat/extension-page-harness.ts. Asserts welcome JS chunk contains the raw SVG source signature (stroke="currentColor" + viewBox="0 0 32 32"). Honestly narrowed to SOURCE-BUNDLING only; explanatory comment disavows live-DOM coverage and points to A35.
|
||||
3. **A35 live-DOM host-side harness assertion** (Task 3 + debug-fix strengthening): tests/uat/lib/harness-page-driver.ts driveA35. Opens welcome.html as a real Puppeteer tab; lets populateMark() run at DOMContentLoaded; reads the LIVE injected `.welcome-hero__mark svg` element + getComputedStyle().stroke. **5 sub-checks**: A35.1 svg present; A35.2 stroke=\"currentColor\"; A35.3 getComputedStyle().stroke resolved non-default (linen-50); A35.4 no `<img>` in slot; **A35.5 light.computedStroke === dark.computedStroke === \"rgb(250, 247, 241)\" (linen-50 decouple-proof, NEW from debug-fix)**. UAT 36/36 GREEN — A35 is the genuine automated proof of the runtime injection + cascade + theme decoupling.
|
||||
4. **Operator-empirical Puppeteer screenshots** (Task 4): scripts/04-06-welcome-hero-screenshots.mjs produces /tmp/04-06-welcome-hero-{light,dark}.png via prefers-color-scheme: dark emulation. First operator verdict: TWEAK (dark cascade flipped to ink-900). /gsd-debug session resolved via --mks-mark-stroke brand-component token. Re-shot screenshots + operator re-empirical 2026-05-26: "Confirmed fixed — close Plan 04-06".
|
||||
|
||||
## TDD Gate Compliance
|
||||
|
||||
Plan 04-06 was a `type: execute` plan with `tdd="true"` on Tasks 1-2 (the source-contract + implementation pair). Gate sequence verified in git log:
|
||||
|
||||
1. ✅ **RED gate (test commit):** `f0b88d4` (test(04-06): Wave 0 — inline-SVG source-contract RED + cursor-visibility regression pin). 3 RED + 1 GREEN-on-arrival at commit time; isolated `npm test -- tests/welcome/ --run` showed 3/3 FAILED before Task 2 GREEN.
|
||||
2. ✅ **GREEN gate (feat commit):** `c416143` (feat(04-06): Wave 1 GREEN — dark-logo currentColor strategy + inline-SVG injection) after RED. 3 RED flipped to 3 GREEN; cursor-visibility test preserved 1 GREEN.
|
||||
3. **REFACTOR gate:** N/A — no separate refactor commit needed; Task 2 implementation was minimal-to-pass.
|
||||
|
||||
TDD discipline preserved end-to-end.
|
||||
|
||||
## Charter Linkage
|
||||
|
||||
Plan 04-06 has no REQ-* requirements (Phase 4 is optional hardening; all v1 REQs covered by Phases 1-3 per ROADMAP). Charter linkage is via the `charter-d-p4-03` tag in frontmatter. D-P4-03 = visual polish (cursor visibility + dark-surface logo contrast) — both items closed by Plan 04-06.
|
||||
|
||||
## Cross-Plan Provenance Note for Plan 04-07
|
||||
|
||||
Plan 04-07 (Phase 4 closure aggregator) is now the ONLY remaining Phase 4 plan. Inputs for 04-07:
|
||||
|
||||
- **D-P4-03 closure:** documented here (cursor + dark-logo both closed; A35 + cursor-visibility unit test pin live).
|
||||
- **D-P4-04 (alpha tester integration):** honored out-of-band (per ROADMAP entry).
|
||||
- **ROADMAP success criteria status:** SC #1 CLOSED (04-08); SC #2 CLOSED (04-05); SC #3 CLOSED (04-02); SC #4 CLOSED (04-02). All 4 ROADMAP success criteria are now CLOSED.
|
||||
- **Cosmetic-advisory ADV-2A** (architecture banner string at harness.test.ts:283 missing A33/A34/A35): non-blocking; Plan 04-07 may opportunistically refresh the banner if it touches that file.
|
||||
- **04-CONTEXT #9/#10 parallel-vitest flake family:** documented in deferred-items.md (corrected this plan); routed for /gsd-debug or future-plan worker-isolation strategy (`poolOptions.threads.singleThread:true` or `testTimeout` bump) if it becomes a blocker for Phase 4 closure.
|
||||
|
||||
Plan 04-07 should produce the Phase 4 aggregate verification (VERIFICATION.md gsd-verifier audit) + REQUIREMENTS/ROADMAP/STATE marker flips + v1 milestone close prep.
|
||||
|
||||
## Saved-Memory Compliance Audit
|
||||
|
||||
- ✅ **`feedback-no-unilateral-scope-reduction.md`** — full plan scope executed (4 tasks; 11 files modified; SCOPE EXPANSIONS authorized by operator TWEAK verdict; no unilateral truncation).
|
||||
- ✅ **`feedback-trust-harness-over-manual-uat.md`** — operator only judged from screenshots (Task 4 artifact via scripts/04-06-welcome-hero-screenshots.mjs); A35.5 light+dark equality decouple-proof landed in the automated harness (not just the screenshot artifact).
|
||||
- ✅ **`feedback-gsd-ceremony-for-fixes.md`** — the dark-cascade abstraction error was routed via /gsd-debug (debug session at .planning/debug/04-06-dark-mode-mark-decouple.md; fix commit `a8bcc17` is a separate atomic fix-commit, NOT a hot-edit folded into a task commit). Ceremony honored.
|
||||
- ✅ **`feedback-pre-checkpoint-bundle-gates.md`** — 6/6 bundle gates run + verified PASS at BOTH the first Task 4 checkpoint AND the post-debug re-checkpoint. Documented above.
|
||||
|
||||
## Threat Surface Scan
|
||||
|
||||
Plan 04-06 introduces no new security-relevant surface:
|
||||
|
||||
- **Inline-SVG injection:** safe because the input is a Vite-bundled compile-time literal (no runtime untrusted input). DOMParser parse + replaceChildren preserves MV3 CSP discipline (T-04-06-01 mitigation; no innerHTML, no eval). The `?raw` import is processed at build time; the SVG source string is statically known.
|
||||
- **NEW A35 harness tab:** test-only; always closed in finally block (no production surface, no leaked tab); A35 is appended LAST in the drivers array (no pollution-of-future-drivers risk — there are no future drivers); A35 does NOT mutate chrome.storage (opening welcome.html does NOT trigger openWelcomeIfFirstInstall — that runs only on chrome.runtime.onInstalled). Verified safe at design time (cosmetic-advisory ADV-2C).
|
||||
- **`--mks-mark-stroke` brand-component token:** purely additive CSS custom property in :root; no override anywhere; no consumer surface change.
|
||||
|
||||
No `## Threat Flags` section needed.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
Acceptance criterion by criterion (cross-referenced against the success_criteria list in the closure-work prompt):
|
||||
|
||||
- ✅ **04-06-SUMMARY.md written per canonical template + multi-iteration ceremony history**: this file. Frontmatter complete (phase + plan + subsystem + tags + requires + provides + affects + tech-stack + key-files + key-decisions + metrics). Multi-Iteration Ceremony History section provides the 13-row provenance table.
|
||||
- ✅ **All 4 tasks documented**: Tasks 1-3 autonomous (commits `f0b88d4` + `c416143` + `3f8e31a`) + Task 4 operator empirical with TWEAK → fix `a8bcc17` → CONFIRMED arc.
|
||||
- ✅ **All key deliverables enumerated**: currentColor + --mks-mark-stroke decoupling + A35 (5 sub-checks) + back-patch + screenshot script + 01-07-SUMMARY 5-line flip + deferred-items correction.
|
||||
- ✅ **3 re-plan-checker iter-2 cosmetic advisories documented**: ADV-2A (banner: LEAVE per decision), ADV-2B (SKIP_PROD_REBUILD=0 rationale corrected in SUMMARY), ADV-2C (A35-appended-LAST safety noted in Threat Surface Scan).
|
||||
- ✅ **Pre-checkpoint bundle gates 6/6 PASS reported**: dedicated section above with table.
|
||||
- ✅ **Test baselines documented**: vitest 188/188 GREEN (most recent 187/188 with tolerated webm-remux flake); UAT 36/36 GREEN; FORBIDDEN_HOOK_STRINGS 12.
|
||||
- ✅ **D-P4-03 closure evidence**: dedicated section with (a) cursor visibility + (b) dark-surface logo contrast 4-layer coverage.
|
||||
- ✅ **Self-Check section**: this section, criterion by criterion.
|
||||
|
||||
**Created files exist:**
|
||||
- ✅ tests/welcome/inline-svg.test.ts — FOUND
|
||||
- ✅ tests/build/cursor-visibility.test.ts — FOUND
|
||||
- ✅ scripts/04-06-welcome-hero-screenshots.mjs — FOUND
|
||||
- ✅ .planning/phases/04-harden-clean-up-optional/04-06-SUMMARY.md — FOUND (this file)
|
||||
|
||||
**Commits exist (verified via `git log --oneline`):**
|
||||
- ✅ `f0b88d4` (Task 1 RED) — FOUND
|
||||
- ✅ `c416143` (Task 2 GREEN) — FOUND
|
||||
- ✅ `3f8e31a` (Task 3 A35 + back-patch) — FOUND
|
||||
- ✅ `d66cbf6` (Task 4 screenshot harness) — FOUND
|
||||
- ✅ `a8bcc17` (debug-fix --mks-mark-stroke) — FOUND
|
||||
|
||||
No missing items. Plan 04-06 closes cleanly.
|
||||
|
||||
---
|
||||
|
||||
*Phase: 04-harden-clean-up-optional*
|
||||
*Plan: 06*
|
||||
*Completed: 2026-05-26*
|
||||
Reference in New Issue
Block a user