fix: keep the Sacred Triduum from being displaced by a coincident saint (#422) #423

Merged
manlycucumber merged 1 commit from fix/triduum-feria-precedence into develop 2026-07-02 17:23:10 +00:00
manlycucumber commented 2026-07-02 17:21:40 +00:00 (Migrated from github.com)

Found by the validation harness (#45) cross-checking against the missalemeum oracle.

The bug

On a Triduum day that coincides with a fixed saint, the engine celebrated the saint
and displaced the Triduum feria. Holy Thursday 2024 (28 Mar = St John of
Capistrano, III class)
resolved to the saint, with Feria V in Cena Domini (I
class) marked displaced/omit. Nothing outranks the Sacred Triduum (n. 91 line 2);
it admits no commemoration (n. 23).

Root cause

Rubrics1962Precedence::tierOf() gave the apex triduum tier to every observance
whenever the date was in the Triduum, so the coincident saint tied the feria at the
apex and won DayResolver::sortByTier()'s id-based tie-break
(roman:sanctorale:… < roman:temporale:…).

Fix

Gate the triduum tier on kind === FERIA. The coincident saint keeps its normal
(far lower) tier; the Triduum feria always wins and the saint is omitted.

Blast radius (verified)

Scanning 1900–2100, no Triduum day is won by a non-feria after the fix. A day-by-day
diff of an affected year (2024) shows changes confined to exactly:

  • the Triduum day itself (celebration/displaced swap), and
  • its eve's Second-Vespers concurrence, which now correctly yields to the First
    Vespers of Holy Thursday
    instead of the saint.

The golden fixture is re-frozen accordingly (490 years carried at least one such
coincidence — every change an improvement). Regression tests added.

Gates green: lint 110/110, analyse [OK], test 623 passing.

Closes #422.

Found by the validation harness (#45) cross-checking against the missalemeum oracle. ## The bug On a Triduum day that coincides with a fixed saint, the engine celebrated the saint and displaced the Triduum feria. **Holy Thursday 2024 (28 Mar = St John of Capistrano, III class)** resolved to the *saint*, with *Feria V in Cena Domini* (I class) marked `displaced/omit`. Nothing outranks the Sacred Triduum (n. 91 line 2); it admits no commemoration (n. 23). ## Root cause `Rubrics1962Precedence::tierOf()` gave the apex `triduum` tier to **every** observance whenever the *date* was in the Triduum, so the coincident saint tied the feria at the apex and won `DayResolver::sortByTier()`'s id-based tie-break (`roman:sanctorale:…` < `roman:temporale:…`). ## Fix Gate the `triduum` tier on `kind === FERIA`. The coincident saint keeps its normal (far lower) tier; the Triduum feria always wins and the saint is omitted. ## Blast radius (verified) Scanning **1900–2100**, no Triduum day is won by a non-feria after the fix. A day-by-day diff of an affected year (2024) shows changes confined to exactly: - the Triduum day itself (celebration/displaced swap), and - its eve's Second-Vespers concurrence, which now correctly yields to the **First Vespers of Holy Thursday** instead of the saint. The golden fixture is re-frozen accordingly (490 years carried at least one such coincidence — every change an improvement). Regression tests added. Gates green: `lint` 110/110, `analyse` [OK], `test` 623 passing. Closes #422.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Directorium/Core!423
No description provided.