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:
2026-09-04 07:12:55 -04:00
parent 88e8a5b404
commit 290bbac1b5
4 changed files with 68 additions and 2 deletions
+4 -2
View File
@@ -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,
+13
View File
@@ -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