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.
This commit is contained in:
@@ -186,8 +186,21 @@ These come from how gacha games actually schedule things, and they cause most bu
|
|||||||
deadline they were counting down to vanish on its last day. So `latestBoundaryMs` answers the same
|
deadline they were counting down to vanish on its last day. So `latestBoundaryMs` answers the same
|
||||||
question for the *last* region, and `bawiki.ts` and two branches of `fandom.ts` ask it. Nothing
|
question for the *last* region, and `bawiki.ts` and two branches of `fandom.ts` ask it. Nothing
|
||||||
stored changes: it is one comparison, not a resolved boundary written to the feed.
|
stored changes: it is one comparison, not a resolved boundary written to the feed.
|
||||||
- **Patch cycles are ~6 weeks.** Any event over 180 days is a parse error, not a long event. The
|
- **Patch cycles are ~6 weeks, and a span over a year is a parse error rather than a long event.**
|
||||||
validator and the tests both reject it.
|
`test/adapters/game8.test.ts` rejects one across every fixture. Two corrections to what this rule
|
||||||
|
used to say, both load-bearing:
|
||||||
|
- **The ceiling is 365 days, not 180** (raised 2026-09-12, repository owner). A real event finally
|
||||||
|
exceeded 180: Genshin's anniversary 5-star selection runs 336 days, correctly dated on its wiki,
|
||||||
|
and 180 would have dropped a deadline readers want. 365 keeps the guard aimed at what it was
|
||||||
|
built for, because a misread year puts the *end* twelve months out and so reads as span + ~365 —
|
||||||
|
405 days for a six-week event, still caught. What it newly admits is only the genuinely
|
||||||
|
year-long event, a shape this domain does have; the same widening clears Fire Emblem Heroes'
|
||||||
|
seven-month new-player banner (`docs/SOURCES.md` § 12b), which had been parked on this question.
|
||||||
|
- **There is no validator.** This file claimed "the validator and the tests both reject it" and
|
||||||
|
only the second half was ever true — the validator belongs to the quarantine gate described in
|
||||||
|
`docs/INGESTION.md`, which is specified and **not built**. So the rule is enforced per adapter,
|
||||||
|
by a test, against a pinned fixture: a source added without a fixture in that table is a source
|
||||||
|
the rule does not cover.
|
||||||
|
|
||||||
## Working on parsers
|
## Working on parsers
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -516,7 +516,7 @@ quarantine with `reason: 'sanity_failed'` — never to the feed.
|
|||||||
| Rule | Rationale |
|
| Rule | Rationale |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `endsAt` after `startsAt` when both present | A backwards interval is always a parse error |
|
| `endsAt` after `startsAt` when both present | A backwards interval is always a parse error |
|
||||||
| Duration under 180 days | Patch cycles are ~6 weeks; longer means a misread year |
|
| Duration under 365 days | Patch cycles are ~6 weeks; a year-plus span means a misread year. Raised from 180 on 2026-09-12, when a real 336-day event arrived — see AGENTS.md § Domain rules. Until this stage is built, the rule lives only in `test/adapters/game8.test.ts` |
|
||||||
| `startsAt` within [now − 2y, now + 1y] | Catches century typos and relative-date misreads |
|
| `startsAt` within [now − 2y, now + 1y] | Catches century typos and relative-date misreads |
|
||||||
| `endsAt` null exactly when `endPrecision` is `"unknown"` | The two fields must agree |
|
| `endsAt` null exactly when `endPrecision` is `"unknown"` | The two fields must agree |
|
||||||
| `regionEnds` non-null exactly when `regionScoped` | Same |
|
| `regionEnds` non-null exactly when `regionScoped` | Same |
|
||||||
|
|||||||
@@ -97,14 +97,26 @@ describe.each(CASES)("$adapter.id $fixture", ({ adapter, fixture }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("no event runs longer than 180 days", async () => {
|
test("no event runs longer than 365 days", async () => {
|
||||||
// Patch cycles are ~6 weeks. A longer span means a misread year, which is
|
// Patch cycles are ~6 weeks, so a long span is usually a misread year —
|
||||||
// the failure mode most likely to reach a user as a confident wrong date.
|
// the failure mode most likely to reach a user as a confident wrong date.
|
||||||
|
//
|
||||||
|
// The ceiling is 365 and not 180 because a real event finally exceeded 180:
|
||||||
|
// Genshin's anniversary 5-star selection runs 336 days
|
||||||
|
// (2025-10-22 → 2026-09-23), correctly dated on its wiki, and its end is
|
||||||
|
// the kind of deadline this app exists to show. 180 would have dropped it.
|
||||||
|
//
|
||||||
|
// 365 keeps the guard pointed at what it was built for. A misread year
|
||||||
|
// lands the *end* twelve months out, so it shows up as span + ~365 — 405
|
||||||
|
// days for a six-week event, still caught. What 365 newly admits is only
|
||||||
|
// the genuinely year-long event, a shape this domain does have:
|
||||||
|
// the same widening clears Fire Emblem Heroes' real seven-month
|
||||||
|
// new-player banner (docs/SOURCES.md § 12b).
|
||||||
for (const e of await runAdapter(adapter, fixture)) {
|
for (const e of await runAdapter(adapter, fixture)) {
|
||||||
if (e.endsAt === null) continue;
|
if (e.endsAt === null) continue;
|
||||||
const days =
|
const days =
|
||||||
(Date.parse(e.endsAt) - Date.parse(e.startsAt)) / 86_400_000;
|
(Date.parse(e.endsAt) - Date.parse(e.startsAt)) / 86_400_000;
|
||||||
expect(days).toBeLessThanOrEqual(180);
|
expect(days).toBeLessThanOrEqual(365);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user