diff --git a/specs/MASTER-PLAN.md b/specs/MASTER-PLAN.md index 027fc48..10201a2 100644 --- a/specs/MASTER-PLAN.md +++ b/specs/MASTER-PLAN.md @@ -78,6 +78,7 @@ multi-book data. | **soccer** | **settles** — ~15 competitions, 30d | "grades into a void" is a **$19/mo Pro-tier** problem, not a data problem | | **CLV + results feeds** | `/odds/closing` + `/movement` **redacted**; `/results` **403 `required_tier: hobby`**; `/exports/resolved-props` **403 `required_tier: pro`** | **verified on our keys** — plain tier exclusion, not a key or plan fault. **$9/mo** buys CLV + steam + results; **$19/mo** adds the 90-day settlement export | | **books SERVED** | 5 → **13**; props rendered **546 → 2,780** (5.1×); mean **4.22** books/prop | **AGGREGATOR widening is LIVE.** Of 2,234 newly-visible props, **31.2% carry a real non-DFS price**; **68.8% are DFS-only** — shown, tagged, never a market | +| **MLB board size** | **7 → 365 graded props** (52×) in 114s | the 25-cap discarded 95.7% of the slate. Raised to 500 on measured cost. Refusals were **43.8% deliberate policy suppression**, not a data gap | | **model input** | **byte-identical** — 546 gradeable props, `v1_first_book` | `MODEL_BOOKS` gate in `dedupeProps` + `indexOddsProps`. Lifts only on the re-run | | **accrual clock** | **sequential, post-completion** | see §11. Pre-completion data does not count and is never pooled | diff --git a/specs/grade-cap-and-refusal-diagnosis.md b/specs/grade-cap-and-refusal-diagnosis.md index 9025c66..8f097cc 100644 --- a/specs/grade-cap-and-refusal-diagnosis.md +++ b/specs/grade-cap-and-refusal-diagnosis.md @@ -123,11 +123,48 @@ cap stops discarding 95.7% of the slate — not because the bar moved. --- -## EXPECTED EFFECT +## VERIFIED EFFECT (induced on prod, not projected) -At the measured 55% grade rate on 585 unique props, the MLB board should go from -**~7 graded props to roughly 300**, at a cost of about **70 seconds per snapshot -run, five times a day.** +| | before | after | +|---|---:|---:| +| **graded props on the MLB board** | **7** | **365** | +| ledger rows per run | 7 | 365 | +| retention rows | 50 | 1,000 | +| snapshot duration | 16s | **114s** | +| anon `/api/snapshot/mlb` payload | ~6 KB | **220 KB, 0.44s** | + +**52× the board.** Every one of the 365 carries a `forecast_rank` (1–365, all +unique) and **zero leak `p_win` to anonymous callers** — the gating still holds +at 50× the volume. + +Stat mix, previously three stats, now ten: hits 141 · total_bases 78 · rbi 42 · +runs 41 · walks 31 · strikeouts 12 · outs 11 · earned_runs 4 · hits_allowed 3 · +doubles 2. + +### Measured cost curve (induced runs, `?limit=` bisect hook) + +| limit | grades | wall | +|---:|---:|---:| +| 1 | 0 | 42s | +| 25 | 7 | 58s | +| 60 | 39 | 42s | +| 120 | 63 | 66s | +| **500** | **365** | **114s** | + +**~42s of that is FIXED overhead** (odds fetch, roster logs, archetype classify, +retention) — it is paid whether we grade 1 prop or 500. Grading is the cheap +part. **My pre-flight estimate of "~72s" was built from per-prop latency measured +in isolation and ignored that fixed cost; the real figure is 114s.** Wrong by +~40s, in the direction that mattered least, but wrong. + +### A false alarm I chased, and what it actually was + +The first induced run **502'd at 13.4s**, and did not complete in background. I +hypothesised load — memory or a proxy timeout under 20× the work. **That was +wrong.** A `limit=25` run then 502'd in **2 seconds**, which no amount of load +explains, and both recovered on retry: the 502s were **the deploy rolling**, not +the cap. Recorded because the load hypothesis was plausible enough to have been +acted on, and acting on it would have meant reverting a fix that works. **Two things to watch after deploy, stated in advance rather than discovered later:**