Move the rename-stability test to where it can fail

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]>
This commit is contained in:
Lucas Winther
2026-08-28 05:04:39 +02:00
co-authored by Claude Opus 5
parent 1535c2d920
commit ee43270b2b
@@ -1116,6 +1116,21 @@ describe("asOccurrenceEvent", () => {
expect(isCustomEventId(row.id)).toBe(true); expect(isCustomEventId(row.id)).toBe(true);
}); });
test("renaming a rule does not move its occurrence ids", () => {
// The token is random precisely so fixing a typo never costs the marks
// attached to an occurrence. Exercised here rather than against
// occurrenceId, which never takes a title and so could not fail it: this
// path passes the whole rule, so a rename is a real input to the result.
const rule = repeating();
const renamed = { ...rule, title: "Abyss, actually" };
const now = new Date("2026-09-15T12:00:00").getTime();
const before = asOccurrenceEvent(rule, nextOccurrences(rule, now, 1)[0]!);
const after = asOccurrenceEvent(renamed, nextOccurrences(renamed, now, 1)[0]!);
expect(after.id).toBe(before.id);
expect(after.title).toBe("Abyss, actually");
});
test("a derived end is a real end, so the clock counts down to it", () => { test("a derived end is a real end, so the clock counts down to it", () => {
// The rule stores endsAt: null; the occurrence resolves it. A row reaching // The rule stores endsAt: null; the occurrence resolves it. A row reaching
// a view must never carry the unresolved form, or it renders as // a view must never carry the unresolved form, or it renders as