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
This commit is contained in:
Kev
2026-08-07 20:31:55 -04:00
parent 7a318ccce0
commit 60469422af
4 changed files with 296 additions and 0 deletions
+30
View File
@@ -85,6 +85,22 @@ const CONTRACT = [
component: 'web/src/app/studio/page.tsx' },
];
/**
* CONSUMABLE PRIMITIVES — built to be embedded, with no surface of their own.
*
* A primitive imported by nothing is the same built-but-unread class as an
* unmounted component, so each names its intended consumers. Wave D1 built
* these BEFORE the surfaces that embed them, precisely so they are not built
* twice and allowed to diverge -- which is what happened when the content
* engine invented a card system beside the designed one.
*/
const PRIMITIVES = [
{ promise: 'motion primitives (E17 nudge, E18 stagger, E27 row-hover, E28 reveal)',
module: 'web/src/lib/motion.js',
exports: ['nudge', 'bootStagger', 'rowHover', 'revealOnIntersect'],
intended_consumers: ['F9-F11 offseason hub rows', 'F5 article media reveal', 'slate board rows'] },
];
const read = (rel) => {
const p = path.join(ROOT, rel);
return fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : null;
@@ -179,6 +195,20 @@ describe('every promised honest field reaches a rendered pixel', () => {
});
});
describe('consumable primitives exist and are complete', () => {
it.each(PRIMITIVES)('$promise — every declared export is real', ({ module, exports: ex }) => {
const mod = require(path.join(ROOT, module));
for (const name of ex) expect(typeof mod[name]).toBe('function');
});
it.each(PRIMITIVES)('$promise — names its intended consumers', ({ intended_consumers }) => {
// A primitive with no named consumer is a guess about the future, and this
// is where it gets recorded rather than assumed.
expect(Array.isArray(intended_consumers)).toBe(true);
expect(intended_consumers.length).toBeGreaterThan(0);
});
});
describe('the guard itself is honest', () => {
it('fails when a promised field is produced but never consumed', () => {
// Simulate the served_grade bug: present in the payload, absent from the