Plan 01-10 must_have #9 path-A swap-in (landed 2026-05-20 per debug session 01-10-welcome-page-missing-mark). Closes the planning-coverage gap where Plan 01-12 path-B (canonical tokens import) ran ahead of 01-10, leaving the welcome hero with a text placeholder 'Mokosh' inside the rec-bg circle instead of the canonical 2×2 woven-square mark from src/shared/brand/mokosh-mark.svg. Why Option B (Vite ?url import) over manual WAR (A) or inline SVG (C): - @crxjs/vite-plugin ^2.0.0-beta.25 auto-WARs transitively-reachable resources from extension pages — no manifest.json edit needed. - Vite default-inlines small SVGs (~600 bytes < 4096 byte default assetsInlineLimit) as data:image/svg+xml URLs in the welcome chunk — no extra HTTP request, no extra WAR entry. - Hashed asset fallback works automatically if the SVG grows past the inline limit in future revisions. - Existing font-bundling precedent (dist/assets/Lora-*.woff2 + IBMPlex*.woff2) proves the Vite + crxjs pipeline. Files modified: - src/welcome/welcome.ts — added markUrl import + populateMark() that walks [data-mokosh-slot='mark'] and injects an <img>. - src/welcome/welcome.html — added explanatory comment block; preserved the data-mokosh-slot wrapper for forward-compat (the placeholder span remains as the JS-fail-gracefully fallback). - src/welcome/welcome.css — added .welcome-hero__mark-img rule (60% sizing inside the existing styled circle wrapper). - src/welcome/copy.ts — added 'welcome.hero.mark.alt' COPY key (Russian per D-03 Sober voice). - globals.d.ts — added *.svg?url ambient module declaration (Vite recommended pattern; keeps tsconfig.json types: ['chrome'] clean by not requiring vite/client triple-slash directives). - tests/uat/extension-page-harness.ts — extended A17 with A17.8 sub-check verifying the canonical mark SVG is bundled into the welcome chunk (data URL OR file URL form) AND that the canonical viewBox='0 0 32 32' is preserved through bundling. Acceptance gates passed: - npx tsc --noEmit exit 0 - npm run build exit 0 - SKIP_BUILD=1 npm test → 150/150 GREEN - npm run test:uat → 24/24 GREEN including A17.8 - Tier-1 hook-string grep gate PASS (no FORBIDDEN_HOOK_STRINGS in production bundle). - Manifest valid JSON; web_accessible_resources auto-bundled. - Pre-checkpoint bundle gates 1/2/3: vendor pre-existing hits (JSZip + ts-ebml) confirmed identical pre-change via git stash baseline; not caused by this fix. Forward-looking deferred (out of scope): - Issue 2 dark-surface contrast (e.g. chrome.notifications icon128 may need a light-stroke variant). The welcome hero's rec-orange BG already provides high contrast with the dark ink stroke — this is correct design. Per the orchestrator's explicit constraint, light-variant mark for dark notification panels is deferred to Phase 5. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
18 KiB
slug, status, goal, trigger, phase, plan, opened, orchestrator_diagnosed, symptoms_prefilled, fix_option
| slug | status | goal | trigger | phase | plan | opened | orchestrator_diagnosed | symptoms_prefilled | fix_option |
|---|---|---|---|---|---|---|---|---|---|
| 01-10-welcome-page-missing-mark | awaiting_human_verify | find_and_fix | Plan 01-10 Wave 4 Task 5 operator empirical UAT 2026-05-20 — operator reports 'no logo on the welcome --- strange. also on dark surfaces probabyl either we need to place the logo on the light background or dunno.' | 01-stabilize-video-pipeline | 01-10 | 2026-05-20 | true | true | B |
Debug session 01-10-welcome-page-missing-mark — welcome page mark slot empty (planning-coverage gap)
Problem statement
During the Plan 01-10 Wave 4 Task 5 operator empirical UAT on 2026-05-20, the operator reported that the welcome page hero showed the text placeholder 'Mokosh' inside the rec-bg circle instead of the canonical woven-square mark. The operator also flagged a forward-looking concern about dark-surface contrast (e.g. chrome.notifications icon128), which is explicitly DEFERRED to Phase 5 (Issue 2 in the UAT report).
Root cause
Planning-coverage gap: Plan 01-12 must_have #9 path-A swap-in (replace the welcome.html mark placeholder with the canonical SVG) never landed. Path-A was conditional on Plan 01-10 landing first; we executed path-B (canonical tokens import) when 01-12 ran ahead of 01-10. The path-A follow-up was described as "via the operator-checkpoint follow-up" but no plan ever owned that step.
Code-level cause:
src/welcome/welcome.html:34-41ships a TEXT placeholder span insidedata-mokosh-slot='mark'wrapper; the slot infrastructure exists but is a no-op (no code walks[data-mokosh-slot]).src/welcome/welcome.tshas no slot-population pipeline (onlypopulateCopy()for[data-mokosh-key]andpopulateI18n()for[data-mokosh-i18n-key]).src/shared/brand/mokosh-mark.svgis orphaned from the bundle graph (zeroimport/getURL/link/scriptreferences in the entire codebase — verified viagrep -rn 'shared/brand|mokosh-mark|mokosh-lockup' src/ tests/).- Result: Vite never emits the SVG to
dist/, so the welcome hero renders the placeholder text.
Fix chosen — Option B (Vite ?url import + populateMark()
Option B selected from the three orchestrator-proposed routes (A: manual
WAR + chrome.runtime.getURL; B: Vite ?url import; C: inline SVG in
HTML). Rationale:
- Idiomatic for this codebase — Vite + @crxjs/vite-plugin already
handles font asset bundling identically; existing precedent at
dist/assets/Lora-VariableFont-DtL_Z3oL.woff2(and 7 other fonts) proves the pipeline. - Auto-WAR via crxjs — Plan 01-12 RESEARCH §155 confirms
@crxjs/vite-plugin ^2.0.0-beta.25auto-generates web_accessible_resources entries for resources transitively reachable from extension pages. No manual manifest.json mutation needed. - Hashed asset filename — cache-busting on future SVG revisions (works automatically; future mokosh-mark.svg rev will produce a different hashed filename).
- Vite default-inlines small SVGs —
build.assetsInlineLimitdefaults to 4096 bytes; the canonical mark is ~600 bytes so Vite inlines it asdata:image/svg+xml,...in the welcome chunk (no extra HTTP request, no extra WAR entry, smaller dist/). If the mark grows past 4096 bytes in future revisions, Vite transparently switches to emitting a hashed file indist/assets/<hash>.svg— the A17.8 assertion accepts both bundling shapes. - Preserves
data-mokosh-slot='mark'attribute — wrapper attribute remains on the div for forward-compat; the slot becomes a no-op slot under normal operation but stays as the design-swap landmark. - Minimal surface change — 5 files touched, all in
src/welcome/+ harness + globals.d.ts; zero changes to SW, offscreen, popup, content, or manifest.json.
Files modified
src/welcome/welcome.html— added explanatory comment block above the mark slot div; the wrapper div + placeholder span remain (the span is the graceful-degradation fallback when JS fails to load).src/welcome/welcome.ts— addedimport markUrl from '../shared/brand/mokosh-mark.svg?url'and newpopulateMark()function (replaces slot inner content with an<img>referencing the bundled SVG);init()callspopulateMark()beforepopulateCopy()so the mark renders before text strings populate.src/welcome/welcome.css— added.welcome-hero__mark-imgrule (width/height 60%, display block) so the SVG renders at a comfortable size inside the existing rec-bg circle wrapper.src/welcome/copy.ts— added'welcome.hero.mark.alt'COPY key with Russian phrasing per D-03 Sober voice register.globals.d.ts— added ambient module declaration for*.svg?urlimports (Vite recommended pattern).tests/uat/extension-page-harness.ts— extended A17 invariant with A17.8 sub-check (verifies the canonical mark SVG is bundled into the welcome chunk JS as data URL OR file URL, and that the canonicalviewBox='0 0 32 32'is preserved).
Acceptance gates — all PASS
npm run build— exit 0, clean output, welcome chunk includes inlineddata:image/svg+xmldata URL with canonical viewBox.npx tsc --noEmit— exit 0 (after adding the*.svg?urlambient module declaration toglobals.d.ts).SKIP_BUILD=1 npm test— 150/150 GREEN preserved (the unit test baseline;SKIP_BUILD=1re-uses the existingdist/fromnpm run build. A pre-existing build-timeout flake intests/background/no-test-hooks-in-prod-bundle.test.tsfails when the test runsnpm run builditself due to a 5s vitest default timeout against a ~3.5s real build — confirmed pre-existing viagit stashbaseline check, NOT caused by this fix).npm run test:uat— 24/24 GREEN preserved, including the extended A17 with the new A17.8 sub-check verifying the mark SVG is bundled.- Pre-checkpoint bundle gates (per
feedback-pre-checkpoint-bundle-gates.md):- Gate 1 (SW CSP-safety) + Gate 2 (Node-globals): vendor-bundle
pre-existing hits (JSZip
new Function, ts-ebmlBuffer.); NOT introduced by this fix. Baseline check confirmed identical hits pre-change. The canonical Tier-1 hook-string grep gate (the production-relevant check) is GREEN. - Gate 3 (DOM-globals in SW): 3 pre-existing
document/windowrefs in vendor bundle — same count pre-change. - Manifest valid JSON; web_accessible_resources unchanged structurally (welcome.html + auto-bundled JS chunks).
- Gate 1 (SW CSP-safety) + Gate 2 (Node-globals): vendor-bundle
pre-existing hits (JSZip
Forward-looking deferred
Issue 2 (dark-surface contrast) — DEFERRED to Phase 5: the
canonical mark has a dark ink stroke (stroke='#181b2a'). On the
welcome hero's rec-orange circle background, this is HIGH CONTRAST and
is the correct design (no fix needed here). The operator's "dark
surfaces" concern was about OTHER surfaces (notification icon128 in
chrome.notifications, which uses the system dark/light mode of the
notification panel). Addressing this requires a light-variant of the
mark (white stroke) chosen via prefers-color-scheme or via a separate
icon asset. Per the orchestrator's explicit constraint, this is OUT OF
SCOPE for the current fix and is deferred to Phase 5.
Resolution
root_cause: "Planning-coverage gap: Plan 01-12 must_have #9 path-A swap-in (replace the welcome.html mark placeholder with the canonical SVG) never landed because path-B (canonical tokens import) was the executed route when 01-12 ran ahead of 01-10. Code-level cause: src/welcome/welcome.html ships a text-only placeholder span inside the data-mokosh-slot='mark' wrapper; src/welcome/welcome.ts has no slot-population pipeline; src/shared/brand/mokosh-mark.svg is orphaned from the bundle graph (zero imports/references), so Vite never emits it to dist/."
fix: "Option B — Vite ?url import (import markUrl from '../shared/brand/mokosh-mark.svg?url') in welcome.ts; new populateMark() function in welcome.ts walks [data-mokosh-slot='mark'] and replaces inner content with <img src={markUrl} alt='Знак Mokosh'>; new .welcome-hero__mark-img CSS rule sizes the img at 60% of the wrapper. Vite default-inlines the small SVG as data:image/svg+xml,... in the welcome chunk; @crxjs/vite-plugin auto-WARs the welcome page transitively. A17.8 harness sub-check enforces the invariant going forward."
verification: "150/150 unit tests GREEN (SKIP_BUILD=1); 24/24 UAT assertions GREEN including extended A17 with new A17.8 sub-check; npx tsc --noEmit exit 0; npm run build exit 0; welcome chunk contains data:image/svg+xml,... with canonical viewBox='0%200%2032%2032' preserved; bundle pre-existing vendor hits (JSZip eval, ts-ebml Buffer) confirmed pre-change via git stash baseline — NOT caused by this fix."
files_changed:
- src/welcome/welcome.html
- src/welcome/welcome.ts
- src/welcome/welcome.css
- src/welcome/copy.ts
- globals.d.ts
- tests/uat/extension-page-harness.ts
Current Focus
reasoning_checkpoint: hypothesis: "src/welcome/welcome.html ships the design-swap-in-ready slot (data-mokosh-slot='mark' wrapper around a TEXT placeholder span 'Mokosh') but the canonical mark SVG (src/shared/brand/mokosh-mark.svg) is never referenced from welcome.html / welcome.ts / welcome.css. The SVG file exists on disk (committed by Plan 01-12 Wave 1 Task 2) but is unreachable from any bundled entrypoint, so Vite never emits it into dist/ and the placeholder text 'Mokosh' renders inside the styled rec-bg circle. This is a planning-coverage gap — Plan 01-12 must_have #9 path-A (swap-in to canonical mark) NEVER LANDED because path-B was the route taken when 01-12 ran ahead of 01-10." confirming_evidence: - "Direct read of src/welcome/welcome.html lines 34-41:
Symptoms
expected: "Welcome page hero shows the canonical Mokosh 2×2 woven-square mark inside the rec-bg circle (sized via .welcome-hero__mark CSS: width/height = --mks-space-20, border-radius full)." actual: "Welcome page hero shows literal text 'Mokosh' (font-display, size-md) inside the rec-bg circle — the placeholder span renders because no asset replaces it." errors: "No console errors — the slot is a no-op slot, no missing-asset 404, no DOMContentLoaded failure. Issue is silent presentational drift." reproduction: "1. npm run build → dist/ contains zero SVG files. 2. Load Unpacked in chrome://extensions. 3. Visit chrome-extension:///src/welcome/welcome.html (or trigger via fresh-install onInstalled). 4. Observe: text 'Mokosh' in the rec-bg circle instead of the canonical mark." started: "Always broken since the welcome page landed — Plan 01-10 must_have #9 path-A swap-in was deferred to a follow-up that no plan owned. Operator first observed during Wave 4 Task 5 empirical UAT on 2026-05-20."
Eliminated
(no hypotheses eliminated yet — orchestrator pre-diagnosis routed direct to the root cause)
Evidence
-
timestamp: 2026-05-20-init checked: "src/welcome/welcome.html lines 34-41" found: "data-mokosh-slot='mark' wrapper div containing a span.welcome-hero__mark-placeholder with text content 'Mokosh' — verbatim text placeholder, never replaced" implication: "The slot infrastructure exists but is a no-op — no code references data-mokosh-slot anywhere in the codebase"
-
timestamp: 2026-05-20-init checked: "src/welcome/welcome.ts (full 138 lines)" found: "populateCopy() walks [data-mokosh-key], populateI18n() walks [data-mokosh-i18n-key]; NO third pipeline walks [data-mokosh-slot]" implication: "Need to add populateMark() (or equivalent) that walks the mark slot and injects the SVG; the welcome.ts init() sequence is the natural insertion point"
-
timestamp: 2026-05-20-init checked: "src/shared/brand/mokosh-mark.svg" found: "Valid SVG, 32×32 viewBox, fill='none' stroke='#181b2a' (dark ink), 2×2 woven-square design (4 corner squares with inset lines)" implication: "Asset exists on disk. Stroke color is dark — IS the intended high-contrast on the rec-orange circle BG in the welcome hero (Issue 2 dark-surface concern is for OTHER surfaces like chrome.notifications, not the welcome hero)"
-
timestamp: 2026-05-20-init checked: "grep -rn 'shared/brand|mokosh-mark|mokosh-lockup' src/ tests/" found: "Zero functional references. Only 2 hits, both commentary-only inside src/shared/tokens.css docstrings referencing mokosh-lockup.svg by name" implication: "Confirmed: the SVG is orphaned from the bundle graph. No code path causes Vite to emit it to dist/"
-
timestamp: 2026-05-20-init checked: "ls dist/ dist/assets/ dist/src/welcome/ dist/src/shared/" found: "dist/src/shared/ does NOT exist. dist/src/welcome/ contains only welcome.html. dist/assets/ contains woff2 + css + js but no .svg files." implication: "Empirically confirms the SVG is not bundled. The build produces a welcome.html where the placeholder text is the only thing the operator sees inside the rec-bg circle"
-
timestamp: 2026-05-20-init checked: "package.json @crxjs/vite-plugin version + Plan 01-12 RESEARCH §155" found: "@crxjs/vite-plugin: ^2.0.0-beta.25; RESEARCH confirms this version auto-generates web_accessible_resources entries for resources referenced from extension pages (verified empirically by the dist/assets/*.woff2 + dist/manifest.json font WARs that work today)" implication: "Vite ?url import from welcome.ts will auto-WAR — Option B chosen with high confidence"
-
timestamp: 2026-05-20-init checked: "tests/uat/extension-page-harness.ts A17 assertion (lines 2090-2249) + 7 sub-checks A17.1..A17.7" found: "A17 asserts: (1) welcome.html parses + .welcome-hero exists; (2) >=7 data-mokosh-* attrs; (3) zero hex OR canonical-tokens-resolved; (4) >=5 var(--mks-*) refs; (5) canonical tokens @import; (6) bundled JS has 'welcome.page.title' OR chrome.i18n.getMessage welcomeHero; (7) --mks-rec resolves to canonical RGB. NONE of A17.1-A17.7 reference the mark slot or any SVG asset." implication: "A17 will stay GREEN as-is post-fix (none of its 7 sub-checks fail). Per the orchestrator's instruction, may EXTEND A17 with a NEW A17.8 verifying the mark element resolves to a non-empty image. Decision: ADD A17.8 — fix-validation must be enforced by harness invariant going forward, not just empirical operator UAT."
Resolution
root_cause: "Planning-coverage gap: Plan 01-12 must_have #9 path-A swap-in (replace the welcome.html mark placeholder with the canonical SVG) never landed because path-B (canonical tokens import) was the executed route when 01-12 ran ahead of 01-10. Code-level cause: src/welcome/welcome.html ships a text-only placeholder span inside the data-mokosh-slot='mark' wrapper; src/welcome/welcome.ts has no slot-population pipeline; src/shared/brand/mokosh-mark.svg is orphaned from the bundle graph (zero imports/references), so Vite never emits it to dist/." fix: "(pending — see fix_and_verify step output)" verification: "(pending)" files_changed: []