MLB statsapi + WNBA ESPN live boxscores -> per-player current values
(live:{sport}:{date} TTL 90s, /api/live/:sport + Next proxy). Pure
propState math (HIT / ON PACE / NEEDS N / HOLDS / LINE PASSED — never
red in-progress), attachLiveProgress strip join on nameKey+statType,
proximity-to-hit slate float, StatStrip LiveTracker in the ROW-GRAMMAR
outcome slot (spec amended + lock test updated). Grades never change
in-game — tracking, labeled as such. 2698 -> 2757 tests, web build 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6.4 KiB
VYNDR — ROW-GRAMMAR.md v1.0
The row grammar law. Density is unlimited when grammar is fixed: every element is DATA with ONE meaning in the SAME slot on every row of its type. Locked by tests/unit/rowGrammar.test.js — a slot-order change that isn't a deliberate spec amendment fails the suite.
1. THE LAW
- One meaning per element. A mark (dot, chip, strikethrough, color) means exactly one thing, everywhere it appears.
- One slot per element. The same element renders in the same position on every row of its type. A reader who learns one row has learned every row.
- All data is mono (
var(--mono)/.mono) withtabular-numswhere numbers align. Data never glitches. - No truncation, ever, of a player name, a game time, or a pitcher line. Rows wrap or stack; they do not ellipsize identity or schedule facts. (
text-overflow: ellipsisis banned on those elements.) - Absent beats wrong. A slot with no real data renders nothing — never a placeholder value, never a fabricated zero.
2. CANONICAL PROP-ROW SLOT ORDER
Every prop row (StatStrip snapshot mode, and any future surface that renders a graded prop inline) reads left → right in this fixed order:
[1 identity] [2 viability] [3 stat+line+side] [4 market context] [5 model output] [6 outcome] [7 actions] [8 provenance]
| slot | contents | notes |
|---|---|---|
| 1 identity | player name · team · archetype badge | strip header — name appears ONCE per strip (S42 law) |
| 2 viability | lineup chip (CONFIRMED / NOT IN LINEUP / PROJ) · injury chip | real feeds only; absent feeds → no chips |
| 3 stat+line+side | TB O1.5 |
white, mono — the subject of the row |
| 4 market context | best-price dot · movement chip (STEAM ▲ / VALUE ▲) | what the MARKET is doing, before what the model says |
| 5 model output | revision strikethrough (original grade) → current grade badge | history then present: A̶ B reads "was A, now B" |
| 6 outcome | live TRACKING mark (1/2 TB · ▲6th + progress bar + state chip), then settled chip (✓ HIT / ✕ MISS / PUSH + actual) |
S11 amendment: live progress is a PROTO-OUTCOME and lives in this slot; the two are mutually exclusive (a settled prop shows only the settled chip). Once settled, actions (slot 7) disappear — the bet is over |
| 7 actions | parlay + · BOOK IT ⟶ |
suppressed when live, dead or settled (the pre-game market for a locked line closes at first pitch) |
| 8 provenance | Graded 2h ago at -115 |
the receipt, always last |
Sub-line (stat + market context, one line under the row, in this order):
[last-10 dot strip] [line-movement sparkline] [current-line delta]
- Each sub-line element renders only when its real data exists (dots need a real game log; the sparkline needs ≥3 captured history points; the delta needs a previous snapshot). Zero real data → no sub-line.
Strip header order (slot 1 + 2): name → team → archetype → viability chips. Identity is one contiguous run; status chips follow it.
3. COLOR LAW — one meaning per color
| color | meaning | examples |
|---|---|---|
signal green --g-a / --hit |
edge / best / confirmed-positive | grade-A badge, best-price dot, VALUE chip, HIT chip, CONFIRMED lineup, delta TOWARD, CLV beat, dot-strip filled ● (cleared the line) |
amber --amber |
caution / steam / building | STEAM chip, GTD injury, delta AWAY, RECORD BUILDING, SYNC at 1.5× |
red --miss |
settled-negative truth ONLY: miss / dead / stale / faded close | MISS chip, NOT IN LINEUP, OUT, SYNC STALE, CLV faded |
dim --text-1/2 |
absent / projected / neutral | PROJ lineup, awaiting copy, PUSH, dot-strip hollow ○ (didn't clear) |
Red is never used for mere movement-against or a lower price — those are amber (caution) and plain (fact). The line-movement sparkline is therefore green when the net move is TOWARD the graded side, amber when net AGAINST, dim when flat — never red (nothing has settled).
S11 amendment — live TRACKING marks (slot 6 proto-outcomes): green = already-cleared over (HIT ✓, filled), on-pace over, or an under still holding; amber = NEEDS N or an under whose line has been passed. An IN-PROGRESS prop is NEVER red — red stays reserved for the settled miss and the NOT-IN-LINEUP dead read. The read is locked pre-game and never re-grades; every live card carries "TRACKING — read locked pre-game" exactly once (specs/LIVE-TRACKING.md).
4. MARK LAW — the micro-vocabulary
- ● / ○ dot strip — last 10 games vs TONIGHT'S locked line, newest first. Filled green = that game's stat cleared the line; hollow dim = it didn't. Real game logs only; no log → no dots.
- sparkline — the REAL captured line over time (intraday refresh history, {t, line} points, capped 24). Never rendered under 3 real points.
- strikethrough — a dead or superseded model read (NOT IN LINEUP grade, revised-from grade). The original is preserved, struck, never deleted.
- ▲ ▼ — line movement direction (market fact). ✓ ✕ — settled result.
- glow — A-tier only (NORTH STAR rule). Chrome may glitch; data never.
5. MOBILE STACKING (≤390px physics)
- A prop row WRAPS (
flexWrap) — slots keep their order, overflowing slots continue on the next visual line. Order is never re-shuffled for width. - The sub-line always stacks BELOW its row, full width.
- Strip header wraps after the identity run; viability chips may drop to a second line but stay ahead of the stats run.
- Wide data grids (
game-lines-grid) scroll horizontally inside their own container; the page never scrolls horizontally. - Names, game times, and pitcher lines wrap to a new line rather than truncate (law §1.4).
6. AUDIT (Session 6, A1 board) — violations found and fixed
- MovementChip rendered AFTER the grade (market context inside the model slot). Moved to slot 4, before the revision/grade pair.
- ViabilityChips rendered between team and archetype, splitting the identity run. Moved after the archetype badge (identity → viability).
fade-upkeyframe started atopacity: 0— violating the S33 "entrance keyframes floor at the visible state" rule (a paused frame was invisible, and the hero LCP paint was delayed by the animation). Floored at.6. Everything else already conformed: best-price dot precedes the grade, the outcome chip suppresses actions, provenance is last, awaiting rows carry the honest schedule copy.
— ROW-GRAMMAR v1.0 · July 2026 —