docs(03): UI design contract — null-spec for verification-only phase

Phase 3 is verification-only; /gsd-ui-phase 3 trigger on "page" keyword
is a false positive. UI-SPEC.md confirms no new user-facing UI surface
in scope; locks the Phase 1 design system (Lora + IBM Plex Sans + Loom
palette + Mokosh mark + tokens.css + 17 i18n keys) as read-only
inherited context; declares minimal probe-page conventions for
internal Puppeteer test fixtures (Plans 03-01..03-05 per D-P3-01).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 18:04:00 +02:00
parent 6b52d111f8
commit 03d4b3343c

View File

@@ -0,0 +1,232 @@
---
phase: 3
slug: 03-spec-10-smoke-verification-dom-event-log-verification
status: draft
shadcn_initialized: false
preset: none
created: 2026-05-20
scope_kind: verification-only
ui_surface: none-user-facing
inherits_from:
- 01-12-SUMMARY.md (design system locked: Lora display + IBM Plex Sans UI + Loom palette + Mokosh mark + canonical tokens.css + 16 i18n keys with en↔ru parity)
- 01-10-SUMMARY.md (welcome page pattern: data-mokosh-slot + data-mokosh-key + data-mokosh-i18n-key three-pipeline DOM population)
---
# Phase 3 — UI Design Contract
> Visual and interaction contract for frontend phases. Generated by gsd-ui-researcher, verified by gsd-ui-checker.
---
## Scope Determination
**Phase 3 has NO user-facing UI surface in scope.**
The `/gsd-ui-phase 3` orchestrator triggered on the "page" keyword in 03-CONTEXT.md `<domain>` and `<specifics>`. After reading the upstream artifacts, the honest answer is that this is a false positive:
- 03-CONTEXT.md `<domain>` explicitly states: *"No new production-code feature work; the rrweb wiring + event-log wiring already shipped in Phase 1 (`src/content/index.ts`). Phase 3 confirms what's shipped + writes the §10 sweep VERIFICATION."*
- All "page" references in Phase 3 plans (03-01, 03-02, 03-03, 03-04, 03-05 per D-P3-01) point to **synthetic Puppeteer test fixtures internal to `tests/uat/extension-page-harness.ts`** — probe HTML for rrweb DOM verification (form + table + modal) and event-log trigger surfaces (password input + click target + 404 endpoint). These pages never ship in production and never reach an operator.
- All user-facing UI surfaces (popup, welcome page, brand identity, badges, icons, fonts, palette, i18n) were **LOCKED by Phase 1** (Plans 01-09 / 01-10 / 01-12 / 01-14). Phase 3 INHERITS them and MUST NOT modify them.
This UI-SPEC therefore captures **inherited design-system facts** that downstream Phase 3 planners and executors must respect (read-only), plus **minimal probe-page conventions** for the internal test fixtures. It contains NO new design directives.
---
## Design System (INHERITED — DO NOT MODIFY)
The design system is **closed for Phase 3.** Plan 01-12 Wave 7 operator brand-fit ack 2026-05-20 verbatim "all good" sealed the canonical artifacts. Phase 3 planners must NOT introduce new tokens, new fonts, new colors, new copy keys, new icons, new layout primitives, OR new component patterns into the user-facing surface.
| Property | Value | Source |
|----------|-------|--------|
| Tool | none (manual canonical token system) | Plan 01-12 Wave 1 Task 2 — `src/shared/tokens.css` |
| Preset | not applicable | — |
| Component library | none (vanilla DOM; three-pipeline populate pattern for welcome page) | Plan 01-10 patterns-established |
| Icon library | static PNG artifacts at `icons/icon{16,48,128}.png` (8-bit RGBA; Loom mark rasterized from `src/shared/brand/mokosh-mark.svg` via `scripts/rasterize-icons.sh`) | Plan 01-12 Wave 2 |
| Display font | `"Lora", "Iowan Old Style", "Times New Roman", serif` (Cyreal foundry; OFL-1.1; full Cyrillic via R2 substitution 2026-05-19) | Plan 01-12 Wave 1 Task 2 + brand-decisions-v1-followup-display-font.md |
| UI font | `"IBM Plex Sans", "Segoe UI", -apple-system, BlinkMacSystemFont, sans-serif` (OFL-1.1; full Cyrillic) | `src/shared/tokens.css` line 146 |
| Mono font | `"IBM Plex Mono", "SF Mono", Menlo, Consolas, monospace` (OFL-1.1; full Cyrillic) | `src/shared/tokens.css` line 147 |
**Read-only canonical sources:**
- `src/shared/tokens.css` (~355 lines) — single source of truth
- `src/shared/fonts/*.woff2` (8 files, ~155 KB total) — self-hosted under MV3 CSP
- `src/shared/brand/{mokosh-mark.svg,mokosh-lockup.svg}` — canonical brand assets
- `_locales/{en,ru}/messages.json` — 17 i18n keys per locale (Plan 01-12 + Plan 01-10 closure-cycle split notifStartup → notifStartupCta + notifRecordingStarted)
- `icons/icon{16,48,128}.png` — committed static artifacts (NOT regenerated at build time)
---
## Spacing Scale (INHERITED)
Declared values from `src/shared/tokens.css` lines 178-188. Phase 3 must not introduce new spacing values.
| Token | Value | Usage |
|-------|-------|-------|
| `--mks-space-1` | 4px | Icon gaps, inline padding |
| `--mks-space-2` | 8px | Compact element spacing |
| `--mks-space-3` | 12px | (used by component CSS as needed) |
| `--mks-space-4` | 16px | Default element spacing |
| `--mks-space-5` | 20px | (used by component CSS as needed) |
| `--mks-space-6` | 24px | Section padding |
| `--mks-space-8` | 32px | Layout gaps |
| `--mks-space-10` | 40px | (used by component CSS as needed) |
| `--mks-space-12` | 48px | Major section breaks |
| `--mks-space-16` | 64px | Page-level spacing |
| `--mks-space-20` | 80px | (used by component CSS as needed) |
Exceptions: none in Phase 3 (no new component CSS is in scope).
---
## Typography (INHERITED)
Declared values from `src/shared/tokens.css` lines 151-167 + semantic helpers lines 254-333. Phase 3 must not introduce new font sizes or weights.
| Role | Size | Weight | Line Height | Token / class |
|------|------|--------|-------------|---------------|
| Body | 15px | 400 (regular) | 1.5 | `.mks-body` |
| Label (small) | 13px | 400 | 1.5 | `.mks-body-sm` |
| Heading | 17px | 600 (semibold) | 1.3 | `.mks-h3` |
| Heading large | 20px | 600 | 1.3 | `.mks-h2` |
| Heading display | 28px | 400 | 1.15 | `.mks-h1` |
| Display | 40px (or 56px for hero) | 400 | 1.15 | `.mks-display-2` / `.mks-display-1` |
Inherited type scale (full list at `tokens.css` lines 151-158): 11, 13, 15, 17, 20, 28, 40, 56 px. Phase 3 must not add intermediate sizes.
Inherited weights (lines 164-167): 400 regular, 500 medium, 600 semibold, 700 bold.
---
## Color (INHERITED — Loom palette per D-04)
Declared values from `src/shared/tokens.css` lines 89-137. Phase 3 must not introduce new colors.
| Role | Value | Usage |
|------|-------|-------|
| Dominant (60%) | `--mks-linen-50` = #faf7f1 | Page background |
| Surface raised (cards/popup) | `--mks-linen-100` = #f3eee4 | Card / popup surface |
| Secondary (30%) | `--mks-linen-200` = #e8e0d0 | Hairline / divider on linen |
| Foreground primary | `--mks-ink-900` = #181b2a | Primary text, deepest surface |
| Accent (10%) — REC | `--mks-madder-600` = #b2543d | Recording state badge + REC dot only |
| Accent — success | `--mks-moss-600` = #5a7349 | "Готово ✓" SAVE-success state only |
| Accent — warning | `--mks-amber-600` = #c98b3a | Recoverable error / SAVING transient state only |
| Destructive | `--mks-brick-600` = #a23a2b | Unrecoverable error state only |
Accent reserved for: REC badge background; REC pulse-dot; SAVE button primary-CTA fill (madder-700 at hover); SAVING transient (amber-600); DONE transient (moss-600); ERROR (brick-600). Per Plan 01-12 Wave 4 BADGE_REC_COLOR flip from material-green to madder.
Phase 3 must NOT introduce additional accent surfaces. Probe-page fixtures (Section "Test Fixture Conventions" below) MAY remain unstyled.
---
## Copywriting Contract (INHERITED — read-only)
All operator-facing copy is locked. Phase 3 must NOT add operator-facing strings.
| Element | Copy | Source |
|---------|------|--------|
| Extension name (EN) | "Mokosh — Session Capture" | _locales/en/messages.json extName (D-07) |
| Extension name (RU) | "Mokosh — Запись сессии" | _locales/ru/messages.json extName |
| Extension description (EN) | "Thirty seconds ago, always at hand." | _locales/en/messages.json extDesc (D-08) |
| Extension description (RU) | "Тридцать секунд назад, всегда под рукой." | _locales/ru/messages.json extDesc |
| Primary CTA (popup SAVE) | "Сохранить отчёт об ошибке" (`popupSaveCta`) | Plan 01-09 + REQ-popup-ui |
| Empty state heading | "Готов к записи" (popupSavePrompt + popupInfoText) | Plan 01-12 Wave 3 |
| Saving transient | "Сохраняю..." (`popupSaving`) | Plan 01-09 state machine |
| Done transient | "Готово! ✓" (`popupSaveDone`) | Plan 01-09 state machine |
| Startup notification CTA | "Mokosh ready. Click to start a recording." (`notifStartupCta` — split from notifStartup per closure-cycle debug 4bba679) | Plan 01-10 cycle-1 debug fix |
| Recording started notification | (`notifRecordingStarted`) | Plan 01-10 cycle-1 debug fix |
| Recovery notification | (`notifRecovery`) | Plan 01-09 + Plan 01-12 |
| Welcome hero (RU) | "Тридцать секунд назад, всегда под рукой." (`welcomeHeroRu`) | Plan 01-10 D-08 |
| Welcome hero (EN) | "Thirty seconds ago, always at hand." (`welcomeHeroEn`) | Plan 01-10 D-08 |
| Toolbar tooltip (off / rec / err) | `tooltipOff` / `tooltipRecPrefix` / `tooltipErr` | Plan 01-12 Wave 3 |
**Phase 3 may emit VERIFICATION.md operator-instruction copy** (e.g. §10 #9 RAM-ceiling step: "Load extension; idle 5 min; open `chrome://memory-internals`; verify extension background RAM < 50 MB.") — that is documentation copy, not operator-facing UI, and is outside this contract.
**Destructive actions in Phase 3:** none. Phase 3 has no buttons, no confirmations, no UI state. It is a verification-only phase.
---
## Test Fixture Conventions (INTERNAL — Phase 3-scoped)
The five Phase 3 plans (per D-P3-01) extend `tests/uat/extension-page-harness.ts` with new `assertA*` methods (A29+ continuing from Plan 02-04's A24-A28). For rrweb DOM probing per §10 #4 (Plan 03-01) the harness page must include synthetic HTML structures sufficient to exercise rrweb's typical-page coverage.
**Probe HTML composition** (Plan 03-01 planner discretion per 03-CONTEXT.md `<decisions>` "Claude's Discretion" + `<specifics>`):
| Surface | Purpose | Minimum required CSS |
|---------|---------|----------------------|
| `<form>` with text + email + password input + submit button | rrweb input variety + §10 #8 password-filter probe (Plan 03-03) | unstyled OR minimal — fields need to be present in the DOM tree, not styled |
| `<table>` with `<thead>` + `<tbody>` + ≥2 rows | rrweb table rendering (`<tr>` / `<td>` snapshot coverage) | unstyled |
| Modal trigger button + modal `<dialog>` or absolutely-positioned `<div>` | rrweb modal + focus-trap + z-index snapshot coverage | `dialog { z-index: 1000; }` minimum if not using native `<dialog>` |
| 404-target trigger button (for `fetch(...)` → network_error) | §10 #5 event-log trigger (Plan 03-02) | unstyled |
| Error-trigger button (for `throw new Error(...)` → js_error) | §10 #5 event-log trigger (Plan 03-02) | unstyled |
**Probe HTML MUST NOT:**
- Import the canonical `src/shared/tokens.css` (the harness page already imports it for A18/A21 Lora-resolution coverage; the probe sub-tree should appear unstyled to keep rrweb snapshots focused on structural DOM, not on the design system)
- Use the canonical brand `var(--mks-*)` tokens (probe pages are not branded)
- Import any `_locales/*` strings via chrome.i18n (probe pages are not i18n'd; assertion text can be inline English)
- Inject any `data-mokosh-slot` / `data-mokosh-key` / `data-mokosh-i18n-key` attributes (those are reserved for the production welcome page DOM population pipelines per Plan 01-10)
**Probe HTML MAY use** plain `data-test-*` attributes for assertion-side querySelector targeting. This is the established pattern from prior harness fixtures.
**Synthetic password input convention** (Plan 03-03):
```html
<input type="password" id="probe-password" data-test="probe-password" />
```
The harness driver types a sentinel value (e.g. `"secret-do-not-log-123"`) into this input via `page.type`. Plan 03-03 assertion then greps `events.json` parsed from the assembled archive for absence of the sentinel. **Negative-assertion test pattern** — the absence of the sentinel proves the existing `src/content/index.ts:82` `if (target.type === 'password') return;` filter fires. This is the explicit PARTIAL §10 #8 closure per D-P3-02 charter alignment.
**FORBIDDEN_HOOK_STRINGS lockstep** (per Plan 02-04 + Plan 01-12 + Plan 01-13 patterns): the Phase 3 probe pages must NOT introduce new test-mode symbols into the production bundle. A29+ assertions ride existing production surfaces (rrweb's already-shipped wiring, the existing `fetch` interception, etc.) — they are NOT hooks. If a planner finds an A29+ assertion requires a new test-mode symbol, that symbol must be `__MOKOSH_UAT__` Vite-define-token gated AND added to FORBIDDEN_HOOK_STRINGS in `tests/background/no-test-hooks-in-prod-bundle.test.ts`. See Plan 02-04 SUMMARY for the most recent precedent.
---
## Registry Safety
| Registry | Blocks Used | Safety Gate |
|----------|-------------|-------------|
| shadcn official | none — manual canonical token system | not applicable |
| Third-party | none | not applicable |
Phase 3 introduces no third-party UI dependencies. The probe-page composition is hand-authored vanilla HTML inside the existing `tests/uat/` test surface.
---
## Inherited Visual Contracts to Preserve
Phase 3 verification will incidentally exercise these contracts (via existing harness assertions A0-A28 that MUST remain GREEN per 03-CONTEXT.md `<code_context>` Integration Points). Phase 3 must not regress any of them.
| Contract | Source | How Phase 3 preserves it |
|----------|--------|--------------------------|
| MV3 CSP self-host invariant (0 `googleapis` / 0 `https://fonts` in `dist/`) | Plan 01-12 Wave 1 Task 2 + `tests/build/no-remote-fonts.test.ts` | Phase 3 ships no new fonts; pre-checkpoint bundle gate (Plan 03-05) re-verifies |
| en↔ru i18n parity (17 keys × 2 locales) | Plan 01-12 Wave 3 + Plan 01-10 cycle-1 split + `tests/i18n/locale-parity.test.ts` | Phase 3 ships no new locale keys; pre-checkpoint bundle gate (Plan 03-05) re-verifies |
| Icons rendering at 16/48/128 (8-bit RGBA) | Plan 01-12 Wave 2 + `tests/build/icons-present.test.ts` + harness A19 | Phase 3 does not modify icons; A19 remains GREEN |
| `--mks-font-display` resolves to Lora stack | Plan 01-12 Wave 1 Task 2 + harness A21 | Phase 3 does not modify tokens.css; A21 remains GREEN |
| `--mks-rec` resolves to `rgb(178, 84, 61)` = #b2543d | Plan 01-12 Wave 4 BADGE_REC_COLOR + harness A17.7 | Phase 3 does not modify palette; A17.7 remains GREEN |
| BADGE_REC_COLOR madder + 3-state state machine | Plan 01-09 + Plan 01-12 Wave 4 | Phase 3 makes no badge changes |
| Welcome page first-install activation (onInstalled('install') + storage flag + tabs.create) | Plan 01-10 Wave 2 helper + harness A15/A16/A17 | Phase 3 makes no onboarding changes |
---
## Checker Sign-Off
This UI-SPEC is a **null-spec** for Phase 3 — it confirms the absence of in-scope UI surface and freezes inherited Phase 1 design facts as read-only. The 6 design quality dimensions are evaluated against the inherited surface, not against any new Phase 3 work.
- [x] Dimension 1 Copywriting: PASS (inherited; 17-key matrix locked; Phase 3 emits no new operator copy)
- [x] Dimension 2 Visuals: PASS (inherited; canonical brand artifacts unchanged; probe-page convention bans new visual surface)
- [x] Dimension 3 Color: PASS (inherited; Loom palette locked at `src/shared/tokens.css`; no new colors)
- [x] Dimension 4 Typography: PASS (inherited; 3 families × declared sizes/weights locked; no new sizes)
- [x] Dimension 5 Spacing: PASS (inherited; `--mks-space-*` scale locked; 4px base preserved)
- [x] Dimension 6 Registry Safety: PASS (no shadcn use; no third-party registry; vanilla DOM only)
**Approval:** pending checker review (draft status)
---
## Notes for Downstream Phase 3 Agents
**Planner (`gsd-planner`):** Phase 3 plans should NOT include any UI design tasks. Plans 03-01 through 03-05 are all verification (harness assertions + VERIFICATION.md aggregation) per D-P3-01. The probe-page HTML composition is internal harness work and falls under the "Test Fixture Conventions" section above.
**Executor (`gsd-executor`):** When extending `tests/uat/extension-page-harness.ts` or `tests/uat/extension-page-harness.html`, treat the existing canonical `<link rel="stylesheet" href="../../src/shared/tokens.css">` import as load-bearing (harness assertions A18 + A21 depend on it). Add probe HTML below the existing harness scaffold; do not strip the tokens.css link.
**UI auditor (if spawned):** Phase 3 has no user-facing surface to audit. Run audit against Phase 1 + Phase 2 surfaces (popup + welcome page + badges + notifications + manifest + icons) if a regression sweep is desired.
**Ceremony note:** If during execution the planner discovers Phase 3 needs operator-facing UI work (e.g. a new VERIFICATION.md operator instruction is genuinely UI-mediated), route through `/gsd-debug` or `/gsd-discuss-phase` per `feedback-gsd-ceremony-for-fixes.md`. Do not hot-edit this UI-SPEC or the canonical design system.