Define the Observance value object and ID grammar #9
Labels
No labels
area: build
area: ci
area: compare
area: data
area: engine
area: model
area: provenance
area: rite
area: validation
backport
blocked
breaking
confirmed
dependencies
duplicate
epic
github_actions
invalid
needs-info
needs-triage
php
priority: high
priority: low
priority: medium
regression
type: bug
type: chore
type: correction
type: docs
type: enhancement
type: feature
type: fix
type: perf
type: refactor
type: security
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Directorium/Core#9
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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), theObservanceidentity is a value object with an immutable slug:<rite>:<cycle>:<body>— e.g.roman:sanctorale:laurentius,roman:temporale:advent:sunday-3.romanfor now (dispatches to that rite's cycle sub-grammar, so other rites are additive with zero retrofit).temporale | sanctorale | votive.<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 slugstoString()with round-trip invariantparse(toString(x)) == xrite(),cycle(),anchorFamily()(temporale only),segments();equals()is pure string identityRite,Cycle,AnchorFamily,ObservanceKindvalue objects (PHP 7.4final class; guardedfromString)Observanceidentity shell: id, kind, titulars (≥1), names (locale→label,larequired), aliases (secondaryFacetfor genuine double-identity days); Layer-2/3 accessors stubbed + documenteddocs/design/observance-id-grammar.mdcommittedNotes
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.