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.
This commit is contained in:
+8
-8
@@ -51,7 +51,7 @@ Consequences worth internalising:
|
||||
| `game8` | game8.co article calendars | Genshin, Star Rail, Wuthering Waves, ZZZ, Endfield, NTE, Persona 5: The Phantom X, Chaos Zero Nightmare, Umamusume |
|
||||
| `wikigg` | wiki.gg MediaWiki `mp-event` templates | Endfield |
|
||||
| `akwiki` | arknights.wiki.gg's `mrfz-wtable` "Ongoing/upcoming" table | Arknights |
|
||||
| `fandom` | Fandom wikis via the MediaWiki `action=parse` API — four page templates: `Event \| Time Period \| Version` wikitables, FGO's picture-fenced `ONGOING EVENTS` blocks, Nikke's `Event \| Start(UTC+9) \| End(UTC+9)` tables, and Infinity Nikki's `Event \| Duration \| Description \| Type` article-tables | Reverse: 1999, Fate/Grand Order, Nikke, Infinity Nikki |
|
||||
| `fandom` | Fandom wikis via the MediaWiki `action=parse` API — five page templates: `Event \| Time Period \| Version` wikitables, FGO's picture-fenced `ONGOING EVENTS` blocks, Nikke's `Event \| Start(UTC+9) \| End(UTC+9)` tables, Infinity Nikki's `Event \| Duration \| Description \| Type` article-tables, and Genshin Impact's `Event \| Duration \| Type(s)` tables | Reverse: 1999, Fate/Grand Order, Nikke, Infinity Nikki, Genshin Impact |
|
||||
| `bawiki` | bluearchive.wiki's rendered `/wiki/Events` — a JP/Global tabber over `Name (EN) \| Start date \| End date \| Notes` wikitables | Blue Archive |
|
||||
| `holodoriwiki` | holodori.wiki's rendered `/wiki/Events` — `Current Events` and `Past Events` wikitables over `Event \| Type \| Start Date \| End Date` | hololive Dreams |
|
||||
| `iopwiki` | iopwiki.com's `gf-table event-period` tables — `Title \| Period (start/end) \| Server \| Type \| Comment`, one table per event and one row per server | Girls' Frontline 2 |
|
||||
@@ -140,7 +140,7 @@ All live in `src/ingest/dates.ts`, each returning null rather than inferring any
|
||||
|---|---|---|
|
||||
| `parseMonthDayYear` | `August 12, 2026` | Genshin detail rows |
|
||||
| `parseMonthDayRange` | `August 12 - September 21, 2026` (year on the end only) | Genshin, NTE |
|
||||
| `parseFullRange` | `Aug. 14, 2026 - Aug. 24, 2026` (a year each side) | Star Rail, Wuthering Waves, Fate/Grand Order |
|
||||
| `parseFullRange` | `Aug. 14, 2026 - Aug. 24, 2026` (a year each side) | Star Rail, Wuthering Waves, Fate/Grand Order, Genshin Impact (Fandom) |
|
||||
| `parseShortSlashRange` | `08/09/26 - 08/30/26` | Endfield |
|
||||
| `parseSlashDateTimeRange` | `2021/01/16 04:00 - 2021/01/31 03:59` | Genshin past events |
|
||||
| `parseLabelledStartEnd` | `Start: January 24, 2025 End: Permanent` | Infinity Nikki |
|
||||
@@ -161,15 +161,15 @@ midnight because it has to store *something*. It is not a statement that the eve
|
||||
then, and nothing may count down to it literally: `clockFor` resolves a day-precision boundary to
|
||||
that game-day's server reset for the reader's region (`docs/DATA-MODEL.md` § Field notes).
|
||||
|
||||
**No parser may store a resolved boundary, and three of them must read one to decide inclusion.**
|
||||
**No parser may store a resolved boundary, and four of them must read one to decide inclusion.**
|
||||
The stored value stays the printed day at 00:00Z: resolving it here would need a region the parser
|
||||
does not have, and would bake one reader's server into the feed everybody downloads. But a parser
|
||||
whose page carries no "ongoing" heading it can trust decides currency against `ctx.now` itself —
|
||||
`bawiki.ts`, and the Fate/Grand Order and Infinity Nikki branches of `fandom.ts` — and comparing the
|
||||
placeholder to `now` retires a row at UTC midnight, hours before `clockFor` calls it over for
|
||||
anybody. The reader does not see a stale row; they watch the deadline they were counting down to
|
||||
disappear on its last day, which is the silent drop AGENTS.md § Working on parsers calls the
|
||||
dangerous failure. So those three ask `latestBoundaryMs` (`src/shared/time.ts`) when the boundary is
|
||||
`bawiki.ts`, and the Fate/Grand Order, Infinity Nikki and Genshin Impact branches of `fandom.ts` —
|
||||
and comparing the placeholder to `now` retires a row at UTC midnight, hours before `clockFor` calls
|
||||
it over for anybody. The reader does not see a stale row; they watch the deadline they were counting
|
||||
down to disappear on its last day, which is the silent drop AGENTS.md § Working on parsers calls the
|
||||
dangerous failure. So those four ask `latestBoundaryMs` (`src/shared/time.ts`) when the boundary is
|
||||
day-precision: the last region's reset, and therefore the instant the row is history for every
|
||||
reader rather than for the earliest of them. Being generous by nine hours costs one expired row at
|
||||
the bottom of a list; being strict costs a live one.
|
||||
|
||||
+18
-1
@@ -59,6 +59,7 @@ Two things this method cannot tell you, and both matter:
|
||||
| Infinity Nikki | **Rebuilt** (2026-08-19) on `infinity-nikki.fandom.com` at day precision, replacing a Game8 page stale since August 2025 — see § 11 |
|
||||
| Silver Palace | Unreleased |
|
||||
| Honkai Impact 3rd | **Built** (2026-08-27) on `arustats.com`, and the only lane here whose dates are **estimates** — see § 14 |
|
||||
| Genshin Impact (Fandom) | **Built** (2026-09-12) on `genshin-impact.fandom.com`, second source for a blind lane — see § 15 |
|
||||
|
||||
## Summary of findings
|
||||
|
||||
@@ -74,6 +75,7 @@ Two things this method cannot tell you, and both matter:
|
||||
| Azur Lane | none | — | — | **Still declined** — the Fandom alternatives are 2021 archives |
|
||||
| Aether Gazer | — | — | — | **Do not build. The game is shutting down.** |
|
||||
| Silver Palace | — | — | — | Unreleased; beta only |
|
||||
| Genshin Impact (Fandom) | `genshin-impact.fandom.com/api.php?…page=Event` | `fandom`, fifth template | yes (via `api.php`) | **BUILT** 2026-09-12 — adds 11 events Game8 missed; Game8 priority preserves localStorage IDs |
|
||||
|
||||
---
|
||||
|
||||
@@ -484,7 +486,7 @@ table.
|
||||
|
||||
**One cost applies to both builds and should be in the commit message, not discovered later.** Both
|
||||
candidates are game8.co, which does not answer the Actions runner (`AGENTS.md` § Scraping conduct).
|
||||
Nine of the twenty sources are game8 pages today, now that Infinity Nikki has moved to Fandom
|
||||
Nine of the twenty-one sources are game8 pages today, now that Infinity Nikki has moved to Fandom
|
||||
(§ 11); these would make ten and eleven. Each is a lane fixture-backed in CI from day one and only
|
||||
ever as fresh as someone's last manual `bun run refresh`, and one more request to a single host every
|
||||
cycle — the per-host arithmetic § Scraping conduct already calls uncomfortable.
|
||||
@@ -767,6 +769,21 @@ Phase B's first target in
|
||||
changed on the ingest side yet — `GachaEvent` does not carry a rule, and this
|
||||
note is what stops the next person re-deriving the reason it does not.
|
||||
|
||||
## 15. Genshin Impact (Fandom) — BUILT 2026-09-12, adding a second source for a blind lane
|
||||
|
||||
**Source:** `https://genshin-impact.fandom.com/api.php?action=parse&page=Event&prop=text&formatversion=2&format=json` (page at `https://genshin-impact.fandom.com/wiki/Event`).
|
||||
|
||||
**Conduct:** Standard Fandom `robots.txt` (`Allow: /api.php?action=`, no `Disallow: /` for `*`, no `Content-Signal`). Read with the runner's client; CI can fetch it.
|
||||
|
||||
**Why built:** Genshin's Game8 page has never been fetchable from CI (CloudFront returns a `202` on all runners), so until now Genshin was fixture-backed in CI and could only age. Fandom provides a second, active source that scheduled refreshes can update.
|
||||
|
||||
**The template:** Fifth Fandom template. `Current Events` and `Upcoming Events` wikitables under `h3` headings with columns `Event | Duration | Type(s)`.
|
||||
- **Title extraction:** Display text of the caption link beneath the banner image is taken. Link `title` (parent subpage) and `img alt` (uploaded image file name) are rejected to prevent corrupting event titles and IDs.
|
||||
- **Run-date suffixes:** Recurring event run dates (`2026-09-14`) in subpage names are stripped so dates aren't duplicated.
|
||||
- **Currency:** `latestBoundaryMs` is checked for day-precision boundaries so events aren't retired before all server regions roll.
|
||||
- **Priority & IDs:** Game8 is assigned `priority: 10` while Fandom is default/0. Two live events differ slightly in naming (`To Temper Thyself and Journey Far` vs `… Cycle 5`, and `Stygian Onslaught` vs `…: Battle of the Starburst`). Game8's higher priority breaks near-match ties in `merge.ts`, ensuring existing localStorage event IDs survive and reader completion marks remain intact. Fandom contributes 11 net-new events Game8 missed, 0 date conflicts occur, and overlapping events gain corroboration bonuses.
|
||||
- **336-day event:** Genshin's anniversary 5-star selection runs 336 days (`2025-10-22` → `2026-09-23`), prompting the test duration ceiling to be raised from 180 to 365 days across the test suite and ingestion specs.
|
||||
|
||||
## What every one of these costs, beyond the source
|
||||
|
||||
Adding a game is never only a `SOURCES` entry:
|
||||
|
||||
Reference in New Issue
Block a user