Task 2's version called occurrenceId twice with identical arguments, which
any pure function satisfies — occurrenceId never takes a title, so it could
not fail the thing it claimed to pin. Task 5 passes the whole rule into
asOccurrenceEvent, so a rename is a real input there and the assertion has
something to bite on.
Found by the Task 2 review.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Pre-flight scan finding. The function is implemented in Task 2 and its four
tests sat in Task 4's block, so Task 2 would have shipped untested code and
Task 4 would have tested a function it did not write. Task 2's stated count
of 23 already assumed the corrected placement.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Eleven tasks from the design, each with its own test cycle and commit.
Ordered so the schema field lands before anything derives from it and the
store migration is proved before a single row is expanded.
Three things the plan had to settle that the spec left to the implementer.
The overlap check is one exported predicate, because a form that restates
its schema's rule drifts from it and starts refusing saves that would
succeed. The timeline's expansion needs App to pass the same four scope
filters the lists use, so the predicate is extracted rather than copied.
And custom-ui.test.tsx renders statically with no testing-library in the
project at all, so anything needing a click is stated as a pure function
and tested directly rather than through a harness that does not exist.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
The app can express a window closing and a day repeating, and nothing in
between — daily.ts counts in days and stops there. That gap is already
costing parsed data: arustats scheduleBosses is read and discarded because
"a recurring rotation with no end is not a deadline" (docs/SOURCES.md:740).
A rule fixes exactly that. Content repeating every fourteen days ends, at
the latest, when its next occurrence opens — a boundary entailed by the
interval rather than invented for a form. So an occurrence may state no end
and still be a deadline, which is the distinction the spec turns on.
Proposes it first on the reader's own events (F13), where the rule is typed
rather than fetched: no parser, no review gate, no GachaEvent change, and a
tested recurrence model in shared/ for the ingest side to adopt later.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
The rules a future change could undo without noticing, written where whoever
touches that area next will read them.
Three of them are traps rather than descriptions. An absent `gameOrder` means
the reader has never placed a game, not an empty order — reading it the other
way hands every existing install a blank list, which is the `knownGames`
mistake again. `games` is left in feed order deliberately, because the code
that hides a reader's games diffs it. And the catch-up window bounds display
and never storage: a fortnight's streak exists on one device and nowhere else,
so nothing prunes the log against a window.
The spec that produced the work goes in alongside, including the helper it
specified and the implementation dropped, so the next reader sees why rather
than wondering.
Also corrects the test count in AGENTS.md, which said 772 and was already
stale before this.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>