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
9.3 KiB
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/studiooutput andspecs/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 inspecs/design-reference/exports/. That decision unblocks F5 article media and E16/F8 on the build side. Voice:specs/VOICE.mdgoverns; 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
- Take one of the two open decisions (card system is cheapest — unblocks two).
- Or run a parallel workstream seed above.
- Do not start model work — it is date-blocked and will stay so for ~2 weeks.
- Verify before building: this arc corrected its own board four times.
git grepbeats any summary, including this one.