← All findingssource · memory/project_six_layer_gap_audit.md
8-agent workflow (one auditor per layer + synthesis, all reading actual code) compared the stack to a six-layer prop-intelligence write-up (minutes engine / role-change detector / matchup model / film system / distribution engine / command center). Verdicts: L1 minutes PARTIAL, L2 role-change PARTIAL, L3 matchup WEAK, L4 film PARTIAL, L5 distribution PARTIAL, L6 command-center PARTIAL.
Biggest insight — the stack's market-first design is mostly RIGHT, which
reframes the roadmap. The write-up preaches "project blind, then compare to
price; CLV as diagnostic not philosophy." Project-blind correctly applies to
the PROJECTION layer, NOT the grade layer — and the stack ALREADY has the
line-blind artifact there: projections-engine marginals/copula never see the
line, and observations.parquet freezes model_prob at run_ts. grade_v2
being price-derived is defensible (it's the one monotone-validated conviction
signal). The real gap: the stack logs a line-blind projection AND logs
closing lines in bet_clv but NEVER JOINS them into the calibration diagnostic
the write-up prescribes. Cheap to fix — both halves already on disk.
Also confirmed by the stack's OWN backtest: "most prop errors start at minutes" is true here — minutes is the only model component that ever measured lift (5.19→4.66 MAE); per-stat rate models sit at L5 parity. BUT the write-up's mechanism ("everything multiplies through one minutes number") is wrong for us — the copula already learns minutes-sensitivity as a parallel projection, so a naive rate×minutes cascade would double-count variance. Minutes spend belongs on VARIANCE (RotoWire, confirmed lineup, scenario branches), not a cascade.
STALE MEMORY CORRECTIONS from this audit (verify against these):
- RotoWire projected-minutes READ PATH NOW EXISTS (contradicts
project_wnba_lineups_gap): SDS
types.go:254-256has ProjectedMinutes, both NBA+WNBA adapters readgl.projected_minutes, GetLineup serves it, refresher writes it. Dormant ONLY because ROTOWIRE_USERNAME/PASSWORD unset on prod worker. Activation = creds + trigger, ~0.5-1d, NOT a build. - The beneficiaries/possession-inheritance engine is BUILT + WNBA-enabled
(
beneficiaries.py) AND duplicated in SDS (/beneficiaries/player/:id) — but STRANDED: sport-agents hardcodesinjury_beneficiaries:{}, data-hydrator consumes neither route. (Refines project_wnba_backlog "beneficiaries recalc" item — it's a WIRING problem, not a rebuild.)
TOP QUICK WINS (each <1wk, ordered; ~2wk total gets a shipped command center + Player Game Card without touching a model):
- Activate RotoWire (0.5-1d, config+verify) — needs a RotoWire subscription. Single best ROI; unlocks FIX 3 live + #6 + minutes-error miss-tag.
- Named upside/failure/confidence per prop (2-3d) — pure post-process on the 5000-sample tensor: upside=q90+driving co-stat, failure=q10+firing flag, confidence=(q75-q25)/q50. Deterministic, no LLM. Centerpiece of the card.
- Wire beneficiary signal to pick layer (2-4d) — consume SDS route into PlayerBundle+MethodologyFlags; do 1d PE-parquet vs SDS-SQL cross-check first, retire the loser.
- Autopsy-into-settle + 8-tag miss enum (2-3d) — autopsy agent already runs but manual-only; add to settle sweep, pre-fill tags deterministically from fields re-grade already computes (excused→blowout/foul, recency_agrees+ favorable_margin→conversion-unlucky, CLV sign→bad-price).
- WNBA possession/rebound trend branch (2-3d) — MERGES the pre-approved
rebounds branch: new
stat=="rebounds"in diagnostic.go computeMethodologyFlags, L3-vs-L10 slope of possession proxy (FGA+0.44·FTA team-share) + OREB-rate vs 3PA-rate. Only tracking-free role signal for WNBA. - Morning brief page (3-4d) + operator push digest ~08:00 CET (1-2d) — the European-hours payoff; read-model join, no new modeling.
DO NOT BUILD (with reasons): position-DvP/USG% as model features (A/B'd, REVERTED, commit 8762d3d, noise); scout's OpportunityCalculator (FABRICATES paint_touches/drives as fixed box-score functions — the exact outputs-as-opportunity trap); dead matchup_analyzer.py archetype matrix (default constants); WNBA archetype/scheme/catch-and-shoot tags (no public WNBA tracking exists); film/clip UI (no video access — hard constraint); step-4 FG%/FT% recombination (measured 2.1% worse); routing leaguedashptstats into the 56% scout classifier (its problem is imputation→UNDER bias, not feature count — new tracking goes to projections/diagnostic as display/LLM context only); hard-cutover of conserved-sampler blowout constants (never backtested — forward-shadow only, same posture as EB shrinkage); "purifying" grade_v2 of market (its price-derivation IS the validated signal).
Recommended first product = ONE excellent Player Game Card for a single WNBA game's 6-10 priced players (WNBA = active league + hardest constraint, so proving it there makes NBA additive). Ships sections 1-6+8 (+post-settle 9) from data ALREADY collected + quick-wins #2/#3/#5, gated on #1/#3 wirings. Omit the NBA-only recent-form film card (section 7) for WNBA v1 rather than fake it. Lives as a section of the morning-brief page.
How to apply: This is a roadmap, nothing built yet. Full synthesis + per-layer audits saved to scratchpad (gap_synthesis.json / gap_audits.json) and rendered to an artifact. Re-confirm scope with the operator before starting any item. The project_cv_rebound_tracking_spec Tier A (leaguedashptstats) overlaps upgrade #9 here.