feat: freeze resolveYear() as a golden-fixture safety gate (#365) #416

Merged
manlycucumber merged 1 commit from feature/365-golden-year-fixture into develop 2026-07-02 15:09:20 +00:00
manlycucumber commented 2026-07-02 15:07:46 +00:00 (Migrated from github.com)

Closes #365.

Freezes the engine's resolved liturgy as a byte-stable golden fixture so the corpus data-for-code swaps (#41 sanctoral, #42 temporal, #43 precedence) can be proven inert — data replaces code without moving the resolved calendar by a byte.

What

  • tests/Golden/GoldenYear — per-year digest: SHA-256 of each day's DayContract JSON with the volatile provenance stamps (corpusVersion, engineVersion) stripped, so the digest tracks the liturgy, not metadata. The #41 plumbing swap (same feasts, new corpus id) is therefore inert; any real change is caught.
  • tests/Golden/resolve-year-digests.ndjson — the committed fixture, one {"year","days","sha256"} line per year, 1584–2200 (617 years).
  • tests/Golden/GoldenYearDigestTest — the CI guard: re-resolves every year, asserts byte-identical digests, names any drift. Runs in the check job via composer test, so it gates #42/#43.
  • bin/freeze-golden-year.php — regenerates the fixture; run only when a calendar change is reviewed and accepted (e.g. #41 expanding the sanctoral), then commit the result.

Boundary note

resolveYear() reaches back one year for the trailing Christmas cycle, so its effective floor is 1584 (resolving 1583 would need the pre-Gregorian-floor 1582 cycle). The fixture covers 1584–2200; the 1583 gap is documented in KNOWN-LIMITATIONS.md and tracked in #415.

Verification

  • Deterministic: two freezes byte-identical; LF-only.
  • Version stamps confirmed absent from the hashed preimage (plumbing swap inert); contractVersion/office content present.
  • Tamper-detection: flipping one fixture digest fails the guard with a year-named diagnostic; restore → green.
  • Local gate: PSR-12 clean, PHPStan [OK], 576 tests / 30,619 assertions green (~7s).
Closes #365. Freezes the engine's resolved liturgy as a byte-stable golden fixture so the corpus data-for-code swaps (#41 sanctoral, #42 temporal, #43 precedence) can be proven inert — data replaces code without moving the resolved calendar by a byte. ## What - **`tests/Golden/GoldenYear`** — per-year digest: SHA-256 of each day's `DayContract` JSON with the volatile provenance stamps (`corpusVersion`, `engineVersion`) stripped, so the digest tracks the *liturgy*, not metadata. The #41 plumbing swap (same feasts, new corpus id) is therefore inert; any real change is caught. - **`tests/Golden/resolve-year-digests.ndjson`** — the committed fixture, one `{"year","days","sha256"}` line per year, 1584–2200 (617 years). - **`tests/Golden/GoldenYearDigestTest`** — the CI guard: re-resolves every year, asserts byte-identical digests, names any drift. Runs in the `check` job via `composer test`, so it gates #42/#43. - **`bin/freeze-golden-year.php`** — regenerates the fixture; run only when a calendar change is reviewed and accepted (e.g. #41 expanding the sanctoral), then commit the result. ## Boundary note `resolveYear()` reaches back one year for the trailing Christmas cycle, so its effective floor is **1584** (resolving 1583 would need the pre-Gregorian-floor 1582 cycle). The fixture covers 1584–2200; the 1583 gap is documented in `KNOWN-LIMITATIONS.md` and tracked in #415. ## Verification - Deterministic: two freezes byte-identical; LF-only. - Version stamps confirmed absent from the hashed preimage (plumbing swap inert); `contractVersion`/office content present. - Tamper-detection: flipping one fixture digest fails the guard with a year-named diagnostic; restore → green. - Local gate: PSR-12 clean, PHPStan `[OK]`, 576 tests / 30,619 assertions green (~7s).
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!416
No description provided.