From f0e32ae0c1663df1156598d36445c2ec73f7306a Mon Sep 17 00:00:00 2001 From: Will Estes Date: Mon, 10 Aug 2026 17:25:27 -0400 Subject: [PATCH] calendar: fix transferred candidates blindly winning outright MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found via real data (the May sanctoral pull): a transfer landing on a day whose own native winner was temporal blindly took over as winner, regardless of that day's own precedence category — so a transferred-in Simplex saint (St. Felix I, impeded by Pentecost's Ember Saturday) was overwriting Trinity Sunday itself instead of being merely commemorated, the way a native Simplex candidate on an ordinary Sunday already correctly is. Fixes applyIncomingTransfer to run the arriving candidate through decideOccurrence using the receiving day's own temporalCategory, the same rules a native occurrence there would use, instead of assuming an empty temporal slot means automatic victory. Co-Authored-By: Claude Sonnet 5 --- src/calendar/index.ts | 12 +++++++++++- tests/calendar/day-label.test.ts | 6 +++++- tests/calendar/transfer.test.ts | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/calendar/index.ts b/src/calendar/index.ts index 264fd56..126b883 100644 --- a/src/calendar/index.ts +++ b/src/calendar/index.ts @@ -59,7 +59,17 @@ function applyIncomingTransfer( return winner; } if (winner.kind === 'temporal') { - return { kind: 'sanctoral', id: candidate.id, name: candidate.name, rank: candidate.rank }; + // Found via real data: a transferred-in Simplex saint was blindly + // winning outright even when it landed on a privileged Sunday (Trinity + // Sunday, specifically) — the arriving candidate needs to go through + // the *same* precedence rules a native occurrence would have used, + // not just take over because nothing else was assigned here. + const decided = decideOccurrence(temporalCategory, winner.id, candidate); + commemorations.push(...decided.commemorations); + // If the candidate fails here too (decided.transfer set), that's a + // transfer chain — not modeled, same "not delivered rather than + // guessed at" stance as the privileged-feria-major case above. + return decided.winner; } const collision = resolveCollision(candidate, winner); commemorations.push(...collision.commemorations); diff --git a/tests/calendar/day-label.test.ts b/tests/calendar/day-label.test.ts index a2748a1..1cad7c1 100644 --- a/tests/calendar/day-label.test.ts +++ b/tests/calendar/day-label.test.ts @@ -11,7 +11,11 @@ describe('getDayLabel — ordinal temporal label', () => { }); it('names the anchor day itself, not "day after itself"', () => { - expect(getDayLabel(resolveDay('2026-05-31'))).toBe('Trinity Sunday'); + // St. Felix I (May 30, Simplex) is impeded by that date's own Pentecost + // Ember Saturday and transfers forward into Trinity Sunday, where he's + // commemorated (not displacing the Sunday) — real sanctoral content + // now populates this date, so the label reflects both, feast name first. + expect(getDayLabel(resolveDay('2026-05-31'))).toBe('St. Felix I, Pope and Martyr — Trinity Sunday'); expect(getDayLabel(resolveDay('2026-04-05'))).toBe('Easter'); expect(getDayLabel(resolveDay('2026-02-18'))).toBe('Ash Wednesday'); }); diff --git a/tests/calendar/transfer.test.ts b/tests/calendar/transfer.test.ts index d3267d9..e63b9f6 100644 --- a/tests/calendar/transfer.test.ts +++ b/tests/calendar/transfer.test.ts @@ -31,4 +31,26 @@ describe('transfer mechanism (resolveDay integration)', () => { rank: 'duplex-2-classis', }); }); + + // Found via real data (the May sanctoral pull): a transferred-in + // candidate was blindly winning outright whenever the receiving day's + // own native winner was temporal, regardless of that day's own + // precedence category — so a transferred-in Simplex was overwriting + // Trinity Sunday itself instead of going through the same ordinary- + // Sunday rule a native candidate would have. + it('a simplex saint impeded by a privileged feria transfers forward and is merely commemorated, not made to win, on the ordinary Sunday it lands on', () => { + // St. Felix I (May 30, Simplex) is impeded by that date's own + // Pentecost Ember Saturday (privileged-feria-major) and transfers + // forward into Trinity Sunday 2026 (May 31, an ordinary Sunday). + const saturday = resolveDay('2026-05-30'); + const sunday = resolveDay('2026-05-31'); + + expect(saturday.winner).toEqual({ kind: 'temporal', id: 'pentecost-sunday' }); + expect(saturday.commemorations).toEqual([]); + + expect(sunday.winner).toEqual({ kind: 'temporal', id: 'post-pentecost-01' }); + expect(sunday.commemorations).toEqual([ + { kind: 'sanctoral', id: 'st-felix-i', name: 'St. Felix I, Pope and Martyr', rank: 'simplex' }, + ]); + }); });