Define the Observance value object and ID grammar #9

Closed
opened 2026-07-01 00:50:37 +00:00 by manlycucumber · 0 comments
manlycucumber commented 2026-07-01 00:50:37 +00:00 (Migrated from github.com)

Problem

Every liturgical observance needs a stable, parseable identity — the join key across all editions, years, texts, and the output contract. It must carry identity only, never edition-varying attributes like rank or colour.

Design

Per the approved design (docs/design/observance-id-grammar.md), the Observance identity is a value object with an immutable slug:

<rite>:<cycle>:<body> — e.g. roman:sanctorale:laurentius, roman:temporale:advent:sunday-3.

  • rite — leading segment; only roman for now (dispatches to that rite's cycle sub-grammar, so other rites are additive with zero retrofit).
  • cycletemporale | sanctorale | votive.
  • body — temporale: <anchorFamily>:<slot>[:coord] (anchorFamily ∈ paschal/advent/christmas/epiphany/civil-fixed/month-computed); sanctorale/votive: [<provenance>:]<subject-slug> (Latin slug).

The slug carries no rank, colour, octave, or date — those are per-edition attributes (Layer 2; issues #10/#11 et al.) or per-year realization (Layer 3). Temporal day IDs are structural only (no Easter-offset aliases).

Acceptance criteria

  • ObservanceId::parse() validates the <rite>:<cycle>:<body> grammar (regex + structural-temporal rules) and rejects malformed slugs
  • Canonical toString() with round-trip invariant parse(toString(x)) == x
  • Accessors rite(), cycle(), anchorFamily() (temporale only), segments(); equals() is pure string identity
  • Rite, Cycle, AnchorFamily, ObservanceKind value objects (PHP 7.4 final class; guarded fromString)
  • Observance identity shell: id, kind, titulars (≥1), names (locale→label, la required), aliases (secondaryFacet for genuine double-identity days); Layer-2/3 accessors stubbed + documented
  • PHPUnit added and wired into CI; identity-focused tests pass
  • docs/design/observance-id-grammar.md committed

Notes

Clean-room: authored from the committed design + liturgical facts; no prior engine code is read or ported. Rank "remap" (legacy duplex/semidouble/simple → I–IV) is a data-load concern handled with the edition attribute layer, not here.

## Problem Every liturgical observance needs a stable, parseable identity — the join key across all editions, years, texts, and the output contract. It must carry *identity only*, never edition-varying attributes like rank or colour. ## Design Per the approved design (`docs/design/observance-id-grammar.md`), the `Observance` identity is a value object with an immutable slug: `<rite>:<cycle>:<body>` — e.g. `roman:sanctorale:laurentius`, `roman:temporale:advent:sunday-3`. - **rite** — leading segment; only `roman` for now (dispatches to that rite's cycle sub-grammar, so other rites are additive with zero retrofit). - **cycle** — `temporale | sanctorale | votive`. - **body** — temporale: `<anchorFamily>:<slot>[:coord]` (anchorFamily ∈ paschal/advent/christmas/epiphany/civil-fixed/month-computed); sanctorale/votive: `[<provenance>:]<subject-slug>` (Latin slug). The slug carries **no rank, colour, octave, or date** — those are per-edition attributes (Layer 2; issues #10/#11 et al.) or per-year realization (Layer 3). Temporal day IDs are **structural only** (no Easter-offset aliases). ## Acceptance criteria - [ ] `ObservanceId::parse()` validates the `<rite>:<cycle>:<body>` grammar (regex + structural-temporal rules) and rejects malformed slugs - [ ] Canonical `toString()` with round-trip invariant `parse(toString(x)) == x` - [ ] Accessors `rite()`, `cycle()`, `anchorFamily()` (temporale only), `segments()`; `equals()` is pure string identity - [ ] `Rite`, `Cycle`, `AnchorFamily`, `ObservanceKind` value objects (PHP 7.4 `final class`; guarded `fromString`) - [ ] `Observance` identity shell: id, kind, titulars (≥1), names (locale→label, `la` required), aliases (`secondaryFacet` for genuine double-identity days); Layer-2/3 accessors stubbed + documented - [ ] PHPUnit added and wired into CI; identity-focused tests pass - [ ] `docs/design/observance-id-grammar.md` committed ## Notes Clean-room: authored from the committed design + liturgical facts; no prior engine code is read or ported. Rank "remap" (legacy duplex/semidouble/simple → I–IV) is a data-load concern handled with the edition attribute layer, not here.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Directorium/Core#9
No description provided.