feat(fixtures): season-2026 practice corpus loader and integrity test (8.0) - #359
Open
JoelA510 wants to merge 4 commits into
Open
feat(fixtures): season-2026 practice corpus loader and integrity test (8.0)#359JoelA510 wants to merge 4 commits into
JoelA510 wants to merge 4 commits into
Conversation
… (8.0) Add a read-only loader and integrity test for fixtures/season-2026/practice/, mirroring the game-corpus loader. All thirteen files parse into .strict() Zod records; nothing is dropped, and every parse limit the corpus README states (28 unresolved venues, the Excel-corrupted availability and constraint cells, the two decoder rings' 12 disagreements) is carried as a finding with its raw value beside it, graded by a frozen severity table. The join with the game corpus enumerates teams from the roster and people from the roster, and reports which registration person keys are minted, where select_coaches.csv disagrees with the roster, and which venue names the game corpus does not know. Dates stay YYYY-MM-DD strings, times stay minutes past midnight, and the loader constructs no Date. Every README and plan figure is derived at test time. Two did not hold: the "65 teams that play a game hold no practice slot" claim (the roster says 44, every named schedule side says 53) and the README's disagreement table (it names 9 of the 12). The prompt's "seven files" is thirteen. The finding vocabulary is registered with tests/reasonCodeReachability.test.js and every one of its 24 codes is driven from a public entry point. Two small reuse seams open in the game-corpus modules: computeFixtureChecksums() takes a file list and trim() is exported. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011ppMMPnorTKrb9ZVaGTpS9
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Enumerate the select-coach check from the roster's Select teams too, so a coach the sheet omits is SELECT_COACH_OMITTED_BY_SHEET (8 in the corpus) rather than a name inside another row's detail string. - Split the sheet-to-roster check: SELECT_COACH_NOT_ON_ROSTER_TEAM (8) for a person the roster does not have on the team, SELECT_COACH_SLOT_DIFFERS (1, emerson crane) for the same person at another slot. Slot is a clash-breaker, not a role. - Take the season year from the game corpus, the single producer; report reservations outside it as PERMIT_RESERVATION_OUTSIDE_SEASON and delete seasonYearOfReservations(). - An alias with a label but no venue is DECODER_RING_ALIAS_VENUE_BLANK (11v11 Field 1), never a silent skip from the venue and closure joins. - DAY_NAME_TO_CODE is a Map; 'constructor' no longer resolves. - parsePlayerRegistration() requires the season year and judges birth years, the same contract as parseCoachRegistration(). - Closure-span comment matches inclusiveSpanDays() (92 and 120). - README: the source's "65 teams" claim is kept visible and the derived 44 (from the roster) and 53 (from every named schedule side) added with their derivations; 6 / 22 / 136 marked unreconciled. No CSV touched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011ppMMPnorTKrb9ZVaGTpS9
- compareDecoderRings() compares each display name once; a duplicated alias row is the parser's DUPLICATE_DECODER_CODE, not a second comparison. - Every disagreement carries a kind (label-conflict / blank-vs-label); the test asserts 12 = 11 + 1 and says why the blank counts. - PERMIT_RESERVATION_OUTSIDE_SEASON is PERMIT_RESERVATION_OUTSIDE_SEASON_YEAR, which is what it checks; reservations before the first and after the last scheduled date are meta figures. - One duplicate detector, noteDuplicate(), at all five sites; the corpus finding list is byte-identical before and after. - Season-long closures are decided in the loader by overlap with the scheduled season (>= half its days), not by a 60-day span in the parser; seasonLong and SEASON_LONG_CLOSURE_MIN_DAYS are gone, spanDays stays. - The omitted-coach control filters one team out of the sheet (reachable) instead of forging an empty record set (refused at the header). - README: no escaped underscores, no bullet that reads as a minus, and the sentence says where 44 and 53 are each computed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011ppMMPnorTKrb9ZVaGTpS9
- compareDecoderRings() indexes the fields sheet by first occurrence, as the aliases side already did; a duplicated code_name can neither invent nor reconcile a disagreement. - AVAILABILITY_UNPARSED is judged from the data: an empty window the source does not account for (unavailable, competitive-programme) is unparsed whether or not the label says so. - A season-long closure must be an all-day row (00:00 to 23:00, the sheet's own spelling); a multi-day all-fields row with a daily window is reported apart as timeBoundedClosures, never promoted. Corpus: still exactly Cedarbrook, Fivepines, Quarrywood. - One venue-to-closures map, one ALIAS_RESOLVES_TO_CLOSED_VENUE per closure. - The severity table's blocking count is asserted, and all three blocking codes are raised by one control in the corpus test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011ppMMPnorTKrb9ZVaGTpS9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 8 task 8.0 (
docs/PHASE_8_PLAN.md). Adds a read-only loader and integrity test forfixtures/season-2026/practice/, mirroringpackages/core/src/fixtures/season2026{Loader,Parsers}.jsandtests/season2026Fixture.test.js. Three supervisor review rounds (8 + 7 + 5 items) are folded in.packages/core/src/fixtures/season2026PracticeParsers.js— pure parsers, one.strict()Zod schema and one exact column contract per file (13 files, not the prompt's "seven"), a frozen finding-code table (28 codes) with a frozen severity table, one duplicate detector (noteDuplicate) for all five keyed files,compareDecoderRings()comparing the first occurrence of a code on both sides and carrying akindper disagreement. Excel-date and unparsed availability rows are judged from the data, with the source's label read beside it. NoDateconstruction; dates areYYYY-MM-DD, times are minutes past midnight; weekdays viaavailability/calendar.js's civil-date arithmetic; day names via aMap.packages/core/src/fixtures/season2026PracticeLoader.js—node:fsIO via the game loader's own helpers, the cross-corpus join, a deep-frozen result withfindings,findingsByCode(every code, zero included),seasonLongClosures(all-day, all-fields rows covering ≥ half the days from first to last scheduled date),timeBoundedClosures(the same date test but a daily window — reported apart, never promoted) andmeta(rowsRead / rowsParsed per file, plus what each check examined). The game corpus is the single producer of the season year;dirdefaultsseasonto the game corpus beside it and refuses one from anywhere else. OneALIAS_RESOLVES_TO_CLOSED_VENUEper season-long closure of the alias's venue.tests/season2026PracticeCorpus.test.js— 49 cases: read-only guarantee, every README/plan figure derived at test time, positive controls, including one that raises all three blocking codes beside an assertion on the severity table's blocking count.tests/reasonCodeReachability.test.js— the vocabulary is registered as audited. The corpus itself emits 22 of the 28 codes; the six it does not carry (AVAILABILITY_UNPARSED,PERMIT_DAY_MISMATCH,PERMIT_RESERVATION_OUTSIDE_SEASON_YEAR,CHANGE_LOG_DAY_MISMATCH,DUPLICATE_DECODER_CODE,PRACTICE_TEAM_NOT_ON_ROSTER) are driven from public parsers fed one- or two-row files. Header counts 19 / 424 / 413 / 11 are read back by the test itself.fixtures/season-2026/practice/README.md— the source's "65 teams" claim kept visible, the derived 44 / 53 added with where each is computed; 6 / 22 / 136 marked unreconciled. Two seams in the game-corpus modules:computeFixtureChecksums(dir, files)andexport const trim. No CSV modified.Claims table
PRACTICE_TEAM_PLAYS_NO_GAME= [16BSelect02]ROSTER_TEAM_HOLDS_NO_PRACTICE); 53 from every named side of combined_schedule.csv (computed in the test). README correctedmeta.examined.reservationsBeforeSeason/AfterSeason9v9 Field 2,7v7 Field 2,11v11 Field 2source_sheetSelect OLD; named finding, rows keptALIAS_RESOLVES_TO_CLOSED_VENUE= 1 (one closure, one finding)PRACTICE_TEAM_NOT_ON_ROSTER= 0unavailableorcompetitive-programme);2026-MM-DD⇒(MM+12):00–(DD+12):00on every rowFindings the corpus README does not state
select_coaches.csvvs../coach_roster.csv, both directions: 8 sheet rows name a person the roster does not have on that team (7 minted +teagan hobbes); 1 names a rostered coach at another slot (emerson crane, 19BSelect01, sheet slot 1 / roster slot 2 — slot is a clash-breaker, not a role); 8 roster coaches of Select teams are omitted by the sheet.Maplewood, the game corpusMaplewood Back/Maplewood Front;Larkfield Greenhosts no game.VENUE_NOT_IN_GAME_CORPUS= 33 across all 9 venue-bearing files (list derived from the column contracts).field_constraints.csvGardening Day row hasfields = 2026-01-07(Excel-corrupted1-7).2026.verity bramtefordregistered twice; playersimre hesgaley,ilse wyndafield;Willowmead Parkinventoried twice.player_registration.csvrow; of 10 unresolvable co-coach keys, 7 are registered players' keys (CO_COACH_KEY_IS_PLAYER) and 3 nowhere.11v11 Field 1carries a label but no venue (DECODER_RING_ALIAS_VENUE_BLANK);11v11 Field 2carries neither.confirmedis empty on all 27 code-name rows and is carried on every disagreement.game_change_log.csvmatchup cells.Positive controls (assertions proven able to fail)
Inline, kept as tests: header-only and full extra column, long row, empty file, unknown enum value, unknown record key, non-ISO and impossible calendar dates (
Feb 30), a third slot regime, a reconciled decoder ring (11 < 12), a duplicated alias row (still 20 / 12 plusDUPLICATE_DECODER_CODE), a duplicated code-name row on the fields side in both orders (agree-with-first → 0, differ-with-first → 1; a last-wins index gets both wrong),unparsedand unlabelled date-shaped availability rows, an empty unlabelled window (AVAILABILITY_UNPARSED) againstunavailable/competitive-programme(not), a permit on the wrong weekday, a 2027 reservation (finding) and a 2026-01-05 one (figure, not finding), a change-log note on the wrong day, birth year without a season year for both registration parsers (refuse), a 59-day mid-season closure (season-long) vs a 60-day January one (not), the 2026-09-05..11-28 16:00–19:00 all-fields row (time-bounded, not season-long, no alias finding), two season-long closures of one venue (two alias findings; corpus stays at one), a sheet with one team's rows removed (its three roster coaches reported),'constructor'/'__proto__'as day names, aseasonfrom a non-sibling directory (refused), and one control that raises all three blocking codes beside the severity-table count.Executed against corrupted copies of the corpus in a scratch directory (removed), across the rounds: dropping a grid row, a non-roster team code, Rookery→Rookerie, an
unparsedrow, resolving one(unresolved)venue, shortening the Cedarbrook closure, Friday→Thursday, 16BSelect02→16BSelect01, a minted select coach on a roster key, an added column, a new class value, a wrong-weekday reservation, an edit inside the 142-row makeup sheet, a 30-minute slot, a venue misspelt only in the equipment sheet, a wrong change-log note, a duplicated decoder code, aconfirmedmark, dropping a team from the siblingcoach_roster.csv, every reservation re-dated to 2027 beside the 2026 corpus, dropping one select_coaches row, swapping 19BSelect01's slots, filling the 11v11 Field 1 venue, a player born 2026. ThenoteDuplicategeneralisation was proven by a byte-for-byte comparison of the serialised corpus finding list before and after (111,484 bytes, identical).Verification
Statically reviewed:
/code-reviewat high and medium (11 items, 10 fixed, 1 handled by carryingconfirmedrather than resolving on it); supervisor rounds 1, 2 and 3 (20 items, all fixed).Executed (actual output at head
7ce44d9):Test-verified: everything in the claims table and the inline controls above. The corrupted-copy controls were executed, not kept as tests.
Left open, deliberately: the 65 / 6 / 22 figures (unknown derivation, now stated in the README); the change-log organisation names (operator); whether
used_for/remainderonfield_code_names.csvshould ever be load-bearing (retained as record data); what a time-bounded season closure means for practices (reported astimeBoundedClosureswith its window; the corpus has none).🤖 Generated with Claude Code
https://claude.ai/code/session_011ppMMPnorTKrb9ZVaGTpS9