From 165d94f8f5609772e4e7b327660758c598a63017 Mon Sep 17 00:00:00 2001 From: Will Estes Date: Sat, 5 Sep 2026 20:25:05 -0400 Subject: [PATCH] Move an active octave's Matins reading ahead of homily content An active octave's own reading (data/propers/octave-readings/*.yml) is a direct Scripture excerpt, not patristic homily commentary -- the same kind of content as the bible-plan readings, not the winner's/ commemorations' own homiletic pool. It was being appended at the very end of buildReadingPool unconditionally, landing after every other reading regardless of who won the day or how many commemorations piled on. Moved to right after the bible-plan block instead, so it groups with other Scripture-type content rather than trailing behind patristic homilies. Live case: Nov 8, 2026 (All Saints' octave closing day) previously read [1 Tim 1, St. Cyprian, Gospel, St. Augustine, St. Athanasius, Gospel, Ezekiel] -- Ezekiel now sits right after 1 Tim 1, ahead of everything else, per direct instruction. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01LGsATZvfnpQ81HQuoF5JuL --- src/hours/matins.ts | 67 ++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/src/hours/matins.ts b/src/hours/matins.ts index 3413214..ca85dd3 100644 --- a/src/hours/matins.ts +++ b/src/hours/matins.ts @@ -919,6 +919,48 @@ function buildReadingPool(day: LiturgicalDay, temporalId: string, date: string, : { kind: 'lesson', text: { text: r.text, status: r.status, citation: r.citation }, responsory, label }, ); } + // An active octave's own Matins reading (`data/propers/octave- + // readings/*.yml`) is a direct Scripture excerpt, not patristic homily + // commentary — the same kind of content as the bible-plan readings + // just pushed above, not the winner's/commemorations' own homiletic + // pool below. Placed here, right after the bible-plan block and ahead + // of everything else, rather than appended at the very end (where it + // sat before 2026-09-05) — user, 2026-09-05, re: Nov 8 2026 (All + // Saints' octave closing day): the Ezekiel reading there read as + // misplaced trailing after the day's other homilies. Previously it was + // also the *last* thing sorted (matching the day-label's own + // winner/temporal/sanctoral/octave ordering), but that convention is + // for commemoration *priority*, not for what kind of reading this is — + // Scripture stays grouped with Scripture. Note this shifts the pool's + // own position-0/1/2+ split (see distributeIntoNocturns): an octave + // reading now competes for the Nocturn 1/2 "exactly one reading" slots + // the same as anything else at this position, potentially displacing + // what would otherwise have landed there. + for (const octave of activeOctavesFor(date)) { + const reading = getOctaveReading(octave.id, octave.dayNumber); + if (reading) { + // Unlike nocturn-readings' `source` (a plain, non-bilingual string — + // see `withOccasion`'s own doc comment), an octave reading's `source` + // is itself `{la, en}` (2026-08 fix). The occasion name is still a + // single plain string either way, so it's appended to both language + // slots rather than routed through `withOccasion`. + const occasion = occasionName(octave.id, day); + const label = occasion + ? { + la: reading.source.la ? `${reading.source.la} (for ${occasion})` : reading.source.la, + en: reading.source.en ? `${reading.source.en} (for ${occasion})` : reading.source.en, + } + : reading.source; + parts.push({ + kind: 'lesson', + text: { text: reading.text, status: reading.status }, + label, + responsory: reading.responsory + ? { text: reading.responsory, status: { la: 'verified', en: 'verified' } } + : undefined, + }); + } + } const ids = nocturnReadingIds(day, temporalId, date, threeNocturns); // Ordering is by *id priority* (winner first, then commemorations in // `day.commemorations` order — a winning saint's own content always @@ -1002,31 +1044,6 @@ function buildReadingPool(day: LiturgicalDay, temporalId: string, date: string, for (const key of sortedGroupKeys) { parts.push(...byGroup.get(key)!); } - for (const octave of activeOctavesFor(date)) { - const reading = getOctaveReading(octave.id, octave.dayNumber); - if (reading) { - // Unlike nocturn-readings' `source` (a plain, non-bilingual string — - // see `withOccasion`'s own doc comment), an octave reading's `source` - // is itself `{la, en}` (2026-08 fix). The occasion name is still a - // single plain string either way, so it's appended to both language - // slots rather than routed through `withOccasion`. - const occasion = occasionName(octave.id, day); - const label = occasion - ? { - la: reading.source.la ? `${reading.source.la} (for ${occasion})` : reading.source.la, - en: reading.source.en ? `${reading.source.en} (for ${occasion})` : reading.source.en, - } - : reading.source; - parts.push({ - kind: 'lesson', - text: { text: reading.text, status: reading.status }, - label, - responsory: reading.responsory - ? { text: reading.responsory, status: { la: 'verified', en: 'verified' } } - : undefined, - }); - } - } return parts; }