Files
vyndr/specs/MASTER-PLAN.md
T
builtbykev 1372e6bcf7 Order Zero Phases 1-3: keyed verification, ruler_version boundary, report
PHASE 1 (measured on the live prod feed with the real key):

- WNBA is NOT thin at the feed -- 4.21 books/prop vs MLB's 3.61. It was
  allow-list-starved exactly as MLB was. This removes one candidate
  explanation for its anti-predictive result; it does not explain it, and
  WNBA stays abstaining.
- We cannot see 64.8% of the MLB slate at all (zero admitted books).
- Exchanges are real (smarkets 27%, novig 22%, kalshi 15% on MLB) but
  pinnacle, matchbook and polymarket measured 0% on BOTH sports. There is
  no sharp anchor for player props. The consensus is a MARKET consensus,
  not a SHARP one -- recorded as a permanent limitation, not a milestone.
- DFS is the trap, quantified: prizepicks covers 82% of MLB props, the
  highest in the feed. Admitting it "for breadth" would have looked like
  the biggest available win. Permanently excluded.
- Endpoints: /context WORKS and is FREE (umpire, roof, pitcher handedness,
  lineup confirmation -- richer than what we hand-built). /odds/closing and
  /movement are REDACTED (full structure, zero prices). /results and
  /exports/resolved-props are 403.
- The $19/mo question is answered: soccer IS graded, ~15 competitions in 30
  days (MLS 41k, Liga MX 15k, Brasileirao 12k, UCL/Europa/Conference). Our
  "soccer grades into a void" is a Pro-tier problem, not a data problem.
  NBA is absent because it is July -- seasonal, not inferable either way.

PHASE 2 delta, corrected: MLB mean +1.50 pts, median 0, p90 +10.0, 17.0%
of comparable props move >=5 pts, one-directional (the incumbent prices
the over below the exchange-inclusive consensus). WNBA symmetric and
tight. The median prop does not move -- the change is a right-skewed
minority. That the rulers DIFFER is established; that the new one is
BETTER is not, and that is the re-run.

PHASE 2 item 6: ledger_entries.ruler_version applied to prod, 1,384
existing rows backfilled to v1_first_book (a statement of fact -- every
row to date was produced by the first-book rule). ledgerService stamps
CURRENT_RULER_VERSION on new rows. Never pool edge or CLV across it.

Repo migration numbering lags prod; 025_ledger_ruler_version.sql records
the DDL for review.

PHASE 3: MLB isotonic p_win remains PROVISIONAL -- calibrated against
v1_first_book, does not promote until re-run on the consensus ruler.

NOT LIVE, deliberately: ALLOWED_BOOKS unchanged, served slate
byte-identical, CURRENT_RULER_VERSION still v1_first_book, no live path
calls consensusRuler.

Gates: 4,022 tests passed / 322 suites; next build exit 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-31 23:52:28 -04:00

27 KiB
Raw Blame History

VYNDR — MASTER PLAN

Single source of truth. Sessions EXECUTE against this and UPDATE it in place. Created 2026-07-31 by consolidation. Nothing built in this pass.

HOW TO USE: this supersedes ad-hoc re-derivation. Before any order, read the phase you're in. After any order, tick the item and add one line. Do not re-audit anything marked KNOWN — that redundancy is what this document exists to kill.


0. VERIFICATION LEDGER (what was re-checked in this pass)

NOTHING was re-verified. No query was run. Everything required is already captured in 22 artifacts produced this session plus the canonical board. Per the order's own clause — "If everything needed is already in the artifacts, say so and skip verification" — this is that case.

Taken as KNOWN (source in brackets):

  • Model architecture, all layers [model-architecture-recovery-map.md]
  • Grade↔outcome correlations, collapse cost [full-output-grade-mapping.md]
  • p_win calibration + holdout verdicts [grade-diagnostic-t0.md, pwin-recalibration-holdout.md]
  • Market-relative edge inversion [grade-fix-part1-investigation.md]
  • Design implemented-vs-designed, 61 items [design-vs-build-gap-audit.md]
  • Surface states, orphans, waves [pre-audit-status-pull.md, incomplete-surface-triage.md]
  • Resolution pipeline true state [resolution-and-clv-investigation.md, wave3-*.md]
  • Tier/monetization + founder mechanism [tier-structure-pull.md, tier-redesign-spec.md, build2-review-zero-report.md]
  • Sport-boundary cost [model-architecture-recovery-map.md §Phase 2]

Genuinely OPEN → carried as explicit unknowns (not verified because they need a build or a decision, not a query): sport order (Kev's call, §A2); board-reasoning gating (a/b/c, §C2); CLV flag decision (§D3); the ~70 undefined team colours (§B).


A. PER-SPORT MODELS — Phillips doctrine: each sport is its OWN model

A1. MLB layer stack (the reference module), bottom-up

# layer state note
1 Data/feeds BUILT statsapi free+unlimited; statcast; park; weather; probables. Settles end-to-end.
2 Similarity (comparable instances) BUILT · NOT WIRED · NOT DEPLOYED python/utils/similarity.py; grade path skips to season/recent averages
3 Archetypes (batter + pitcher) BUILT · display only classifies + renders; does NOT feed the grade
4 Variable weights PARTIAL/ASSUMED engine1's flat ±1.0/±0.5 deltas are hand-set, never fitted
5 Conditions (park/weather/platoon/arsenal) BUILT · CHALLENGER ONLY rides env_*/challenger_*; "measured, never served"
6 Bayesian inference BUILT · NOT WIRED · NOT DEPLOYED python/utils/bayesian.py, 320 ln, genuinely sport-agnostic math
7 Calibration MEASURED, NOT APPLIED isotonic qualifies on holdout (rel .1038→.0939, res .139→.123, n=119)
8 Grade ladder BROKEN letter is a factor index, r≈0.005, inverted (B 52.4% < C 56.9%)

The through-line: layers 2, 3, 5, 6 are built and not connected; layer 8 is connected and meaningless. MLB's fix is connection, not construction.

A2. Sport order (OPEN — Kev decides)

Proposed by readiness × clock: 1) MLB (reference, only qualifying model) → 2) CFB (has a <30-day clock; soft-market thesis) → 3) NFL4) NBA5) CBB6) WNBA re-attempt (abstains today) → 7) soccer (quota-blocked). Each gets the same 8-layer template. No sport is abandoned — abstention is a state, not a verdict.


B. DESIGN IMPLEMENTATION — 61 items catalogued

BUILT-TO-SPEC 20 · DRIFTED 7 · PARTIAL 16 · ABSENT 18. Ordered wire-in: D1-A done (6 combat glyphs, boundary-blue completed, reaction primitives, READ-FAB). D1-finish done (rationale/reveal/chips modules — built, NOT mounted). Remaining: D1-close (mount — blocked on a ROW-GRAMMAR slot amendment + §C2) · D1-B (45 unwired glyphs + the 41-vs-74 archetype scope call) · S2 primitive set (movement strip, crown, disagreement axis, SPLIT) · S3 article media · The Report email + archive · Offseason artboards · team colours: only 10 of ~80 defined — the rest render honest-neutral until a real source exists.


C. SURFACES

C1 — done: Wave 1 wiring · /compare · /record · Build-1 gate. C2 — OPEN DECISION (blocks D1-close): board reasoning is served ungated while tiers.js declares reasoning_visible:false. Options (a) gate it, (b) accept as free funnel, (c) leave unrendered. C3 — remaining: /record has no nav link (the surface that justifies the price) · /notifications · Offseason hub · /system · S3 media · /soccer (quota) · share cards (blocked by D).


D. RESOLUTION PIPELINE → USER OUTPUT

KNOWN and load-bearing: settlement WORKS (scheduler → settleAllOutcomes + settleAllLedgers, 937+ settled, growing daily). What is unreachable is the user-output TAIL: /api/grading/resolve has no caller, and its fanout holds webPush/Telegram/Discord but no share-card step and no recap. D1 wire a trigger (or move the fanout into the settle pass) · D2 share-card generation + /notifications consent + result posts + recap · D3 CLV flag decisionclvCaptureReliable() is one env var, and the pre-registered rule stands: flip only if close_moved is a clear majority AND coverage is representative. 🔴 Never wire /api/grading/resolve as a second settlement path — it double-counts.


E. SPORT BOUNDARY

Adding a sport is a ~10-file core edit with four silent-failure modes (MARKET_MAP → zero props; three stat whitelists → silent 400s; missing projection → universal refusal; no settled feed → grades forever). Collapse to a registry so a sport is a module. Blocks all of A2 after MLB.


F. CHROME AUDIT — 11 items, 4 need a Desk session. Runs when surfaces are stable, not before.


THE PHASES — 7 phases, ~18 orders

phase orders contents blocks
1. MLB model truth 4 promote isotonic p_win (MLB only, WNBA abstains) · rebuild the ladder on calibrated p_win · re-adjudicate (ROI-by-grade, skew, proj-v1.1, C1 floor) · connect layers 2/3/5/6 everything model-shaped
2. Resolution tail 3 trigger · share cards + notifications + posts + recap · CLV flag decision share cards, social proof
3. Surfaces + design lane (parallel with 1-2) 4 C2 decision → D1-close mount · /record nav + remaining surfaces · D1-B glyphs/archetypes · S2 primitives Chrome audit
4. Sport boundary 2 registry collapse · MLB re-expressed as the first module all further sports
5. Sport rollout 1 per sport CFB → NFL → NBA → CBB → WNBA retry → soccer, each on the 8-layer template
6. Monetization finish 2 Stripe Phase-B live proof on first real signup · founder launch to the 3 existing users
7. Chrome audit + hardening 2 the 11-item visual sweep · credential rotation + migration-drift reconciliation ship

Phases 14 and 67 = ~17 orders. Phase 5 = 1 order per sport (6 listed). Total ≈ 23 orders to the end state, of which ~11 are unblocked today.


DEFINITION OF DONE

VYNDR is complete when:

  1. MLB layers 18 are BUILT AND CONNECTED — similarity, archetypes, fitted weights, conditions and Bayesian all feed the grade; calibration applied; the ladder monotone (A>B>C, no inversion) and proven on held-out data.
  2. Every listed sport is finished on the same 8-layer template, or explicitly abstaining with its reason recorded — never silently absent.
  3. Design fully implemented — all 61 catalogued items BUILT-TO-SPEC.
  4. Every surface built, reachable and honest — no orphans, no live-but-not-honest surface, no dead component.
  5. Resolution pipeline live end-to-end — settle → share card / notification / post / recap, firing on a real settlement.
  6. Sport boundary is a registry — a new sport is a module, not a core edit.
  7. Chrome audit passed, logged-out and entitled.
  8. The record is publishable on its own terms — CLV either trustworthy-and- representative or honestly absent; no claim outruns its evidence.

The remaining work is finite and countable: ~23 orders across 7 phases.


STANDING LAWS (carried into every order)

Truth Law — absent beats wrong, no fabrication up or down · per-sport models, never a global engine · lookahead guard (lock-time fields only) · overfitting guard (fit one split, prove another) · never mint A's without new information · aggregate proof is free, itemized judgment is paid · one canonical founder flag · atomicity by unique index, never a count · cache-bust every post-deploy check · verify-after-write.


9. WHAT'S ACTUALLY MISSING FOR THIS TO WORK AS A PRODUCT

The phases above say what is UNBUILT. This says what is missing for VYNDR to genuinely do what it claims. Some of it is not a build, and one of it is not fixable by us at all. Written plainly because a plan that only counts code is the comfortable version.

9.1 🔴 THE CENTRAL ONE: there is no demonstrated edge yet

Every edge measurement this session came back null, negative, or unproven:

measurement result
served grade → outcome r ≈ 0.005, and inverted (B 52.4% < C 56.9%)
p_win fair_prob (3 formulations) negative in all three, both sports, both splits
p_win alone, MLB, holdout +0.165, p ≈ 0.07 — not significant
p_win alone, WNBA negative — abstains
CLV / beat-close null by guard — instrument not trustworthy
ROI by grade likely an artifact of a meaningless letter

The product's core claim — "our read is better than the market" — is not currently supported by our own data. Everything else in this plan is scaffolding around that. Building all 23 orders and not closing this leaves a beautifully-built product that doesn't do the one thing it sells.

What closes it: not code. Sample and honest iteration. The instrument fields are ~10 days old (442 rows). At ~90 decided MLB rows/week, that is ~610 weeks of accrual.

CORRECTED 2026-07-31 — see §11. The "610 weeks out" above quietly assumed the clock is already running. It is not. Those 442 rows measure a model with a bent single-book ruler and six disconnected layers — a model that will not exist once Phase 1 lands. They do not count toward the verdict and must not be pooled with post-completion rows.

The clock starts at a verified "running as intended" gate, per sport. 610 weeks is the accrual duration, not the distance to the answer. The distance to the answer is build time + verification + 610 weeks.

Independently forced by arithmetic, not just discipline: the §10.1 ruler fix changes the denominator, so pre-fix and post-fix edge/CLV numbers are not the same measurement.

9.2 The projection — the actual engine — is thin and unvalidated

The grade's only real inputs today are l5/l20 averages, an opponent rank, rest and usage. Similarity, archetypes, park/weather/platoon and the Bayesian layer are all built and not connected. So VYNDR is currently a recent-form average wearing an intelligence system's clothes. Phase 1 connects them — but connecting them is a hypothesis, not a guarantee. They must each prove out on held-out data or be left disconnected honestly.

9.3 A one-sport product marketed as multi-sport

MLB is the only qualifying model. WNBA abstains on its own data. NBA and soccer don't even settle — they grade into a void. Until Phase 5, the honest framing is "an MLB product with other sports in development." The site should not imply otherwise.

9.4 No customers, therefore no feedback loop

3 users, 0 paid. The founder mechanism is built and race-proven, /record exists, the gate works — and none of it has met a real user. Nothing here is validated by usage: not the price, not the tier line, not whether the locked-shell tease converts, not whether anyone wants this. The first 10 real users will teach more than the next 10 build orders.

9.5 No distribution — the biggest non-code gap

There is no acquisition path at all. The newsletter send is unscheduled, share cards are unbuilt (blocked on the resolution tail), social proof has no fuel (needs a real record), partner/affiliate links are all enabled:false. A product nobody sees cannot be validated regardless of how good the model gets. This appears in no phase above and belongs on the board as its own track.

9.6 The read isn't actionable at the last mile

Push-to-book is a teaser — no affiliate is live, so a user who trusts a read still leaves to place it manually. Bankroll guidance (Kelly) is Desk-gated. The gap between "here's a good read" and "I placed it" is unclosed.

9.7 Operational fragility

Single-box, single Redis (persistence is a Coolify setting, not app-controlled), one cron. Settlement silently covers 2 sports. Three credentials remain flagged for rotation, including a Stripe live key that transited a chat transcript. No staging environment — every verification this session ran against prod.


THE HONEST SUMMARY

Built well: the truth infrastructure. Honest empty states, refusal paths, n-gates, the append-only ledger, the settled/live gate, the atomic founder cap. This codebase does not lie about what it knows — that is rare and it is real.

Not yet true: that the model beats the market. Not disproven either — unmeasured at adequate n, on one sport, with a projection whose best layers aren't connected.

So the finish line is not 23 orders. It is 23 orders plus a verdict from accrued data that we cannot rush — and the discipline to report that verdict honestly if it says the edge isn't there. The plan above builds the machine. Only time and honest measurement decide whether the machine is right.


10. TO BE A REAL AGGREGATOR AND A MODEL PEOPLE PAY FOR

Kev's question: what makes this the top product, not just a finished one. The answer that matters most: the aggregator gap and the model gap are the SAME gap in two places. Fix the data breadth and both halves improve at once.

10.1 The one finding that reframes everything

CORRECTED 2026-07-31 by Order Zero — specs/order-zero-book-breadth-test.md. The original text below blamed a missing regions/bookmakers param. That was wrong. PropLine's OpenAPI contract states verbatim: bookmakers"Omitted = all books." Omitting it is correct and always was.

The real cause is ours. PropLine sends 18 books; oddsNormalizer ALLOWED_BOOKS (11 entries) intersects them at exactly 5 — which is precisely the "5 MLB books" the audit measured. We discard 13 of 18 ourselves, and 6 of our 11 allow-list entries don't exist at PropLine at all.

Measured on real public data (MLB pitcher_strikeouts, 5 complete events): the feed carries 4.41 books/prop; after our filter, 1.50 — and 12 of 34 props become invisible entirely (zero allowed books).

Also corrected: "73% single-book" is the long tail of deep/reliever props sole-posted by DraftKings or Bovada. On the core props we actually grade, the market is 1012 books wide.

And a real negative: pinnacle appears on 0 of 40 MLB props. The one sharp book in our allow-list contributes nothing here. The independent low-vig references that are present on 100% of core props are exchangesnovig, smarkets, kalshi (+ matchbook, polymarket). DFS pick'em (prizepicks/underdog/sleeper/dabble) also covers 100% but is not a market price and must never enter a consensus.

So this is not a test to run. It is a build we can do: split one allow-list into takeable / reference / excluded, and make fair_prob_lock a median consensus across reference books. No param, no cost, no tier, no new source.

Our "market" is often ONE book. MLB props are 73% single-book (2.18 audit). And proplineAdapter sends only { apiKey, markets }no regions, no bookmakers param (:152). We take PropLine's default response.

That single fact causes four separate problems we have been treating as unrelated:

  1. No line shopping — the #1 free-tier hook in this category needs many books.
  2. fair_prob_lock is a de-vigged SINGLE SOFT BOOK, not a consensus. That is the ruler the model is judged against — a bent one. (Flagged as T1; never run.)
  3. CLV is weak — you cannot measure "beat the close" against one book's close.
  4. No steam/disagreement detection — needs ≥2 books to even exist.

(Items 14 stand. Only the cause was wrong — and the fix is cheaper than the original diagnosis implied.)

10.1b We use 1 of PropLine's 29 endpoints

Reading the full spec surfaced ten unused endpoints that map directly onto §10.2 and §10.3 gaps — /odds/closing ("the canonical CLV helper"), /odds/history, /exports/odds-history, /movement (steam across all 16 books), /best-line, /ev, /results + /exports/resolved-props (resolution across 33 sports), /context (free: probable pitchers, confirmed lineups, home-plate umpire, first-pitch weather), /markets/hit-rates, /players/{n}/trends.

Two overturn standing beliefs: "NBA/WNBA/soccer have no free settled feed" may be a $19/mo problem rather than a data problem; and we hand-built probable pitchers / depth charts / lineup confirmation that /context serves free.

VERIFIED 2026-08-01 with the real keyspecs/order-zero-consensus-ruler.md. /context WORKS, FREE (umpire, roof, pitcher handedness, lineup confirmation — richer than what we hand-built). /odds/closing and /movement are REDACTED on our tier (full structure, zero prices) — my first pass wrongly called them "works" on a non-empty body. /results and /exports/resolved-props are 403.

But the settlements exist to be bought: /markets/resolution-summary shows soccer graded across ~15 competitions in 30 days (MLS 41k, Liga MX 15k, Brasileirão 12k, UCL/Europa/Conference…). "Soccer grades into a void" is a $19/mo Pro-tier problem, not a data problem. NBA is absent because it is July — seasonal, not a coverage gap, and not inferable either way.

WNBA is NOT thin at the feed — 4.21 books/prop vs MLB's 3.61. It was allow-list-starved exactly as MLB was. This removes one candidate explanation for its anti-predictive result; it does not explain it, and WNBA stays abstaining.

No sharp anchor exists for props: pinnacle, matchbook and polymarket all measured 0% on both sports. The consensus ruler is therefore a MARKET consensus, not a SHARP one — stated as a permanent limitation, not a milestone.

10.2 What a real DATA AGGREGATOR has that we don't

capability ours gap
Book breadth 5 admitted of 18 sent; 4.41→1.50 books/prop after our own filter not a feed gap — one allow-list (10.1). Core props are already 1012 books wide
True consensus / no-vig line single-book de-vig unblocked now: median across reference books (exchanges + pinnacle), n≥2 or labelled fallback
Historical odds archive STARTEDclosing_captures 844k rows, lock_lines (033) new, in-grade history capped at 24 points no full open→close series per prop. This is what makes CLV and backtesting real
Market breadth 11 live markets the category ships 50+ (alt lines, combos, innings, quarters)
Alt-line ladders from books we compute a ladder; we don't ingest the books' users shop rungs
Injury / lineup wire partial (depthChart, confirmed-vs-projected) no real-time news wire
Player news NewsWire on Explore not beat-level, not per-prop

None of this is model work. It's ingestion. And it is the half competitors compete on hardest, because it is visible to a free user in five seconds.

10.3 What a prediction model people PAY for has that we don't

  1. A distribution, not a point. We project a point (l5/l20 average) and take an empirical P(over). Paid-tier models simulate a full distribution per stat (negative-binomial / Poisson / MC). We already have thisprojection/distribution.js computes real survival probabilities and a rung ladder — but it is proj-v1.1, ledger-only, and it lost to the champion. The asset exists; it is unconnected and unproven.
  2. Opportunity modelled FIRST. In props, playing time is the dominant driver — plate appearances, snaps, minutes, batting-order slot. We carry ab_per_game and minutes as features, not as a projected opportunity with its own uncertainty. This is the single biggest modelling upgrade available.
  3. Per-stat models. Hits, strikeouts and total bases have different shapes. One additive factor index across all of them is why the ladder is meaningless.
  4. Matchup granularity that actually reaches the grade. Arsenal, handedness, park, weather, platoon — all built, all challenger-only, none feed the grade.
  5. Calibrated probabilities with honest intervals. Measured (isotonic qualifies on MLB) — not applied.
  6. A backtest harness on real historical odds. Blocked by 10.2's archive gap: you cannot backtest a price you never stored.
  7. CLV as the north-star metric, published honestly. Instrument built, guard-blocked, and weak until book breadth lands.

10.4 The uncomfortable pattern

Almost every model capability above is ALREADY BUILT and DISCONNECTED: similarity, Bayesian, archetypes, park/weather/platoon, the distribution ladder, calibration. VYNDR does not have a building problem. It has a connection and proof problem — plus one genuine ingestion gap (book breadth) that starves both halves at once.

That is good news: the expensive part is largely done. But it also means no new feature fixes this. Connecting the layers and proving them on held-out data is the work.

10.5 If I had to order it for "top product"

  1. Book breadth testBook breadth FIX + consensus fair line (10.1). The test is done (Order Zero). It is now a build: split ALLOWED_BOOKS into takeable / reference / excluded, make fair_prob_lock a median consensus. Upgrades aggregator, model denominator and CLV together. Gated on exchange prop-price validation + the WNBA measurement (needs the PropLine key).
  2. Opportunity projection (10.3.2) — the biggest genuine modelling gain.
  3. Per-stat distributions — connect distribution.js, prove per stat.
  4. Connect the built layers (Phase 1) — each proven on held-out or left off.
  5. Full odds archive — store every book's open→close; unlocks backtesting.
  6. Market breadth — 11 → 50+ markets is mostly ingestion + the 4-layer wiring.
  7. Then the sports rollout, on a template that is actually worth replicating.

The ordering principle: do not replicate a thin model across six sports. Get MLB genuinely good first — a copied-six-times thin model is six times the maintenance for the same absent edge.

10.6 The honest caveat on "top product"

The category's leaders are judged on one number: do their picks beat the closing line, at scale, published. We cannot claim that yet — not because the product is unfinished, but because we have not measured it at adequate n on a market we can trust. Book breadth + the odds archive + accrued settlements are what make that claim possible. Everything in §10 is in service of being able to make it — or of being able to say honestly that we can't.


11. THE ACCRUAL CLOCK — SEQUENTIAL, POST-COMPLETION

Kev's correction, 2026-07-31. Supersedes any "accrual runs in parallel with building" framing anywhere in this document.

11.1 The causality

You cannot meaningfully accrue until the product is right and running as intended — model layers connected, ruler fixed (real consensus, not one soft book), sports in, operating in the vision.

Only then does the accrual clock start, and only then does time produce a verdict. Building faster shortens the time TO clock-start. It never runs the clock.

The flawed assumption being removed: that today's half-connected model accrues useful evidence while we build. It does not. That data measures a model that will not exist after the layers are connected — a different model wearing the same name.

11.2 Measurement rule (non-negotiable)

  • Settled data accrued before completion does NOT count toward the edge verdict.
  • NO POOLING across the completion boundary. Pre-fix and post-fix are different models — the same class of error as the model-version boundary, at whole-model scale.
  • The clock starts at verified "running as intended", not at "today".

11.3 Two clocks — stated separately so neither corner-cuts

1. MLB-MODEL VERDICT clock. Starts when MLB is genuinely complete: built layers connected + honest consensus ruler + running as designed. Its accrued n judges MLB.

2. FULL-PRODUCT TRACK RECORD clock. Starts when the vision is running: sports in, aggregator built, operating as intended. Its accrued n judges the product claim.

Each subsequent sport gets its OWN clock, starting when that sport's model is complete — never when it is stubbed in. (Per-sport doctrine: a sport that merely renders is not a sport that measures.)

11.4 "Complete" — defined honestly

A model/sport is complete-enough-to-accrue when its built layers are connected and it runs against an honest ruler (real consensus), operating as designednot when every conceivable feature exists.

This definition is doing real work in both directions: it blocks the corner-cut ("close enough, start counting") and it blocks never-ship ("one more feature"). The full-product claim additionally requires the vision's sports + aggregator running.

11.5 The verification gate

Between build and clock. Before any accrual counts, verify — not assume — that the product is running as intended:

  • connected layers actually fire (present in the served payload, not merely present in the repo)
  • the ruler is a real consensus (fair_prob_source: 'consensus_n', n≥2)
  • the sport settles correctly (spot-checked against real box scores)
  • surfaces are honest (no fabricated values; absent renders absent)

This gate is verified, not assumed. No accrual line item runs during the build phases.

11.6 The 10-user track, reframed

Real users are onboarded to a complete product, so their usage teaches about the real thing rather than a half-built one.

We do NOT acquire users early to "start accrual." That is the corner being explicitly refused.

11.7 The finish line

build orders complete
      ↓
running-as-intended VERIFIED  (§11.5 gate)
      ↓
clock starts  (per sport, two clocks, §11.3)
      ↓
verdict reported honestly — including if it says the edge is not there

That last clause is the whole point. A clock you are willing to stop early is not a measurement, and a verdict you are only willing to publish if it is favourable is not a verdict.