From 387ae4d54e5812b62c15821171a71bc4a057117b Mon Sep 17 00:00:00 2001 From: Kev Date: Sat, 8 Aug 2026 00:10:34 -0400 Subject: [PATCH] Handoff doc: ground-truth build state at 71d3b7b Written from the repo, not summary -- every claim grep- or run-verified, UNKNOWN where the repo cannot say. State: HEAD and gitea main in sync at 71d3b7b, tree clean, 4,539 tests passing, web build exit 0. Push remote is gitea, never origin. DONE this arc, existence-verified: E1 movement strip, F9-F11 offseason hub shell, E10 Report template, E12 /report archive, content engine + studio API + preview, Wave-D1 motion primitives, honest served grade, archetype doctrine. Also verified done and previously mis-boarded: D1 glyphs (39 of 83 -- every one that maps to a real archetype), A1 card token, B1 boundary channel, book comparison, THE WIRE. GATED with each gate named and each absence verified by 0-file grep: F5 article media and E16/F8 on the card-system reconciliation, in-season hub IA on the content formula, E9/E15 on model accrual, E2/E6 on licensing, E3 crown on measurement, E13 on another order. NO UNGATED WAVE-2 TARGETS REMAIN -- the next move is a decision, not a build. The two open decisions are stated with what each unblocks. Card-system reconciliation is the cheapest: it frees F5 and E16/F8 together, and it exists because I built a 1080x1350 renderer without checking whether a designed card system existed. It did. Accrual clock recorded at 0 eligible dates on all four items, with the first trigger (10 calibration dates) and the attempt-floor-not-trust-floor caveat carried forward. Standing doctrine carried: Truth Law including designer samples and the inverse Number(null) breach (zero is a real fact); the 83-glyph taxonomy with 44 dormant slots; the repaired champion and the standing flag that every prior factor verdict was measured against the broken baseline; calibration withdrawn; unissuable A with a B+ 0.663 ceiling; both CI guards; and compose-don't-fork, which this arc failed three times and caught twice. Both parallel workstreams written as seed prompts. specs/HANDOFF-2026-08-08.md Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01W1sivYNqY2TS5ftykmHBU9 --- specs/HANDOFF-2026-08-08.md | 198 ++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 specs/HANDOFF-2026-08-08.md diff --git a/specs/HANDOFF-2026-08-08.md b/specs/HANDOFF-2026-08-08.md new file mode 100644 index 0000000..a4f119b --- /dev/null +++ b/specs/HANDOFF-2026-08-08.md @@ -0,0 +1,198 @@ +# VYNDR build handoff — 2026-08-08 + +Written from the repo, not from summary. Every claim below was grep- or +run-verified at `71d3b7b`. Where something could not be verified from the repo +it says UNKNOWN. + +## Repo state + +``` +HEAD 71d3b7b78692c31ba0596ec88874986ff1b58116 +gitea main 71d3b7b78692c31ba0596ec88874986ff1b58116 (in sync) +tree clean — 0 modified/untracked +tests 4,539 passing / 4 skipped +web build exit 0 +``` + +**Push remote is `gitea`, not `origin`.** `origin` is GitHub and has no +credential on this machine; every push must be `git push gitea main`. This cost +twenty commits of false "no credentials" diagnosis — see +`docs/GIT-PUSH-DIAGNOSIS.md`. + +--- + +## BUILD STATE per surface + +### DONE this arc — verified present + +| surface | file | lines | +|---|---|---| +| **E1 movement strip** | `web/src/components/vyndr/MovementStrip.tsx` | 113 | +| **F9–F11 offseason hub shell** | `web/src/app/offseason/page.tsx` + `components/vyndr/OffseasonHub.tsx` | 21 + hub | +| **E10 Report issue template** | `src/services/report/reportTemplate.js` | 169 | +| **E12 /report archive** | `web/src/app/report/page.tsx` + `components/vyndr/ReportArchive.tsx` + `src/routes/report.js` | 17 + comp + route | +| **Content engine** | `src/services/content/contentEngine.js` + 3 templates + `cardRenderer.js` | 172 + | +| **Content studio API + preview** | `src/routes/contentStudio.js` + `web/src/app/studio/page.tsx` | 175 + 131 | +| **Wave-D1 motion primitives** | `web/src/lib/motion.js` (E17/E18/E27/E28) | 100 | +| **Honest served grade** | `src/services/model/servedGrade.js` | 142 | +| **Archetype doctrine** | `specs/ARCHETYPE-TAXONOMY-DOCTRINE.md` | 53 | + +Also DONE and verified: **D1 glyph library** (39 of 83 wired — every glyph that +maps to a real archetype; colours match the registry exactly), **A1 card token** +(`--bg-1`, 32 consumers), **B1 boundary channel** (`--priced-out`, 4 consumers), +**book comparison** (mounted via `GradeResultCard → scan/page`), **THE WIRE** +(`vyndr/Ticker`). + +### GATED — verified absent, with the gate named + +| surface | gate | verified | +|---|---|---| +| **F5 article media** | card-system reconciliation | `ArticleHero`/`StatCallout`/`PullQuote` = 0 files | +| **E16/F8 share cards + crops** | card-system reconciliation *and* the resolution tail has no share-card generation step | `ShareCard.tsx` has **0 importers** | +| **In-season hub IA** | the content formula (social chat) | no spec exists anywhere | +| **E9 calibration curve** | model accrual — 0 eligible dates | `CalibrationCurve` = 0 files | +| **E15 Price Triplet MODEL leg** | model — EV layer | renders honest `NO_MODEL` | +| **E2 BookChip tiles / E6 push-to-book** | licensing / affiliate approval | every book `enabled:false` | +| **E3 best-number crown** | measurement — measured flat | `CrownBadge` = 0 files | +| **E13 Scanner S6** | another build order | — | + +**There are no ungated Wave-2 targets left.** The next move is a decision, not a +build. + +--- + +## THE TWO OPEN DECISIONS + +### 1. Card-system reconciliation — unblocks F5 *and* E16/F8 together + +The content engine emits **1080×1350 SVG** cards (`src/services/content/cardRenderer.js`). +The design package defines **five master sizes** with layouts and rasterised PNGs +in `specs/design-reference/exports/`: settle 1080×1350, story 1080×1920, square +1080, X 1200×675, record 1080×1350, article OG 1200×630. + +**I built the renderer without checking whether a designed card system existed. +It did.** They are a parallel invention — not wrong, but they must become one +visual language before F5 (whose hero graphics are generated data visuals) or +E16 can proceed. + +The decision: does the content engine conform to the E16 masters, or do the +masters absorb the engine's generator? **Cheapest unblock on the board — it +frees two gated items at once.** + +### 2. In-season hub information architecture + +`Vyndr Offseason.dc.html` specifies an **offseason** hub, and its shell is built. +Nothing specifies what that surface is **in-season**, or how content, articles, +wire and the live slate share year-round navigation. Every component exists; the +composition does not. + +The spec is explicit that **sport state lives in the sport tab** (`NFL · CAMP −5D`) +and never in a separate offseason tab — so this is not a new route, it is a mode. +Gated on the social chat's content formula, which determines the recurring slots. + +--- + +## ACCRUAL CLOCK + +``` +champion marker: engine1@2026-08-07-fullwindow + + calibration_refit 0/10 WAITING (~2 weeks) + hits_factor_lift 0/10 WAITING (~2 weeks) + prior_verdict_reaudit 0/14 WAITING (3+ weeks) + rbi_lineup_slot_gate 0/14 WAITING (3+ weeks) + +blocked: no settled rows yet carry the repaired champion marker +``` + +**FIRST TRIGGER: 10 eligible calibration dates → calibration re-fit.** Then, in +order: hits factor lift → prior verdict re-audit → rbi lineup-slot gate. + +**Thresholds are ATTEMPT floors, not TRUST floors.** Reaching 10 dates means the +re-fit *can be measured*, not that it is trustworthy. A 10-date map is thin, +deploys PROVISIONAL with auto-demotion, and its interval will be wide. + +**No measurement on reconstructions of the retired forecast.** Anything requiring +settled data waits. `src/services/model/reAuditEligibility.js` enforces it — +eligibility is a version marker, counted in DATES not rows, and a mixed table +counts only the repaired rows. + +--- + +## STANDING DOCTRINE + +**Truth Law.** No fabricated data anywhere — including **designer sample data**. +The design files' numbers (Nabers 1,120.5, Wembanyama +420→+330, Nº 128, DAY +RECORD 9–4) are a *spec for what a live feed renders*, never content to paste. +Tests assert none of it ships. `Number(null) === 0` is the classic breach; note +its inverse also bites — **zero is a real fact** ("0 cleared B+" is our most +honest post). + +**83-glyph four-sport taxonomy.** A glyph renders ONLY where its archetype is +modeled and proven. 39 wired; **44 dormant slots** for WNBA/NBA/Soccer. Wiring +them would mean inventing 44 archetypes to consume artwork — decoration +presented as classification, forbidden. `DUAL THREAT` and `PAINT BOSS` are +modeled archetypes with no mark: the mirror gap, flagged to design. + +**Repaired champion.** The forecaster read `res.last10` — **ten games** — as its +season rate. Fixed to the full season log with recency weight 0.40 → 0.20. +Resolution: hits 0.00251 → 0.00817. **Every factor verdict in the programme was +measured against the broken baseline and may deserve re-audit** — direction +unknown, not pre-priced. + +**Calibration is WITHDRAWN.** `CALIBRATION_DEPLOYED = []`. The maps were fitted +on the retired forecast; refitting today would refit it again. Served `p_win` is +repaired-champion raw. + +**Grade doctrine.** `A+`, `A`, `A-` are **unissuable** — structurally, not rarely. +Ceiling is **B+ at 0.663 realized against a 0.6005 baseline**. Bands that cannot +be separated from the baseline SAY so. The served letter derives from `p_win`; +`engine1.grade` is preserved as `engine_grade` and read by no serving code. + +**Two guards, both in CI:** +- `renderReachability.test.js` — a promised field must trace payload → adapter → + component → **mounted**. Built-but-unread killed three surfaces before this. +- `baseRateWindow.test.js` — no fixed N may stand in for a season. Six paths + across two sports fell to that class. + +**Compose, don't fork.** The recurring failure this arc: building beside an +existing thing instead of on it (cards vs E16, `MovementStrip` nearly vs +`gradeShift`, `reportTemplate` nearly vs `newsletterService`). Check for the +existing implementation first — twice it was already there. + +--- + +## PARALLEL WORKSTREAM SEEDS + +### A. Social strategy chat + +> VYNDR's content engine ships posts from real data (`src/services/content/`, +> three templates, Truth-Law enforced — an unbacked token refuses to render). +> Review `/studio` output and `specs/CONTENT-ENGINE.md`. Produce: the content +> formula/calendar (what posts recur, on what cadence), and **the card-format +> decision** — the engine's 1080×1350 renderer vs the five designed masters in +> `specs/design-reference/exports/`. That decision unblocks F5 article media and +> E16/F8 on the build side. Voice: `specs/VOICE.md` governs; the engine templates +> encode a sharper register — decide whether that becomes the house voice. + +### B. Multi-sport archetype build + +> VYNDR has archetype registries for MLB (15), NBA (15), Soccer (6), WNBA (5) — +> but **only MLB batters is MODELED**; the rest have no proven factor model, so +> their glyphs stay dormant per `specs/ARCHETYPE-TAXONOMY-DOCTRINE.md`. 44 of 83 +> designed glyphs await their sport. Pick a sport, build its archetype +> classifier from real features, and take it through the two-part gate +> (`src/services/model/factorGate.js` — must MOVE the prediction and improve +> out-of-sample Brier, cumulative-Bonferroni corrected). Prerequisite: that +> sport needs settled outcomes. WNBA settles via ESPN box scores; NBA and Soccer +> do not settle at all yet, which is the real first task there. + +--- + +## Where to start in the next chat + +1. Take one of the two open decisions (card system is cheapest — unblocks two). +2. Or run a parallel workstream seed above. +3. **Do not** start model work — it is date-blocked and will stay so for ~2 weeks. +4. Verify before building: this arc corrected its own board four times. `git + grep` beats any summary, including this one.