4bbd78b1fd
Deploy / deploy (push) Successful in 1m23s
Adds pre-1955 TemporalFeastRecords (rank duplex-1-classis, real octaves) for the three "feasts of the Lord" that were previously only referenced as bare date offsets: Corpus Christi/Sacred Heart's own days already couldn't lose to a sanctoral candidate, but with no record the day fell back to the generic Trinity-week feria collect and never displayed its real name; Ascension had no protection at all against an ordinary saint winning it outright. Sacred Heart's own record carries the forbidsSuccessorCommemoration flag added in the prior commit, refusing to commemorate Most Precious Blood on the rare late-Easter date they fall adjacent. octave.wins is set to duplex on all three, matching Pentecost's own verified threshold, despite a known conflict with a previously live-verified case (St. Ubald winning First Vespers within Ascension's own octave) -- kept per direct instruction; the affected tests (Ubald, St. Margaret of Scotland) were updated to assert the new behavior, and the tradeoff is documented in ascension.yml and TODO.md. A handful of unrelated test fixtures that happened to land inside these new octave windows were moved to nearby clean dates. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014axryJBrRswYh2niA7WCUc
94 lines
4.5 KiB
TypeScript
94 lines
4.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { resolveEveningDay } from '../../src/calendar/vespers';
|
|
|
|
describe('resolveEveningDay', () => {
|
|
it('anticipates tomorrow when tomorrow is a Sunday and today is a plain feria (Saturday before Advent I)', () => {
|
|
// Nov 30, 2025 is Advent I Sunday.
|
|
const day = resolveEveningDay('2025-11-29');
|
|
expect(day.date).toBe('2025-11-30');
|
|
expect(day.season).toBe('advent');
|
|
});
|
|
|
|
it('does not anticipate between two plain ferias', () => {
|
|
// 2033-09-06: Tuesday, ordinary trinitytide, genuinely free of any
|
|
// saint or active octave on both this date and the next (2026-06-16,
|
|
// used here previously, fell inside Sacred Heart's own octave once
|
|
// that was modeled 2026-08-26 -- see TODO.md).
|
|
const day = resolveEveningDay('2033-09-06');
|
|
expect(day.date).toBe('2033-09-06');
|
|
});
|
|
|
|
it('anticipates Easter from Holy Saturday', () => {
|
|
// Easter 2026 is Apr 5, so Holy Saturday is Apr 4.
|
|
const day = resolveEveningDay('2026-04-04');
|
|
expect(day.date).toBe('2026-04-05');
|
|
expect(day.season).toBe('eastertide');
|
|
});
|
|
|
|
it("a Sunday always keeps its own Second Vespers, even before a higher-ranked weekday feast", () => {
|
|
// Aug 10, 2026 (Monday) is St. Lawrence, Duplex II classis — well above
|
|
// the "has First Vespers" threshold — but Sunday never cedes.
|
|
const day = resolveEveningDay('2026-08-09');
|
|
expect(day.date).toBe('2026-08-09');
|
|
});
|
|
|
|
it('an ordinary feria before a real high-ranked feast anticipates it', () => {
|
|
// Aug 14, 2026 (Friday) is a plain feria; Aug 15 is the Assumption,
|
|
// Duplex I classis.
|
|
const day = resolveEveningDay('2026-08-14');
|
|
expect(day.date).toBe('2026-08-15');
|
|
expect(day.winner.kind).toBe('sanctoral');
|
|
if (day.winner.kind === 'sanctoral') {
|
|
expect(day.winner.id).toBe('assumption');
|
|
expect(day.winner.vespersFrom).toBe('firstVespersOfTomorrow');
|
|
}
|
|
});
|
|
|
|
// The cases below are live-verified against the real Monastic
|
|
// Tridentinum 1617 engine (see commemorationOfDisplacedPredecessor/
|
|
// -Successor's own doc comments in calendar/vespers.ts) —
|
|
// "commemoratio de præcedenti/sequenti" vs. "nihil de præcedenti" in
|
|
// the raw output, not just inferred from the daytime rule.
|
|
it('a Semiduplex loser is still commemorated when tomorrow claims First Vespers', () => {
|
|
// Aug 8, 2026 (Ss. Cyriacus/Largus/Smaragdus, Semiduplex) loses the
|
|
// evening to Aug 9 (Sunday); still commemorated.
|
|
const day = resolveEveningDay('2026-08-08');
|
|
expect(day.date).not.toBe('2026-08-08');
|
|
expect(day.commemorations).toContainEqual(
|
|
expect.objectContaining({ kind: 'sanctoral', id: 'ss-cyriacus-largus-and-smaragdus' }),
|
|
);
|
|
});
|
|
|
|
it('a Simplex loser is not commemorated when tomorrow claims First Vespers', () => {
|
|
// Aug 7, 2026 (St. Donatus, Simplex) loses the evening to Aug 8
|
|
// (Ss. Cyriacus/Largus/Smaragdus, now Semiduplex-threshold-eligible
|
|
// for First Vespers — see hasFirstVespers); not commemorated.
|
|
const day = resolveEveningDay('2026-08-07');
|
|
expect(day.date).not.toBe('2026-08-07');
|
|
expect(day.commemorations.some((c) => c.kind === 'sanctoral' && c.id === 'st-donatus')).toBe(false);
|
|
});
|
|
|
|
it('a winning day still commemorates a non-Simplex loser on the other side', () => {
|
|
// Jul 25, 2026 (St. James the Greater, Duplex II. classis) keeps its
|
|
// own Second Vespers outright, but still commemorates Jul 26
|
|
// (St. Anne).
|
|
const day = resolveEveningDay('2026-07-25');
|
|
expect(day.date).toBe('2026-07-25');
|
|
expect(day.commemorations).toContainEqual(expect.objectContaining({ kind: 'sanctoral', id: 'st-anne' }));
|
|
});
|
|
|
|
it('a winning day still commemorates a Simplex loser on the other side (asymmetric with the reverse direction)', () => {
|
|
// Aug 24, 2026 (St. Bartholomew, Duplex II. classis) keeps its own
|
|
// Second Vespers outright, but still commemorates Aug 25 (St. Louis,
|
|
// Simplex) -- live-verified "commemoratio de sequenti," unlike the
|
|
// reverse direction (a Simplex predecessor losing to tomorrow's First
|
|
// Vespers, see the Donatus case above) where Simplex IS excluded.
|
|
// Reported by the user 2026-08-26; previously both directions shared
|
|
// one Simplex-excluding commemorationOf, inferred symmetric but never
|
|
// independently verified for this direction.
|
|
const day = resolveEveningDay('2026-08-24');
|
|
expect(day.date).toBe('2026-08-24');
|
|
expect(day.commemorations).toContainEqual(expect.objectContaining({ kind: 'sanctoral', id: 'st-louis' }));
|
|
});
|
|
});
|