Route bible-plan incipit/responsory lookup through the book-alias table
bible-plan.ts's *.yml import uses English-style book abbreviations
("jdt", "1kgs", "luke", ...) for ~30 books where that diverges from
this store's canonical form ("jdth", "3reg", "luc", ...).
scripture/index.ts's own BOOK_ALIASES already normalized this for
verse-text lookup, but the incipit (bible-book-incipits.ts) and
responsory (matins-responsories.ts) lookups used the raw abbreviation
directly, silently missing on any canonically-keyed book and falling
back to a bare "Reading" heading. The 3 Gospel aliases self-healed via
a separate citation-regex fallback that only exists for Gospels; every
other aliased book (Judith, Kings, Samuel, Esdras, Osee, Jonas, Josue,
Micheas, Abdias, Judges, the Johannine epistles, James, Jude, Philemon,
Titus, Zacharias, Sophonias) had no such fallback. Exports
canonicalBook from scripture/index.ts and routes both lookups through
it -- one shared normalization instead of two independently-aliased
ones that can drift again.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGjUyhUZJaSjiniEmnLdak
This commit is contained in:
@@ -5252,3 +5252,33 @@ branch (demoted case) and `getDayLabel`'s final fallback (winning-outright case)
|
||||
in `tests/calendar/ember-days.test.ts` cover both. `npm test` (2024 passed) and `tsc --noEmit`
|
||||
both pass.
|
||||
|
||||
**Second follow-on, same session**: user then flagged `/vu/2026-09-18/matins` (Ember Friday,
|
||||
commemorated) showing the Judith reading under a bare "Reading" heading. Real root cause, and a
|
||||
much broader bug than just Judith: `data/hours/bible-plan/*.yml`'s ~390-row TSV import uses
|
||||
English-style book abbreviations (`jdt`, `1kgs`, `luke`, ...) for the ~30 books where that
|
||||
diverges from this store's canonical Vulgate-numbering form (`jdth`, `3reg`, `luc`, ...) —
|
||||
`scripture/index.ts`'s own `BOOK_ALIASES` already normalizes this for verse-*text* lookup, but
|
||||
`bible-plan.ts`'s incipit (`bible-book-incipits.ts`) and responsory (`matins-responsories.ts`)
|
||||
lookups both used the raw, unaliased abbreviation, silently missing on any canonically-keyed
|
||||
book and falling back to the generic "Reading" heading. The 3 Gospel aliases (`luke`/`mark`/
|
||||
`john`) happened to self-heal through a second, independent citation-regex fallback that only
|
||||
exists for Gospels (`matins.ts`'s `getGospelIncipitFromCitation`) — every other aliased book
|
||||
(Judith, both Kings pairs, both Samuel books, Esdras, Osee, Jonas, Josue, Micheas, Abdias,
|
||||
Judges, the 3 Johannine epistles, James, Jude, Philemon, Titus, Zacharias, Sophonias) had no such
|
||||
fallback and was silently broken wherever it happened to be the first book of a reading. Fixed by
|
||||
exporting `canonicalBook` from `scripture/index.ts` (the same substitution `getScriptureChapter`
|
||||
already applies internally) and routing both `bible-plan.ts` lookups through it — one shared
|
||||
normalization, not two independently-aliased lookups that can drift again. New test in
|
||||
`tests/propers/bible-plan.test.ts`. `npm test` (2025 passed) and `tsc --noEmit` both pass.
|
||||
|
||||
Separately, the user also asked about seeing 3 lessons in a row all headed "Pope St. Gregory the
|
||||
Great, Homily 33 on the Gospels, on Luke 7:36-50" (Ember Friday's own 3-lesson split of one
|
||||
homily, each with its own distinct text/responsory — see the 2026-08-22 Ember-day entry above).
|
||||
Confirmed this is correct content, not a duplication bug, but also confirmed it's *not* actually
|
||||
how the reference source itself labels it: `Tempora/093-5.txt` only carries the attribution once,
|
||||
on `[Lectio1]` — `[Lectio2]`/`[Lectio3]` have no repeated header at all, continuing silently under
|
||||
the same nocturn. This app's own authoring convention repeats the full `source` string identically
|
||||
on every split lesson, and does so consistently across the *entire* nocturn-readings corpus, not
|
||||
just Ember days — flagged for the user as a real presentational rough edge, not fixed yet pending
|
||||
their call on scope (a corpus-wide UI/authoring change, not a narrow one-file fix).
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import type { LanguageCode, TranslationStatus } from '../psalter/types';
|
||||
import { resolvePassages, type ScriptureCitation } from './octave-readings';
|
||||
import { getResponsoryForBook } from './matins-responsories';
|
||||
import { getBookIncipit } from './bible-book-incipits';
|
||||
import { canonicalBook } from '../scripture';
|
||||
|
||||
const GOSPEL_BOOKS = new Set(['matt', 'mark', 'luke', 'john']);
|
||||
|
||||
@@ -115,8 +116,9 @@ function resolveReading(record: BiblePlanReadingRecord, bookIndex: number): Bibl
|
||||
};
|
||||
const citationLabelText = formatCitationLabel(record.passages);
|
||||
const firstBook = record.passages[0]?.book;
|
||||
const responsory = firstBook ? getResponsoryForBook(firstBook, bookIndex)?.text : undefined;
|
||||
const incipit = firstBook ? getBookIncipit(firstBook) : undefined;
|
||||
const canonicalFirstBook = firstBook ? canonicalBook(firstBook) : undefined;
|
||||
const responsory = canonicalFirstBook ? getResponsoryForBook(canonicalFirstBook, bookIndex)?.text : undefined;
|
||||
const incipit = canonicalFirstBook ? getBookIncipit(canonicalFirstBook) : undefined;
|
||||
return {
|
||||
text,
|
||||
status,
|
||||
|
||||
@@ -58,6 +58,19 @@ export function getScriptureChapter(book: string, chapter: number): ScriptureCha
|
||||
return chapters.get(`${BOOK_ALIASES[book] ?? book}-${chapter}`);
|
||||
}
|
||||
|
||||
/** `book` normalized to this store's own canonical abbreviation — the
|
||||
* same substitution `getScriptureChapter` applies internally, exposed for
|
||||
* callers (bible-plan.ts's incipit/responsory lookups) that key off a
|
||||
* *different* store keyed by the canonical form only (bible-book-
|
||||
* incipits.ts, matins-responsories.ts) and would otherwise silently miss
|
||||
* on any of `BOOK_ALIASES`' ~30 entries — live case: "jdt" (Judith)
|
||||
* resolves its verse text fine but fell through bible-book-incipits.ts's
|
||||
* `jdth`-keyed lookup, rendering as a bare "Reading" heading instead of
|
||||
* "A reading from the book of Judith" (2026-09-03). */
|
||||
export function canonicalBook(book: string): string {
|
||||
return BOOK_ALIASES[book] ?? book;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param verseRange e.g. "2-19" — inclusive. Whole (authored) chapter when
|
||||
* omitted. Unauthored book/chapter combinations resolve to an empty array
|
||||
|
||||
@@ -17,3 +17,24 @@ describe('getBiblePlanReadings citation labels', () => {
|
||||
expect(readings[2]?.citation.la).toBe('Luke 18:1-23');
|
||||
});
|
||||
});
|
||||
|
||||
// A reading's `label` (the "Léctio libri..." incipit) previously looked up
|
||||
// bible-book-incipits.ts's canonical-abbreviation-only table using the raw
|
||||
// book abbreviation from data/hours/bible-plan/*.yml -- which, for ~30
|
||||
// books, is one of scripture/index.ts's own English-style aliases (e.g.
|
||||
// "jdt" for Judith), not the canonical form ("jdth") that table is keyed
|
||||
// by. The alias resolved verse *text* fine (getScriptureChapter already
|
||||
// consulted the alias table) but silently missed the label lookup,
|
||||
// rendering as the generic "Reading" heading instead -- live case: Sept
|
||||
// 18 2026's own Ember Friday commemoration, `post-pentecost-16-friday`'s
|
||||
// first reading (Judith 11-13). Fixed 2026-09-03 by routing both the
|
||||
// incipit and responsory lookups through scripture/index.ts's own
|
||||
// `canonicalBook`, the same normalization the text lookup already used.
|
||||
describe('getBiblePlanReadings label uses the same book-alias normalization as verse-text lookup', () => {
|
||||
it('an aliased book ("jdt" for Judith) still gets its real incipit label, not the generic fallback', () => {
|
||||
const readings = getBiblePlanReadings('post-pentecost-16', 'friday', '2026-09-18');
|
||||
expect(readings[0]?.citation.la).toBe('Jdt 11-13');
|
||||
expect(readings[0]?.label?.en).toBe('A reading from the book of Judith');
|
||||
expect(readings[0]?.label?.la).toBe('Léctio libri Judith');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user