Commit Graph

469 Commits

Author SHA1 Message Date
will 45c1f4e958 Update tests for Sept 1 saints removal
Deploy / deploy (push) Successful in 1m28s
september-sanctoral.test.ts: Sept 1 now resolves to a plain temporal
day with no commemorations; the Raymond Nonnatus transfer-collision
case now wins uncontested since the native Sept 1 saints are gone.

vespers.test.ts: the semiduplex-keeps-its-own-Vespers-against-a-
lower-ranked-tomorrow regression test used Raymond Nonnatus vs. St.
Giles as its example pair; re-pointed to St. Agatha (semiduplex) vs.
St. Dorothea (simplex), a different adjacent pair that exercises the
same concurrentia rule.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XMSokiTD2Qc5vPP2YQu3Q
2026-09-01 06:24:20 -04:00
will 64271befee Drop St. Giles and Ss. Twelve Brothers from Sept 1
User decision to carry no saints on Sept 1. Data files for both
saints (and their propers/commemoration bundles) are left in place,
restorable by re-adding the sanctoral-calendar.yml list entry, same
pattern used when St. Hermes was dropped from 8/28.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XMSokiTD2Qc5vPP2YQu3Q
2026-09-01 06:24:14 -04:00
will e7c5fc0c24 Give a Vigil's own First Vespers Magnificat its real weekday fallback
Deploy / deploy (push) Successful in 1m31s
A Vigil never has a fixed proper Magnificat antiphon in the real rubric
-- its Rule block ("ex C1v; ... Laudes 2") always borrows whatever the
current ferial weekday's own antiphon is, live-verified across 4
different years (2025-2028) at the Vigil of St. Andrew's own First
Vespers. getMagnificatAntiphon now special-cases saint.rank === 'vigil'
to fall through to the same weekday-default table the plain temporal
branch already used, rather than trying (and missing) a fixed Common
lookup.

Closes the 11th and last Common-category Magnificat antiphon gap; see
TODO.md for the full writeup, including how the first pass wrongly
closed this one as "not a gap" before being asked to double check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QEe9oTbn1UjQVAYcCoW1a
2026-08-31 22:27:27 -04:00
will ccc406003c Author 10 sanctoral Common-category Magnificat antiphons
getMagnificatAntiphon's Common-category fallback
(magnificat-antiphon-${benedictusCommon}) had never been authored for
any of the 11 real Common categories saints fall back to -- only the
temporal-cycle side of this gap had been closed previously. Sourced
each from its Commune file's own [Ant 3] (Second Vespers), live-verified
against Ss. Placid and Companions, St. Blaise, and St. John Gualbert's
real evenings.

common-of-a-vigil (the 11th category) is handled separately, in code --
see the next commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QEe9oTbn1UjQVAYcCoW1a
2026-08-31 22:27:17 -04:00
will 8702955a5f Fix wrong Ant-tag sourced for two Common-category Benedictus antiphons
benedictus-antiphon-common-of-a-confessor.yml and -the-bvm.yml were each
reading their Commune source file's [Ant 1] (the Common's First Vespers
antiphon), not [Ant 2] (the real Lauds antiphon) -- discovered while
sourcing the sibling Magnificat antiphon set. Live-verified wrong via St.
Alexius's real Lauds query (renders "Euge, serve bone", not "Similabo
eum").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QEe9oTbn1UjQVAYcCoW1a
2026-08-31 22:27:08 -04:00
will e0156c1512 Fix Vespers concurrentia to compare today's rank against tomorrow's directly
Deploy / deploy (push) Successful in 1m27s
keepsOwnSecondVespers used a fixed duplex-2-classis floor on today's rank
alone, so a lower-ranked but still-real sanctoral winner (e.g. Simplex)
tomorrow could still steal First Vespers from a higher-ranked-but-below-the-
floor winner today (semiduplex St. Raymond Nonnatus losing to simplex St.
Giles on 2026-08-31). The real "De Concurrentia Officii" rubric compares the
two days' ranks directly, with ties going to tomorrow — replace the floor
with that comparison when both sides have a real sanctoral winner, keeping
the floor only as a fallback against a plain Sunday.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QEe9oTbn1UjQVAYcCoW1a
2026-08-31 22:01:33 -04:00
will 06fc8ef0ec Add missing commemoration bundle for St. Rose of Lima
Deploy / deploy (push) Successful in 1m29s
Her Aug 31 commemoration (e.g. under St. Raymond Nonnatus) was falling
back to a bare collect with no Ant./V./R. since she was authored after
the earlier commemoration-bundle sweep and never got her own.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QC6jHsj75xcsTkapqJR6fD
2026-08-31 09:31:58 -04:00
will 1923433a29 Normalize versicle notation to plain V./R. across propers
Deploy / deploy (push) Successful in 1m31s
Unicode ℣/℟ (U+2123/U+211F) were mixed unpredictably with plain V./R.
across ~550 proper YAML files, sometimes within the same file. Screen
readers can't announce the unicode glyphs. Replace all instances with
plain text.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QC6jHsj75xcsTkapqJR6fD
2026-08-31 09:23:30 -04:00
will a339068f81 Show a transferred saint's status in the day label
Deploy / deploy (push) Successful in 1m32s
getDayLabel now surfaces the transfer signal added in the previous
commit: a transferred-in winner gets "(Rank, transferred)" instead of
just "(Rank)"; a transferred-in commemoration gets "(transferred)"
appended to its bare name; and the date a saint transferred away from
gets a trailing "St. X (transferred away)" note so a reader isn't left
wondering why an expected saint is missing that day. Deliberately worded
differently on the two sides (plain "transferred" reads as "arrived via
transfer" next to a rank parenthetical; "transferred away" spells out the
direction on the origin date, where there's no rank alongside it to
anchor that reading) and deliberately omits a landing date on the away
note, per direct instruction, since a real landing can chain further than
the single adjacent day resolveDay actually checks (an unmodeled case,
e.g. a transfer running into Holy Week).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013g7AsSvMD9oazR17f3BxLz
2026-08-31 08:53:12 -04:00
will db9c844caf Track a transferred saint's origin date on DayWinner and Commemoration
Adds transferredFrom to both DayWinner's sanctoral variant and
Commemoration's sanctoral variant, set in calendar/index.ts's
applyIncomingTransfer whenever a transferred-in candidate actually lands
(wins outright) or ends up merely commemorated (lost a collision, or fell
below the landing day's own threshold) — previously this signal was
discarded after resolveDay used it once to decide the winner, so nothing
downstream could tell a transferred feast apart from a native one.

Also adds transferredAway to LiturgicalDay, set from a date's own native
occurrence when its candidate couldn't be kept there at all, so a UI can
note "this office moved elsewhere" without asserting a specific landing
date (which a later, unmodeled multi-hop chain — e.g. into Holy Week —
could get wrong).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013g7AsSvMD9oazR17f3BxLz
2026-08-31 08:53:02 -04:00
will cb60039ab2 Fix Sept sanctoral test for Raymond's new semiduplex rank
Deploy / deploy (push) Successful in 1m28s
Raymond's rank deflation (a1ed3d2) changes cascading behavior in years
where Aug 31 is a Sunday: he now loses to the Sunday outright (needs
duplex+ to win, per Divino Afflatu's ordinary-sunday threshold) and
transfers forward onto Sept 1, winning the collision there over St.
Giles. Move the original clean-year Giles test to 2026 and add a new
test documenting the 2025 transfer/collision case explicitly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013g7AsSvMD9oazR17f3BxLz
2026-08-31 08:23:08 -04:00
will a1ed3d2f9c Deflate St. Raymond Nonnatus's rank to semiduplex
Canonized 1657, well past the ~1600 late-canonization threshold; per
project policy his source Duplex rank gets deflated one tier, same
treatment already applied to St. Rose of Lima.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013g7AsSvMD9oazR17f3BxLz
2026-08-31 08:23:02 -04:00
will 514300821a Bulk-author nameLa for all 299 remaining saints, close bilingual header backlog
Deploy / deploy (push) Successful in 1m31s
Authors a real Latin nameLa for every saint in src/data/calendar/saints/
except the deliberate example-confessor placeholder (standard
ecclesiastical Latin forms, a lighter sourcing bar than this app's usual
reference-engine verification -- flagged for future spot-check). Fixes a
real mechanism bug found in the process: calendar/index.ts's sanctoral
collision-resolution branch was dropping nameLa for any saint that won
after beating another same-day candidate. Updates ~180 pre-existing test
fixtures across the calendar suite for the new field.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwsZQMjALCvy7u9tFDWmuQ
2026-08-31 06:44:10 -04:00
will a6261f044a Add nameLa mechanism for bilingual header, proof set of 11 feasts + St. Lawrence
Deploy / deploy (push) Successful in 1m32s
Threads an optional nameLa field through SanctoralIdentity/SaintRecord/
TemporalFeastRecord/ActiveOctave so day-label.ts can render real Latin
proper names instead of always falling back to English. Authors the
proof set: all 11 named temporal feasts plus St. Lawrence (chosen to
exercise the octave-headline and octave-commemoration code paths too).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwsZQMjALCvy7u9tFDWmuQ
2026-08-31 06:30:48 -04:00
will 76cc363a75 Fix stale St. Damasus header comment on octave precedence
Deploy / deploy (push) Successful in 1m41s
Claimed Semiduplex wins outright over the Advent feria with the feria
commemorated in return -- true when written, but no longer true after
the later octave-wins-class rework. Dec 11 falls inside the Immaculate
Conception octave, whose elevated wins:duplex threshold now outranks a
plain Semiduplex, so Damasus is actually demoted to a commemoration
and the Advent feria keeps the day. No behavior change, found and
confirmed live while authoring St. Juan Diego's neighboring entry.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwsZQMjALCvy7u9tFDWmuQ
2026-08-31 06:00:42 -04:00
will 3ceb1e9df0 Add Our Lady of Guadalupe (Dec 12)
Sourced from the reference engine's national-calendar file. Own proper
collect, Ant 1, and Matins Nocturn 2 narrative reading (Juan Diego's
apparition account), same scope as the Our Lady of Lourdes feast --
Common of the BVM (C11) carries the rest. No canonization-deflation
question here (an apparition title, cultus confirmed 1754/1910). At
Duplex she ties the Immaculate Conception octave's threshold on a
non-closing day, which favors the occurring saint, so she wins Dec 12
outright.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwsZQMjALCvy7u9tFDWmuQ
2026-08-31 06:00:36 -04:00
will e1595e05ec Add St. Juan Diego (Dec 9)
Sourced from the reference engine's national-calendar file (canonized
2002, outside both Tridentine 1906 and Divino Afflatu 1954). Source
rank "Duplex optional" has no FeastClass slot; mapped to Duplex then
deflated one tier to Semiduplex per the late-canonization rule. Live-
verified he's actually a commemoration, not the day's winner: Dec 9
falls inside the Immaculate Conception octave, whose elevated
wins:duplex threshold outranks a plain Semiduplex.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwsZQMjALCvy7u9tFDWmuQ
2026-08-31 06:00:22 -04:00
will 2df1fd0d3b Add St. Rose of Lima (Aug 30), rank deflated for late canonization
Deploy / deploy (push) Successful in 1m37s
She was previously excluded on a mistaken "post-1617, out of scope"
reading that conflated vu's hour-structure track (Monastic 1617) with
its calendar/saints track (Tridentine 1906 + Divino Afflatu 1954,
which has included her since her 1671 canonization). Her source rank
of Duplex is deliberately deflated to semiduplex, correcting for the
rank creep that made "new canonization" and "Duplex" a near-automatic
pairing from the Baroque period on. She wins Aug 30 outright over Ss.
Felix and Adauctus, who keep their existing commemoration.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwsZQMjALCvy7u9tFDWmuQ
2026-08-31 05:41:16 -04:00
will efb1717e27 Add test coverage and TODO.md log for the full temporal-cycle sweep
Deploy / deploy (push) Successful in 1m31s
Extends tests/hours/matins.test.ts's proof-date table to cover all 28
newly-authored temporal ids end-to-end, including Easter and Pentecost
Sunday. Documents the full sweep in TODO.md, including the
easter-sunday/pentecost-sunday misdiagnosis and correction so the
"1 nocturn in the source" vs. "no content" distinction doesn't get
re-litigated later.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 23:21:03 -04:00
will 73db52bd96 Author Easter and Pentecost Sunday's own Matins nocturn content
Both feasts' source keeps the ancient single-nocturn, 3-lesson Matins
form (unlike every other Sunday in the surrounding sweep), which was
initially mistaken for "no content exists" and left unauthored. Their
Lectio1-3 actually carry a real Gospel incipit plus a full Pope St.
Gregory the Great homily each (Homily 21 on Mark 16:1-7 for Easter,
Homily 30 on John 14:23-31 for Pentecost) — a nocturn-count difference,
not a content gap. Authored as nocturn:1 content, same as this app's
existing Ember-day single-nocturn files; this app's own threeNocturns
rule still renders 3 nocturns for these Sundays regardless.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 23:20:57 -04:00
will 1cb6ca16da Author Matins temporal-cycle nocturn readings for Advent through Ascensiontide
Extends the post-Pentecost nocturn-readings sweep to the other 26 temporal
ids spanning the rest of the liturgical year — Advent, Christmastide,
post-Epiphany, Septuagesima through Lent, Passiontide/Holy Week, and
Eastertide — transcribed directly from the reference engine's own
per-season Tempora source files.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 23:20:47 -04:00
will 7f0b0f05df Move today's completed work from Open Work into the dated build log
Deploy / deploy (push) Successful in 1m30s
Was inline-editing "DONE" notes into the top-of-file priority list
instead of following TODO.md's own convention: completed work moves out
of "Open work" entirely and into a dated ### entry at the bottom. Fixes
that for everything done today that never got a proper log entry --
the Vigil of Christmas content, the Advent IV/Dec 24 Sunday collision
resolution, the full sanctoral commemoration bundle sweep (218/218),
and closing out the last two Vespers Magnificat "gaps" as not gaps.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 18:40:13 -04:00
will f1f46e2573 Close the two remaining Vespers Magnificat "gaps" as not gaps
Deploy / deploy (push) Successful in 1m33s
Live-checked both instead of leaving them as unauthored: the Vigil of
Christmas never has its own Vespers in the real rite (Dec 23 evening is
plain Advent-4 ferial Vespers, not First Vespers of the Vigil; Dec 24
evening is always Christmas's own), and marian-saturday's Commune file
has no Vespers antiphon of its own either, because a Saturday's Vespers
is always structurally ceded to the following Sunday. Neither is missing
content to author -- there's no historical text for either case.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 18:38:08 -04:00
will 04a8686551 Finish the last 5 vigils: weekday-keyed commemoration antiphons
Deploy / deploy (push) Successful in 1m32s
Corrected an earlier "no source exists" claim by live-querying real
commemorated instances of the Vigils of St. Lawrence and the Assumption
across six different weekdays. Their source files' own [Rule] block
("Versum Feria") turns out to be a real, sourced mechanism, not an
absence: a mere commemoration doesn't reuse the vigil's own antiphon at
all -- it borrows the plain ferial day's antiphon/versicle instead, and
that antiphon quotes the Benedictus canticle in weekday sequence (same
shape vespers-magnificat-antiphons.yml already uses for the Magnificat).
The versicle is a single fixed text. Sunday has no entry: a Vigil
transfers off an ordinary Sunday rather than ever reaching a
commemoration there, confirmed live as well as already true in this
app's own precedence rules.

sanctoralCommemorationPart now takes weekday and resolves this
dynamically for common-of-a-vigil saints, rather than needing a static
per-saint file. All 218 saints with an authored collect now have a real
commemoration antiphon.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 18:12:12 -04:00
will b5f16ceb23 Finish the sanctoral commemoration bundle sweep (213/218 saints)
Deploy / deploy (push) Successful in 1m29s
Follow-up to the earlier bulk pass. Sourced the remaining category
templates: BVM feasts (13, reused the already-verified BVM suffrage
versicle plus each feast's own antiphon), angels (4, versicle inferred
from a saint file's own "structural category" note), Confessor-Doctor/
-Pope (7, resolved to C4a/C5a/C4b -- each inheriting its base category's
Ant2/Versum2 unchanged, no new content needed), several confessors and
apostles-plural (2, reusing already-sourced category versicles), and 5
fully-proper feasts (All Saints x2, Finding of the Holy Cross, Most
Precious Blood, Transfiguration, Our Lady of Ransom) given their own
real Ant2/Versum2 straight from their Sancti files.

213 of ~218 real saints now covered. Only the 5 Vigils remain open --
no dedicated Commune template exists for that category in the reference
engine, and FeastClass 'vigil' rarely reaches the commemoration code
path anyway.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 17:10:34 -04:00
will 2c3f63ef97 Bulk-author sanctoral commemoration antiphon+versicle bundles
Deploy / deploy (push) Successful in 1m28s
Found that 217 of 220 saints with an authored collect had no
${propers}-commemoration.yml bundle, so sanctoralCommemorationPart was
silently falling back to a bare collect with no antiphon whenever that
saint was merely commemorated rather than winning outright (user-reported
for St. Raymond Nonnatus and the Decollation of St. John the Baptist).

Bulk-fixed: reused each saint's own proper antiphon where authored, else
the standard de-Communi [Ant 2]/[Versum 2] for that saint's own Common
category. Confirmed via three already live-verified commemorations
(Ss. Felix and Adauctus, St. Clare, St. Sabina) that [Ant 2]/[Versum 2]
are the real tags used for a mere commemoration, not [Ant 1]/[Nocturn 2
Versum] as first assumed -- corrected St. Raymond Nonnatus's file
accordingly. 182 of ~218 real saints now covered; entries not
independently live-verified are marked draft. Remaining ~36 (BVM feasts,
angels, confessor-doctors/popes, vigils) tracked in TODO.md.

New tests/propers/commemoration-sweep.test.ts (182 cases) asserts every
bundle has a real antiphon+versicle+collect, never bare/missing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 16:42:20 -04:00
will e8463f25b2 Give St. Raymond Nonnatus and the Decollation their own commemoration antiphons
Deploy / deploy (push) Successful in 1m30s
Same bare-collect-only gap as Ss. Felix and Adauctus: both saints were
falling back to a plain collect with no antiphon when merely commemorated
(today's and yesterday's Vespers respectively). Raymond has no proper
antiphon of his own, so uses the standard Common-of-a-Confessor-Not-Bishop
text; the Decollation reuses his own already-authored proper Lauds
antiphon, paired with the generic Common-of-a-Martyr versicle. Both
live/reference-verified.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 15:55:15 -04:00
will 6334b3eaaa Give Ss. Felix and Adauctus a real commemoration antiphon
Deploy / deploy (push) Successful in 1m29s
Their commemoration was falling back to a bare collect (only
ss-felix-and-adauctus-collect.yml existed, no combined Ant+V/R bundle),
so it rendered with no antiphon at Lauds when they're commemorated on a
Sunday (today, 2026-08-30). Live-verified against that exact date.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 08:59:22 -04:00
will a18ad7f57c Resolve Advent IV landing on Dec 24 as the Vigil, with Advent IV commemorated
Deploy / deploy (push) Successful in 1m25s
When Advent 4's own Sunday lands on Dec 24, the Vigil of Christmas's
identity (rank, collect, Lauds antiphons, Matins Gospel nocturn) now
governs the day, matching the reference engine's own rule that a
privileged Sunday never displaces it. Unlike the reference engine's own
"no commemoratio" for this exact collision, Advent 4 is deliberately
still commemorated — the Sundays of Advent have real standing of their
own. Matins' three-nocturn Sunday psalmody is untouched either way,
since it's driven by weekday, not by which id wins.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 08:55:00 -04:00
will 654ec868cb Give the Vigil of Christmas (Dec 24) its own proper content
Deploy / deploy (push) Successful in 1m28s
Non-Sunday Dec 24 previously just inherited Advent 4's ferial collect and
antiphons with nothing of its own. Import the Vigil's real proper content
from the reference engine (Duplex I classis): its own collect, all 5 Lauds
antiphons, the Benedictus antiphon, and Matins' Gospel (Matt 1:18-21) +
St. Jerome homily, wired via a new `vigil-of-christmas` temporal id scoped
to non-Sunday Dec 24 only. Advent IV landing on Dec 24 itself is untouched,
left as its own separate design question.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 07:45:44 -04:00
will b3a7176cb8 Add the O Antiphons (Dec 17-23) as an unconditional Vespers Magnificat override
Deploy / deploy (push) Successful in 1m27s
advent-4's own remaining Magnificat-antiphon gap turned out to be a
mechanism problem, not missing content: Dec 17-23 always carries one of
the seven "O Antiphons" at Vespers, keyed to the calendar date itself,
not to whichever Advent week (advent-3 or advent-4, varies by year)
happens to govern that date -- a single per-week file was structurally
the wrong shape.

Added vespers-o-antiphons.yml (MM-DD keyed) and a new lookup tier in
getMagnificatAntiphon, checked unconditionally ahead of both the
per-week temporal file and a real sanctoral winner's own antiphon --
direct instruction: the O Antiphon wins this one text slot on these
seven dates regardless of who otherwise wins the day (e.g. St. Thomas,
Dec 21, still keeps every other part of his own office). Two of the
seven (O Clavis David/O Oriens, Dec 20-21) couldn't be live-verified --
every reference-engine track routes those two dates through St.
Thomas's Vigil/feast instead, which this app's own vigil-of-st-thomas.yml
already documents diverging from -- so they're marked draft rather than
verified.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 07:04:30 -04:00
will 66bd970fed Author the missing Vespers Magnificat antiphon for 52 temporal ids
Every temporal id had its Lauds (Benedictus) antiphon authored, but only
3 of 57 had the Vespers (Magnificat) counterpart -- a whole-calendar
gap exposed by 2026-08-29's Vespers rendering with no Magnificat
antiphon at all. Sourced from the reference engine's static Tempora/
Sancti files, same convention and per-id reference dates already
established for the Benedictus antiphons.

advent-4 and marian-saturday are the only two ids still missing one
(neither resolves from the static files alone) -- follow-up commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 07:03:52 -04:00
will 5ae1f3a3e0 Fix Vespers status wrongly saying "Second Vespers" when a Sunday anticipates it
Deploy / deploy (push) Successful in 1m29s
getVespersStatusLabel detected First-Vespers anticipation only via
winner.vespersFrom, a tag only ever set for a sanctoral tomorrow-winner
(tagVespersFrom). When Vespers anticipates a Sunday that wins its own
day outright (a temporal winner, e.g. 2026-08-29 anticipating 2026-08-30
since the Decollation of St. John Baptist is below the duplex-2-classis
floor that would let it keep its own evening), the tag never gets set
and the status wrongly read "Second Vespers (of today)" even though the
whole page was showing tomorrow's identity.

Comparing the resolved day's date against the originally-requested date
detects anticipation uniformly regardless of winner kind, so this drops
the vespersFrom dependency entirely.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 06:10:52 -04:00
will 95901ef56a Always list the day's actual winner first in getDayLabel
The anchor-day and plain-temporal-fallback branches were listing any
commemorated saint before the winning identity, so a lower-ranked saint
merely riding along as a commemoration (e.g. St. Andrew on Advent I, or
Ss. Tryphon/Respicius/Nympha on an ordinary Sunday) read as if it were
the day's own winner, with the actual winner's rank label dangling at
the end with no name attached. The winner should always lead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ME8QNPdEmHSbSx1r6VmDRG
2026-08-30 06:10:14 -04:00
will 5e56611944 Give St. Sabina her Lauds commemoration antiphon and correct collect
Deploy / deploy (push) Successful in 1m25s
She was rendering as a bare collect (propers: null had no
sanctoral-commemoration fallback), and even that collect used
collect-c6's Virgin-and-Martyr text -- she was a matron, not a virgin.
Live-verified against Divino Afflatu: added collect-c7 (the Common's
own non-Virgin-Martyr template) and a full antiphon/versicle/collect
commemoration bundle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sPkfGLiq58pmmDoBWH5UX
2026-08-29 11:06:57 -04:00
will 7393b3e2be Drop the redundant (Exodus)/(Deuteronomy) parenthetical from canticle names
Deploy / deploy (push) Successful in 1m27s
Both Canticle of Moses entries carried a book-name parenthetical in
their display name, redundant with (and now, since the last commit,
duplicated verbatim by) the citation shown right underneath. Only one
canticle is ever displayed per day, so there's nothing to disambiguate
in the UI -- trim to plain "Canticle of Moses" for both.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sPkfGLiq58pmmDoBWH5UX
2026-08-29 10:40:13 -04:00
will 4e1266d4ae Give each half of Saturday's split Deuteronomy canticle its own citation
Deploy / deploy (push) Successful in 1m27s
canticleText() always returned the whole canticle's stored citation
("Deut 32:1-65"), even when only slicing out half its verses -- both
Saturday Lauds pieces showed the same full range regardless of which
half was actually being said. Derive the citation from the slice's own
first/last verse numbers instead, only when slicing; a full canticle's
stored citation is left as-is, since it already matches what's shown
and a formula can't reproduce an irregular one like
canticum-trium-puerorum's "Dan 3:57-88,56" (a non-contiguous liturgical
splice).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sPkfGLiq58pmmDoBWH5UX
2026-08-29 10:37:39 -04:00
will 7153a846c2 Strip the editorializing parenthetical out of the Canticle of Moses's citation
Deploy / deploy (push) Successful in 1m26s
The user-facing citation field carried an explanatory aside
("liturgical division; split across two Lauds slots") instead of a
plain reference. Move that explanation into the file's own header
comment (which already existed) and leave citation as just "Deut
32:1-65".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sPkfGLiq58pmmDoBWH5UX
2026-08-29 10:32:39 -04:00
will d77c9ca68f Add regression tests for Decollation's ferial-numbers/proper-antiphons split
Deploy / deploy (push) Successful in 1m23s
Confirms 2026-08-29 Lauds and 2026-08-28 First Vespers both keep the
ferial psalm numbers (Duplex, below duplex-majus) while still layering
on the feast's own proper antiphons -- and that an override group with
no matching ferial slot (Puellae saltanti / Arguebat) is dropped, not
substituted in.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sPkfGLiq58pmmDoBWH5UX
2026-08-29 10:27:39 -04:00
will 631d133b16 Apply the same psalm-number/antiphon split to Vespers' psalmody override
Deploy / deploy (push) Successful in 1m24s
Mirrors the Lauds fix: a proper override's psalm numbers stay gated at
duplex-majus+, while its antiphons still layer onto the ferial weekday's
own numbers below that rank, paired by group index.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sPkfGLiq58pmmDoBWH5UX
2026-08-29 10:23:33 -04:00
will f733ffa71f Re-gate Lauds proper psalm numbers behind duplex-majus+, keep antiphons rank-agnostic
A feast's own proper psalm-group antiphons should surface at any rank
(f3cf30c), but the actual psalm numbers sung should only substitute at
duplex-majus+, per real Tridentine/Monastic rubric — a lower-rank feast
keeps the ferial psalm cycle and only gets proper text layered onto it.
Below duplex-majus, merge the proper override's antiphons onto the
ferial weekday's own psalm numbers/canticle, paired by group index.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sPkfGLiq58pmmDoBWH5UX
2026-08-29 10:23:29 -04:00
will 949196b847 Author proper Lauds/Vespers antiphons for the Beheading of St. John Baptist
Deploy / deploy (push) Successful in 1m32s
Live-verified against Divinum Officium (Tridentine 1906/1910 and
Divino Afflatu 1954, Sancti/08-29.txt) — the feast's own 5-antiphon
set ([Ant Vespera], reused verbatim at Lauds as [Ant Laudes]), now
wired through both the newly rank-agnostic Lauds/Vespers proper tier
and the new minor-hour derivation mechanism. Vespers gets only the
first four (mapped onto vu's Monastic-1617-structured four-psalm
Vespers, matching common-of-a-martyr.yml's own 109/111/112/115
baseline) — the reference's own fifth antiphon is a secular five-
psalm-Vespers detail that doesn't apply here, and is used only at
Lauds' Laudate psalm instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFGHb4XMe6Wya4pGpPhEEi
2026-08-29 07:35:33 -04:00
will 74ddd61aee Derive Prime/Terce/Sext/None antiphons from a saint's own Lauds set
resolveMinorHourAntiphon fell straight from a (rarely-authored)
dedicated per-hour proper file to the saint's generic Common-category
antiphon, skipping the real proper text a saint may already have as
its 5-antiphon Lauds/Vespers set. The reference engine's own
getanthoras() mechanism derives exactly these four minor-hour
antiphons from that same 5-antiphon set by fixed index (Prime/Terce/
Sext/None <- antiphons 1/2/3/5) whenever no dedicated per-hour proper
exists; vu had no equivalent, so any minor hour fell back to the
generic Common antiphon even when the feast's own text was already
sitting right there in its Lauds override.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFGHb4XMe6Wya4pGpPhEEi
2026-08-29 07:35:22 -04:00
will f3cf30c1c7 Stop gating Lauds/Vespers proper psalmody antiphons behind rank
getPsalmodyOverrideFor bundled "which psalm numbers are said" and
"which antiphons are used" into one lookup, both gated behind the same
duplex-majus+ rank threshold. A saint's own authored proper antiphon
text should never be gated behind rank — only the weaker, generic
Common-category substitute has any business being rank-gated. Splits
the lookup into two independent tiers: the feast's own proper (any
rank, via the new getPsalmodyProperOverrideId) tried first, then the
existing duplex-majus+ Common-category fallback — mirroring the split
getMinorHourOverrideId already made for the chapter/responsory/hymn/
versicle bundle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFGHb4XMe6Wya4pGpPhEEi
2026-08-29 07:34:48 -04:00
will b163f502b8 Scope renderCitation to the currently displayed languages
renderCitation deduplicated a text's citation values across every
stored language, not just the ones actually being rendered. Once a
citation's La/En abbreviations genuinely differ (e.g. "Jac 1:12" vs.
"Jas 1:12", or "Sap. 10:10" vs. "Wis. 10:10"), both survived the
dedupe and got joined together regardless of view mode, leaking the
other language's abbreviation into a single-language display.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFGHb4XMe6Wya4pGpPhEEi
2026-08-29 07:33:48 -04:00
will 7ab517cbe3 Fall back to a saint's collectCommon/collectName in commemorations too
sanctoralCommemorationPart() only ever checked a commemorated saint's
own propers, so a saint like St. Sabina — no propers of her own, but
a real collectCommon + collectName template fallback, verified text
and all — rendered as an outright "missing" commemoration. The day's
primary-collect resolver (getDayCollect) already had this same
collectCommon/collectName fallback tier; this brings the
commemoration path in line with it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFGHb4XMe6Wya4pGpPhEEi
2026-08-29 07:33:30 -04:00
will a3a9d568ed Include the canticle's own citation in Lauds' resolved output
canticleText() built the resolved text/status from the weekday
canticle's verses but never copied the source YAML's own citation
field across, so every Lauds canticle rendered with no book/chapter/
verse citation at all despite the data already carrying one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFGHb4XMe6Wya4pGpPhEEi
2026-08-29 07:33:15 -04:00
will a6e4bb15b1 Author real proper Matins/Vespers content for the Nativity of St. John the Baptist
Deploy / deploy (push) Successful in 1m30s
nativity-of-st-john-the-baptist.yml's `common` field (common-of-an-apostle)
was the same mistaken placeholder as the Beheading's, but this feast
needed a different fix: the reference engine assigns it no Commune at
all -- every [Rule] line in Sancti/06-24.txt and SanctiM/06-24.txt points
to proper text, never a Commune category -- so there's no better-fitting
id to swap in either.

Authored the real proper content that was still falling through to the
apostle Common, live-verified against the local Divinum Officium CGI
instance (Monastic Tridentinum 1617):

- Matins invitatory antiphon ("Regem Præcursóris Dóminum")
- Matins hymn ("Antra desérti téneris," with the Monastic doxology
  substitution already used by this feast's own Lauds/Vespers hymns)
- Full Matins Nocturn 1-3 psalmody + nocturn versicles (Nocturn 1/2 reuse
  St. Lawrence's own shared psalm-number pool per "Psalmi Dominica";
  Nocturn 3 reuses St. Lawrence's own canticle scripture files verbatim,
  since the citations are identical)
- Vespers psalmody (only 4 psalm slots at this Monastic rank, not 5 as a
  naive reading of the raw Ant Vespera list would suggest)
- Nocturn 2/3 responsories on the existing nocturn-readings file

`common: common-of-an-apostle` is left in place as a fully inert
placeholder (a non-optional field with no better id available) with an
updated comment explaining why.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WvnBMq7HGfXRyMsVLu2v4D
2026-08-29 06:24:33 -04:00
will d4ec104d59 Fix Beheading of St. John the Baptist's wrong Common category
decollation-of-st-john-baptist.yml's `common` field was set to
common-of-an-apostle -- a mistaken placeholder (he isn't an apostle) that
leaked into the Aug 29 Matins invitatory and the Lauds/Vespers office
bundle. Corrected to common-of-a-martyr, matching the file's own already-
correct `minorHoursCommon` field.

Also corrected a stale comment in the feast's own nocturn-readings file
claiming neither Nocturn 2 nor 3 has a proper responsory: Nocturn 2's own
closing responsory is genuine proper text (not a Commune reference like
Nocturn 3's), and is now authored.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WvnBMq7HGfXRyMsVLu2v4D
2026-08-29 06:22:49 -04:00
will a2d082e608 Keep a short litany + Our Father at Compline on a Double, don't omit
Deploy / deploy (push) Successful in 1m28s
compline-preces.yml was already the secular Tridentine 1906/1910 text
word-for-word (verified live against both tracks), so no text change
was needed there. The actual gap: both Monastic and secular tracks drop
Compline's Preces to nothing on a Double-or-higher, unlike Vespers/Lauds
which fall back to a short form. Per explicit request, this is now a
deliberate vu-specific deviation from both tracks: on a Double, Compline
substitutes the same short Kyrie/Pater-Noster litany Vespers already
falls back to on Sundays/feasts, instead of showing nothing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHXJAWVAabCKX1JgmDh4Rn
2026-08-29 05:29:56 -04:00