feat: add LiturgicalDay aggregate and day() entry point #205

Merged
manlycucumber merged 1 commit from feature/13-liturgical-day into develop 2026-07-01 05:36:08 +00:00
manlycucumber commented 2026-07-01 05:35:32 +00:00 (Migrated from github.com)

Closes #13. Completes Epic #6 (Package scaffold & engine foundations).

Establishes the public contract seam: day($date) returns an immutable LiturgicalDay. This is the entry point the resolver phases will populate — it exists now, with a stable shape, so the rest of the engine (and downstream repos) can build against it.

What lands

  • Introibo\Core\day(DateTimeImmutable $date): LiturgicalDay — the headline entry point, a namespaced function (files autoload). Takes a DateTimeImmutable so the returned day can't be mutated out from under the caller. Until the resolver phases are wired in, it returns an empty placeholder day.

  • Introibo\Core\Calendar\LiturgicalDay — the immutable aggregate. Holds the day's date() plus four roles as list<Observance>:

    • celebration() — the office(s) actually celebrated (normally one principal)
    • commemoration() — offices commemorated within another office
    • displaced() — offices impeded on this day (transferred away or omitted)
    • tempora() — the temporal office(s): the Sunday or feria of the season

    LiturgicalDay::placeholder($date) is the well-defined empty day; isEmpty() reports it. Immutable once built — it stores only value objects and hands back copied arrays, so a returned collection cannot mutate the aggregate.

Acceptance criteria

  • day() accepts a date and returns a LiturgicalDay with the four arrays
  • Empty/placeholder day construction is well-defined and tested (placeholder(), isEmpty())
  • The aggregate is immutable once built (returned-collection mutation test)
  • Unit test asserts the shape of a returned day for a trivial date

Per the issue note, this is the contract seam only; the output-contract epic (#52) formalises serialisation and the resolver epics populate the roles.

Verification

Local (portable toolchain): composer validate OK · composer lint 26/26 · composer analyse PHPStan L6 [OK] · composer test 89/89 green.

Closes #13. Completes Epic #6 (Package scaffold & engine foundations). Establishes the **public contract seam**: `day($date)` returns an immutable `LiturgicalDay`. This is the entry point the resolver phases will populate — it exists now, with a stable shape, so the rest of the engine (and downstream repos) can build against it. ## What lands - **`Introibo\Core\day(DateTimeImmutable $date): LiturgicalDay`** — the headline entry point, a namespaced function (files autoload). Takes a `DateTimeImmutable` so the returned day can't be mutated out from under the caller. Until the resolver phases are wired in, it returns an empty placeholder day. - **`Introibo\Core\Calendar\LiturgicalDay`** — the immutable aggregate. Holds the day's `date()` plus four roles as `list<Observance>`: - `celebration()` — the office(s) actually celebrated (normally one principal) - `commemoration()` — offices commemorated within another office - `displaced()` — offices impeded on this day (transferred away or omitted) - `tempora()` — the temporal office(s): the Sunday or feria of the season `LiturgicalDay::placeholder($date)` is the well-defined empty day; `isEmpty()` reports it. Immutable once built — it stores only value objects and hands back copied arrays, so a returned collection cannot mutate the aggregate. ## Acceptance criteria - [x] `day()` accepts a date and returns a `LiturgicalDay` with the four arrays - [x] Empty/placeholder day construction is well-defined and tested (`placeholder()`, `isEmpty()`) - [x] The aggregate is immutable once built (returned-collection mutation test) - [x] Unit test asserts the shape of a returned day for a trivial date Per the issue note, this is the contract seam only; the output-contract epic (#52) formalises serialisation and the resolver epics populate the roles. ## Verification Local (portable toolchain): `composer validate` OK · `composer lint` 26/26 · `composer analyse` PHPStan L6 `[OK]` · `composer test` 89/89 green.
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!205
No description provided.