Files
vyndr/specs/HANDOFF-2026-08-08.md
builtbykev 387ae4d54e 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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1sivYNqY2TS5ftykmHBU9
2026-08-08 00:10:34 -04:00

199 lines
9.3 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.
# 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 |
| **F9F11 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 94) 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.