Add Dec 26-30's own Sunday rule -- a deliberate remix, not a live-verified fix
Deploy / deploy (push) Successful in 54s
Deploy / deploy (push) Successful in 54s
Per direct instruction, and explicitly framed as this project's own departure from Monastic 1617 itself: within Dec 26-30 inclusive (exactly one real Sunday falls somewhere in that window every year), whichever date is the actual Sunday always wins as Nat1-0 outright, with no rank check at all -- even Stephen/John/Holy Innocents (Duplex II. classis) get fully displaced, not just commemorated. The displaced saint isn't commemorated in place either; he reappears in full as Dec 30's own winner instead (the block's one date with no fixed saint of its own). Rank never matters for this rule -- confirmed with Becket (Semiduplex) transferring the same way as the Duplex-II-classis saints. This deliberately diverges both from what Monastic 1617 itself does on Dec 26-29 (live-verified two commits ago: the saint wins there, Sunday merely commemorated) and from the general privileged-sunday transfer rule elsewhere (which only transfers ranks below duplex-majus and commemorates everything else in place) -- this window transfers every rank and commemorates nothing in place, a genuinely new, third behavior specific to this 5-day block. Implemented as calendar/index.ts's applyChristmasOctaveSunday, a narrowly-scoped layer in the same spirit as applyMarianSaturday/ applyChristTheKing, rather than by changing the shared decideOccurrence/transfer machinery every other Sunday relies on. Dec 31 and everything outside Dec 26-30 is untouched -- St. Silvester still beats the Sunday there via the plain, unchanged ordinary-sunday rule. Verified against all five possible Sunday positions within the window (Dec 26/27/28/29/30) plus the "nothing displaces anything" control case, each with its own dedicated test in the new tests/calendar/christmas-octave-sunday.test.ts. Updates two existing tests whose assertions were correct under the old rule and are now superseded specifically within this window (Stephen/Innocents no longer win their own Sunday-collision dates there) while confirming the underlying ordinary-sunday rule is still live and real outside it (Dec 31/St. Silvester). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -103,6 +103,7 @@ export function resolveDay(isoDate: string): LiturgicalDay {
|
||||
winner = applyOctaves(isoDate, winner, commemorations);
|
||||
winner = applyMarianSaturday(isoDate, weekday, temporalCategory, winner, commemorations);
|
||||
winner = applyChristTheKing(isoDate, winner, commemorations);
|
||||
winner = applyChristmasOctaveSunday(isoDate, weekday, winner, commemorations);
|
||||
|
||||
return { date: isoDate, weekday, season, temporalCategory, winner, commemorations };
|
||||
}
|
||||
@@ -137,6 +138,65 @@ function applyChristTheKing(isoDate: string, winner: DayWinner, commemorations:
|
||||
return { kind: 'temporal', id: 'christ-the-king' };
|
||||
}
|
||||
|
||||
/**
|
||||
* Per direct instruction, scoped to exactly Dec 26-30 — every year
|
||||
* contains exactly one real Sunday somewhere in that 5-day window.
|
||||
*
|
||||
* On whichever of Dec 26-29 it actually falls, Nat1-0 (the Sunday within
|
||||
* the Octave of the Nativity) always wins outright, full stop — no rank
|
||||
* check at all, a deliberate departure from what Monastic 1617 itself
|
||||
* does there (a Duplex-II-classis saint — Stephen/John/Innocents — beats
|
||||
* the Sunday there in the real engine; see TODO.md). The displaced
|
||||
* saint isn't even commemorated in place; he reappears in full on Dec
|
||||
* 30 instead — the block's one date with no fixed saint of its own —
|
||||
* rather than the general privileged-sunday transfer/commemorate split
|
||||
* used everywhere else. Dec 30 itself, on a year it's the *actual*
|
||||
* Sunday (nothing displaced), resolves normally: Nat1-0 wins clean since
|
||||
* nothing was ever assigned there to begin with.
|
||||
*/
|
||||
function applyChristmasOctaveSunday(
|
||||
isoDate: string,
|
||||
weekday: ReturnType<typeof weekdayOf>,
|
||||
winner: DayWinner,
|
||||
commemorations: Commemoration[],
|
||||
): DayWinner {
|
||||
const [year, monthStr, dayStr] = isoDate.split('-');
|
||||
if (monthStr !== '12') {
|
||||
return winner;
|
||||
}
|
||||
const day = Number(dayStr);
|
||||
|
||||
if (day >= 26 && day <= 29 && weekday === 'sunday') {
|
||||
return { kind: 'temporal', id: 'christmas-octave-sunday' };
|
||||
}
|
||||
|
||||
if (day === 30) {
|
||||
for (let d = 26; d <= 29; d++) {
|
||||
const candidateDate = `${year}-12-${String(d).padStart(2, '0')}`;
|
||||
if (weekdayOf(candidateDate) !== 'sunday') {
|
||||
continue;
|
||||
}
|
||||
const displaced = getSanctoralCandidatesFor(candidateDate)[0];
|
||||
if (!displaced) {
|
||||
break;
|
||||
}
|
||||
// Drop the now-redundant "Octave of <displaced>" commemoration —
|
||||
// applyOctaves already pushed one above, using Dec 30's *original*
|
||||
// temporal winner; now that the displaced saint is winning the day
|
||||
// outright instead, commemorating his own octave alongside himself
|
||||
// would be the same redundancy applyOctaves' own `isSelf` check
|
||||
// already avoids on a saint's actual day.
|
||||
const idx = commemorations.findIndex((c) => c.kind === 'octave' && c.id === displaced.id);
|
||||
if (idx !== -1) {
|
||||
commemorations.splice(idx, 1);
|
||||
}
|
||||
return { kind: 'sanctoral', id: displaced.id, name: displaced.name, rank: displaced.rank };
|
||||
}
|
||||
}
|
||||
|
||||
return winner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layered on top of everything above, same spirit as applyOctaves: never
|
||||
* changes decideOccurrence's own rules, just relabels the result on a free
|
||||
|
||||
Reference in New Issue
Block a user