Commit Graph
367 Commits
Author SHA1 Message Date
github-actions[bot] 67c9526587 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34751710331.
2026-09-13 10:23:38 +00:00
github-actions[bot] 106573671a chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34714267143.
2026-09-12 19:28:56 +00:00
github-actions[bot] 583465e3ed chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34685891621.
2026-09-12 09:27:58 +00:00
Lucas Winther 00a28f08c2 chore(data): add pgr-karendar-events snapshot 2026-09-12 09:10:04 +02:00
Lucas Winther 4382ed35ee feat: add Punishing: Gray Raven with karendar.com source
Add karendar.com as the event source for Punishing: Gray Raven (PGR).
Karendar publishes a dedicated Global event calendar with exact UTC
timestamps in clean server-rendered HTML.

- Register 'pgr' in GameId and GAMES registry (#CC292B, Kuro Games).
- Add parseWeekdayDayMonthYearUtc in src/ingest/dates.ts with unit tests.
- Implement karendarParser in src/ingest/parsers/karendar.ts reading
  'week', 'ongoing', and 'upcoming' sections, mapping indefinite/permanent
  ends to endsAt: null, and categorizing tags to EventType.
- Register pgr-karendar-events in src/ingest/adapters/index.ts.
- Add pinned fixture, expected output, and comprehensive test suites.
- Update documentation in AGENTS.md, README.md, docs/INGESTION.md,
  and docs/SOURCES.md.
2026-09-12 09:10:02 +02:00
Lucas Winther 2d6299445c chore: manually refresh source snapshots. 2026-09-12 08:20:28 +02:00
Lucas Winther c2d5d08551 chore: manually refresh source snapshots. 2026-09-12 07:55:50 +02:00
Lucas Winther 81ac9fb3dd add Genshin Impact Fandom event source
Add genshin-impact.fandom.com as a second source for Genshin Impact,
which has been fixture-backed in CI because Game8 CloudFront-blocks the
Actions runner with 202s.

- Add fifth Fandom template parser in src/ingest/parsers/fandom.ts
  extracting titles from caption display text, stripping dated subpage
  suffixes, and checking currency via latestBoundaryMs.
- Register genshin-fandom-events in src/ingest/adapters/index.ts and
  set genshin-game8-events priority: 10 so existing event IDs survive
  near-match ties, preventing localStorage completion marks from
  orphaning.
- Explicitly sort adapter groups by priority descending in
  scripts/build-feed.ts to align with parseGame.
- Pin fixtures and add test coverage in test/adapters/game8.test.ts.
- Update AGENTS.md, README.md, docs/INGESTION.md, and docs/SOURCES.md.
2026-09-12 05:20:56 +02:00
Lucas Winther 0f224b62f3 widen event duration ceiling to 365 days
Patch cycles are ~6 weeks, so a span over 180 days previously indicated
a misread year. However, real year-long events exist in this domain:
Genshin's anniversary 5-star selection runs 336 days (2025-10-22 to
2026-09-23), correctly dated on its wiki, and Fire Emblem Heroes runs a
seven-month new-player banner (docs/SOURCES.md § 12b).

Widening the ceiling to 365 days admits genuinely year-long events while
still catching misread years, which place the end 12 months out (span +
~365, or 405+ days for a 6-week event).

Update test/adapters/game8.test.ts duration test, AGENTS.md domain rules,
and docs/INGESTION.md sanity checks.
2026-09-12 05:19:50 +02:00
github-actions[bot] 27ed47725f chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34641086597.
2026-09-11 19:52:08 +00:00
github-actions[bot] e553bdcfa7 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34586293407.
2026-09-11 09:51:47 +00:00
github-actions[bot] b99c11cbed chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34522815604.
2026-09-10 19:51:26 +00:00
github-actions[bot] bae21028a4 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34462992369.
2026-09-10 09:52:36 +00:00
github-actions[bot] 2798e15748 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34397595602.
2026-09-09 19:52:29 +00:00
github-actions[bot] 3949bd3a62 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34337307274.
2026-09-09 09:54:49 +00:00
github-actions[bot] e4087f2143 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34272002502.
2026-09-08 19:58:23 +00:00
Lucas Winther 4257335f8a chore: manually refresh sources 2026-09-08 21:56:29 +02:00
github-actions[bot] 1bbfae3eb0 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34212259180.
2026-09-08 09:51:25 +00:00
github-actions[bot] 0d72507881 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34160239024.
2026-09-07 20:39:59 +00:00
github-actions[bot] e7d3d552c1 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34111797670.
2026-09-07 10:31:01 +00:00
github-actions[bot] 473bcdc7b8 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34054496893.
2026-09-06 19:19:20 +00:00
Lucas WintherandClaude Opus 5 8f3e851274 report a source that is quiet rather than broken, instead of a bare 0
The build log prints a count per source, and CI now declines to fail on
a page that states its own emptiness — which leaves that source showing
an unexplained 0, reading as exactly the fault the gate just decided it
was not. The zero we are content with is the one that has to say why.

It is also the only line that would ever prompt anyone to ask whether a
lane quiet for a month is a game between patches or a wiki that reworded
the sentence a statesNoEvents check is still matching. Nothing else in
the pipeline can tell those apart.

The test count in the layout block was stale at 898 and moves with these
two commits, so it is corrected here.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-06 18:03:46 +02:00
Lucas WintherandClaude Opus 5 1156c358a7 fix: stop failing the build on a page that says it has no events
Infinity Nikki's wiki prints "There are no Events in this category"
between versions, and the refresh runner has honoured that since
2026-09-03 — it stores the empty parse as the source's real answer
rather than letting a quiet lane reach the broken tier. The feed build
never asked, so the same page arrived at CI as parsedCount 0,
indistinguishable from a parser that has stopped reading a redesigned
page, and brokenSources failed every build while every refresh stayed
green.

The runner's verdict cannot travel on its own: only a parser has seen
the page, and by the time brokenSources runs there is nothing left but
the feed. So the fact rides on SourceHealth, defaulted so an older feed
the service worker cached keeps validating and reads as the strict
answer.

Both ends now ask it the same way — of an empty parse only, from the
page's own words only — because a redesign yields zero rows too, and
excusing that is the silently emptied calendar the gate exists for.

The rule sits in a module rather than in build-feed.ts, which writes
public/ and so runs a build if a test imports it. That is how the two
ends drifted apart with nothing to catch it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-06 18:02:16 +02:00
Lucas Winther e51585f2b2 chore: manually refresh sources 2026-09-06 17:40:03 +02:00
github-actions[bot] f65c7fc2d5 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 34024890638.
2026-09-06 09:31:55 +00:00
github-actions[bot] 5dd57d3781 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33986194791.
2026-09-05 19:08:58 +00:00
github-actions[bot] 41954044b8 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33957237624.
2026-09-05 09:10:37 +00:00
github-actions[bot] 83312f2016 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33912471169.
2026-09-04 19:42:17 +00:00
github-actions[bot] 5936ea725f chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33859846418.
2026-09-04 09:45:22 +00:00
github-actions[bot] 8073726c4e chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33799403577.
2026-09-03 19:57:39 +00:00
Lucas WintherandClaude Opus 5 b039e44dcc chore(data): refresh the Infinity Nikki snapshot
First successful fetch since 2026-08-26. The page currently lists no events
in either section, so eventCount is 0 and the lane is honestly empty rather
than holding rows that expired on 27 August.

Run by hand with --force, since the six-hour floor was not up and the
source had four failed cycles behind it. robots.txt read normally.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-03 19:03:39 +02:00
Lucas WintherandClaude Opus 5 4d45635b0e Write down that a source can be empty without being broken
The two preceding changes make sentences in docs/ false. INGESTION.md
described `canParse` as a structural check without saying that "structural"
excludes the presence of a row — which is exactly the drift that let this
bug in — and described the Stage 1 gate as rejecting every empty parse.
SOURCES.md § 11 left a reader to conclude that an empty Infinity Nikki lane
means the source has died.

AGENTS.md gets the rule in both places somebody would look: § Working on
parsers, next to the bullet about a source resting on one row, and § Fandom
where the fourth template is described.

The general lesson is worth more than the incident. Any page that can list
nothing can produce this, so the guidance is about what identifies a page
versus what happens to be on it — not about this wiki.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-03 18:46:15 +02:00
Lucas WintherandClaude Opus 5 4b2b3d0958 Store an empty parse when the page itself says it lists nothing
Refusing every zero-event body is right when the alternative is silently
emptying a calendar, and wrong when the page has told us it is empty. A
gacha game goes quiet between versions, and read strictly that is a source
failing every cycle until the next patch ships: three of them reach the
broken tier and fail the workflow over a lane that is correctly empty,
while the snapshot being held ages out of date. Infinity Nikki sat in
exactly that state for four cycles.

So an empty parse is stored when the source's `statesNoEvents` vouches for
it, and the cycle counts as confirmed rather than failed. Everything else
is unchanged: a body that parses to nothing on its own still keeps the
previous snapshot, and a first fetch that yields nothing still stores
nothing.

The gate turns on the page's statement, never on the adapter merely being
able to make one — otherwise implementing `statesNoEvents` would quietly
switch the zero-events gate off for that source. A test pins that.

The run says which of the two empties it saw. "0 events — down from 6"
reads as the shape change it is not, and that note is what somebody
checking on a quiet lane actually sees.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-03 18:45:57 +02:00
Lucas WintherandClaude Opus 5 a73f35b7cd Identify the Infinity Nikki page by its headings, not by finding a row
The wiki emptied both its Current and Upcoming tables on 2026-09-03 — 2.7's
events had ended and 2.8 was not listed yet — and said so in words: "There
are no Events in this category". Nothing else moved; Past Events still
carries twenty tables of the same shape.

`isInfinityNikkiEventPage` looked for a *populated* table, so it read that
as a redesign. The source spent four cycles reporting "the source has
likely been redesigned" at a page nobody had touched, reached the broken
tier, and went on serving a snapshot whose every row expired on 27 August.

A check that reads data cannot tell a rewrite from a quiet week. It now
reads the section headings, which an empty table does not take with it —
either heading rather than both, since requiring the pair would fail the
source over a renamed heading it does not even read, and one already
separates this page from the other three Fandom templates. docs/INGESTION.md
asked for structural checks all along; this one had drifted into content.

`statesNoEvents` then reports the page's own declaration, so the runner can
tell an answer from a failure. It insists on the statement rather than an
empty table, because a redesign yields an empty table too.

The emptied page is pinned as a fixture: an empty answer is a shape, and it
is the one that used to read as a redesign.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-03 18:45:24 +02:00
Lucas WintherandClaude Opus 5 0809fa1122 Let a parser report that a page states it lists no events
A count of zero has two causes and nothing downstream can tell them apart:
a source whose selectors all broke, and a game that is simply between
patches. Both parse to nothing, so `canParse` plus a row count cannot
separate them — and the pipeline currently has to assume the worst, which
is right for a redesign and wrong for a quiet week.

`statesNoEvents` is the seam for the one thing that can settle it: the
page's own words. Optional, because most pages say nothing either way, and
absent means the strict gate stands.

No parser implements it yet and nothing reads it — the contract widens here
so the parser and the refresh gate can land as their own changes.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-03 18:44:51 +02:00
Lucas Winther d5301c5ceb Merge branch 'main' of https://github.com/StereotypicalCat/gacha-event-tracker 2026-09-03 18:13:24 +02:00
Lucas Winther 8568be1892 chore: manually refresh sources 2026-09-03 18:08:22 +02:00
github-actions[bot] 61a1b7e532 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33741629116.
2026-09-03 09:57:27 +00:00
github-actions[bot] fe35a639aa chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33675938499.
2026-09-02 19:53:24 +00:00
github-actions[bot] fed76900b5 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33615707656.
2026-09-02 09:44:25 +00:00
github-actions[bot] 2ef9829627 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33552622815.
2026-09-01 19:59:25 +00:00
github-actions[bot] 26e3d9f6e4 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33496426182.
2026-09-01 10:15:32 +00:00
github-actions[bot] ac1ceb4897 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33443803303.
2026-08-31 21:56:37 +00:00
github-actions[bot] a96b9718e5 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33388081400.
2026-08-31 11:41:08 +00:00
github-actions[bot] 2a14c16edf chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33332103597.
2026-08-30 19:53:46 +00:00
Lucas Winther c551ca33ab chore: manually refresh source snapshots. 2026-08-30 12:57:34 +02:00
Lucas WintherandClaude Opus 5 393ea594ea Only warn about staleness for games the reader has switched on
The footer's staleness notice is an instruction, and the only remedy it
offers is "go and check that game's source page". That is not something a
reader can act on for a game they turned off and cannot see a single row
of — and with nineteen lanes, naming eleven they do not play buries the one
they do. A new lane arrives switched off (F8), so an untouched install was
being warned about most of the catalogue.

Scoped in two places, not one: the named list, and the count the
summarising branch measures against. Without the second, that branch would
never fire for a reader with most of the calendar off and they would get a
list where a sentence was the readable answer.

The notice now also states whose games it counted, in the words NextUp
already uses for the same set. Narrowing what the footer measured while
still printing "nothing has refreshed" would turn a claim about four games
into one about eighteen, in the one paragraph on the page whose job is
being trusted about age.

The headline age and the credits stay whole: the first is a fact about the
feed and feeds the bug form, the second is attribution owed to every source
we read regardless of what is on screen.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-30 12:56:00 +02:00
github-actions[bot] 8b3d130521 chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33306719302.
2026-08-30 10:32:55 +00:00
github-actions[bot] 1ddb1604ab chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33271849258.
2026-08-29 19:49:40 +00:00
github-actions[bot] ea072362fa chore(data): refresh source snapshots
Automated fetch from Refresh sources run 33250736261.
2026-08-29 11:42:39 +00:00