ambek .planning
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
# Phase 1: Design Tokens + Rams Foundation - Context
|
||||
|
||||
**Gathered:** 2026-10-22
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## Phase Boundary
|
||||
|
||||
Distill the Telemetry Rams design system into a single centralized, importable token package — including a Rams-styled MapLibre basemap derived from OpenFreeMap `liberty` — proven with a rendered component sheet and a user-approved mockup-vs-implementation side-by-side gallery, before any product screen is built. Ends the inline-Tailwind-duplication and design-source conflict. Bot, Mini App shell, search, and routing are separate phases; this phase builds no product screens.
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## Implementation Decisions
|
||||
|
||||
### Token package format
|
||||
- **D-01:** Tailwind v4 CSS-first package: tokens declared as CSS custom properties plus the `@theme` directive. No v3-style JS config. CSS variables double as the consumption path for MapLibre basemap styles and later phases.
|
||||
- **D-02:** Token naming mirrors the mockup vocabulary verbatim (~40-token Material-style scale: `signal-orange`, `matte-black`, `space-md`, `display-lg`, ...) so mockup-derived markup maps 1:1 and fidelity comparison stays direct.
|
||||
- **D-03:** The token package ships together with a rendered component sheet that consumes it — the sheet itself proves token completeness (DSGN-01's "every rendered component derives from tokens" is demonstrated, not asserted).
|
||||
- **D-04:** Pre-slot the dual Telegram light/dark theme boundary now (themeable shell surfaces as token slots), while map cartography stays Rams-constant. Phase 3 (PX-02) then maps two background values onto slots instead of restructuring tokens.
|
||||
|
||||
### Source-of-truth resolution
|
||||
- **D-05:** Root `DESIGN.md` is superseded for specifics: keep it as Rams philosophy prose with a header banner pointing to the token package. `telemetry_rams/DESIGN.md` content (the mockup-matching system) flows into the package; the losing typography claim (Helvetica/Inter + 5 colors) is explicitly marked superseded.
|
||||
- **D-06:** The four mockup `code.html` files stay untouched, read-only generated reference artifacts (fine as-is per CONCERNS.md). Their inline `tailwind.config` blocks are superseded but NOT edited. Fidelity comparison targets rendered output, not markup.
|
||||
- **D-07:** The token package owns all numeric values (hex, px, rgba, font sizes). Design docs describe principles and link to the package; docs never restate hex codes or dimensions — the drift that caused the conflict cannot recur.
|
||||
|
||||
### Basemap styling depth
|
||||
- **D-08:** Full Rams pass on the OpenFreeMap `liberty` fork in this phase: grayscale/muted land + water grounding, desaturated roads, muted label styling; `signal-orange` accent reserved exclusively for the route line (rendered in Phase 5). Orange remains navigation-only semantics.
|
||||
- **D-09:** Basemap colors are derived from the token package (values read/synced from the package), not hand-tuned in the style JSON — honoring DSGN-01's "map cartography follows the same tokens". Exact derivation mechanism (generation script vs synced values file) is planner/researcher's choice.
|
||||
- **D-10:** Map labels adopt Rams typography (Space Grotesk / Geist), coherent with the HUD, using the same font assets.
|
||||
|
||||
### Component sheet + gallery
|
||||
- **D-11:** Component sheet scope is mockup-derived: everything the 4 mockup screens actually show — buttons, cards, chips/badges, the maneuver banner, inputs, and a typography specimen. No invention of unseen components.
|
||||
- **D-12:** The approval gallery is a static side-by-side HTML page: rendered implementation components against the four mockup screens' renders, token-by-token. This page is the DSGN-02 mechanism template — every later UI phase extends the same pattern.
|
||||
- **D-13:** DSGN-01's audit sweep is automated: a script that scans rendered CSS/classes and flags any color/spacing/typography/radius value not in the token set. "Zero off-token values" is evidence, not eyeball claim.
|
||||
- **D-14:** Gallery renders are produced with Playwright real-browser screenshots (script committed for reuse by later UI phases under the design-taste-frontend skill's real-browser inspection rule).
|
||||
|
||||
### Build pipeline
|
||||
- **D-15:** Minimal `package.json` + Tailwind v4 CLI and npm scripts; design gallery/sheet + basemap style packaged in one design folder consumed by later phases. No app framework scaffold — the Mini App shell shape is decided in Phase 3.
|
||||
- **D-16:** Self-host Geist + Space Grotesk woff2 in the repo as part of the token package; Google Fonts CDN links are removed going forward (may remain in mockups).
|
||||
- **D-17:** Local npm scripts only (build / gallery / audit) in Phase 1; CI workflows come with Phase 2's deploy pipeline. Keep tooling minimal.
|
||||
|
||||
### OpenCode's Discretion
|
||||
- Exact derivation/refresh mechanism basemap ← tokens (script vs synced file)
|
||||
- Gallery page file layout within the design folder
|
||||
- Audit script implementation details and threshold handling
|
||||
- Icon strategy details within the sheet (Material Symbols vs inline SVG usage observed in mockups)
|
||||
|
||||
</decisions>
|
||||
|
||||
<specifics>
|
||||
## Specific Ideas
|
||||
|
||||
- "Map cartography stays Rams-constant" — the map background must look identical under Telegram light and dark themes; only shell surfaces re-theme.
|
||||
- Mockup screens are the spec — the gallery side-by-side against their rendered output is the fidelity bar.
|
||||
- Scope creep avoided by design: motion/animation polish, incident components (reporter screen's modal flow) render only as static sheet entries where the mockups show them; full interactive flows belong to later phases.
|
||||
|
||||
</specifics>
|
||||
|
||||
<canonical_refs>
|
||||
## Canonical References
|
||||
|
||||
**Downstream agents MUST read these before planning or implementing.**
|
||||
|
||||
### Design system (binding)
|
||||
- `stitch_minimalist_route_navigator/telemetry_rams/DESIGN.md` — canonical token vocabulary, component rules, zero-radius / no-blur constraints
|
||||
- `DESIGN.md` — Rams philosophy (kept for principles; its typography/palette specifics are superseded per D-05)
|
||||
- `stitch_minimalist_route_navigator/active_route_guidance/code.html` — markup/layout reference (read-only) for maneuver banner and incident telemetry band
|
||||
- `stitch_minimalist_route_navigator/navigate_map_overview/code.html` — layout reference for map screen + layer controls
|
||||
- `stitch_minimalist_route_navigator/community_incident_reporter/code.html` — layout reference for incident card components
|
||||
- `stitch_minimalist_route_navigator/telegram_live_traffic_feed/code.html` — layout reference for chip/badge components
|
||||
|
||||
### Planning inputs
|
||||
- `.planning/ROADMAP.md` §Phase 1 — goal, success criteria, notes (repo hygiene, skill usage, no research phase)
|
||||
- `.planning/REQUIREMENTS.md` — DSGN-01, DSGN-02 (this phase's requirements)
|
||||
- `.planning/codebase/CONCERNS.md` — Zone.Identifier debt, design-source conflict, mockup fragility (Phase 1 resolves these)
|
||||
- `.planning/codebase/STACK.md` — token duplication, Play-CDN caveat, design constraints
|
||||
- `.agents/skills/design-taste-frontend/SKILL.md` — applies in existing-brand special case: keep Rams palette/type/dashboard house rules; real-browser inspection for the gallery artifact
|
||||
|
||||
</canonical_refs>
|
||||
|
||||
<code_context>
|
||||
## Existing Code Insights
|
||||
|
||||
### Reusable Assets
|
||||
- Inline `tailwind.config` block in each `code.html` — byte-identical token source to extract into the v4 package (matches `telemetry_rams/DESIGN.md:2-148`)
|
||||
- Mockup `<screen>/code.html` + `<screen>/screen.png` pairs — ready-made inputs for the side-by-side gallery
|
||||
- SVG patterns in mockups (route vectors, `stroke-linecap="square"`, 2px strokes) — reuse for sheet icon components
|
||||
|
||||
### Established Patterns
|
||||
- kebab-case token/class names (`bg-matte-black`, `text-signal-orange`) — carry into the v4 package
|
||||
- 8px baseline grid, 4px/8px multiples for every dimension
|
||||
- Uppercase labels with expanded tracking; Material Symbols Outlined iconography
|
||||
- Color semantics: orange = navigation/primary, red = hazards/errors, green = police-only (per mockups); keep strict
|
||||
|
||||
### Integration Points
|
||||
- The token package is consumed by: the rendered sheet + gallery (Phase 1), the Mini App shell (Phase 3), every UI phase's Tailwind build
|
||||
- The basemap style JSON becomes the MapLibre style loaded by Phase 3/5/6's map views
|
||||
- Playwright capture script becomes the DSGN-02 gallery evidence toolchain for all UI phases
|
||||
|
||||
</code_context>
|
||||
|
||||
<deferred>
|
||||
## Deferred Ideas
|
||||
|
||||
- Interactive mockup/implementation compare tool — a static page suffices for v1; revisit if gallery review becomes painful
|
||||
- Full incident-report interaction flows — Phase 1 renders reporter-screen components statically only; the privacy boundaries of incident reporting ship post-v1 (v2 cluster REP-01/02, per REQUIREMENTS.md)
|
||||
- CI workflow for gallery + audit — deferred to Phase 2 deploy pipeline (D-17)
|
||||
|
||||
None — discussion stayed within phase scope.
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 01-design-tokens-rams-foundation*
|
||||
*Context gathered: 2026-10-22*
|
||||
@@ -0,0 +1,57 @@
|
||||
# Phase 1: Design Tokens + Rams Foundation - Discussion Log
|
||||
|
||||
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||
> Decisions captured in CONTEXT.md — this log preserves the analysis.
|
||||
|
||||
**Date:** 2026-10-22
|
||||
**Phase:** 01-design-tokens-rams-foundation
|
||||
**Mode:** default (interactive)
|
||||
|
||||
## Areas Discussed
|
||||
|
||||
### Token package format
|
||||
| Question | Options presented | Selection |
|
||||
|---|---|---|
|
||||
| Package form | Tailwind v4 @theme / v3 JS config / plain CSS vars + adapter | Tailwind v4 CSS-first (@theme) |
|
||||
| Naming | Mirror mockup names / semantic rename / you decide | Mirror mockup names |
|
||||
| Bare tokens vs tokens + rendered sheet | Tokens + sheet / tokens only / you decide | Tokens + rendered sheet |
|
||||
| Telegram light/dark pre-planning | Pre-slot dual theme / defer to Phase 3 / you decide | Pre-slot dual theme |
|
||||
|
||||
### Source-of-truth resolution
|
||||
| Question | Options presented | Selection |
|
||||
|---|---|---|
|
||||
| Root DESIGN.md conflict | Supersede + keep philosophy / merge + rewrite / archive | Supersede, keep philosophy |
|
||||
| Fate of mockups + inline Tailwind blocks | Stay read-only / migrate mockups / you decide | Mockups stay read-only |
|
||||
| Owner of numeric values | Package owns / docs own / you decide | Package owns values |
|
||||
|
||||
### Basemap styling depth
|
||||
| Question | Options presented | Selection |
|
||||
|---|---|---|
|
||||
| Rams-ification depth | Full Rams pass / grayscale only / iterate in gallery | Full Rams pass |
|
||||
| Color sourcing | Derived from tokens / fork + hand-tune / you decide | Derived from tokens |
|
||||
| Label typography | Rams fonts / stock / compare in gallery | Rams fonts in labels |
|
||||
|
||||
### Component sheet + gallery scope
|
||||
| Question | Options presented | Selection |
|
||||
|---|---|---|
|
||||
| Sheet components | Mockup-derived set / core primitives / you decide | Mockup-derived set |
|
||||
| Gallery form | Static side-by-side / interactive tool / you decide | Static side-by-side page |
|
||||
| DSGN-01 audit | Automated / manual / you decide | Automated token audit |
|
||||
| Render production | Playwright / manual captures / you decide | Playwright screenshots |
|
||||
|
||||
### Build pipeline choice
|
||||
| Question | Options presented | Selection |
|
||||
|---|---|---|
|
||||
| Phase 1 tooling | Minimal npm + v4 CLI / full framework / CSS only | Minimal npm + v4 CLI |
|
||||
| Fonts | Self-host woff2 / keep Google Fonts CDN / you decide | Self-host fonts |
|
||||
| CI scope | Local scripts / CI day one / you decide | Local scripts first |
|
||||
|
||||
## Corrections Made
|
||||
|
||||
No corrections — user accepted recommended options throughout.
|
||||
|
||||
## Deferred Ideas
|
||||
|
||||
- Interactive compare tool (revisit if gallery review painful)
|
||||
- Incident-report interaction flows (v2: REP-01/02)
|
||||
- CI workflow (Phase 2)
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
phase: 01-design-tokens-rams-foundation
|
||||
fixed_at: 2026-10-22T02:05:00Z
|
||||
review_path: .planning/phases/01-design-tokens-rams-foundation/01-REVIEW.md
|
||||
iteration: 1
|
||||
findings_in_scope: 6
|
||||
fixed: 6
|
||||
skipped: 0
|
||||
status: all_fixed
|
||||
---
|
||||
|
||||
# Phase 1: Code Review Fix Report
|
||||
|
||||
**Fixed at:** 2026-10-22T02:05:00Z
|
||||
**Source review:** `.planning/phases/01-design-tokens-rams-foundation/01-REVIEW.md`
|
||||
**Iteration:** 1
|
||||
|
||||
**Summary:**
|
||||
- Findings in scope: 6 (BLOCKER CR-01 + WR-01..WR-05; INFO findings out of scope per orchestrator)
|
||||
- Fixed: 6
|
||||
- Skipped: 0
|
||||
|
||||
**Note on provenance:** a prior fixer run applied all six fixes as atomic commits (61d15c2…43b7d99)
|
||||
but terminated before writing this report. This pass *independently re-verified* each committed fix
|
||||
(diffs audited against the review's prescribed mechanism, all four verification gates re-run
|
||||
empirically, see Verification section) — no fixes were re-applied; master was already clean.
|
||||
|
||||
## Fixed Issues
|
||||
|
||||
### CR-01: Dead `--radius-DEFAULT` token — bare `rounded` compiles to `0.25rem` (BLOCKER)
|
||||
|
||||
**Commit:** `61d15c2`
|
||||
**Files modified:** `theme/src/tokens.css`, `theme/scripts/audit.mjs`, `theme/scripts/audit.test.mjs`
|
||||
**Applied fix:** Replaced the inert v3-style `--radius-DEFAULT: 0px` with the deprecated bare
|
||||
`--radius: 0px` — the key Tailwind v4.3.3 actually drives the bare `rounded` utility from
|
||||
(`node_modules/tailwindcss/theme.css` "Deprecated" block). Block comment corrected (bare
|
||||
`rounded` is now var-driven; `rounded-none`/`rounded-full` are literal built-ins; the DEFAULT
|
||||
sub-key must not reappear). Audit radius drift guard extended to `/--radius(?:-[A-Za-z0-9-]*)?…/`
|
||||
so a future non-zero bare key trips exit 2. Regression tests T9 added: bare-key presence,
|
||||
inert-DEFAULT absence, non-zero bare key → exit 2, and a controlled build asserting
|
||||
`.rounded` compiles to `var(--radius)` with `--radius: 0px` emitted by `@theme static`.
|
||||
|
||||
### WR-01: Prose candidate leakage compiles Rams-forbidden `.shadow`/`.blur` into the shipped stylesheet
|
||||
|
||||
**Commit:** `689bc9f`
|
||||
**Files modified:** `theme/src/theme.css`, `theme/src/tokens.css`, `theme/scripts/audit.test.mjs`
|
||||
**Applied fix:** (1) `@source` narrowed from the whole mockup tree to the four mockup markup
|
||||
files, plus `@source not "../scripts"` / `@source not "../basemap"` so toolchain prose can never
|
||||
mint utility classes. (2) Defense in depth at the key: the deprecated bare `--shadow`,
|
||||
`--shadow-inner`, `--drop-shadow`, `--blur` namespaces are set to `initial` in `@theme static`,
|
||||
so bare shadow/blur utilities can never compile from any candidate source (scale keys remain —
|
||||
mockup-worn `shadow-*` classes still compile and stay under adjudication 1). T5 regression
|
||||
checks added: no `.shadow{` / `.blur{` in `dist/rams.css`, no `border-radius:.25rem` anywhere
|
||||
in dist.
|
||||
|
||||
### WR-02: `familiesFromShorthand` logic bug — off-token families in `font:` shorthands pass unflagged
|
||||
|
||||
**Commit:** `5e95741`
|
||||
**Files modified:** `theme/scripts/audit.mjs`, `theme/scripts/audit.test.mjs`
|
||||
**Applied fix:** Two-layers, contract-true: (1) any literal (non-`var()`) `font:` shorthand is
|
||||
flagged outright with the convention message (`font: var(--type-*)`), naming the extracted
|
||||
families; `var()` shorthands pass. (2) `familiesFromShorthand` itself repaired — iteratively
|
||||
strips the leading style/variant/weight keyword run (any CSS-grammar order, incl. oblique
|
||||
angles), then the size[/line-height] component (incl. `calc()`), per comma group, so the family
|
||||
is genuinely extracted for the message instead of being silently dropped by the old
|
||||
single-strip + numeric-filter bug. T10 regression tests: literal shorthand → exit 1, Arial
|
||||
extracted, sanctioned-family shorthand still flagged, `var()` shorthand passes.
|
||||
|
||||
### WR-03: Color-evasion gaps — named keywords, modern color functions, `text-shadow` all pass
|
||||
|
||||
**Commit:** `ee48e76`
|
||||
**Files modified:** `theme/scripts/audit.mjs`, `theme/scripts/audit.test.mjs`
|
||||
**Applied fix:** (1) Full CSS Color keyword list (`NAMED_COLORS`, ~148 entries) flagged on the
|
||||
color-bearing property set (`COLORISH_PROPS` incl. shorthands, fill/stroke, borders,
|
||||
text-decoration, accent-color); `currentcolor`/`transparent` and css-wide keywords stay
|
||||
sanctioned. (2) Modern color functions — `oklch()/oklab()/lab()/lch()/hwb()/color()/color-mix()`
|
||||
— flagged on any property unless the value is `var()`-bearing (Tailwind's own `color-mix`
|
||||
emissions are var-driven and pass). (3) `text-shadow` added to `shadowViolations`: any
|
||||
non-none value forbidden (Rams Shapes). T11 regression tests: `color: red`, `oklch(...)`,
|
||||
`color(display-p3 ...)`, non-hex `text-shadow` all exit 1 and are listed; sanctioned keywords
|
||||
pass. Audit header (§5) updated to document the extended surface.
|
||||
|
||||
### WR-04: D-13 contract shortfall — spacing and typography numerics not audited
|
||||
|
||||
**Commit:** `5e254cb`
|
||||
**Files modified:** `theme/scripts/audit.mjs`, `theme/gallery.html`
|
||||
**Applied fix:** Implemented the missing checks rather than amending the claim. (1) Spacing:
|
||||
`padding`/`margin`/`gap` families (logical variants included) — literals must equal a
|
||||
`--spacing-*` token value, be zero, or `auto`; dimensional geometry (width/height, offsets,
|
||||
border widths, the 18×18 checkbox) is spec-per-components-header and out of scope
|
||||
(adjudication 6). (2) Typography: `font-size`/`font-weight`/`line-height`/`letter-spacing`
|
||||
validated against the `--type-*` scale, parsed from the compound token grammar (`weight
|
||||
size/line-height family…` + `-tracking` companions); `normal`/`bold` keyword equivalents
|
||||
sanctioned; `@font-face` blocks exempt from numeric scale as asset metadata (D-16) but still
|
||||
color/family-checked (adjudication 7). `npm run audit` output now reports
|
||||
"6 spacing values / 10 type sizes / 9 trackings". Gallery D-13 evidence wording updated to
|
||||
"colors, spacing, typography, radius, shadows, blur". T12 regression tests: off-scale
|
||||
numerics (`padding: 13px`, `font-size: 17px`, weight 650, tracking) → exit 1 and listed;
|
||||
token-value literals (1rem, 0.25rem, 14px, 700, 20px, -0.04em), zero/auto, and font-face
|
||||
metadata pass.
|
||||
|
||||
### WR-05: Static server path guard uses prefix match without separator
|
||||
|
||||
**Commit:** `43b7d99`
|
||||
**Files modified:** `theme/scripts/screenshot.mjs`
|
||||
**Applied fix:** `sep` imported from `node:path`; guard changed to
|
||||
`if (target !== THEME && !target.startsWith(THEME + sep))` — the docroot prefix must end at a
|
||||
path separator, so a decoded `..%2FthemeX` (which joins to a `themeX`-sibling path passing the
|
||||
old bare `startsWith(THEME)`) now 403s.
|
||||
|
||||
## Skipped Issues
|
||||
|
||||
None — all six in-scope findings fixed and verified.
|
||||
|
||||
## Verification (all four gates, empirically re-run in this pass)
|
||||
|
||||
1. **Build radius gate** — `npm run build --workspace theme`; `grep -o 'border-radius:[^;}]*' theme/dist/rams.css | sort -u` →
|
||||
`border-radius:0`, `border-radius:var(--radius)`, `border-radius:3.40282e38px`
|
||||
(the sanctioned `rounded-full` ≥1e30px literal clamp). **No `.25rem` / non-token radius forms.**
|
||||
`.rounded` compiles to `border-radius:var(--radius)` with `--radius:0px` emitted by `@theme static`. ✅
|
||||
2. **Audit gate** — `npm run audit` (repo root) →
|
||||
`AUDIT CLEAN — 354 declarations checked … — 0 off-token values. token sheet: 55 colors / 9 radius
|
||||
tokens (all zero) / 7 sanctioned font families / 6 spacing values / 10 type sizes / 9 trackings`. ✅
|
||||
3. **Test suite** — `node theme/scripts/audit.test.mjs` → **38 passed, 0 failed**
|
||||
(was 16/16 pre-fix; now includes T9 CR-01, T10 WR-02, T11 WR-03, T12 WR-04, extended T5 WR-01). ✅
|
||||
4. **Screenshot server guard (live probe)** — server started under the real capture run
|
||||
(`node theme/scripts/screenshot.mjs`, listener located by PID), probed with `curl --path-as-is`:
|
||||
- `/..%2FthemeX/secret` → **403 forbidden** (the exact WR-05 exploit shape: a `themeX` sibling
|
||||
that the old bare prefix check passed)
|
||||
- `/..%2FthemeX/gallery.html` → **403**
|
||||
- `/..%2Fstitch_minimalist_route_navigator/…` → **403**
|
||||
- `/src/sheet.html` → 200 (correct content — no over-blocking)
|
||||
- `/gallery.html` → 200 — ✅
|
||||
(Method note: a first probe port grab had hit Chromium's own devtools listener — PID-matched
|
||||
listener selection fixed that; the guard result above is from the real capture server.)
|
||||
Bonus: full capture run completed `CAPTURE OK — 6/6` non-blank captures.
|
||||
|
||||
Also verified byte-for-byte: deep diff audit of all six fix commits against the REVIEW.md
|
||||
prescribed fix shapes (`git show 61d15c2 689bc9f 5e95741 ee48e76 5e254cb 43b7d99`) — mechanisms
|
||||
are real (key-level token disarmament, regex/grammar repair, parser extension, guard change),
|
||||
not cosmetic suppressions; per CR-01 guidance the elimination of the banned utility is the
|
||||
intended goal, so post-fix compiled output genuinely lacks `.rounded`/`.shadow`/`.blur`
|
||||
non-zero/off-token forms.
|
||||
|
||||
---
|
||||
|
||||
_Fixed: 2026-10-22T02:05:00Z_
|
||||
_Fixer: OpenCode (gsd-code-fixer)_
|
||||
_Iteration: 1_
|
||||
@@ -0,0 +1,312 @@
|
||||
---
|
||||
phase: 01-design-tokens-rams-foundation
|
||||
reviewed: 2026-10-22T01:08:55Z
|
||||
depth: standard
|
||||
files_reviewed: 13
|
||||
files_reviewed_list:
|
||||
- package.json
|
||||
- theme/package.json
|
||||
- theme/src/tokens.css
|
||||
- theme/src/theme.css
|
||||
- theme/src/components.css
|
||||
- theme/src/sheet.html
|
||||
- theme/basemap/build.mjs
|
||||
- theme/basemap/liberty-rams.json
|
||||
- theme/basemap/index.html
|
||||
- theme/scripts/audit.mjs
|
||||
- theme/scripts/audit.test.mjs
|
||||
- theme/scripts/screenshot.mjs
|
||||
- theme/gallery.html
|
||||
findings:
|
||||
critical: 1
|
||||
warning: 5
|
||||
info: 7
|
||||
total: 13
|
||||
status: issues_found
|
||||
---
|
||||
|
||||
# Phase 1: Code Review Report
|
||||
|
||||
**Reviewed:** 2026-10-22T01:08:55Z
|
||||
**Depth:** standard (with empirical verification: controlled Tailwind builds, live audit runs, test-suite execution, machine verification of the 6,089-line generated `liberty-rams.json`)
|
||||
**Files Reviewed:** 13
|
||||
**Status:** issues_found
|
||||
|
||||
## Summary
|
||||
|
||||
The phase delivers a genuinely well-engineered token package: `npm run audit` exits 0 on the
|
||||
real build (354 declarations checked), the TDD suite passes 16/16, all 7 self-hosted woff2
|
||||
files exist and are wired correctly (no CDN fonts), the compiled `dist/rams.css` emits the
|
||||
`--color-*`/`--spacing-*`/`--type-*` tokens plus the D-04 shell slots with the dark-scheme
|
||||
media query, and `liberty-rams.json` was machine-verified clean (no accent hex/rgb forms, no
|
||||
`line-gradient`, no `icon-color`, no non-zero halo blur, only opacity ramps preserved,
|
||||
font substitutions honestly recorded in `metadata`).
|
||||
|
||||
However, the adversarial pass found one blocker in the foundation deliverable itself, plus a
|
||||
cluster of audit-gate holes proven by end-to-end evasion tests:
|
||||
|
||||
1. **BLOCKER (CR-01):** `--radius-DEFAULT: 0px` is a dead token in Tailwind v4.3.3 — the bare
|
||||
`rounded` utility is driven by the deprecated `--radius` key, not `--radius-DEFAULT`. The
|
||||
shipped `theme/dist/rams.css` therefore contains `.rounded{border-radius:.25rem}` — a
|
||||
non-zero radius value owned by **no token**, violating the binding zero-roundness
|
||||
constraint, D-07 ("the token package owns all numeric values"), and the tokens.css comment
|
||||
that asserts "every token-driven rounded-* utility compiles to 0".
|
||||
2. **Vocabulary leakage (WR-01):** `.shadow{…}` and `.blur{…}` (Rams-forbidden constructs,
|
||||
with off-token values `#0000001a` / `blur(8px)` baked in) compile into the shipped
|
||||
stylesheet from **prose**, not from any mockup class attribute — so audit adjudication 1's
|
||||
rationale ("utilities the mockups wear") does not even cover them.
|
||||
3. **Audit-gate holes (WR-02/03/04):** proven evasions — `font: 700 14px/18px Arial` passes
|
||||
unflagged (logic bug in `familiesFromShorthand`), as do `color: red`, `oklch(...)`,
|
||||
`color(display-p3 …)`, non-hex `text-shadow`, and all spacing/type-scale numerics
|
||||
(`padding: 13px`, `font-size: 17px`), contradicting the tool's own coverage claims and
|
||||
D-13's stated contract.
|
||||
|
||||
None of these are caught by the current green gates, which is exactly why they need fixing
|
||||
before later phases consume the package.
|
||||
|
||||
## Critical Issues
|
||||
|
||||
### CR-01: Dead `--radius-DEFAULT` token — bare `rounded` compiles to `0.25rem`, violating the binding zero-roundness constraint (BLOCKER)
|
||||
|
||||
**File:** `theme/src/tokens.css:98-109` (token), `theme/src/theme.css:13-15` (build entry); evidence in compiled `theme/dist/rams.css` (minified, line 2): `.rounded{border-radius:.25rem}`
|
||||
**Issue:** The radius block sets `--radius-DEFAULT: 0px` intending to zero the bare `rounded`
|
||||
utility (v3-style `DEFAULT` key), but Tailwind v4.3.3 does **not** read `--radius-DEFAULT` for
|
||||
that utility — the bare `rounded` is driven by the deprecated `--radius` key (see
|
||||
`node_modules/tailwindcss/theme.css:508`, `@theme default inline reference { --radius: 0.25rem; }`).
|
||||
Empirically verified with controlled builds against the repo's own Tailwind 4.3.3:
|
||||
|
||||
- `@theme { --radius-DEFAULT: 0px; }` → `.rounded { border-radius: 0.25rem; }` (token ignored)
|
||||
- `@theme { --radius: 0px; }` → `.rounded { border-radius: var(--radius); }` (correct override)
|
||||
|
||||
Consequences:
|
||||
- The shipped `dist/rams.css` contains `.rounded{border-radius:.25rem}` — a numeric value
|
||||
owned by no token, in the phase deliverable whose thesis is D-07 ("the token package owns
|
||||
all numeric values") and the "zero off-token values" evidence claim.
|
||||
- The tokens.css comment (lines 98-101) is factually wrong: it carves out only
|
||||
`rounded-none`/`rounded-full` as literal built-ins and asserts every other token-driven
|
||||
`rounded-*` compiles to 0. Bare `rounded` compiles to `0.25rem` with the current token set.
|
||||
- Any later phase wearing `rounded` (a Tailwind-default habit; the class *is* in the compiled
|
||||
vocabulary) silently gets 4px corners. The audit does flag it once worn (verified with a
|
||||
fixture page: `theme/dist/rams.css:2: .rounded { border-radius: .25rem } — non-zero
|
||||
border-radius`), but the package is supposed to prevent, not be caught by, its own gate.
|
||||
- The audit's radius drift-guard (`theme/scripts/audit.mjs:173`,
|
||||
`/--radius-[A-Za-z0-9-]*\s*:\s*(…)/`) only matches `--radius-*` with a dash, so a future
|
||||
bare `--radius` override escapes the drift guard entirely; `radiusAllowed()`
|
||||
(`audit.mjs:409`) also passes any `var()` unconditionally.
|
||||
|
||||
**Fix:**
|
||||
```css
|
||||
/* theme/src/tokens.css — @theme static radius block */
|
||||
@theme static {
|
||||
--radius: 0px; /* v4's deprecated bare key — THE key that drives the bare `rounded` utility */
|
||||
--radius-xs: 0px; /* …rest unchanged… */
|
||||
}
|
||||
```
|
||||
Delete `--radius-DEFAULT: 0px;` (inert in v4) or keep it only with a comment marking it
|
||||
inert; correct the block comment to state that `rounded`/`rounded-none`/`rounded-full` are
|
||||
literal built-ins and that `--radius` must be overridden explicitly. Rebuild and confirm
|
||||
`.rounded{border-radius:0px}` in `dist/rams.css`. Extend the audit drift-guard:
|
||||
|
||||
```js
|
||||
/* audit.mjs — cover the deprecated bare key too */
|
||||
for (const m of text.matchAll(/--radius(?:-[A-Za-z0-9-]*)?\s*:\s*([^;}]+?)\s*;/g)) { … }
|
||||
```
|
||||
|
||||
## Warnings
|
||||
|
||||
### WR-01: Prose candidate leakage compiles Rams-forbidden `.shadow`/`.blur` utilities into the shipped stylesheet
|
||||
|
||||
**File:** `theme/src/theme.css:24` (`@source "../../stitch_minimalist_route_navigator"`), plus the CLI's implicit auto-scan of `theme/`
|
||||
**Issue:** `@source` points at the whole mockup tree — including `telemetry_rams/DESIGN.md`
|
||||
prose — and the CLI auto-scan ingests the toolchain's own text (e.g. `scripts/audit.mjs:36`
|
||||
prose "shadow/backdrop-blur/bg-black"). Tailwind extracts class candidates from natural
|
||||
language. Result in `dist/rams.css` (all verified present, none worn by any mockup class
|
||||
attribute or implementation page):
|
||||
|
||||
- `.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a)…box-shadow:…}` — bare `shadow` is worn by **no** mockup (mockups wear `shadow-md`/`shadow-sm`/`shadow-[…]` only)
|
||||
- `.blur{--tw-blur:blur(8px);…}` — bare `blur` likewise unworn anywhere
|
||||
- `.rounded` (see CR-01) entered the vocabulary the same way (e.g. `telemetry_rams/DESIGN.md:155` "devoid of rounded ornament")
|
||||
|
||||
These carry off-token values (`#0000001a`, `8px`) into the artifact, and audit adjudication 1
|
||||
("utilities the mockups wear but the design doc rejects") does not cover them — they are not
|
||||
mockup-worn at all. The audit skips them only because no page harvests those classes, so the
|
||||
"zero off-token values" evidence holds by accident of non-usage.
|
||||
**Fix:** Scope `@source` to the four mockup markup files and exclude tooling prose from the
|
||||
auto-scan:
|
||||
```css
|
||||
@source "../../stitch_minimalist_route_navigator/active_route_guidance/code.html";
|
||||
@source "../../stitch_minimalist_route_navigator/navigate_map_overview/code.html";
|
||||
@source "../../stitch_minimalist_route_navigator/community_incident_reporter/code.html";
|
||||
@source "../../stitch_minimalist_route_navigator/telegram_live_traffic_feed/code.html";
|
||||
@source not "../scripts";
|
||||
@source not "../basemap";
|
||||
```
|
||||
After the fix, `.rounded`/`.shadow`/`.blur` should disappear from `dist/rams.css` (verify by
|
||||
grep); only mockup-worn classes remain in the compiled vocabulary.
|
||||
|
||||
### WR-02: `familiesFromShorthand` logic bug — off-token families in `font:` shorthands pass the audit unflagged
|
||||
|
||||
**File:** `theme/scripts/audit.mjs:449-455` (helper), consumed at `audit.mjs:439-441`
|
||||
**Issue:** The strip regex removes only the **first** shorthand token:
|
||||
`'700 14px/18px Arial'` → strips `'700 '` → leaves `'14px/18px Arial'`, which the
|
||||
`/^[0-9.]/` filter then drops as "numeric" — so the family list comes out empty and **no
|
||||
`font:` shorthand can ever be flagged**, regardless of family. Verified end-to-end:
|
||||
`.a-font-shorthand { font: 700 14px/18px Arial; }` produces zero violations (Arial is
|
||||
off-token and should be flagged per the T2 contract). The test suite only covers the
|
||||
`font-family:` longhand, so the hole is untested. The package's own convention is
|
||||
`font: var(--type-*)` everywhere, so nothing currently trips it — but the gate's contract
|
||||
(T2: "off-token font → flagged") is silently incomplete.
|
||||
**Fix:** Simplest contract-true fix — flag any literal (non-var) `font:` shorthand outright,
|
||||
matching the package convention:
|
||||
```js
|
||||
if (prop === 'font' && !/var\(/i.test(value)) {
|
||||
violations.push('literal font: shorthand — use font: var(--type-*) (Rams typography tokens)');
|
||||
} else if (prop === 'font-family' && !/var\(/i.test(value)) {
|
||||
violations.push(...fontViolations(value, tokens));
|
||||
}
|
||||
```
|
||||
(Alternatively repair `familiesFromShorthand` to iteratively strip weight and size/line-height
|
||||
components.) Add a T2-style test case for the shorthand form.
|
||||
|
||||
### WR-03: Color-evasion gaps — named keywords, `oklch()`/`lab()`/`lch()`/`hwb()`/`color()`, and `text-shadow` all pass the audit
|
||||
|
||||
**File:** `theme/scripts/audit.mjs:361-394` (`literalHexViolations` — hex/`rgb()`/`hsl()` only), `audit.mjs:419-429` (`shadowViolations` — `box-shadow`/`backdrop-filter`/`filter` only)
|
||||
**Issue:** Verified evasions (fixture run through the real audit — none flagged):
|
||||
`.b { color: red; }`, `.c { background: oklch(0.6 0.2 30); }`, `.e { fill: color(display-p3 1 0 0); }`,
|
||||
and `.h2 { text-shadow: 0 1px 0 red; }` (any non-hex `text-shadow`). Modern CSS Color 4
|
||||
functions and named keywords are fully unaudited escape hatches, and `text-shadow` (a shadow
|
||||
Rams forbids) is not in `shadowViolations`. For a tool whose purpose is "zero off-token
|
||||
values is evidence, not an eyeball claim", these are known-open doors that later phases can
|
||||
walk through accidentally (e.g. `color: white`, `oklch()` from a design-tool export).
|
||||
**Fix:** Extend the literal checks:
|
||||
```js
|
||||
const NAMED = new Set(['red','green','blue','white','black','gray','grey','yellow','orange',
|
||||
'purple','pink','brown','silver','gold','cyan','magenta','lime','navy','teal','olive',
|
||||
'maroon','aqua','fuchsia']);
|
||||
// in literalHexViolations: flag NAMED keywords on color-ish props
|
||||
// (keep currentcolor/inherit/transparent sanctioned);
|
||||
// flag /\b(?:oklch|oklab|lab|lch|hwb|color|color-mix)\(/ unless the value contains var(.
|
||||
// in shadowViolations: add text-shadow (any non-none value).
|
||||
```
|
||||
|
||||
### WR-04: D-13 contract shortfall — spacing and typography numerics are not audited at all
|
||||
|
||||
**File:** `theme/scripts/audit.mjs:433-446` (`checkDeclaration` — no spacing/type-size/weight/line-height properties), claims at `audit.mjs:8-9`, `theme/gallery.html:155`, `.planning/phases/01-design-tokens-rams-foundation/01-CONTEXT.md` (D-13)
|
||||
**Issue:** D-13 states the audit "flags any color/**spacing**/**typography**/radius value not
|
||||
in the token set", the audit header says "any color / typography / radius / shadow / blur
|
||||
value", and the gallery tells the approver "colors, typography, radius, shadows, blur **all**
|
||||
derive from theme/src/tokens.css". Verified: `padding: 13px; gap: 7px;`, `font-size: 17px;
|
||||
font-weight: 650; line-height: 1.7;` all pass unflagged. The typography check is font-family
|
||||
only; spacing is entirely absent. The evidence claim is broader than the implementation.
|
||||
**Fix:** Either implement the missing checks (spacing literals validated against the 8px-grid
|
||||
scale; `font-size`/`font-weight`/`line-height` validated against the `--type-*` scale) or
|
||||
amend the claim wording in `audit.mjs`'s header and `gallery.html` to "color families, font
|
||||
families, radius, shadows, blur" so the recorded DSGN-01 evidence matches what actually runs.
|
||||
|
||||
### WR-05: Static server path guard uses prefix match without separator — sibling `theme*` paths escape the docroot
|
||||
|
||||
**File:** `theme/scripts/screenshot.mjs:68-71`
|
||||
**Issue:** `join(THEME, decodeURIComponent(url.pathname))` then `target.startsWith(THEME)`.
|
||||
A URL-encoded `..%2FthemeX` decodes to `../themeX`, joins to `/…/araharah/themeX`, which
|
||||
**passes** the `startsWith('/…/araharah/theme')` check while being outside the docroot — the
|
||||
classic incomplete-prefix-traversal idiom. Exploitability is low (bound to `127.0.0.1`,
|
||||
ephemeral port, alive only during capture, no CORS headers), but the guard exists precisely
|
||||
to prevent this and fails at its boundary condition.
|
||||
**Fix:**
|
||||
```js
|
||||
import { sep } from 'node:path';
|
||||
// …
|
||||
const target = join(THEME, decodeURIComponent(url.pathname));
|
||||
if (target !== THEME && !target.startsWith(THEME + sep)) {
|
||||
res.writeHead(403); res.end('forbidden'); return;
|
||||
}
|
||||
```
|
||||
|
||||
## Info
|
||||
|
||||
### IN-01: Dead `send` script
|
||||
|
||||
**File:** `theme/package.json:13`
|
||||
**Issue:** `"send": "mkdir -p dist/fonts && cp -r fonts/geist fonts/space-grotesk dist/fonts/"`
|
||||
is referenced by nothing (not delegated from the root, not a dependency of any other script),
|
||||
and its output is unused — `dist/rams.css` references `url(../fonts/…)`, which resolves from
|
||||
`dist/` to the tracked `theme/fonts/` directly; nothing serves `dist/fonts/`.
|
||||
**Fix:** Remove the script (or document its purpose if one is intended).
|
||||
|
||||
### IN-02: `playwright` is a runtime `dependency` of a CSS package
|
||||
|
||||
**File:** `theme/package.json:8-10`
|
||||
**Issue:** `@araharah/theme` ships no runtime JS, yet `playwright` sits under
|
||||
`dependencies` — any consumer installing the theme package for its CSS pulls the browser
|
||||
toolchain as a prod dependency.
|
||||
**Fix:** Move `playwright` to `devDependencies` (it is only used by `scripts/screenshot.mjs`,
|
||||
a dev-time capture tool).
|
||||
|
||||
### IN-03: `python3` dependency in an otherwise Node-only toolchain
|
||||
|
||||
**File:** `theme/package.json:17`
|
||||
**Issue:** `basemap:preview` shells out to `python3 -m http.server 8123`, introducing a
|
||||
Python runtime requirement into the Node-first toolchain (AGENTS.md free-first/Node-first
|
||||
stack). A tiny Node static server already exists in `screenshot.mjs` and could be extracted
|
||||
and shared.
|
||||
**Fix:** Extract the `serveTheme()` server (with a port argument) into a small shared script,
|
||||
or accept and document the Python requirement.
|
||||
|
||||
### IN-04: Root scripts miss the workspace's `test` and `basemap` entries
|
||||
|
||||
**File:** `package.json:8-14`
|
||||
**Issue:** The root delegates `build`/`sheet`/`gallery`/`audit`/`capture` but not `test` or
|
||||
`basemap` — `npm test` at the repo root fails ("Missing script") even though the theme
|
||||
workspace defines a passing 16/16 test suite, and the basemap rebuild documented in
|
||||
`theme/basemap/build.mjs:31` must be invoked with the longer `--workspace` form.
|
||||
**Fix:** Add `"test": "npm run test --workspace theme"` and
|
||||
`"basemap": "npm run basemap --workspace theme"` to the root scripts.
|
||||
|
||||
### IN-05: Font probing — no fetch timeout; partial substitutions unrecorded
|
||||
|
||||
**File:** `theme/basemap/build.mjs:305-315` (`probeGlyph`), `build.mjs:321-345` (`resolveFontStacks`)
|
||||
**Issue:** (a) `fetch` has no `AbortSignal.timeout`, so a stalled glyphs endpoint hangs the
|
||||
basemap build indefinitely. (b) If *some* of a role's intended stacks are hosted (e.g.
|
||||
`'Geist Regular'` 200 but `'Space Grotesk Regular'` 404), `served.minor` silently becomes the
|
||||
partial list with no `rams-font-substitutions` record — undermining the "honest fallback
|
||||
provenance" the feature exists to provide. (Current committed output hit the clean
|
||||
all-404 → full-fallback path, so both are latent.)
|
||||
**Fix:** Add `{ signal: AbortSignal.timeout(10_000) }` to the probes; record a substitution
|
||||
entry whenever `served[kind]` differs from `FONT_INTENT[kind]`, not only on full fallback.
|
||||
|
||||
### IN-06: Sheet inputs have no accessible name
|
||||
|
||||
**File:** `theme/src/sheet.html:167-168`
|
||||
**Issue:** Both `input-field` text inputs are labeled by placeholder only — no `<label>`/`aria-label` — leaving them nameless to assistive tech.
|
||||
**Fix:** Add `aria-label="Destination search"` / `aria-label="Bot command input"` (or wrap with visually-hidden label text), consistent with the Rams register.
|
||||
|
||||
### IN-07: Mockup capture fallback is invisible in the gallery artifact
|
||||
|
||||
**File:** `theme/scripts/screenshot.mjs:130-138`
|
||||
**Issue:** When the network render of a mockup fails, the committed `screen.png` is copied in
|
||||
as the gallery's "mockup reference render" — indistinguishable from a true render in the
|
||||
final artifact. Only the capture log records the substitution, so a DSGN-02 approver can
|
||||
unwittingly compare the implementation against a fallback capture made under different
|
||||
conditions (offline, no CDN fonts).
|
||||
**Fix:** Emit a machine-readable marker alongside the capture (e.g. a `screenshots/manifest.json`
|
||||
with `{ file, source: "network" | "fallback" }`) and/or note fallback occurrences in the
|
||||
phase summary where DSGN-02 is recorded.
|
||||
|
||||
---
|
||||
|
||||
**Verified-clean aspects (for the record):** `npm run audit` exits 0 on the real build (354
|
||||
declarations, 97 rules, 298 compiled-vocabulary rules out of scope, 49 classes harvested);
|
||||
`node scripts/audit.test.mjs` passes 16/16; `liberty-rams.json` machine-verified: 110 layers,
|
||||
no accent hex/rgb forms, no `line-gradient`, no `icon-color` paints, no non-zero
|
||||
`text-halo-blur`, only the 3 documented untouched layers (`road_area_pattern`,
|
||||
`road_one_way_arrow`, `road_one_way_arrow_opposite`), `building-3d` removed with reason
|
||||
recorded, Noto Sans font substitution honestly recorded in metadata; all 7 self-hosted woff2
|
||||
present and matched 1:1 by the `@font-face` URLs; `--shell-*` slots + dark-scheme media query
|
||||
present in the compiled CSS; the basemap proof page reads the route color from the token
|
||||
package at runtime; the audit's used-class harvesting and utilities-layer scoping behave as
|
||||
documented (verified with fixture pages); the audit does flag `.rounded` the moment any page
|
||||
wears it.
|
||||
|
||||
_Reviewed: 2026-10-22T01:08:55Z_
|
||||
_Reviewer: OpenCode (gsd-code-reviewer)_
|
||||
_Depth: standard_
|
||||
@@ -0,0 +1,162 @@
|
||||
---
|
||||
phase: 01-design-tokens-rams-foundation
|
||||
verified: 2026-10-22T02:55:00Z
|
||||
status: passed
|
||||
score: 13/14 plan must-haves verified literally (14/14 at goal level); 4/4 roadmap success criteria verified
|
||||
overrides_applied: 0
|
||||
re_verification: # initial — no previous VERIFICATION.md existed
|
||||
previous_status: null
|
||||
previous_score: null
|
||||
gaps_closed: []
|
||||
gaps_remaining: []
|
||||
regressions: []
|
||||
gaps: []
|
||||
deferred:
|
||||
- truth: "Basemap POI icons come from the hosted colored OFM sprite (not token-derived)"
|
||||
addressed_in: "Phase 3 / Phase 5 (first product map phase)"
|
||||
evidence: "Logged in phase deferred-items.md #1; Phase 3 SC1 renders the live position on the Rams basemap, Phase 5 renders route display — treatment candidates (text-only POIs, custom grayscale sprite) attached to those map phases"
|
||||
- truth: "Sprite-pattern layers (landcover_wetland, road_area_pattern) left un-derived"
|
||||
addressed_in: "Phase 3 / Phase 5"
|
||||
evidence: "Logged in phase deferred-items.md #3; visible only at zooms above the proof view"
|
||||
- truth: "Self-hosted pbf glyph route for Rams map-label fonts (Space Grotesk/Geist as map glyphs)"
|
||||
addressed_in: "Candidate for Phase 2+ (Worker infra) / product map phases"
|
||||
evidence: "Recorded in liberty-rams.json metadata.rams-font-substitutions reason: 'revisit with a Worker-served glyphs route'; no Phase 1 SC requires self-hosted glyphs, and no later phase SC claims it — tracked here for visibility"
|
||||
---
|
||||
|
||||
# Phase 1: Design Tokens + Rams Foundation — Verification Report
|
||||
|
||||
**Phase Goal:** The Telemetry Rams design system exists as one centralized, importable token set — including map basemap cartography — with a user-approved mockup-vs-implementation gallery proving the fidelity bar before any product screen is built.
|
||||
**Verified:** 2026-10-22T02:55:00Z
|
||||
**Status:** passed
|
||||
**Re-verification:** No — initial verification
|
||||
|
||||
## Goal Achievement
|
||||
|
||||
### Observable Truths (roadmap success criteria = the contract)
|
||||
|
||||
| # | Truth (Roadmap SC) | Status | Evidence |
|
||||
|---|--------------------|--------|----------|
|
||||
| 1 | Every rendered Rams component derives exclusively from the centralized token set — audit sweep finds zero off-token values | ✓ VERIFIED | `npm run audit` re-run on freshly rebuilt dist: **AUDIT CLEAN — 354 declarations, 0 off-token values** (55 colors / 9 radius tokens all zero / 7 families / 6 spacing / 10 type sizes / 9 trackings). `border-radius` forms in dist: `0`, `var(--radius)`, `3.40282e38px` (sanctioned rounded-full clamp) — no `.25rem`. tokens.css is the audit allowlist source (`DEFAULT_TOKENS = src/tokens.css`). |
|
||||
| 2 | Side-by-side gallery exists and is user-approved (DSGN-02 mechanism) | ✓ VERIFIED | `theme/gallery.html` (290 lines, CDN-free, token-driven): 4 mockup-vs-sheet rows + basemap row + token ledger (names only) + approval strip; `<img>` links to all 5 committed captures (visually inspected — real renders). `01-04-DSGN-02-APPROVAL.md` records verbatim user response **"approved"** (2026-10-22T00:51:39Z), scope = fidelity bar + basemap direction. |
|
||||
| 3 | Rams-styled MapLibre basemap renders in a browser | ✓ VERIFIED | `theme/basemap/liberty-rams.json` (110 layers, `metadata.rams-cartography.derived-from = theme/src/tokens.css` with per-role derivation formulas) + `index.html` MapLibre proof page (loads `./liberty-rams.json`, route color read at runtime via `getComputedStyle('--color-signal-orange')`). Committed real-browser capture `screenshots/basemap-kl.png` inspected: grayscale/muted KL metro, muted labels, zero orange except the reserved route vector. |
|
||||
| 4 | Design authority is singular (conflict resolved) | ✓ VERIFIED | Root `DESIGN.md` carries the SUPERSEDED-FOR-SPECIFICS banner (conflicting Helvetica/Inter typography + palette explicitly marked superseded, values delegated to the package). `README.md` contains zero hex/px. Mockup tree untouched (git porcelain clean — read-only per D-06, `@source` scoped to its markup only). One token package (`theme/`), all scripts delegate to it. |
|
||||
|
||||
**Score (goal level):** 4/4 success criteria verified
|
||||
|
||||
### Plan-Level Must-Haves (merged from PLAN frontmatters)
|
||||
|
||||
| Plan | Truth | Status | Evidence |
|
||||
|------|-------|--------|----------|
|
||||
| 01 | Tokens importable as plain CSS (`@theme static` + `:root`) | ✓ VERIFIED | tokens.css 176 lines; dist carries token vars |
|
||||
| 01 | Build produces compiled dist with Tailwind v4 utilities | ✓ VERIFIED | `npm run build` → dist/rams.css (90ms, v4.3.3); audit harvests 49 classes from 3 pages |
|
||||
| 01 | Zero Google Fonts CDN refs; self-hosted fonts | ✓ VERIFIED | grep for `fonts.googleapis|fonts.gstatic|cdn.tailwindcss` in theme/ → 0 hits; 7 woff2 files present + `@font-face` blocks + `dist/fonts` |
|
||||
| 01 | DESIGN.md superseded banner | ✓ VERIFIED | lines 1–3 of DESIGN.md |
|
||||
| 02 | Sheet displays every mockup component family | ✓ VERIFIED | Visual inspection of `sheet-full.png`: typography specimen (D-11), buttons, inputs, chips/badges, telemetry card, maneuver banner, checkboxes/toggle |
|
||||
| 02 | Legibility specimen included (D-11) | ✓ VERIFIED | SEC-00 // LEGIBILITY section, 13 `--type-*` specimens |
|
||||
| 02 | Sheet dist CSS contains zero off-token values | ✓ VERIFIED | audit exit 0 post-rebuild; components.css = 104 `var(--` refs, no literal hex (only documented 18×18 checkbox geometry, adjudication 6) |
|
||||
| 03 | Basemap renders: grayscale landing, muted water/roads/labels, zero signal-orange in basemap | ✓ VERIFIED | Capture inspection + metadata; audit-style accent guard in build.mjs (`assertNoAccent`) |
|
||||
| 03 | Values derived from tokens, not hand-tuned | ✓ VERIFIED | build.mjs parses tokens.css; metadata records `desaturate(tokenHex, …)` per role |
|
||||
| 03 | Map labels use self-hosted Space Grotesk/Geist assets (D-10) | ⚠ VERIFIED-WITH-RECORDED-DEVIATION | See "Recorded deviation" below — hosted OpenFreeMap glyphs endpoint only serves Noto Sans (Space Grotesk/Geist 404 at build time, probed); closest hosted stack substituted, recorded in `metadata.rams-font-substitutions` with reason + revisit path. Pre-planned in 01-03 plan body, REVIEW-adjudicated clean, and inside the basemap render the user explicitly approved. |
|
||||
| 04 | Audit is scripted evidence, zero off-token values (D-13) | ✓ VERIFIED | 38/38 regression tests pass (incl. T9–T12 evasion tests); exit 2 radius-drift guard |
|
||||
| 04 | Static side-by-side gallery vs all 4 mockups (D-12) | ✓ VERIFIED | gallery.html, 4 rows + basemap row, all `<img>`s resolve |
|
||||
| 04 | Playwright real-browser capture script committed (D-14) | ✓ VERIFIED | scripts/screenshot.mjs committed; 6/6 captures present and visually verified non-blank |
|
||||
| 04 | User viewed gallery + basemap and approved | ✓ VERIFIED | Approval record, verbatim "approved" |
|
||||
|
||||
**Score (plan level):** 13 verified literally / 14 (1 verified-with-recorded-deviation, no goal-level gap)
|
||||
|
||||
### Recorded Deviation (D-10 map-label glyph stacks) — suggested formal override
|
||||
|
||||
Map label glyph stacks are `Noto Sans Bold / Noto Sans Regular`, not self-hosted Space Grotesk/Geist. MapLibre label glyphs must be served as pbf glyph ranges; the OpenFreeMap glyphs endpoint hosts only Noto Sans and self-hosted woff2 cannot serve glyph ranges without a glyphs route (Worker arrives in Phase 2). The substitution was pre-planned in the 01-03 plan body, is machine-recorded in `metadata.rams-font-substitutions` (intended/served/reason), was adjudicated clean by 01-REVIEW, and the user approved the rendered basemap that displays it. Rams-type *roles* are honored (bold-major / regular-minor hierarchy, muted matte labels). To formalize in the record, the developer may add to this file's frontmatter:
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
- must_have: "Map labels use the self-hosted Space Grotesk / Geist assets (D-10)"
|
||||
reason: "OpenFreeMap glyphs endpoint hosts only Noto Sans (woff2 cannot serve pbf glyph ranges pre-Worker); closest hosted stack substituted, recorded in style metadata, and covered by the user's DSGN-02 basemap approval"
|
||||
accepted_by: "(developer)"
|
||||
accepted_at: "(timestamp)"
|
||||
```
|
||||
|
||||
### Required Artifacts
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
| -------- | -------- | ------ | ------- |
|
||||
| `theme/src/tokens.css` | Token package (55 colors, 10 spacing, 9 radius all zero, 13 type vars) | ✓ VERIFIED | 176 lines; `--radius: 0px` bare key + family zeroed (CR-01 fix commit 61d15c2 present) |
|
||||
| `theme/src/theme.css` | @import tokens + @font-face + scoped @source | ✓ VERIFIED | imports tokens.css + components.css; `@source not ../scripts` / `../basemap` (WR-01 fix present) |
|
||||
| `theme/src/components.css` | var()-only component classes | ✓ VERIFIED | 104 var() refs, no literal hex |
|
||||
| `theme/src/sheet.html` | Component sheet consuming dist/rams.css | ✓ VERIFIED | link at line 15; renders all 7 component families (screenshot inspected) |
|
||||
| `theme/dist/rams.css` | Built stylesheet | ✓ VERIFIED | rebuilt this pass; radius forms token-only; no `.shadow{`/`.blur{` (WR-01) |
|
||||
| `theme/basemap/build.mjs` + `liberty-rams.json` + `index.html` | Token-derived basemap + render proof | ✓ VERIFIED | derivation provenance in metadata; style JSON valid; proof page wired |
|
||||
| `theme/scripts/audit.mjs` (+ test harness) | Automated D-13 audit | ✓ VERIFIED | 814 lines; scans dist, parses tokens.css allowlist, 38/38 tests |
|
||||
| `theme/scripts/screenshot.mjs` | Playwright capture toolchain (D-14) | ✓ VERIFIED | WR-05 docroot guard fix present (`startsWith(THEME + sep)`) |
|
||||
| `theme/gallery.html` | DSGN-02 gallery (min 80 lines) | ✓ VERIFIED | 290 lines, CDN-free |
|
||||
| `theme/fonts/{geist,space-grotesk}/*.woff2` | Self-hosted typefaces | ✓ VERIFIED | 7 files |
|
||||
| `.gitignore` (+ Zone scrub) | Repo hygiene | ✓ VERIFIED | 0 `*:Zone.Identifier` files remain; secrets/node_modules/dist entries present |
|
||||
| `package.json` (root) | Workspace delegates | ✓ VERIFIED | build/sheet/gallery/audit/capture → theme workspace |
|
||||
|
||||
### Key Link Verification
|
||||
|
||||
| From | To | Via | Status | Details |
|
||||
| ---- | -- | --- | ------ | ------- |
|
||||
| theme/src/theme.css | theme/src/tokens.css | CSS @import | ✓ WIRED | line 14 |
|
||||
| theme build | theme/dist/rams.css | tailwindcss CLI | ✓ WIRED | ran this pass (90ms) |
|
||||
| theme/src/sheet.html | theme/dist/rams.css | `<link rel=stylesheet>` | ✓ WIRED | line 15 |
|
||||
| theme/src/components.css | tokens.css | var(--color-*)/var(--spacing-*) | ✓ WIRED | 104 refs; literal scan clean |
|
||||
| theme/basemap/build.mjs | theme/src/tokens.css | token parse | ✓ WIRED | metadata `derived-from`; derivation report to stdout |
|
||||
| theme/basemap/index.html | liberty-rams.json | MapLibre style URL | ✓ WIRED | line 115 |
|
||||
| theme/basemap/index.html | token package | getComputedStyle at runtime | ✓ WIRED | reads `--color-signal-orange`/`--color-matte-black` |
|
||||
| theme/scripts/audit.mjs | tokens.css (allowlist) + dist/rams.css (scan) | default paths | ✓ WIRED | exit 0 run; exit-1/2 behavior covered by 38 tests |
|
||||
| theme/scripts/screenshot.mjs | theme/screenshots/* | Playwright captures | ✓ WIRED | 6/6 captures on disk |
|
||||
| theme/gallery.html | theme/screenshots/* | `<img>` rows | ✓ WIRED | 9 img elements incl. basemap row |
|
||||
|
||||
### Data-Flow Trace (Level 4)
|
||||
|
||||
| Artifact | Data Variable | Source | Produces Real Data | Status |
|
||||
| -------- | ------------- | ------ | ------------------ | ------ |
|
||||
| basemap/index.html | route placeholder color | `getComputedStyle(--color-signal-orange)` from dist/rams.css | Yes (token value, not hand-tuned) | ✓ FLOWING |
|
||||
| liberty-rams.json | all cartography colors | tokens.css parse + desaturate() | Yes (provenance metadata per role) | ✓ FLOWING |
|
||||
| sheet.html / gallery.html | styles | dist/rams.css tokens | Yes (renders verified visually) | ✓ FLOWING (static design artifacts — no dynamic data expected) |
|
||||
|
||||
### Behavioral Spot-Checks
|
||||
|
||||
| Behavior | Command | Result | Status |
|
||||
| -------- | ------- | ------ | ------ |
|
||||
| Build produces dist | `npm run build --workspace theme` | Done in 90ms, v4.3.3 | ✓ PASS |
|
||||
| Audit sweep zero off-token | `npm run audit` | AUDIT CLEAN — 354 declarations, 0 off-token (exit 0), re-run post-rebuild | ✓ PASS |
|
||||
| Theme test suite | `node theme/scripts/audit.test.mjs` | 38 PASS / 0 FAIL (first invocation hit a stale `/tmp/opencode/audit-test` symlink from the fixer's sandbox — environment artifact, not a test failure; clean re-run passed) | ✓ PASS |
|
||||
| CR-01 fix: bare `rounded` var-driven | grep dist | `.rounded` → `border-radius:var(--radius)`, `--radius:0px` emitted; no `.25rem` | ✓ PASS |
|
||||
| Basemap renders as Rams cartography | inspect committed `screenshots/basemap-kl.png` (real-browser capture) | Grayscale/muted map, muted labels, orange only on reserved route vector | ✓ PASS |
|
||||
| Sheet renders all component families | inspect committed `screenshots/sheet-full.png` | Typography specimen + buttons + inputs + chips + card + banner + switches, zero radius | ✓ PASS |
|
||||
| Renders without committed captures | serve theme/ + open gallery.html live | Not re-run live — captures committed post-fix and no worn class changed rendering between capture and now (`.rounded`/`.shadow`/`.blur` worn by zero pages) | ? SKIP (evidence already real-browser + user-approved) |
|
||||
|
||||
### Requirements Coverage
|
||||
|
||||
| Requirement | Source Plan(s) | Description | Status | Evidence |
|
||||
| ----------- | -------------- | ----------- | ------ | -------- |
|
||||
| DSGN-01 | 01-01, 01-02, 01-03 | All screens render from a centralized token set — no off-token values; basemap cartography follows the same tokens | ✓ SATISFIED | Audit exit 0 (scripted evidence, D-13); tokens.css single source; basemap derived per-role from tokens (D-09); component/basemap renders verified |
|
||||
| DSGN-02 | 01-04 | Mockup-vs-implementation gallery reviewed for fidelity before proceeding | ✓ SATISFIED | gallery.html + Playwright captures + recorded verbatim approval ("approved", 00:51:39Z); mechanism documented for per-phase reuse |
|
||||
|
||||
**Orphaned requirements:** none — REQUIREMENTS.md traceability maps exactly DSGN-01/DSGN-02 to Phase 1, and both are claimed by plans. (Info: the traceability table's "Pending" checkbox text was not flipped to Complete — doc-maintenance nit, not a gap.)
|
||||
|
||||
### Anti-Patterns Found
|
||||
|
||||
| File | Line | Pattern | Severity | Impact |
|
||||
| ---- | ---- | ------- | -------- | ------ |
|
||||
| theme/src/theme.css | 31–34 | `@source` scans mockup markup (Tailwind Play-CDN replacement pattern) | ℹ️ Info | Intentional and deliberately narrowed (WR-01) — prose leakage tests exist (T5) |
|
||||
| theme/basemap/index.html | 127 | "PLACEHOLDER ROUTE VECTOR" | ℹ️ Info | Documented scope staging — route rendering is Phase 5 per plan; reads color from tokens at runtime |
|
||||
| stitch_minimalist_route_navigator/*/code.html | — | legacy inline `onclick` demo handlers | ℹ️ Info | Read-only mockups (D-06), untouched by design |
|
||||
| DESIGN.md | 31–39 | hex/px restated in legacy philosophy prose | ℹ️ Info | Under explicit SUPERSEDED-FOR-SPECIFICS banner naming palette/typography as superseded; README carries zero numerics; D-05 pre-authorized keeping philosophy prose |
|
||||
|
||||
No TODO/FIXME/stub markers; no blocker or warning anti-patterns.
|
||||
|
||||
### Human Verification Required
|
||||
|
||||
None outstanding. The phase's blocking human checkpoint (DSGN-02 gallery + basemap review) was completed on 2026-10-22 with a recorded verbatim approval — the one item a human must decide in this phase is already decided and archived (`01-04-DSGN-02-APPROVAL.md`). Visual fidelity, real-browser rendering, and basemap appearance were all covered by that approved review, and the committed captures inspected in this verification match what was approved (no worn class changed rendering between capture time and the post-fix state).
|
||||
|
||||
### Gaps Summary
|
||||
|
||||
No goal-level gaps. All four roadmap success criteria verified against the live codebase, with the code-review blocker fix (CR-01) and all five warnings (WR-01..05) confirmed present in the artifacts and the 38-test regression suite green. One documented, pre-adjudicated, user-approved deviation exists at plan-truth level (D-10 map-label glyph stacks → closest hosted stack, machine-recorded) — it does not block the phase goal, has a recorded revisit path, and a formal override entry is suggested above if the developer wants it in the durable record.
|
||||
|
||||
---
|
||||
|
||||
_Verified: 2026-10-22T02:55:00Z_
|
||||
_Verifier: OpenCode (gsd-verifier)_
|
||||
@@ -0,0 +1,11 @@
|
||||
# Phase 01 — Deferred Items (out-of-scope discoveries)
|
||||
|
||||
Log of issues found during execution that belong to other plans/phases.
|
||||
Do NOT fix here. (Executor scope boundary: only fix issues directly
|
||||
caused by the current task's changes.)
|
||||
|
||||
| # | Found during | Item | Disposition |
|
||||
|---|--------------|------|-------------|
|
||||
| 1 | plan 03 (basemap) | Liberty POI icons come from the hosted ofm sprite (`https://tiles.openfreemap.org/sprites/ofm_f384/ofm`) as colored raster icons — outside the plan's paint-property derivation list (`poi_r1/r7/r20` icon-image; not visible at the z13 proof view since POIs appear z15+) | Candidate treatment for the first product map phase (Phase 3 shell / Phase 5 guidance): text-only POIs, icon-opacity reduction, or a custom grayscale sprite served from the Worker |
|
||||
| 2 | plan 03 (basemap) | Upstream liberty warnings: `Expected value to be of type number, but found null instead.` ×3 at the KL view — verified present with the ORIGINAL untransformed liberty style too (scratch comparison page) | Upstream tile-data quirk; not caused by the Rams transform; no action in this phase |
|
||||
| 3 | plan 03 (basemap) | Sprite-pattern layers left untouched (no color paint props to derive): `landcover_wetland` (wetland texture pattern), `road_area_pattern` | Visible only at higher zooms; candidate for a custom Rams pattern sprite in a later map phase |
|
||||
Reference in New Issue
Block a user