Commit Graph

356 Commits

Author SHA1 Message Date
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 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 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 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
will fbb3a2cfc7 Alias common-of-an-evangelist and -several-women-martyrs, not new schemes
St. Mark's and St. Luke's own reference-engine rule files say "ex C1a",
byte-identical to plain C1 (Apostles) -- an Evangelist-not-Apostle
reuses the Apostles' own scheme, not a separate one.

Ss. Perpetua and Felicity's own file says "vide C7b"; C7b returns the
same four psalm numbers and group/canticle/Laudate antiphons as plain
C7 (Holy Woman) -- its only real difference is the Magnificat/Benedictus
antiphon, handled by a separate, already-existing mechanism, not this
psalmody table. (First-draft duplicate category files for this id were
written and then deleted once this was caught by diffing line-by-line
against the live output.)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHXJAWVAabCKX1JgmDh4Rn
2026-08-28 21:33:05 -04:00
will e7fc70bf77 Add Common-of-a-Dedication Vespers psalmody category
Genuinely its own scheme (votive=C8) -- unlike every other Common,
Vespers' numbers (109/110/111/147) don't match any other category's
pattern. Lauds' own version is left unauthored: its OT canticle
("Canticum Ieremiae") has never been transcribed anywhere in this app,
so that file isn't written rather than guessed at (see TODO.md).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHXJAWVAabCKX1JgmDh4Rn
2026-08-28 21:32:54 -04:00
will 15cc76dacf Add Common-of-an-Angel Lauds/Vespers psalmody category
No dedicated numbered Common exists for Angels in the reference engine;
St. Michael's own rule says plain "Psalmi Dominica" with his own proper
antiphons, which Guardian Angels (no proper of her own) reuses
byte-for-byte at both hours. Authored as a reusable category so any
future proper-less Angel addition benefits automatically.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHXJAWVAabCKX1JgmDh4Rn
2026-08-28 21:32:46 -04:00
will 33c9b2415b Fix Vespers ferial psalmody weekday bug, add duplex-majus+ Common psalmody override
Deploy / deploy (push) Successful in 1m33s
Vespers psalms on Mon-Sat were silently following the anticipated
First-Vespers day's weekday instead of the actual calendar date's, since
resolvePsalmody reused resolveEveningDay's result (correct for
propers/office, which legitimately borrow tomorrow's identity, but wrong
for the ferial psalm cycle, which has no per-feast override of its own).

Also adds a duplex-majus+ Common-category psalmody override to both
Lauds and Vespers, mirroring Matins' existing saint/category mechanism.
Lauds already had a per-feast-only override; Vespers had none. 8 of 24
Common categories authored for both hours, live-verified against the
reference engine.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHXJAWVAabCKX1JgmDh4Rn
2026-08-28 20:51:06 -04:00
will 25934865b1 Model a Matins Gospel pericope and its paired homily as one atomic part
Deploy / deploy (push) Successful in 1m25s
Replaces the lesson+isGospel flag with a dedicated 'gospel' ResolvedPart
carrying an optional nested homily. Previously a Gospel pericope and its
patristic homily were two separate pool entries, which the front-light
1/1/rest nocturn slicer could split into different nocturns purely by
index. buildReadingPool now folds an isGospel:true reading and its
immediately-following same-nocturn homily into a single pool entry, so
the pairing is structural rather than a convention the slicer has to
honor. hour-view.ts renders the pair as one visually grouped section.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D1LqodVbQdQVoTGPz9sSw4
2026-08-28 19:46:48 -04:00
will 6a17a74b9b Fix Vespers ferial psalmody following an anticipated feast's identity
When tonight anticipates tomorrow's First Vespers, resolvePsalmody was
keying off the borrowed day's weekday instead of today's actual calendar
weekday, silently shifting the fixed 6-day psalm rotation. The psalm
cycle has no per-feast override and must stay on today's own place in
the rotation regardless of whose office governs the evening's propers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D1LqodVbQdQVoTGPz9sSw4
2026-08-28 19:46:33 -04:00
will 9cd59dae03 Render psalm verses as plain divs instead of an <ol>/<li> list
Deploy / deploy (push) Successful in 1m24s
Screen readers announced "list, N items" for continuous liturgical text
that isn't conceptually a list; styling is class-based so no CSS changes
were needed.
2026-08-28 18:40:51 -04:00
will 17112c06a8 Make the Today link context-sensitive to time of day
Deploy / deploy (push) Successful in 1m26s
When already viewing today, clicking Today now snaps the selected hour
to whatever hour would be default for the current wall-clock time
(same as a fresh visit to /vu); when viewing another date it still just
jumps to today while preserving the current hour, as before. The link's
href is built from the same todayTargetHour() decision as the click
handler, so right-click -> open in new tab lands on the same target
instead of following a stale href.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CbHcmjnqQPJZ1i2yoebmp5
2026-08-28 16:52:09 -04:00
will 03d164f174 Drop St. Hermes from 8/28 sanctoral calendar
Deploy / deploy (push) Successful in 1m24s
He always lost to St. Augustine and, per the generous-commemoration
design, only ever surfaced as a commemoration, so removing him from
the date list suppresses him entirely. st-hermes.yml and its collect
are left in place, restorable by re-adding the list entry.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVigobgkuEayoGdEiubBdt
2026-08-28 12:46:05 -04:00
will b19f88696f Rotate Terce/Sext/None psalm assignments for Wed/Thu/Fri/Sat
Deploy / deploy (push) Successful in 1m24s
Wednesday and Friday now carry their own distinct psalm sets (formerly
Friday's and Saturday's, respectively); Tuesday, Thursday, and Saturday
share the gradual psalm set.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVigobgkuEayoGdEiubBdt
2026-08-28 12:41:41 -04:00
will c25505cdc0 Add the Patronage of St. Joseph as a new movable feast with octave
Deploy / deploy (push) Successful in 1m21s
This Duplex I classis feast (instituted by Pius IX, 1847) didn't exist
anywhere in vu's calendar. Dated per the older, pre-1955 reckoning --
Wednesday after the 2nd Sunday after Easter (Easter+17) -- rather than the
1913 Pius X reform's later placement on the 3rd Sunday after Easter
itself, per direct instruction. Mechanism: one new temporal-feast record
plus a new EASTER_OFFSET_STARTS table entry (the only code change --
everything else is the existing generic anchor-driven resolution).

Authored the feast day's own Matins reading and its full 7-day octave
(days 2/3/4/6/7/8; day 5, the Sunday, has no override in the source at
all, correctly left unauthored).

Fixed one real collateral effect: an existing fixed-year calendar test
(St. Pudentiana vs. St. Peter Celestine, 2038-05-19) broke because that
date now falls on this octave's own closing day, tying Celestine's rank
against the octave's threshold -- the app's own documented tie-break
correctly favors the octave that year. Moved the proof date to 2033.
Also bumped the PWA precache file-size cap (6 MiB -> 8 MiB) since this
content pull pushed the main bundle past the previous limit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhysogLP9eCeKS7JEwRi6y
2026-08-28 07:12:08 -04:00
will 283bb356d7 Author Matins readings for the three Christmas-week saint octaves
Deploy / deploy (push) Successful in 1m25s
St. Stephen, St. John the Apostle, and Holy Innocents each have an 8-day
octave overlapping Christmas week, but their intervening days (2-7) carry
no distinct Lectio content in the source -- every suffix file checked at
Dec 27-31 is a bare @Sancti/MM-DD alias, correctly left unauthored, same
pattern as the fixed-date octaves. Only each octave's own closing "In
Octava" day (Jan 2/3/4 respectively) carries real content: St. Augustine's
sermon on Stephen + St. Jerome on Matt 23:34-35; St. Augustine's Tractate
36 on John + St. John Chrysostom on John 21:20-24; St. Augustine's first
sermon for Childermas + St. John Chrysostom on Matt 2:13-18.

This closes the octave-readings backlog entirely -- every fixed-date,
movable-feast, and Christmas-week saint octave has now been audited by
calendar date against the source.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhysogLP9eCeKS7JEwRi6y
2026-08-28 06:49:15 -04:00
will ca5ee5426a Author Matins readings for the three movable-feast octaves
Deploy / deploy (push) Successful in 1m24s
Ascension, Corpus Christi, and Sacred Heart octave content lives in the
reference engine's Tempora/ directory, keyed by liturgical offset from
Easter rather than calendar date. All three octaves' 7 non-feast days
(day 2 through the closing day) turned out to have genuine, distinct
patristic content -- unlike the fixed-date octaves, none were bare
vide-only days. 21 files authored across the three octaves.

Found and fixed one duplication along the way: each octave's own Sunday
day turned out to duplicate content already authored under a different id
in the earlier post-Pentecost temporal-cycle sweep, since a numbered
post-Pentecost Sunday and the Sunday within Corpus Christi's or Sacred
Heart's octave are structurally the same calendar day every year. Both
duplicate files (corpus-christi-octave-day-4, sacred-heart-octave-day-3)
were dropped after confirming the reading still surfaces via the existing
temporal id.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhysogLP9eCeKS7JEwRi6y
2026-08-28 06:40:01 -04:00
will f76c0837bd Author St. Felix I Matins reading; close two fixed-octave-day gaps
Re-auditing the two prior sanctoral bulk passes (pre-1955 Tridentine track
and SanctiM Monastic-1617 track) turned up one saint missed by both:
St. Felix I (May 30), authored the same single-lesson shape as
st-pontian.yml. This closes the saint-level side of the Matins
patristic/hagiographic reading backlog.

Separately, auditing octave-day content by calendar date (the reference
engine keys it that way, not by octave-day-number) found two real gaps in
already-partially-authored fixed-date octaves: Immaculate Conception's own
closing day (Dec 15, Pius IX bull + St. Epiphanius homily) and Nativity of
the BVM's day 3 (Sep 10, St. Jerome on Matthew's genealogy -- no usable
reference English, own translation used, draft). Every other apparent gap
in these octaves was confirmed a correctly-empty vide-only day, not a
further gap.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhysogLP9eCeKS7JEwRi6y
2026-08-28 06:39:34 -04:00
will 908f7c320d Author Matins Common-of-a-Widow psalmody (secular-sourced), alias Several-Women-Martyrs
Closes the last 2 of 20 Matins psalmody-override Common categories. The
Monastic-1617 track alone was a genuine dead end here -- no real saint
in the Monastic corpus ever invokes this Common, so there was no live
Monastic rendering to verify a hand-resolution against. Resolved per
explicit user authorization to source secular-track content directly,
consistent with this project's existing blended-source design: combined
a direct read of CommuneM/C7.txt's own psalm-substitution rule with one
live secular query (version=Tridentine - 1906) against St. Bridget of
Sweden to supply the actual antiphon text.

Nocturn 1/2 end up near-identical to common-of-a-virgin-martyr.yml (one
antiphon substituted, since Virgin-Martyr's own text literally calls her
a Virgin) -- too close to alias, not close enough to merge, same
reasoning as common-of-a-confessor vs. common-of-a-confessor-bishop.
Nocturn 3 is genuinely Widow-specific (Parable of the Pearl of Great
Price); its English has no source counterpart and is self-translated,
marked draft-quality.

common-of-several-women-martyrs aliased here: its own Monastic template
whole-file-inherits the same base with no genuine Matins-nocturn
override anywhere in the traced redirect chain.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhysogLP9eCeKS7JEwRi6y
2026-08-28 05:40:43 -04:00
will 09cf0c1aa0 Alias Virgin/Confessor-Doctor/Confessor-Pope to existing Matins Common schemes
Read the reference engine's CommuneM/*.txt templates directly (C6a,
C4a, C4b), rather than trial-and-error live queries, to confirm each
whole-file-inherits its parent Common's Matins nocturn psalmody with no
override. Live-verified byte-identical against St. Scholastica (Virgin
-> Virgin-Martyr) and St. Ambrose (Confessor-Doctor -> Confessor-Bishop);
Confessor-Pope -> Confessor-Bishop aliased on the source redirect chain
alone, since none of vu's three Pope-Confessor saints exist on the
Monastic-1617 calendar at all (matching the convention their own files
already use for every other hour).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhysogLP9eCeKS7JEwRi6y
2026-08-28 05:20:13 -04:00
will 9e0c1b3eb1 Author St. Scholastica's proper Matins psalmody
Her psalm numbers and all three nocturn versicles match Common-of-a-
Virgin(-Martyr) exactly, but her page is headed "ex Proprio Sanctorum"
and her antiphons genuinely narrate her own rainstorm-miracle episode --
real proper content, not Common text, so she gets her own saint-level
file rather than being left to the Common fallback.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhysogLP9eCeKS7JEwRi6y
2026-08-28 05:20:06 -04:00
will 87d28a14bd Fix St. Gabriel's Lauds/Vespers capitulum copy-paste bug
Deploy / deploy (push) Successful in 1m31s
lauds-capitulum-st-gabriel-archangel.yml carried Apparition of St.
Michael's own capitulum ("Significávit Deus...") under Gabriel's id --
found in passing while authoring his Matins psalmody. His real
capitulum, read directly from the reference engine's Sancti/03-24.txt
([Capitulum Laudes]), is Daniel's own account of the angel's visitation
(Dan 9:21-22), genuinely proper to Gabriel, not shared with Apparition
despite sharing the same hymn. No separate vespers-capitulum file exists
for this id, so the fix covers both hours via vespersCapitulumForOverride.

Updated tests/hours/lauds.test.ts: removed Gabriel from the shared-
chapter assertion loop (Guardian Angels/Raphael still legitimately share
Apparition's chapter, confirmed via their own saint files' explicit
source cross-references) and added a dedicated test for his own chapter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhysogLP9eCeKS7JEwRi6y
2026-08-28 04:31:47 -04:00
will fd5ab0781e Author proper Matins psalmody for the 5 angel feasts
Common-of-an-Angel doesn't exist in the reference engine -- every angel
feast has genuine proper Matins content of its own, so these are
saint-level overrides, not a Common category. Transcribed directly from
the reference engine's source files (Sancti/05-08 etc.) after a live-CGI
attempt mis-extracted a mid-nocturn antiphon change.

St. Michael needed his own file: the psalmody-override lookup keys off
the day's resolved winner id, not the `propers` field, and his own
Matins antiphons/lessons turn out to genuinely differ from Apparition's
despite his calendar file's "word-for-word identical" claim (true only
of the collect).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PhysogLP9eCeKS7JEwRi6y
2026-08-27 22:23:24 -04:00