feat: add Observance identity value object and ID grammar #201

Merged
manlycucumber merged 1 commit from feature/9-observance-identity into develop 2026-07-01 04:49:27 +00:00
manlycucumber commented 2026-07-01 04:48:16 +00:00 (Migrated from github.com)

Closes #9

The engine's cornerstone type: the immutable Observance identity — designed first (approved in the plan) and built clean-room.

What lands

  • ObservanceId — slug grammar roman:<cycle>:<body> (rite in the slug; the parser dispatches on rite). parse() + canonical toString() with round-trip parse(toString(x)) === x; equals() is pure string identity; rite()/cycle()/anchorFamily()/segments() accessors. Temporal IDs are structural only — the Easter-offset form is rejected (Route 1).
  • Value objects Rite, Cycle, AnchorFamily, ObservanceKind (PHP 7.4 final classes, guarded fromString).
  • IdentityAliases (secondaryFacet for genuine double-identity days; split/merge lineage; external URNs) and the Observance identity shell (id, kind, titulars, names with required Latin, aliases).
  • Identity carries no rank/colour/octave/date — those are per-edition attributes (#10–#13) / per-year realization. The 3-layer split keeps one id stable across every year and rubric edition.

Tooling

  • PHPUnit added (^9.6, PHP 7.4 floor) + a composer test script; phpstan/phpstan-phpunit for test-aware analysis; phpcs/phpstan now scan tests/; CI runs a PHPUnit step across the 7.4→8.3 matrix.

Docs (committed)

docs/design/observance-id-grammar.md · platform-urn-scheme.md · slug-naming-policy.md.

Verified locally

phpcs 12/12 · phpstan L6 [OK] · phpunit 40 tests, 82 assertions OK.

Clean-room: authored from the approved design + liturgical facts; no prior engine code read or ported. Companion issues #10 / #11 / #39 / #52 reworded to the identity/edition split.

Closes #9 The engine's cornerstone type: the immutable `Observance` identity — designed first (approved in the plan) and built clean-room. ## What lands - **`ObservanceId`** — slug grammar `roman:<cycle>:<body>` (rite in the slug; the parser dispatches on rite). `parse()` + canonical `toString()` with round-trip `parse(toString(x)) === x`; `equals()` is pure string identity; `rite()`/`cycle()`/`anchorFamily()`/`segments()` accessors. Temporal IDs are **structural only** — the Easter-offset form is rejected (Route 1). - Value objects **`Rite`, `Cycle`, `AnchorFamily`, `ObservanceKind`** (PHP 7.4 `final` classes, guarded `fromString`). - **`IdentityAliases`** (`secondaryFacet` for genuine double-identity days; split/merge lineage; external URNs) and the **`Observance`** identity shell (id, kind, titulars, names with required Latin, aliases). - **Identity carries no rank/colour/octave/date** — those are per-edition attributes (#10–#13) / per-year realization. The 3-layer split keeps one id stable across every year and rubric edition. ## Tooling - PHPUnit added (`^9.6`, PHP 7.4 floor) + a `composer test` script; `phpstan/phpstan-phpunit` for test-aware analysis; phpcs/phpstan now scan `tests/`; CI runs a PHPUnit step across the 7.4→8.3 matrix. ## Docs (committed) `docs/design/observance-id-grammar.md` · `platform-urn-scheme.md` · `slug-naming-policy.md`. ## Verified locally phpcs **12/12** · phpstan L6 **`[OK]`** · phpunit **40 tests, 82 assertions** OK. Clean-room: authored from the approved design + liturgical facts; no prior engine code read or ported. Companion issues #10 / #11 / #39 / #52 reworded to the identity/edition split.
Sign in to join this conversation.
No reviewers
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!201
No description provided.