feat(feed): show the end a Genshin article states

Genshin and Miliastra rows take the end their own wiki article states, because
the table's date can mean 03:59, 14:59, 17:59 or one instant worldwide. Rows with
no usable time stay on the daily-reset reading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Winther
2026-11-07 02:16:57 +01:00
co-authored by Claude Opus 5.5
parent 43530fc222
commit 24327ea99b
7 changed files with 169 additions and 6 deletions
+15 -1
View File
@@ -109,7 +109,9 @@ disagreement between type label and article path. The owner stopped the in-game
walk here because it is slow to navigate, so the other Genshin rows have no
in-game confirmation.
### Open items, none fixed
### Open items
Item 1 was then built: see its note. The others are not fixed.
1. **Day-precision ends can be hours wrong, in both directions.** Fandom's event
table prints dates only, so the app resolves an end to that game-day's reset.
@@ -127,6 +129,18 @@ in-game confirmation.
remain rounded observations and must not be used to mint timestamps. The
likely fix is reading exact times from article pages, which adds requests per
refresh and so needs its own design and a look at § Scraping conduct.
**Done:** `superpowers/specs/2026-11-07-exact-end-times-design.md`. Every live row
was then checked: 9 of 15 were correct. In-game, Test Run read 17d 16h as its article
implies, where the app said 17d 2h.
**One reading disagrees, and is accepted rather than special-cased.** Forge Realm's
Temper is not in the event tab. Its timer at The Cat's Tail read 38d 22h at about
00:30 UTC on 2026-11-07, implying 15 Dec about 22:30-23:30 UTC. Its article says
05:59 GMT+8 on 15 Dec, which is 14 Dec 21:59 UTC, about 25h earlier, and the app had
been about 20h earlier. The timer may cover something beyond the event, or the
article may be wrong: neither is established. The error is on the safe side. Recheck
when the next `The Forge Realm's Temper` run starts.
2. **Wonderland Treasures has no row in either lane.** In game, `Wonderland
Treasures - Polyphonic Harmony` appears in Genshin's event tab, 38d 13h 47m
remaining around 00:12 UTC on 2026-11-07. It is probably the 7.2 counterpart of
+40
View File
@@ -736,3 +736,43 @@ fetched once each and old cached bundles can continue validating the feed. A
small, evidenced article-family resolver supports old feeds/saved snapshots;
unknown content stays in its original category. See DATA-MODEL's source identity
section and the 2026-11-01 content-classification design.
## Article ends (2026-11-07)
Fandom's Genshin `Event` table prints a date, and the same date can mean 03:59 server time, 14:59,
17:59 or one instant worldwide. Each row's article states which, so the refresh keeps those articles
and the build uses them. Genshin and Miliastra only: `genshin-fandom-events` is the one source wired
up, and other games' articles are laid out differently. Reasoning and evidence are in
`superpowers/specs/2026-11-07-exact-end-times-design.md` and `2026-11-01-genshin-event-audit.md`.
**Fetch.** After the source loop, `runRefresh` lists the live rows from the stored table and calls
`scripts/refresh-articles.ts`. It requests `action=parse&section=0`, about 8 KB, and stores the
response under `snapshots/articles/genshin-fandom/`. An article is due when it was never read, when
it stated no time and 6 hours have passed, or when it stated a time and 7 days have passed since a
read that worked. The listing passes the stored ends to the parser: on a row's last day they are what
keeps it listed, and an unlisted article is deleted.
| Result of a read | Stored article | Row shows |
|---|---|---|
| Network error, non-200 other than 404, robots refusal, or a 200 that is not the API's answer | Kept | The last good time, if any |
| 404 or `missingtitle` | Body deleted; metadata kept for the 6-hour floor | Fallback |
| A real article with no usable End | Overwritten | Fallback, logged but not warned: stubs are ordinary |
None of these touches a source's failure streak, health or broken count.
**Parse.** `parseArticleEnd` reads only the `<td data-source="time_end">` cell, in two shapes:
`December 15, 2026 14:59 (Server Time)` gives `regionEnds` at each server's clock, with `endsAt` the
earliest; `December 16, 2026 05:59 GMT+8` gives one instant. Anything else is no usable time.
**Apply.** `applyArticleEnds` runs in `scripts/build-feed.ts` after `mergeEvents`, because the merge
keeps the higher-confidence copy, often Game8's, and would discard an end set on the Fandom row. It
matches by ID or `mergedIds`, and writes only `endsAt`, `endPrecision`, `regionScoped` and
`regionEnds`. The article's date must equal both the table's and the survivor's. If not, the row
stays as merged and the build logs `! article:`. A survivor already at `exact` is left alone.
**Currency.** `fandom.ts` retires a row on its stated end when the article agrees on the date. Without
this, a row ending 14:59 server time would leave the feed on its last day, hours before it closes.
The parser reads `ctx.articleEnds` for this alone and never writes one onto a row.
**Known exception.** Forge Realm's Temper: the Cat's Tail timer read about a day later than its article
on 2026-11-07. Recheck when the next run starts; see the audit doc.
+3
View File
@@ -663,6 +663,9 @@ The app's entire value is that the dates are right. Therefore:
reading retires an event up to nine hours before the game does and the reader is standing in the
game while we say it. This is a reading of the date the source printed, not a time invented for
it, and the detail sheet says as much.
- **A time the source does state is used.** Genshin and Miliastra rows take the end their own wiki
article states, because the same printed date can mean three different times. A row whose article
states none, or a different date, stays on the reading above.
An empty calendar is a recoverable disappointment. A confidently wrong end date is the failure this
product exists to prevent.
@@ -1,6 +1,6 @@
# Exact end times for Genshin and Miliastra — design
Date: 2026-11-07. Status: **approved** by the owner 2026-11-07; plan at `../plans/2026-11-07-exact-end-times.md`.
Date: 2026-11-07. Status: **built** 2026-11-07; plan at `../plans/2026-11-07-exact-end-times.md`. Detail of the shipped behaviour is in `docs/INGESTION.md` § Article ends.
## Why