Fix privileged-feria-major: nothing is ever commemorated, any rank
Deploy / deploy (push) Successful in 1m32s
Deploy / deploy (push) Successful in 1m32s
The Easter octave cascade built last commit reused the existing "duplex-majus+ still gets a bare commemoration" branch unchanged, trusting its own citation (St. Mark within the Easter Octave). That citation was a misreading. Live-verified: the Annunciation (Duplex I. classis) transfers with zero commemoration on Holy Thursday itself, and Chair of St. Peter at Antioch does the same on Ash Wednesday - the exception was wrong everywhere this category is used, not just Holy Week. privileged-feria-major now matches privileged-sunday exactly: unconditional transfer, no exceptions, any rank. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017XMSokiTD2Qc5vPP2YQu3Q
This commit is contained in:
@@ -4767,3 +4767,32 @@ New tests in `tests/calendar/transfer.test.ts` cover the full chain (Leo/Hermene
|
|||||||
landing in strict native-date order past the whole 2033 span) and the Annunciation's own
|
landing in strict native-date order past the whole 2033 span) and the Annunciation's own
|
||||||
zero-commemoration case (2035). `npm test` (823 passed), `tsc --noEmit`, and `npm run build`
|
zero-commemoration case (2035). `npm test` (823 passed), `tsc --noEmit`, and `npm run build`
|
||||||
all pass.
|
all pass.
|
||||||
|
|
||||||
|
### Correction, same day: `privileged-feria-major`'s own "duplex-majus+ still gets a nod" rule was wrong
|
||||||
|
|
||||||
|
User pushed back immediately: "you dont commemorate -anything- from palm sunday through low
|
||||||
|
sunday" — and was right. The cascade mechanism above was built reusing `applyIncomingTransfer`'s
|
||||||
|
existing `privileged-feria-major` no-op unchanged, on the assumption that its sibling behavior
|
||||||
|
in `decideOccurrence` (a *native* duplex-majus+ candidate there gets a bare commemoration, only
|
||||||
|
below-majus ranks transfer) was itself correct — it had a citation (St. Mark, Duplex II. classis,
|
||||||
|
"merely commemorated" within the Easter Octave). That citation turned out to be a misreading,
|
||||||
|
not just unverified.
|
||||||
|
|
||||||
|
Live-checked two more real dates before touching code: the Annunciation (Duplex I. classis, the
|
||||||
|
highest rank that exists) transfers with **zero** commemoration on Holy Thursday itself in years
|
||||||
|
it lands there (2027/2032/2043) — not just off a Sunday, off an ordinary Holy Week feria too.
|
||||||
|
Then checked whether this was Holy-Week-specific or true of every `privileged-feria-major` use:
|
||||||
|
Chair of St. Peter at Antioch (Duplex majus) transfers the same way off Ash Wednesday (2034).
|
||||||
|
So the exception was wrong everywhere this category is used, not just the Easter span.
|
||||||
|
|
||||||
|
Fixed: `commemorations.ts`'s `privileged-feria-major` case now matches `privileged-sunday`
|
||||||
|
exactly — transfers every rank unconditionally, no commemoration ever, for anyone. Three
|
||||||
|
existing tests had the old (wrong) assumption baked into their expected values and needed
|
||||||
|
updating to real, live-verified outcomes, not just loosened: St. Mark (2030) now transfers
|
||||||
|
instead of being commemorated, landing May 5 that year (vu's own dense April/May calendar
|
||||||
|
pushes him well past his native date); the Annunciation's own 2035 landing moved from Apr 4 to
|
||||||
|
Apr 6, since two *earlier*-native-dated candidates (St. Benedict, also Duplex I. classis, native
|
||||||
|
Mar 21; St. Gabriel the Archangel, Duplex majus, native Mar 24) are now also correctly caught by
|
||||||
|
the same span that year and queue ahead of her.
|
||||||
|
|
||||||
|
`npm test` (822 passed), `tsc --noEmit`, and `npm run build` all pass.
|
||||||
|
|||||||
@@ -143,11 +143,22 @@ export function decideOccurrence(
|
|||||||
};
|
};
|
||||||
|
|
||||||
case 'privileged-feria-major':
|
case 'privileged-feria-major':
|
||||||
// Ash Wednesday, Holy Week, the Easter Octave, the Vigil of
|
// Ash Wednesday, Holy Week, the Easter Octave, Low Sunday, the
|
||||||
// Christmas — never displaced, same as privileged-sunday.
|
// Vigils of Christmas/Pentecost — never displaced, and never gives
|
||||||
if (isAtLeast(sanctoral.rank, 'duplex-majus')) {
|
// even a bare commemoration to any rank, same as privileged-sunday.
|
||||||
return { winner: temporalWinner, commemorations: [sanctoralCommemoration(sanctoral)] };
|
// The "duplex-majus+ still gets a nod" branch this case used to
|
||||||
}
|
// have was wrong, not just unverified: the one case that seemed to
|
||||||
|
// support it (St. Mark, Duplex II. classis, "merely commemorated"
|
||||||
|
// within the Easter Octave) turns out to have been a misreading —
|
||||||
|
// live-verified 2026-09-01, direct instruction ("you dont
|
||||||
|
// commemorate -anything- from palm sunday through low sunday"),
|
||||||
|
// confirmed with two more dates on top of the Annunciation/Palm-
|
||||||
|
// Easter-Sunday evidence already in the privileged-sunday case
|
||||||
|
// below: the Annunciation (Duplex I. classis) transfers with zero
|
||||||
|
// commemoration on Holy Thursday itself in years it lands there
|
||||||
|
// (2027/2032/2043), and Chair of St. Peter at Antioch (Duplex
|
||||||
|
// majus) transfers off Ash Wednesday the same way (2034) — so the
|
||||||
|
// exception was wrong for Ash Wednesday too, not just Holy Week.
|
||||||
return {
|
return {
|
||||||
winner: temporalWinner,
|
winner: temporalWinner,
|
||||||
commemorations: [],
|
commemorations: [],
|
||||||
|
|||||||
+10
-6
@@ -76,12 +76,16 @@ export type FeastClass =
|
|||||||
// 1617 engine, which the original single-tier model wrongly forbade) —
|
// 1617 engine, which the original single-tier model wrongly forbade) —
|
||||||
// see calendar/commemorations.ts's rules for `privileged-feria` (behaves
|
// see calendar/commemorations.ts's rules for `privileged-feria` (behaves
|
||||||
// like `ordinary-sunday`: Duplex+ wins outright) vs `privileged-feria-major`
|
// like `ordinary-sunday`: Duplex+ wins outright) vs `privileged-feria-major`
|
||||||
// (behaves like `privileged-sunday`: never displaced at all, confirmed by
|
// (behaves like `privileged-sunday`: never displaced, and — corrected
|
||||||
// checking St. Mark, Duplex II. classis, merely commemorated rather than
|
// 2026-09-01 — never gets even a bare commemoration at any rank either;
|
||||||
// winning within the Easter Octave). See data/calendar/temporal-
|
// an earlier claim that a duplex-majus+ candidate is "merely commemorated"
|
||||||
// categories.yml for exactly which days fall in which tier — some of that
|
// there, citing St. Mark within the Easter Octave, turned out to be a
|
||||||
// split (e.g. whether Pentecost's own Ember days share Lent's lesser tier
|
// misreading — direct instruction confirmed nothing is ever commemorated
|
||||||
// or Easter's major one) is still a reconstructed guess, not verified.
|
// anywhere from Palm Sunday through Low Sunday, and live-checking Ash
|
||||||
|
// Wednesday found the same). See data/calendar/temporal-categories.yml
|
||||||
|
// for exactly which days fall in which tier — some of that split (e.g.
|
||||||
|
// whether Pentecost's own Ember days share Lent's lesser tier or
|
||||||
|
// Easter's major one) is still a reconstructed guess, not verified.
|
||||||
// `privileged-feria-minor` is a third, weaker tier, added during the
|
// `privileged-feria-minor` is a third, weaker tier, added during the
|
||||||
// December sanctoral pull after finding Advent's own ordinary (non-Ember)
|
// December sanctoral pull after finding Advent's own ordinary (non-Ember)
|
||||||
// ferias have real standing of their own in the live engine — a Simplex
|
// ferias have real standing of their own in the live engine — a Simplex
|
||||||
|
|||||||
@@ -18,12 +18,29 @@ describe('April sanctoral pull (first pass)', () => {
|
|||||||
expect(getDayCollect(day).status.en).toBe('verified');
|
expect(getDayCollect(day).status.en).toBe('verified');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('St. Mark is only ever commemorated, never wins, within the Easter Octave', () => {
|
it('St. Mark gets nothing at all within the Easter Octave — not even a bare commemoration — and transfers past it instead', () => {
|
||||||
const day = resolveDay('2030-04-25');
|
// Corrected 2026-09-01: nothing is ever commemorated anywhere from
|
||||||
expect(day.winner.kind).toBe('temporal');
|
// Palm Sunday through Low Sunday, no exception for any rank (direct
|
||||||
expect(day.commemorations).toEqual([
|
// instruction; live-verified against the Annunciation on Holy
|
||||||
{ kind: 'sanctoral', id: 'st-mark', name: 'St. Mark, Evangelist', nameLa: 'Sanctus Marcus, Evangelista', rank: 'duplex-2-classis' },
|
// Thursday and Chair of St. Peter at Antioch on Ash Wednesday, both
|
||||||
]);
|
// Duplex-majus+ and both transferring with zero commemoration). Mark
|
||||||
|
// (Duplex II. classis) transfers off Apr 25, 2030 the same way; vu's
|
||||||
|
// own dense calendar that week pushes his actual landing all the way
|
||||||
|
// to May 5 (every day in between already spoken for).
|
||||||
|
const native = resolveDay('2030-04-25');
|
||||||
|
expect(native.winner).toEqual({ kind: 'temporal', id: 'easter-sunday' });
|
||||||
|
expect(native.commemorations).toEqual([]);
|
||||||
|
expect(native.transferredAway?.candidate.id).toBe('st-mark');
|
||||||
|
|
||||||
|
const landing = resolveDay('2030-05-05');
|
||||||
|
expect(landing.winner).toEqual({
|
||||||
|
kind: 'sanctoral',
|
||||||
|
id: 'st-mark',
|
||||||
|
name: 'St. Mark, Evangelist',
|
||||||
|
nameLa: 'Sanctus Marcus, Evangelista',
|
||||||
|
rank: 'duplex-2-classis',
|
||||||
|
transferredFrom: '2030-04-25',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('St. Robert beats St. Catherine of Siena on their shared monastic-calendar date', () => {
|
it('St. Robert beats St. Catherine of Siena on their shared monastic-calendar date', () => {
|
||||||
|
|||||||
@@ -89,21 +89,22 @@ describe('decideOccurrence — privileged-feria', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('decideOccurrence — privileged-feria-major', () => {
|
describe('decideOccurrence — privileged-feria-major', () => {
|
||||||
it('is never displaced, same as privileged-sunday — duplex-majus and up are commemorated', () => {
|
it('is never displaced, and never gives even a bare commemoration to any rank — everything transfers forward', () => {
|
||||||
// Verified: St. Mark, Duplex II. classis, only ever commemorated —
|
// Corrected 2026-09-01, direct instruction: nothing is ever
|
||||||
// never wins outright — within the Easter Octave.
|
// commemorated anywhere from Palm Sunday through Low Sunday — the
|
||||||
for (const rank of ['duplex-majus', 'duplex-2-classis', 'duplex-1-classis'] as const) {
|
// earlier "duplex-majus+ still gets a nod" claim (citing St. Mark,
|
||||||
|
// Duplex II. classis, within the Easter Octave) was a misreading.
|
||||||
|
// Live-checked two more dates: the Annunciation (Duplex I. classis)
|
||||||
|
// transfers with zero commemoration on Holy Thursday itself in years
|
||||||
|
// it lands there, and Chair of St. Peter at Antioch (Duplex majus)
|
||||||
|
// does the same on Ash Wednesday — so the fix applies to every use
|
||||||
|
// of this category, not just Holy Week.
|
||||||
|
for (const rank of ['duplex-majus', 'duplex-2-classis', 'duplex-1-classis', 'duplex', 'semiduplex', 'simplex'] as const) {
|
||||||
const result = decideOccurrence('privileged-feria-major', 'id', saint(rank));
|
const result = decideOccurrence('privileged-feria-major', 'id', saint(rank));
|
||||||
expect(result.winner).toEqual({ kind: 'temporal', id: 'id' });
|
expect(result.winner).toEqual({ kind: 'temporal', id: 'id' });
|
||||||
expect(result.commemorations).toEqual([{ kind: 'sanctoral', id: 'x', name: 'St. Ereden', rank }]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('yields nothing short of duplex-majus — transfers instead', () => {
|
|
||||||
const result = decideOccurrence('privileged-feria-major', 'id', saint('duplex'));
|
|
||||||
expect(result.winner).toEqual({ kind: 'temporal', id: 'id' });
|
|
||||||
expect(result.commemorations).toEqual([]);
|
expect(result.commemorations).toEqual([]);
|
||||||
expect(result.transfer).toEqual({ candidate: saint('duplex'), direction: 'forward' });
|
expect(result.transfer).toEqual({ candidate: saint(rank), direction: 'forward' });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -171,15 +171,17 @@ describe('multi-hop forward transfer through Holy Week/the Easter Octave', () =>
|
|||||||
expect(tiburtius?.kind === 'sanctoral' ? tiburtius.transferredFrom : undefined).toBe('2033-04-14');
|
expect(tiburtius?.kind === 'sanctoral' ? tiburtius.transferredFrom : undefined).toBe('2033-04-14');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("2035: the Annunciation (native Easter Sunday itself, Duplex I. classis) transfers past the whole span with zero commemoration anywhere in it — matching the real reference engine's own behavior, not just a native-date-order queue effect", () => {
|
it("2035: the Annunciation (native Easter Sunday itself, Duplex I. classis) transfers past the whole span with zero commemoration anywhere in it, queued behind two earlier-native-dated candidates also caught by the same span", () => {
|
||||||
// Easter 2035 is Mar 25 -- the Annunciation's own fixed date. Live-
|
// Easter 2035 is Mar 25 -- the Annunciation's own fixed date. Live-
|
||||||
// verified 2026-09-01: the real Monastic 1617 engine shows her
|
// verified 2026-09-01: the real Monastic 1617 engine shows her
|
||||||
// transferring off Easter Day with no commemoration anywhere in Holy
|
// transferring off Easter Day with no commemoration anywhere in Holy
|
||||||
// Week/the Octave/Low Sunday (Apr 1 that year), unlike a same-ranked
|
// Week/the Octave/Low Sunday (Apr 1 that year) -- corrected the same
|
||||||
// *native* occurrence there (e.g. St. Mark, Duplex II. classis,
|
// day, direct instruction: nothing is ever commemorated anywhere in
|
||||||
// commemorated when native within some other year's Octave) --
|
// this span, at any rank, not even duplex-majus+ -- so a *native*
|
||||||
// confirming a transferred-in candidate never gets the "duplex-majus+
|
// occurrence there (e.g. St. Mark within some other year's Octave)
|
||||||
// still gets a nod" treatment on these days, only a native one does.
|
// gets exactly the same "transfers, no exception" treatment as a
|
||||||
|
// transferred-in candidate passing through, not the "still gets a
|
||||||
|
// nod" treatment this test used to assert existed.
|
||||||
const easterSunday = resolveDay('2035-03-25');
|
const easterSunday = resolveDay('2035-03-25');
|
||||||
expect(easterSunday.winner).toEqual({ kind: 'temporal', id: 'easter-sunday' });
|
expect(easterSunday.winner).toEqual({ kind: 'temporal', id: 'easter-sunday' });
|
||||||
expect(easterSunday.transferredAway?.candidate.id).toBe('annunciation');
|
expect(easterSunday.transferredAway?.candidate.id).toBe('annunciation');
|
||||||
@@ -189,7 +191,12 @@ describe('multi-hop forward transfer through Holy Week/the Easter Octave', () =>
|
|||||||
expect(day.commemorations.some((c) => c.kind === 'sanctoral' && c.id === 'annunciation')).toBe(false);
|
expect(day.commemorations.some((c) => c.kind === 'sanctoral' && c.id === 'annunciation')).toBe(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const landing = resolveDay('2035-04-04');
|
// vu's own calendar also has St. Benedict (native Mar 21, also
|
||||||
|
// Duplex I. classis, also impeded that year) and St. Gabriel the
|
||||||
|
// Archangel (native Mar 24, Duplex majus) queued *ahead* of the
|
||||||
|
// Annunciation by native date -- they land Apr 4 and Apr 5
|
||||||
|
// respectively, pushing her actual landing to Apr 6.
|
||||||
|
const landing = resolveDay('2035-04-06');
|
||||||
expect(landing.winner).toEqual({
|
expect(landing.winner).toEqual({
|
||||||
kind: 'sanctoral',
|
kind: 'sanctoral',
|
||||||
id: 'annunciation',
|
id: 'annunciation',
|
||||||
|
|||||||
Reference in New Issue
Block a user