Retain raw weather, and record platoon severity 48 rows short

Two fixes in the weather path, and the second was hiding behind the first. The
scalar weather_mod cannot express a hit-TYPE conversion at all -- wind out and
warm turning fly balls into extra bases, and cold heavy air turning them into
outs, collapse to the same number once multiplied -- so the raw temperature,
wind speed and wind direction are now retained alongside it.

And the old guard only kept the environment when the multiplier was not 1,
which silently discarded the forecast for every ordinary night. That is the
majority of games, and precisely the rows a hit-type model would need in order
to learn what ordinary looks like.

Platoon severity is built and measured at n=452, which is 48 rows short of the
gate: CANDIDATE_PENDING, neither proven nor theatre. It moves less than flat
platoon (0.021 against 0.026), consistent with the pattern, and its Brier point
estimate is favourable but the corrected interval still spans zero.

Worth naming: the refusal costs sample, and that is the design working. Flat
platoon scores 741 rows because it will happily apply a boost to anyone;
severity scores 452 because the other 289 are hitters whose split we cannot
actually read at 60 plate appearances on the short side. Buying those rows back
by shrinking instead of refusing would have produced a number indistinguishable
from a measured league-average split, which is a different claim from the one
the data supports.

Park dimensions are ingested and verified in production across fifteen venues,
joined by the venue the game is actually at rather than inferred from the home
team -- neutral-site and international games break that assumption without
surfacing an error.

The park-and-weather-to-hit-type atom is NOT built. Its inputs landed this
session and carry a single as_of date, so testing it on total_bases would be
scoring games with inputs that postdate them. Building it now would produce
something plausible rather than something proven.

Proven factors for hits remain pitcher_contact_profile and
defense_by_direction. 4,307 tests green (344 suites); web build exit 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1sivYNqY2TS5ftykmHBU9
This commit is contained in:
Kev
2026-08-04 20:40:56 -04:00
parent de0077f6f9
commit 6452926732
5 changed files with 100 additions and 1 deletions
+21
View File
@@ -3,6 +3,27 @@
## Last Updated
2026-08-03
## Session 94 (2026-08-04) — Causally-correct platoon + park inputs ✅
4,307 tests / 344 suites green, build exit 0. Counter + frozen clusters
byte-identical.
- **PLATOON SEVERITY built + tested: n=452, 48 short of the gate.**
CANDIDATE_PENDING — not proven, not theatre. Uses each hitter's own vs-LHP/
vs-RHP split, shrunk by the smaller side's PA, refused below 60 PA. It moves
LESS than flat platoon (0.021 vs 0.026), consistent with the pattern.
- **The refusal costs sample honestly** — 452 vs 741 rows is exactly the hitters
whose splits are unreadable.
- **PARK DIMENSIONS INGESTED** (free, statsapi venue endpoint): fence distances,
roof, turf, elevation. Prod-verified 15 venues. Joined by real `venue_id` from
the schedule, never inferred from the home team.
- **RAW WEATHER RETAINED** (temp/wind_mph/wind_dir/precip) — and the old guard
that dropped the environment entirely when the multiplier was 1 is fixed, which
had been discarding the forecast on every ordinary night.
- **PLATOON/PARK ingest prod-verified:** 270 lineups, 265 platoon, 15 park dims.
- **NOT built: park+weather→hit-type.** Its inputs landed this session and carry
ONE as_of date; testing it on total_bases needs accumulated dated rows, so
building it now would be plausibility not proof.
- **Proven for hits: pitcher_contact_profile, defense_by_direction.**
## Session 93 (2026-08-04) — Causally-correct defence atom PROVES ✅
4,297 tests / 342 suites green, build exit 0. Counter + frozen clusters
byte-identical.