Files
vyndr/specs/wave-d1-primitives.md
builtbykev 60469422af Wave D1 primitives — and the audit says E1/E9 were not Wave 1
PHASE 0 — the order proposed E1 + E9 as Wave-1 and told me to follow the
audit if it disagreed. It disagrees: E9 calibration curve is WAVE D3,
gated on MODEL work ("resolve n>=20 vs N30, accrue buckets"), and E1
movement strip is WAVE D6, a large surface build. E9's gate is live right
now -- calibration is WITHDRAWN at 0 eligible dates, so the curve could
only render its empty state today. Building it would ship a component
whose entire purpose is unavailable.

PHASE 1 — three of the five real Wave D1 items were ALREADY DONE, and the
2026-07-31 audit has aged:

  D1 glyph library  audit: 38/83 wired (46%)
                    now:   COMPLETE for everything wireable -- 39 of 83
                           designed glyphs map to a real archetype, all 39
                           are wired, colours match the registry exactly
                           (0 disagreements).
  A1 card token     audit: BUILT-BUT-DRIFTED, "in only 1 file"
                    now:   BUILT-TO-SPEC -- it IS the --bg-1 token,
                           consumed by 32 files. The audit counted literal
                           hex, which is what a correctly tokenised value
                           looks like.
  B1 boundary blue  audit: PARTIAL, hex in 2 files
                    now:   BUILT -- --priced-out/#8fb2de is a token with a
                           documented colour law, 4 consumers.

The 44 unwired glyphs are NOT a wiring gap: they have no backend
archetype, so wiring them means inventing 44 archetypes to consume
artwork -- the fabrication this programme refuses. That is the 41-vs-74
scope question and it is Kev's call. Separately, 2 registry archetypes
have NO designed glyph (DUAL THREAT, PAINT BOSS) -- a design gap.

PHASE 2 — what was genuinely absent is now built. web/src/lib/motion.js:
nudge() capped at 180ms so it reads as acknowledgement rather than
latency; bootStagger capped at 240ms because uncapped, row 40 waits 1.1s
and the stagger BECOMES the latency it exists to disguise; rowHover
returns handlers not CSS so touch cannot stick a hover state; and
revealOnIntersect returns an unobserve in every path and reveals
IMMEDIATELY when there is no IntersectionObserver or motion is reduced --
content is never hidden behind a capability check.

Reduced motion is honoured, not softened. The sharpest of the 10 tests:
bootStagger under reduced motion returns opacity 1, not merely delay 0 --
if the CSS animation supplies the opacity, skipping it leaves the row
invisible forever.

PHASE 3 — the reachability guard gains a PRIMITIVES section: a module
built to be embedded must declare its exports AND name its intended
consumers, because a primitive imported by nothing is the same
built-but-unread class as an unmounted component.

WAVE-2 UNGATED: F9-F11 offseason hub, F5 article media, E10/E12 Report,
E1 movement strip. GATED: E9 + E15 on model, E16/F8 on the resolution tail
and the card-system reconciliation, E2/E6 on licensing, E13 on another
order.

Read-only throughout; serving fingerprint unchanged; accrual clock
unchanged at 0 eligible dates.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1sivYNqY2TS5ftykmHBU9
2026-08-07 20:31:55 -04:00

85 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Wave D1 — and why E1/E9 were not it
## PHASE 0 — the audit's actual wave order
The order proposed E1 + E9 as Wave-1 primitives and instructed me to follow the
audit if it disagreed. **It disagrees.**
| item | the audit's placement |
|---|---|
| **E9 calibration curve** | **WAVE D3 — gated on MODEL work**: *"resolve n≥20 vs N30, accrue buckets"* |
| **E1 movement strip** | **WAVE D6 — large surface builds**, alongside crown / disagreement axis / SPLIT |
**Neither is Wave 1.** And E9's gate is live right now: calibration is
**withdrawn** (`CALIBRATION_DEPLOYED = []`) at **0 eligible dates**, so a
calibration curve today could only render its empty state. Building it now would
produce a component whose entire purpose is unavailable.
**WAVE D1, per the audit:** glyph library · card token + `vy-glitch` naming ·
`nudge()`/boot-stagger/row-hover/IntersectionObserver · boundary-channel blue ·
team-gradient chips + READ-FAB.
## PHASE 1 — three of the five Wave D1 items were already done
Checked rather than assumed, and the audit (2026-07-31) has aged:
| item | audit said | measured now |
|---|---|---|
| **D1 glyph library** | PARTIAL — 38 of 83 wired (46%) | **COMPLETE for everything wireable.** 83 designed glyphs, 41 registry archetypes, **39 map — and all 39 are wired, with colours matching the registry exactly (0 disagreements).** |
| **A1 card token `#0E0E14`** | BUILT-BUT-DRIFTED — "in only 1 file" | **BUILT-TO-SPEC.** It is the `--bg-1` token in `globals.css`, consumed by **32 files** via `var(--bg-1)`. The audit counted literal hex occurrences, which is what a *correctly tokenised* value looks like. |
| **B1 boundary channel** | PARTIAL — hex in 2 files | **BUILT.** `--priced-out: #8fb2de` + `--priced-out-dim` are tokens with a documented colour law in `globals.css`, consumed by 4 files. |
**The 44 unwired glyphs are not a wiring gap.** They have no backend archetype —
wiring them would mean **inventing 44 archetypes to consume artwork**, which is
the fabrication this programme refuses. That is the 41-vs-74 scope question, and
it is Kev's call, not a build task. Separately, **2 registry archetypes have no
designed glyph** (`DUAL THREAT`, `PAINT BOSS`) — a design gap, not a code one.
## PHASE 2 — what was genuinely absent, and is now built
`web/src/lib/motion.js` — the four primitives, all previously 0 files:
| primitive | the rule it enforces |
|---|---|
| **E17 `nudge()`** | ≤180ms. Confirms an action *registered* without claiming it finished — a long pulse reads as latency, the opposite of a perceived-speed primitive. |
| **E18 `bootStagger()`** | **capped at 240ms.** Uncapped, row 40 waits 1.1s and the stagger *becomes* the latency it exists to disguise. |
| **E27 `rowHover()`** | returns handlers, not CSS — so a tap on touch cannot stick a hover state that never clears. |
| **E28 `revealOnIntersect()`** | returns an unobserve fn in every path, and **reveals IMMEDIATELY** without IntersectionObserver or under reduced motion. Content is never hidden behind a capability check. |
**Reduced motion is honoured, not softened** — every primitive skips outright,
and server-side assumes reduced. 10 tests, the sharpest being that
`bootStagger` under reduced motion returns `opacity: 1` and not merely
`delay: 0`: if the CSS animation supplies the opacity, skipping the animation
without forcing it leaves the row invisible forever.
## PHASE 3 — guard registration and Wave-2 readiness
The reachability guard now carries a **PRIMITIVES** section: a module built to be
embedded must declare its exports *and name its intended consumers*. A primitive
imported by nothing is the same built-but-unread class as an unmounted
component. 24 checks green.
### Wave-2 readiness
**Ungated — design complete, no blocker:**
- **F9/F10/F11 offseason hub** (Wave D6) — the largest, fully spec'd
- **F5 article media** (Wave D6) — hero + figure system fully spec'd
- **E10/E12 The Report email + `/report` archive** — design exists
- **E1 movement strip** (Wave D6) — spec'd, absent, now has its motion primitives
**Gated, and by what:**
| item | gate |
|---|---|
| E9 calibration curve | **model** — calibration withdrawn, 0 eligible dates |
| E15 Price Triplet MODEL leg | **model** — EV layer |
| E16 share cards + F8 crops | **resolution tail** *and* the card-system reconciliation |
| E2 BookChip tiles / E6 push-to-book | **licensing / affiliate approval** |
| E13 Scanner S6 | another build order |
**The card-system reconciliation** (content-engine 1080×1350 vs E16's five
masters) gates E16/F8 and should be settled with the social chat, since off-site
posts and on-site share cards are one system.
Isolated throughout: read-only, no serving or model change, **accrual clock
unchanged at 0 eligible dates**.