feat(feed): name the ids merge absorbed, and carry marks off them

When merge fuses two sources' copies, the loser's id leaves the calendar, and it may already hold a reader's ticks from a day it was published alone. Until now that needed a hand-edited RETIRED_IDS entry per fusion.

The survivor now lists what it absorbed in an optional mergedIds field. When a feed arrives the client turns those into carry-forward pairs, skipping any id the feed still publishes, and an import takes the same table. Optional, so an older cached feed still validates and an older bundle drops it unread. RETIRED_IDS stays for parser changes, whose old ids no feed will name again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-14 17:48:15 +02:00
1 parent 59403ca2cc
commit 2924605bd4
13 files changed
+296 -90

No files matched your search

+9
View File
@@ -76,6 +76,15 @@ export const GachaEvent = z
version: z.number().int().positive(),
firstSeenAt: z.string().datetime(),
updatedAt: z.string().datetime(),
/**
* Ids of other sources' copies merge folded into this one. They may already
* be readers' localStorage keys, so the client moves marks from them to
* `id` (docs/DATA-MODEL.md § ID stability). Optional: absent on every
* single-source event and on any feed built before 2026-10-14, and an older
* client's non-strict parse drops it unread.
*/
mergedIds: z.array(z.string()).optional(),
})
// These invariants are cheap here and prevent a whole class of wrong-date bugs
// reaching the feed. See docs/INGESTION.md § Stage 4.