fix(core): drill-down lists descendants under untracked intermediates

listEntries({ parentId: X }) now applies the top-level rule relative to X: this user's
live entries on descendants of X (up to three levels) with no live-entry work strictly
between them and X, so it agrees with childSummary. Restoring an engagement's re-parenting
onto a soft-deleted entry throws ValidationError("entryId", "target entry is deleted").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-30 20:05:12 +01:00
1 parent 00fc0180b0
commit c6865b2522
5 files changed
+49 -5

No files matched your search

+12
View File
@@ -140,6 +140,18 @@ forEachDialect("entries", (getDb) => {
const top2 = await listEntries(db, userId, {});
expect(top2.items.map((i) => i.id).sort()).toEqual([showEntry.id, lone.id, show2Entry.id].sort());
expect(top2.items.find((i) => i.id === show2Entry.id)!.childSummary).toEqual({ total: 2, completed: 1 });
// drilling into the show lists the episodes, since the season between them has no entry
const drill = await listEntries(db, userId, { parentId: show2 });
expect(drill.items.map((i) => i.work.mediaType)).toEqual(["episode", "episode"]);
expect(await listEntries(db, userId, { parentId: show2, q: "nothing matches" })).toEqual({ items: [], nextCursor: null });
// once the season has an entry, the show lists the season and the season lists the episodes
const seasonEntry = await upsertEntry(db, userId, season, { status: "in_progress" }, "user");
expect((await listEntries(db, userId, { parentId: show2 })).items.map((i) => i.id)).toEqual([seasonEntry.id]);
const seasonDrill = await listEntries(db, userId, { parentId: season });
expect(seasonDrill.items.map((i) => i.work.mediaType)).toEqual(["episode", "episode"]);
expect(seasonDrill.items.find((i) => i.id === seasonEntry.id)).toBeUndefined();
});
test("orphaned child entries are top level until an ancestor has an entry", async () => {