diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-26 23:40:17 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-26 23:40:17 +0200 |
| commit | 2f6d25aff88b4c76c61e36889f1c017b3cc8faee (patch) | |
| tree | baf3027229ef3b95eff2d7fdf0b479f8bdbb2a87 /CLAUDE.md | |
| parent | 1c0137dee8ff3858707281366662891a5ff01044 (diff) | |
| download | colitur-2f6d25aff88b4c76c61e36889f1c017b3cc8faee.tar.gz colitur-2f6d25aff88b4c76c61e36889f1c017b3cc8faee.zip | |
fix(of): anticipate St Joseph onto 18 March per Normae n. 56(f)
W1: when 19 March (St Joseph) falls on Palm Sunday, colitur sent him
forward to Easter+9 instead of anticipating the solemnity backward to
18 March, the one rule in the whole Normae transfer machinery that
names an earlier date. Live in 16 of 1583-2100 (1595, 1606, 1617,
1690, 1758, 1769, 1780, 1815, 1826, 1837, 1967, 1978, 1989, 2062,
2073, 2084).
Blocked on a kernel contract: Rite.t.transfer_target required its
result be strictly later than the impeded date, an obligation argued
purely from the EF's RG 96. Traced against Calendar's actual placement
pass rather than assumed unsafe: the round loop re-resolves the whole
year fresh every round, and its two safety nets (~start/~stop; the
round-count guard) both test the target's own value with no comparison
against origin, so a bounded backward jump converges the same way a
bounded forward one does. The one requirement that stays load-bearing
is target <> origin: Precedence.resolve never deduplicates by slug, so
a candidate returning its own argument unchanged would collide with
itself in the same round's contest. Relaxed the obligation accordingly
(rite.mli) and added the fourth transfer_target branch in
Precedence_of, ahead of the existing three (Precedence_of.transfer_target,
Rule 0). calendar.ml needed no logic change, only two comments that
asserted "every genuine transfer moves forward" as a blanket fact.
Unpinned the two tests that asserted the old wrong (forward) behaviour
and replaced them with assertions of the correct one, plus a new
direct unit test of the backward branch across two independent years.
EF output is untouched: data/ef/ and lib/rites/rite_ef/ carry no diff,
and colitur day/readings for 2026, 1583 and 9999 are byte-identical
against a build of the prior commit. OF's own 2005-2050 window carries
none of the 16 affected years and shows zero unexpected diffs; the
full 1583-9999 domain still reaches a fixed point under the exhaustive
sweep.
Diffstat (limited to 'CLAUDE.md')
| -rw-r--r-- | CLAUDE.md | 76 |
1 files changed, 76 insertions, 0 deletions
@@ -881,6 +881,82 @@ original, distinct architectural reason. dedicated unit test alone. Full account: `.superpowers/sdd/2026-08-12-colitur-rg16a/bvm-saturday-report.md`. +10. **OF W1 — Normae n. 56(f), St Joseph anticipated onto Palm Sunday — + RESOLVED (`of-normae-56f`, 2026-08-26), and the kernel contract change + it forced.** `Rite.t.transfer_target`'s own obligation used to require + the result be **strictly later** than the impeded date, justified + purely from the EF's RG 96 (rite.mli's own comment cited it, "the same + class of item CLAUDE.md tracks under 'EF-shaped things still in + rite-agnostic kernel code'" — item 8 above). This is the FIFTH + EF-shaped kernel misfit found while building OF (after `Preface.t`, + `Mass_formulary.source`, `transfer_target`'s own strictly-later + contract, and `citation_shapes`) and the SECOND fixed rather than only + documented — `citation_shapes` was the first. + + **The rule that forced it**: *"Sollemnitas S. Ioseph, ubi est de + praecepto servanda, si cum Dominica in palmis de Passione Domini + occurrit, anticipatur sabbato praecedenti, die 18 martii"* — St Joseph + impeded by Palm Sunday is ANTICIPATED BACKWARD to the preceding + Saturday, the one clause in the whole Tabula/Normae transfer machinery + that names an earlier date, not a later one. Live in 16 of 1583–2100 + (1595, 1606, 1617, 1690, 1758, 1769, 1780, 1815, 1826, 1837, 1967, + 1978, 1989, 2062, 2073, 2084) — colitur previously sent Joseph forward + to Easter+9 instead (past the Annunciation's own Easter+8, since both + solemnities were impeded that year and collided on the same forward + target). + + **The alternative rejected**: leaving it documented-but-unimplemented + indefinitely, precedence_of.mli's own status quo before this task. No + rite-local workaround exists instead — `Calendar.place_transfers` is + the only channel that ever places a transferred candidate, so a rule + the kernel contract forbids from returning cannot be smuggled in + beside it. + + **What it actually costs**: traced against `Calendar`'s real placement + pass (calendar.ml's `place_transfers`/`year`), not assumed unsafe by + inheritance from the EF-only citation that wrote the original text. + The round loop re-resolves the WHOLE year fresh every round from the + currently-settled assignment, and its two safety nets — the + `~start`/`~stop` domain bound and `max_transfer_rounds`'s round-count + guard — both test the target's own value with no comparison against + `origin` anywhere, so a bounded backward jump converges exactly the + way a bounded forward one does, and "resurrecting a superseded + occupant" cannot occur (a day's occupant is decided fresh each round + by the same contest every other day is). The ONE requirement that + really is load-bearing: `target <> origin`, not merely `target > + origin` — `Precedence.resolve` never deduplicates by slug, so a + candidate returning its own argument unchanged would be handed to the + RG 91/Tabula contest twice in the same round, a genuine self-collision + (disposed of as both `winner` and `loser` against itself), not a + docstring worry. The relaxed obligation is `Rite.t.transfer_target`'s + new text (rite.mli); it does NOT license an unbounded backward + SEARCH as safe merely because a bounded one is proven so — the + termination obligation still falls entirely on the rite, exactly as it + always did for a forward search, and the only shape actually verified + is a CONSTANT one-shot displacement for a specifically-named collision + (`Precedence_of.transfer_target`'s own Rule 0, `Date.add_days origin + (-1)`, no internal search at all). `calendar.ml` itself needed NO + logic change — only two comments correcting a blanket "every genuine + transfer moves forward" claim that the trace showed no longer holds + literally. + + **Blast radius, measured**: EF untouched — `git diff --stat + v1.0.0..HEAD -- data/ef/` and `lib/rites/rite_ef/` both empty (the + field's TYPE is unchanged, only its doc comment; no new required + field), and `colitur day`/`colitur readings` for 2026, 1583 and 9999 + are byte-`cmp`-identical between this change and a `git worktree` + build of the commit immediately before it. OF's own 2005–2050 + differential-testing window (CLAUDE.md's own oracle range) carries + zero of the 16 affected years, and a full sweep of it shows zero + unexpected diffs either. Each affected year's own diff is exactly two + lines (18 March gains Joseph; whichever memorial or feria previously + occupied the old, wrong Easter+9 target resurfaces there instead) — + confirmed on 2062 by direct `cmp` against the pre-fix binary. The + whole domain's transfer placement still reaches a fixed point: + `Validate.run`'s "unconverged" check stayed clean across the full + 1583–9999 exhaustive sweep (`COLITUR_EXHAUSTIVE_SWEEP=1 dune test + --force`, part of `make check`). + ## How to work here - **Superpowers workflow**: `brainstorming` → `writing-plans` → `executing-plans` |
