diff --git a/specs/accrual-watch-and-resumption.md b/specs/accrual-watch-and-resumption.md new file mode 100644 index 0000000..671f51f --- /dev/null +++ b/specs/accrual-watch-and-resumption.md @@ -0,0 +1,120 @@ +# The accrual watch — the program is idle on modeling, and that is correct + +## PHASE 0 — live-surface integrity + +| check | result | +|---|---| +| Grade bands not derived from the retired champion | **PASS** — `gradeBands` is required by *no* serving code. Built across several orders, never wired. No stale band can reach a user because none reaches a user at all. | +| No withdrawn-map leak | **PASS** — `CALIBRATION_DEPLOYED` is `[]` and the calibrate loop iterates it, so `calibrate()` is never called. The only `p_win_calibrated` assignment sits inside that empty loop. Served `p_win` is repaired-champion raw. | +| Refusals on the repaired reference | **PASS** — `projectionFor` reads `l20_avg`, which `mlbGameLogFeatures` now builds from `fullLog`. | +| Factors still fire post-repair | **PASS** — the repair moved the base they adjust, so sign was re-verified across it: at base 0.35/0.50/0.65/0.80, defence lowers, pitcher-contact raises, platoon raises at every point. Firing check only; **not** a lift re-measurement. | + +### One defect found, and it was mine + +The grade card rendered **"Last 20 games average: X"** from `l20_avg` — a field +that, after the repair, holds a **full-season** average. The number moved and the +label did not, so the surface asserted a window that no longer existed. Fixed to +"Season average"; `trapDetection`'s L20 explanations likewise. + +Same class as everything else tonight, one layer out: **a correct-looking string +describing data that moved underneath it.** + +--- + +## PHASE 1 — the existence risk, resolved + +Nineteen commits (`7b85934` → `2391574`) were local-only with no push +credentials. Three retrievable artifacts now exist: + +| artifact | path | size | +|---|---|---| +| session bundle | `~/vyndr-session-2026-08-07.bundle` | 244K | +| **full-history bundle (self-contained)** | `~/vyndr-full-history-2026-08-07.bundle` | 6.8M | +| patch series (20 files) | `~/vyndr-session-patches/` | 1.5M | + +**Use the full-history bundle** — the session bundle verifies as requiring ref +`6452926…`, so it only applies onto a repo that already has this history. The +full-history one clones standalone: + +``` +git clone ~/vyndr-full-history-2026-08-07.bundle vyndr-recovered +``` + +**This is the top non-accrual action item.** Copy one of these off the machine. + +--- + +## PHASE 2 — the accrual watch + +``` +repaired champion marker: engine1@2026-08-07-fullwindow +eligible rows: 0 | eligible dates: 0 +blocked: no settled rows yet carry the repaired champion marker +``` + +| item | need | have | status | +|---|---|---|---| +| calibration re-fit | 10 dates | 0 | WAITING | +| hits factor lift | 10 dates | 0 | WAITING | +| prior verdict re-audit | 14 dates | 0 | WAITING | +| rbi lineup-slot gate | 14 dates | 0 | WAITING | + +Zero is the correct starting line: the repair ships in *this* session's commits, +so no settled row can carry the marker yet. + +### These are ATTEMPT floors, not TRUST floors + +**Reaching 10 dates means "the calibration re-fit can now be measured." It does +NOT mean the re-fit is trustworthy.** We lived this distinction the hard way +tonight: date-block CIs on 2–4 clusters, a LODO gate with 1.4–9.3% power, and a +≥40 date-cluster bar that was correct as a promotion bar and wrong as a deploy +bar. A 10-date map is thin. It deploys **PROVISIONAL with auto-demotion**, like +everything else, and its interval will still be wide. + +**No future session may read "threshold met" as "answer certified."** + +### Real-time estimates + +Roughly one MLB slate per day, but per-stat settled volume differs — hits props +are far more numerous than rbi, and a "date" only counts once its props settle. + +| item | dates | realistic wall-clock | +|---|---|---| +| calibration re-fit, hits lift | 10 | **~2 weeks** | +| verdict re-audit, rbi gate | 14 | **3+ weeks** (rbi accrues slowest) | + +The wait is **designed, not a stall.** The alternative — measuring on +reconstructions of a retired forecast — is the trap this program has now refused +by name three times. + +--- + +## PHASE 3 — the pre-registered resumption order + +Triggered purely by eligible-date thresholds. No re-litigation, no re-deciding: + +1. **@10 dates — calibration re-fit on the repaired champion.** Low-parameter, + LODO where powered, PROVISIONAL, auto-demotion armed, shadow duel restarts on + the repaired forecast. The favourite-longshot bias must be **re-measured**, + not assumed to have survived the repair. +2. **@10 dates — hits factor composed-lift re-measure.** The 1.39% figure is + **void** — measured on the broken baseline. Direction unknown. +3. **@14 dates — prior factor verdict re-audit.** Every null and every THEATER + was scored against a champion worse than a frequency table. Not pre-priced; + some may pass, some may still fail. +4. **@14 dates — rbi lineup-slot / RISP through the two-part gate.** World A + ~90%, within-role residual 0.01908 real, `lineup_context` prod-verified (S89). + +**FIRST TRIGGER:** when `reAuditEligibility.assess()` reports **10 eligible +calibration dates**, the next order is the calibration re-fit. + +**Until then the program is honestly IDLE on modeling.** That is the correct +state, not a gap to fill. + +--- + +## Invariants + +No measurement on reconstructions — held. Phase 0 verified live integrity and +factor *firing*; it did not re-measure lift or re-fit calibration. Serving change +for the label fix, fingerprinted. `p_win` never mutated. No Bonferroni slot.