Refactor Matins psalmody overrides to category-keyed data
Split the store into categories/*.yml (generic Common-category psalm- number/versicle/canticle scheme) and saints/*.yml (per-saint proper antiphon overrides, unchanged shape) per the mechanism's own flagged next step. St. Lawrence's file moves into saints/ with a category cross-reference; resolution behavior (per-saint lookup, ferial fallback when unauthored) is unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+17
@@ -29,7 +29,24 @@
|
|||||||
# chapters authored for this: data/scripture/{sir-14,sir-15,jer-17,sir-31}.yml
|
# chapters authored for this: data/scripture/{sir-14,sir-15,jer-17,sir-31}.yml
|
||||||
# (all sparse, only the cited verses -- same convention as sir-36.yml's
|
# (all sparse, only the cited verses -- same convention as sir-36.yml's
|
||||||
# own Sunday-canticle transcription).
|
# own Sunday-canticle transcription).
|
||||||
|
#
|
||||||
|
# `category: common-of-a-martyr` links this to
|
||||||
|
# data/hours/matins-psalmody-overrides/categories/common-of-a-martyr.yml,
|
||||||
|
# the generic Common-of-a-Martyr scheme authored from St. Ignatius of
|
||||||
|
# Antioch's own live-verified Matins (2029-02-01 -- his own file has no
|
||||||
|
# proper antiphon, "vide C2" i.e. entirely from Common, confirming his
|
||||||
|
# psalmody *is* the category default). Lawrence's own file stays fully
|
||||||
|
# self-contained (own psalm numbers + antiphons, not merged with the
|
||||||
|
# category file at load time) -- the category link is documentation/
|
||||||
|
# cross-reference only, not a runtime merge, per this project's "stay on
|
||||||
|
# the ferial fallback until proper antiphon text is authored per-saint"
|
||||||
|
# decision (2026-08): a saint without an entry here still gets no
|
||||||
|
# override, never the category's generic antiphon text. Note one real
|
||||||
|
# divergence from the category default worth remembering: Lawrence's own
|
||||||
|
# Nocturn 2 has Ps 16 in the slot where the plain Common default (and
|
||||||
|
# Ignatius) has Ps 64 -- his own proper psalm selection, not a typo.
|
||||||
id: st-lawrence
|
id: st-lawrence
|
||||||
|
category: common-of-a-martyr
|
||||||
nocturn1:
|
nocturn1:
|
||||||
groups:
|
groups:
|
||||||
- psalms: [1]
|
- psalms: [1]
|
||||||
@@ -1,29 +1,35 @@
|
|||||||
/** Matins' own analogue of hours/lauds-psalmody-overrides.ts, but keyed
|
/** Matins' own analogue of hours/lauds-psalmody-overrides.ts. Two data
|
||||||
* by Common category rather than per-saint: live-verified (see
|
* stores, both keyed by id:
|
||||||
* data/hours/matins-psalmody-overrides/st-lawrence.yml's own header)
|
*
|
||||||
* that the psalm *numbers* for Nocturns 1-2 are shared across saints of
|
* - `data/hours/matins-psalmody-overrides/categories/*.yml` — the
|
||||||
* the same Common category (a plain-Duplex Martyr and a plain-Duplex
|
* generic Common-of-* Matins psalmody (psalm numbers, versicles,
|
||||||
* Martyr-Bishop share all but one of the same twelve psalm numbers) —
|
* canticle refs, and the plain Common antiphon text), one file per
|
||||||
* only the antiphon text varies, proper to the individual saint when
|
* `SaintRecord.common` category. Live-verified against a saint with no
|
||||||
* authored, generic Common-of-* text otherwise. Deliberately the
|
* proper antiphon of his own (so his own output *is* the category
|
||||||
* opposite indexing choice from Lauds' own per-feast override (see that
|
* default) — see e.g. `categories/common-of-a-martyr.yml`'s own doc
|
||||||
* file's own doc comment) — Lauds' 5-antiphon pool is shared across
|
* comment. Reference/documentation content only: not consulted by
|
||||||
* every Duplex-majus+ feast regardless of category, so per-feast is the
|
* `getMatinsPsalmodyOverride` below, per this project's "stay on the
|
||||||
* natural key there; Matins' pool varies *by* category, so per-category
|
* ferial fallback until proper antiphon text is authored per-saint"
|
||||||
* is the natural key here.
|
* decision (2026-08) — a saint without their own entry in `saints/`
|
||||||
|
* still falls all the way back to matins.ts's own plain ferial table,
|
||||||
|
* never to a category's generic antiphon text. Recorded so the next
|
||||||
|
* saint authored in an already-proven category doesn't have to
|
||||||
|
* re-derive/re-verify the same shared psalm numbers and versicles.
|
||||||
|
*
|
||||||
|
* - `data/hours/matins-psalmody-overrides/saints/*.yml` — real proper
|
||||||
|
* antiphon text for one specific saint (only authored where a saint
|
||||||
|
* genuinely has proper text of their own, confirmed against the live
|
||||||
|
* engine, not merely inherited Common text). Each carries its own
|
||||||
|
* `category` field cross-referencing the file above, but is otherwise
|
||||||
|
* fully self-contained (own psalm numbers, not merged with the
|
||||||
|
* category file at load time) — a saint's proper psalmody occasionally
|
||||||
|
* swaps one slot's psalm number from the category default too (see
|
||||||
|
* `saints/st-lawrence.yml`'s own note), so per-saint files stay
|
||||||
|
* authoritative rather than being computed as a diff.
|
||||||
*
|
*
|
||||||
* `id` is looked up against `hours/resolve-common.ts`'s
|
* `id` is looked up against `hours/resolve-common.ts`'s
|
||||||
* `resolveOfficeWinner(day).id` when it's sanctoral, exactly like every
|
* `resolveOfficeWinner(day).id` when it's sanctoral, exactly like every
|
||||||
* other per-feast/per-category content lookup in this app — but the
|
* other per-feast/per-category content lookup in this app. */
|
||||||
* `id` values populated so far are individual saint ids (St. Lawrence
|
|
||||||
* proper), not Common-category ids, since only the live-verified proof
|
|
||||||
* has been authored; extending this to a real Common-category key
|
|
||||||
* (`common-of-a-martyr`, etc., matching `SaintRecord.common`) with
|
|
||||||
* per-saint antiphon overrides layered on top is the deferred bulk-
|
|
||||||
* content work (see TODO.md) — not built yet, so a saint without their
|
|
||||||
* own entry here falls back to the plain ferial weekday table
|
|
||||||
* (matins.ts's own fallback), not to some other saint's proper
|
|
||||||
* antiphons. */
|
|
||||||
export interface MatinsPsalmodyGroup {
|
export interface MatinsPsalmodyGroup {
|
||||||
psalms: number[];
|
psalms: number[];
|
||||||
antiphon: Partial<Record<string, string>>;
|
antiphon: Partial<Record<string, string>>;
|
||||||
@@ -40,22 +46,42 @@ export interface MatinsPsalmodyNocturn {
|
|||||||
versicle: { v: Partial<Record<string, string>>; r: Partial<Record<string, string>> };
|
versicle: { v: Partial<Record<string, string>>; r: Partial<Record<string, string>> };
|
||||||
}
|
}
|
||||||
export interface MatinsPsalmodyOverride {
|
export interface MatinsPsalmodyOverride {
|
||||||
|
id: string;
|
||||||
|
category?: string;
|
||||||
|
nocturn1: MatinsPsalmodyNocturn;
|
||||||
|
nocturn2: MatinsPsalmodyNocturn;
|
||||||
|
nocturn3: MatinsPsalmodyNocturn;
|
||||||
|
}
|
||||||
|
export interface MatinsPsalmodyCategory {
|
||||||
id: string;
|
id: string;
|
||||||
nocturn1: MatinsPsalmodyNocturn;
|
nocturn1: MatinsPsalmodyNocturn;
|
||||||
nocturn2: MatinsPsalmodyNocturn;
|
nocturn2: MatinsPsalmodyNocturn;
|
||||||
nocturn3: MatinsPsalmodyNocturn;
|
nocturn3: MatinsPsalmodyNocturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
const modules = import.meta.glob<{ default: MatinsPsalmodyOverride }>(
|
const saintModules = import.meta.glob<{ default: MatinsPsalmodyOverride }>(
|
||||||
'../data/hours/matins-psalmody-overrides/*.yml',
|
'../data/hours/matins-psalmody-overrides/saints/*.yml',
|
||||||
|
{ eager: true },
|
||||||
|
);
|
||||||
|
const categoryModules = import.meta.glob<{ default: MatinsPsalmodyCategory }>(
|
||||||
|
'../data/hours/matins-psalmody-overrides/categories/*.yml',
|
||||||
{ eager: true },
|
{ eager: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
const overrides = new Map<string, MatinsPsalmodyOverride>();
|
const overrides = new Map<string, MatinsPsalmodyOverride>();
|
||||||
for (const mod of Object.values(modules)) {
|
for (const mod of Object.values(saintModules)) {
|
||||||
overrides.set(mod.default.id, mod.default);
|
overrides.set(mod.default.id, mod.default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const categories = new Map<string, MatinsPsalmodyCategory>();
|
||||||
|
for (const mod of Object.values(categoryModules)) {
|
||||||
|
categories.set(mod.default.id, mod.default);
|
||||||
|
}
|
||||||
|
|
||||||
export function getMatinsPsalmodyOverride(id: string | undefined): MatinsPsalmodyOverride | undefined {
|
export function getMatinsPsalmodyOverride(id: string | undefined): MatinsPsalmodyOverride | undefined {
|
||||||
return id ? overrides.get(id) : undefined;
|
return id ? overrides.get(id) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getMatinsPsalmodyCategory(id: string | undefined): MatinsPsalmodyCategory | undefined {
|
||||||
|
return id ? categories.get(id) : undefined;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user