fix(game8): decide a column table's header by what it produces

Game8's banner pages lay two schedules side by side inside one <table> under a
spanning label row: "Standard Banners | Banner | Rating | Availability | Paid
Banners | ...". That row is not merely unhelpful, it is plausible — it contains
both column words, so it resolves and puts the range at index 3, which no
three-cell data row has. Every row then fails to date and the table yields
nothing at all, with no error anywhere. So readColumnTable now falls back to
row 1, and only when row 0 produced nothing, which is what keeps every page
that parses today parsing identically.

Those pages also schedule banners rather than events and head their sections
accordingly, so the vocabulary learns "List of All Banners", "All Current
Banners" and — the one that matters — "Previous Banners", whose rows are dated
identically to the live ones directly above them.

This parser serves nine sources, so the widening was measured rather than
trusted: every pinned fixture and every live snapshot was parsed before and
after, and no existing source's output changed by a single event.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Lucas Winther
2026-08-19 03:51:48 +02:00
co-authored by Claude Opus 5
parent 6c7369db10
commit 220e73ff7a
4 changed files with 154 additions and 16 deletions
+7 -1
View File
@@ -231,8 +231,14 @@ several:
repeats each live event under its own `h3` with `Start Date` / `End Date` rows and a paragraph of
prose; those corroborate the dates and supply the blurb the flat table lacks.
*(Persona 5: The Phantom X)*
8. **Two schedules side by side in one `<table>`**, under a spanning label row —
`Standard Banners | Banner | Rating | Availability | Paid Banners | Banner | …`, with the real
header on the row below and three-cell data rows under that. The label row is *plausible*: it
contains both column words, resolves, and puts the range at an index no data row has, so the
table yields nothing at all with no error. `readColumnTable` therefore decides the header by what
it produces — row 1 is tried **only when row 0 produced nothing**. *(Umamusume)*
Shapes 1, 2, 4, 5, 6 and 7 are handled. Before assuming a new Game8 page will work, dump its heading/table
Shapes 1, 2, 4, 5, 6, 7 and 8 are handled. Before assuming a new Game8 page will work, dump its heading/table
structure and check which shape it uses — and check **every** table, not just the obvious one.
Endfield was written off as undatable on a first pass that only inspected its `Duration` rows; its
two real events were in a table further down.