summaryrefslogtreecommitdiff
path: root/lib/rites/rite_ef/precedence_ef.ml
Commit message (Collapse)AuthorAgeFilesLines
* fix(ef): the seasonal commemoration comes first (RG 113 sentence one)Lukasz Kasprzak2026-08-181-1/+40
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | "113. Commemoratio de Tempore fit primo loco. In admittendis et ordinandis aliis commemorationibus, servetur ordo tabellae praecedentiae." Only the second sentence was implemented, adopted on ef-rg16a as the admission and ordering criterion. The first -- the commemoration OF THE SEASON is made in the first place -- was not, so ordering ran through band alone for every commemoration including the seasonal one. Reconciled with RG 110(c), which adds the inseparable Peter/Paul pair "ante omnes alias commemorationes". Both rubrics are primary-source certain: the photographic scans' OCR is illegible at RG 110(c), but docs/research/LT.txt, the electronic transcription, carries the Rubricae Generales complete, and O'Connell's footnote 39 turns out to render that clause exactly rather than gloss it. They share a technical term. RG 113's own sentence fixes the sense of "aliae commemorationes" as the ones other than the de Tempore one it has just placed primo loco, and RG 110(c) sits three paragraphs earlier in the same code. Read consistently, the pair heads the OTHERS, not the whole list: season, then the pair, then the table order. So this runs after rg110_additions, and List.partition's stability keeps the pair adjacent while the seasonal commemoration steps in front of it. Blast radius, two full 1583-9999 sweeps diffed: 3 533 days, every one ORDER-ONLY -- the commemoration set is identical on both sides of every changed day, checked as sorted multisets, zero days where anything else moved. All are 22 February with chair-of-st-peter observed. Exactly the population measured before the rule was written. The order-sensitive test row is in test_precedence_ef.ml's admit_cases, which is still the only place in the suite that asserts commemoration order at all. It needed a mixed-origin candidate: every other candidate in that table is origin = Temporal by default, so the rule is an identity on them.
* fix(ef): days within the Octave of the Nativity, and RG 69 for 29-31 DecLukasz Kasprzak2026-08-181-3/+33
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | M11 was the one entry in the missalemeum allow-list adjudicated against colitur, and it was right to be. The calendarium directs "Com. octavae Nativitatis" under each of 26, 27 and 28 December (LT.txt:5454-5459) and RG 109(c) makes a commemoration of the days within the Octave privileged. colitur emitted none. The cause was a reasoning error stated in Temporal_ef's own comment: "26-28 Dec are Stephen, John and the Innocents, hence sanctoral". Their office is sanctoral -- those II-class feasts win the day -- but they remain days WITHIN the Octave (RG 67, "Dies infra octavam sunt II classis"), and colitur built them as generic Class4 ferias. With no octave-day candidate there was nothing for the feast to be commemorated over. Building days 2-4 exactly as days 5-7 always were makes the commemoration fall out of the existing machinery rather than needing a special case: the feast wins on rank, the octave day loses, RG 109(c) privileges it, RG 111(c)'s single slot goes to it. A second, independent defect surfaced while fixing it. The octave-day branch covered 29-31 December unconditionally, so a Sunday falling there got a feria identity -- where RG 69 says a Sunday occurring 26-31 December SEMPER keeps its own office and commemorates the feast. Confirmed against the oracle rather than argued: missalemeum shows "Sunday in the Octave of Christmas" on 2035-12-30, a Sunday, where colitur showed a feria. Both named and anchors now exclude Sundays; anchors had asserted the octave slugs unconditionally and was wrong the same way. Blast radius, full sweep against the pre-change binary: 25251 days, every one 26-31 December, exactly two shapes, zero unclassified -- 21653 carrying an octave-day slug and 3598 that are all Sundays, the RG 69 correction. Allow-lists: M11 closed and removed. C6 narrowed 138 to 119, nineteen of its days having changed temporal identity rather than verdict. M15 widened 18 to 22 -- both streams now commemorate the octave, but the candidate is temporal-origin and carries no English name to match against missalemeum's own, this entry's documented limit on four more dates. Stated rather than glossed: this trades a substantive divergence, colitur omitting a commemoration the Missal directs, for a comparator limit, the commemoration existing but not being name-matchable. That is a real improvement, but what the oracle now proves is that both streams commemorate something on those days; the identity rests on the rubric and the calendarium. Register: section 6.17.
* docs: a confidence raised while its revisit trigger was deletedLukasz Kasprzak2026-08-131-1/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Five follow-ups from the fix-round re-review, none touching a computed result. M20's note had said "moderate-high, not certain" with a specific revisit trigger attached. The fix round raised the label to "near-certain" and deleted the trigger in the same edit. Upgrading a confidence while removing the condition that would lower it again is the one move this record must not make, so the trigger is restored alongside the higher label: no primary text anywhere names the Major Litanies in a Mass-orations-count worked example, only the general II-class-Sunday rule twice over. RG 434(b) closes the Office-shaped doubt and nothing further. "WORD-IDENTICAL" overstated the relation between RG 111(b) and n. 434(b). Only the trailing "quae tamen omittitur si commemoratio privilegiata facienda sit" is verbatim in both; the openings differ, n. 434(b) recasting the rule into the orations register. The claim was self-refuting -- both texts are quoted adjacent to it -- and the argument never depended on it. Now "identical in its operative clause". And n. 434 is not "a different part of the same document": the running heads put RG 111 under Rubricae generales and n. 434 under Rubricae generales Missalis Romani, two distinct corpora bound in one volume, which is the entire force of the corroboration. The code comment had understated its own point. Also corrects the register's LT line range for n. 434(b) (3574-3576, not 3564-3570; the (b) clause is not in the cited range), and records in calendar.ml the diagnostic that channel (3) trades away: a rite whose transfer_target names a date its own disposition omits used to raise a loud, mislabelled Validate failure and is now silent at the origin. The kernel cannot distinguish that from a deliberate omission without rite knowledge it must not have, so accepting it is right -- but the signal is gone, and that should be written down rather than discovered later.
* docs(ef): fix round 1 corrections (F2-F5) -- inert fields, a date, an ↵Lukasz Kasprzak2026-08-131-1/+29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | attribution, RG434(b) F2: the task report's "colour/subject/names on the Litanies entry are currently inert" was false for names -- test_oracle.ml's identity axis reads Names.find on every commemoration, and the invented English name is exactly why 2026-04-25 registers as a Comm_identity_mismatch, the reason M5 had to be re-gated. Corrected precisely, field by field, in the report. F3: Easter 2027 is 28 March, not 18 April, as previously stated in the report's own "layer 4 is blind to the transfer" reasoning. The conclusion survives (28 March is not 25 April); the date is corrected. F4: "the exhaustive property sweep caught this immediately" was a wrong attribution, in the report, the register, and calendar.ml's own comment. The committed exhaustive sweep walks 1583-9998 in order and aborts at the first failure; the years actually reported (5700, 4747) were draws from prop_invariants, the default dune test run's 200-year random sample. Corrected in all three places. F5: the Litanies' privileged commemoration is due in the MASS specifically (RG 108 + RG 81), never a separate Office answer -- colitur emits one resolved day, and the M20 adjudication rests on that being the Mass reading. Stated explicitly now in M20's own note, the register, and precedence_ef.ml's own RG111(b) comment. Also added to M20 and the register: Rubricae Generales Missalis Romani n. 434(b) ("VIII - De diversis Missae partibus", "D) De orationibus", "I - De orationibus in genere"), verified word for word against all three documents -- word-identical to RG 111(b) but explicitly scoped to the Mass ("post orationem Missae"), answering the objection that RG 111 (Caput XVI, which RG 106 says governs both Office and Mass) might be read as Office-shaped. Moves the M20 adjudication from "moderate-high, not certain" to near-certain.
* feat(ef): the Major Litanies -- entity, RG80 transfer, RG109(f) privilegeLukasz Kasprzak2026-08-131-27/+171
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG 80 (Caput X, "De Litaniis maioribus et minoribus", A): the Major Litanies are assigned to 25 April, transferred to the following Tuesday (always Easter+2) when that date is Easter Sunday or Easter Monday. RG 81, same division: nothing is done in the Office, only in the Mass. RG 109(f) (Caput XVI): a privileged commemoration. Entity: Commemoration_only, Fixed(4,25), via data/ef/adjustments.sexp's `Add major-litanies` -- RG 81 denies it Office standing entirely, which is exactly what Commemoration_only already means to Precedence.resolve (held out of the observed contest by construction). Rank Class4 deliberately, not Class1, to keep the new RG109(f) privilege branch live rather than shadowed by privilege_of's existing "of a I-class day" branch. Colour Violet by consistency with the sibling Minor Litanies; subject Saint, the same "no special exclusion" default this codebase's other Commemoration_only entries use. Names not primary-sourced, flagged as such in the data file's own comment. Transfer: reuses the existing RG 96 placement machinery (Precedence.disposition's Transfer constructor + Calendar's place_transfers/resolve_with_injected) rather than a new candidate channel -- RG 80's own transfer is structurally the same operation RG 96 already performs for an impeded I-class feast. disposition gains a branch, checked before the Commemoration_only catch-all: the Litanies losing to winner slug "ef-easter-sunday" or "ef-easter-1-monday" is Transfer, not Commemorate. transfer_target gains a branch, checked before the general RG 96 search is even computed, returning Easter+2 directly with no search at all -- necessary, not merely simpler, since Easter+2 is itself I-class and a search from there would walk past the exact day RG 80 names (a commemoration needs no unoccupied day the way a displaced feast does). Privilege: privilege_of's previously-dead RG 109(f) branch now recognises the Litanies' own slug. No other code change -- admit's existing Class1/Class2-Sunday branches already implement "a privileged commemoration categorically takes the slot" correctly, from an earlier task. Full blast-radius measurement, adjudication of the resulting missalemeum divergence, and the mutation proofs are in the task's own report, .superpowers/sdd/2026-08-12-colitur-rg16a/major-litanies-report.md.
* docs: an invented Caput, a list that was not closed, and a blind spotLukasz Kasprzak2026-08-131-4/+37
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Three corrections from the fix-round re-review, none changing behaviour. RG 431(e) was attributed to "Caput XX, De hymno Gloria in excelsis". There is no Caput XX -- the Rubricae Generales' Caput series ends at XIX. The paragraph number, letter and subsection title were all right; only the containing division was invented. It sits under "VIII -- De diversis Missae partibus", subsection "C) De hymno Gloria in excelsis". Shipping a new invented structural citation in the very round that corrected a source-fidelity overclaim is what the gate exists to catch. marian_slugs claimed TWO entries found and deliberately excluded after individual consideration, "not merely omitted". There was a third: vigil-of-the-assumption, 14 August, which is de B. Maria Virg. and whose collect implores her protection. It was merely omitted. Added to the list -- behaviourally inert, verified: it wins 7196 times domain-wide, always with the non-Marian eusebius-confessor as its only commemoration, and never loses -- but a closed list's whole value is its enumeration claim, and that claim was false as written. And the new rule has no comparison-layer witness at all. Reverting it reddens three tests, none of them a comparison layer: the differential's row type carries no commemorations, and the oracle's window has no 16-July Saturday. Worse, lectio's fixture DOES carry commemorations and prints +our-lady-of-mt-carmel on all 8 in-window dates where colitur now prints nothing -- a real divergence, neither fixed nor cited, swallowed by a blind spot, which binding decision 1 forbids. Recorded, with the note that colitur's reading here has no reference confirmation anywhere and only extending the oracle fixture to 2033 or later would settle it. Also records the RG 112(d) branch's ordering constraint: it precedes RG 95's Transfer branch, which it does not need to, and must move below it if a Class1 Marian entry is ever added.
* fix(ef): RG 112(d) excludes a same-BVM commemoration (fix round 1, F1)Lukasz Kasprzak2026-08-131-9/+167
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The BVM Saturday Office is itself "de B. Maria Virg."; RG 112(d) (Caput XVI, "De Commemorationibus") excludes another commemoration whose own oration invokes the SAME BVM's intercession. our-lady-of-mt-carmel (16 July, Commemoration_only) was wrongly admitted as an ordinary commemoration alongside the Office on every 16-July-Saturday -- its own collect explicitly invokes "her" (eius) patronage, and both photographic scans print a rubric anticipating exactly this collision (an either/or of Mass texts, not a joint commemoration). Precedence_ef gains marian_slugs (a closed, hand-verified list of sanctoral slugs that are themselves feasts of the BVM) and is_bvm_office (true for subject = Bvm OR a marian_slugs member -- the disjunction is load-bearing: the Office is identified only by subject, since its own slug is deliberately reused from the ordinary ferial fallback; Mt Carmel is identified only by the list, since its own subject tag is Saint, not Bvm). disposition gains a new branch, checked before the pre-existing Commemoration_only catch-all, since the one live witness is Commemoration_only and that branch's own "always Commemorate" had no exception for this shape. Checked exhaustively against every Marian-named sanctoral entry: only Commemoration_only-status entries can ever reach this branch live (a Feast-status one always wins outright instead of losing). Of the two such entries in the data, only Mt Carmel is reachable -- our-lady-of-ransom (24 September) is provably unreachable: 24 September falling on a Saturday forces 1 September to a Thursday, which by construction makes 24 September the September Ember Saturday, Class2, every time, not a sampled coincidence. Re-measured against the full pre-change binary: the original 75,853-day blast radius is unchanged in total, splitting into 74,633 colour-only + 1,220 colour+comms (16-July Saturdays). Mutation-tested: exactly 3 new tests redden, nothing else.
* test,docs: RG110(c)'s adjacency is unobservable by constructionLukasz Kasprzak2026-08-131-4/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The re-review asked for a third commemoration in the shape-(c) row, so that "spliced immediately after its trigger" could be told apart from "appended at the end" -- it had proved an append-at-end variant passed the whole suite green, the pair alone being too short to distinguish them. Attempting it establishes something better than the test requested. On this day-shape a third commemoration is rubrically impossible. Shape (c) requires the trigger to lose the day while still being admitted, and a Class2 trigger can only lose to a I-class day (RG 111(a): one privileged commemoration) or a II-class Sunday (RG 111(b): one, "scilicet de festo II classis"). Both caps are one. The third candidate is now offered and correctly refused, which is the assertion worth having. So RG 110(c)'s "ante omnes alias commemorationes" half has no reachable witness in the EF's rubrical space, and the re-review's own finding that shape (c) never co-occurs with a third commemoration across 8417 years is a consequence of the rubric rather than an accident of the data. The append-at-end variant stays indistinguishable from the splice on every input the engine can construct. Recorded rather than papered over with a synthetic row proving a shape no rubric permits. Also drops Record from the "nothing compares commemoration order" note -- Record.t has no commemorations field at all -- and names, at privilege_of's own (a) branch, that the Holy Name's Sunday privilege currently rests on a substring match rather than on RG 17's closing paragraph, which is its real warrant.
* fix round 1: RG 110(c)'s ordering was inverted; M19 lacked an identity gateLukasz Kasprzak2026-08-131-38/+82
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG 110(c), word for word: "quoties vero oratio unius Apostoli addenda est ad modum commemorationis, huic orationi additur altera immediate, ante omnes alias commemorationes." "Huic orationi" (dative, "to this oration") refers to the trigger's own oration; "additur altera" means the companion is added to it, i.e. follows it. "Ante omnes alias commemorationes" governs the pair's position relative to other, unrelated commemorations, not the pair's own internal order. The previous build prepended the companion uniformly in both RG 110 shapes, citing this same clause for both -- correct for (a)/(b) (the day's own oration, not a list member, has nothing to order against), backwards for (c), where the trigger is itself a list member and the companion belongs after it. Fixed in rg110_additions: shape (a)/(b) still prepends; shape (c) now splices the companion in immediately after its own trigger. Re-pinned the unit test that had asserted the wrong order, and corrected both rows' comments to cite the clause that actually governs each shape. No layer in this codebase compares commemoration order: the lectio differential never compares commemorations, the oracle sorts both sides into a multiset, and the golden tests' own describe function sorts its commemorations field too. Recorded as a new, permanent blind spot in CLAUDE.md and the register, not merely fixed around -- the admit_cases unit table is the only place order is asserted at all. Re-measured the full blast radius against the same pre-change binary: same 14,627 differing days, same four shapes and counts, confirming the fix changed only the content of the 593 shape-(c) rows and nothing else. Mutation-tested: reverting the splice back to a uniform prepend reddens exactly the shape-(c) unit test; a new golden pin for a real shape-(c) day (2004-02-22) stays green under the same mutation, living proof that golden pins cannot see this axis, not merely a claim. Separately, M19's own predicate checked a date and a diff shape but not which candidate -- proved insufficient by fabricating a second, bogus companion on 30 June and confirming the whole suite stayed green. Fixed by requiring the admitted commemoration to be exactly commemoration-of-st-peter, mirroring C16's own identity guard. Added a golden pin for 30 June, the only assertion of that entry's identity outside the allow-list. Also: corrected a false claim in the task report that the electronic transcription carries no corroboration of the Holy Name fallback -- its own table of contents does, at a line not checked on the first pass. Added two further citations, both re-verified against the scan: RG 17's own closing paragraph, settling the Sunday shape's Sunday- exclusion at the rubric level rather than only in the propers; RG 124(c), which assigns red to 30 June by paragraph number rather than by the generic apostle/martyr default. Noted the fragility of deriving the Sunday shape's RG 109(a) privilege from a slug-substring match rather than from a citation. Cosmetic: a stray blank line and an indentation inconsistency.
* precedence(ef): RG 110, the inseparable Peter/Paul commemorationLukasz Kasprzak2026-08-131-6/+155
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG 110 (Caput XIV): "In Officio et Missa S. Petri semper fit commemoratio S. Pauli, et vicissim... pro unica habeantur" -- in the Office and Mass of either Peter or Paul, a commemoration of the other is always made, uncapped by RG 111's own admission count. Both photographic scans, full text including sub-clause (c) (a separate trigger this register previously had not transcribed: the same rule also fires when one Apostle's oration is admitted merely as an ordinary/privileged commemoration, not only when it is the day's own office). Three real pairs in the 1962 calendar, all confirmed on both scans: 25 January (conversion-of-st-paul + peter), 22 February (chair-of-st-peter + paul), 30 June (in-commemoratione-sancti-pauli-apostoli + a new commemoration-of-st-peter). The first two already existed as ordinary sanctoral candidates but were wired into RG 111's ordinary, capped admission contest instead of this rule's own uncapped one -- the defect this closes. 30 June had no companion at all: a genuine gap in lectio's own source data (confirmed directly against tridentine-calendar.ini) and in missalemeum's own oracle output for both fixture years, not only a colitur bootstrap miss, so colitur is now uniquely correct on this date among the three engines compared. Added via data/ef/adjustments.sexp's own Add directive, the architecture's existing extension point for exactly this shape of gap, since data/ef/sanctoral.sexp is generated and lectio must not be touched. Precedence_ef.admit gained rg110_additions/rg110_companion_slug, layered on after admit's own four ordinarily-capped branches decide their normal result: checks both the observed candidate and every already-admitted candidate against the three-pair lookup and prepends any companion found, uncapped and additional, never competing for RG 111's own slot. Measured full blast radius (1583-9999, pre-change binary from git archive at 59fbda8 vs the fixed binary, 3,074,246 days each side, 14,627 differing days, all four predicted shapes, zero unclassified): 3,619 Holy Name fallback days (previous commit), 3,533 days Paul was wrongly excluded from Chair of St Peter's own day by a competing privileged feria, 593 days Chair of St Peter itself was admitted only as an ordinary commemoration with Paul entirely absent, and 6,882 days the new 30 June companion is added. The 3,533+593 figure supersedes an earlier, narrower 852-day estimate that measured only the delta between two older code commits, not the rule's full scope. The lectio differential needed no change: it does not compare commemorations at all, and this fix never touches season, slug, rank, or colour. The missalemeum oracle allow-list needed three changes: M12 removed (22 February 2027 no longer diverges in commemoration count), M15's date list gained 2027-02-22 (now reaching identity comparison for the first time, where it lands on that entry's own pre-existing, unrelated limit -- one of the two commemorations is temporal-origin and unnamed), and a new M19 for the 30 June gap. Mutation-tested, both halves separately: disabling the admit-level addition reddens the two new unit tests, the oracle's own M12-shaped checks, and an existing golden pin (updated to expect the Paul companion); removing only the 30 June data entry reddens solely the oracle's new M19 count, confirming the code and data halves are independently load-bearing.
* docs: two retracted claims that outlived their retractionLukasz Kasprzak2026-08-131-5/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | Both are the defect class this fix round existed to close, which is why they are worth recording rather than quietly overwriting. CLAUDE.md still carried F1's retracted design rationale -- describing entry_14_movable_band as "negative so it can never collide with a real table position" -- and F2's retracted transcription-defect attribution, verbatim, in the one tracked file the project's own workflow tells a fresh session to read first. The fix round struck both everywhere else and missed this file. A session following it as instructed could have re-derived the negative sentinel for entry 20's or entry 23's movable half and re-introduced the inversion in a new branch. precedence_ef.ml's replacement justification for the x10 rescale then introduced a fresh misstatement of the same primary text it was correcting: it attributed "primum mobilia, deinde fixa" to "entry 12's own ninth sub-item" and counted three such rows. Both photographic scans, and the register's own section 4 table, put that clause at entry 13; entry 12 has eight sub-items and no such clause. The split occurs at five rows -- 13, 14, 20, 23's third sub-item, and 24. Entry 24 is the most-evaluated band in the whole domain and is unsplit in the code, which is precisely the sub-rank the new headroom exists to hold. Corrected in the .mli and the register too. No behaviour change; 290 tests green.
* precedence(ef): fix round 1 (F2, F7) -- correct a false transcription claim, ↵Lukasz Kasprzak2026-08-131-28/+58
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | cite RG95's real primary authority F2: the disposition comment for RG112(a) claimed the electronic transcription "carries NEITHER this paragraph's own worked example NOR its own more specific Mass-proper rubric... exactly the transcription's documented defect" -- wrong on both counts, checked directly rather than taken on trust. RG 112 has no worked example in any of the three source documents (the transcription included) -- there was nothing to drop. The Holy Family Mass propers' own 13-January rubric is absent from the transcription not because it silently drops content it otherwise has (the project's own documented defect, dropped calendarium commemoration lines) but because that specific document (a 2006 web capture) contains almost no Mass-propers text of any day: 5 Introit-line occurrences across 26,322 lines, against 61 and 402 in the two photographic scans; its own "Proprium de Tempore" page is a table of contents linking to PDFs the capture never pulled in. A coverage gap in a partial web capture, not an instance of the narrower, different defect the methodology note actually describes. The ruling is unaffected -- the propers' quotation is real, on two independent photographic scans, and settles 13 January on its own -- only the attribution is struck, here and in test_precedence_ef.ml (the register and the task report are corrected separately). F7: RG 95's own second paragraph -- present in all three documents, including the transcription -- is a more direct, occurrence-level authority for the exact collision than RG 112(a): "if two feasts of the same Divine Person... occur together, the one higher in the table is kept, the other omitted." Added as the primary citation on disposition's RG112(a) branch, with RG 112(a) and the propers' note kept as corroboration. Also corrects RG 112(b)'s own framing: it is bidirectional ("et vicissim"), and only the Lord-feast-wins direction (RG 16(a)) is implemented -- the Sunday-wins direction has no witness anywhere in this codebase's data and was wrongly described as already covered.
* precedence(ef): fix round 1 (F1) -- band's -14 sentinel inverted the tableLukasz Kasprzak2026-08-131-52/+97
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | entry_14_movable_band = -14 was justified only by "cannot collide with a real table position (1..28) or unclassified" -- a collision argument, not an ordering one. band's own value is compared by plain <, so a negative number beats every I-class entry (1-13), not merely the fixed Baptism it was built to beat. Not live against the shipped universal sanctoral data (no I-class universal feast falls 7-13 January, which is why the original 1583-9999 sweep showed only the intended shape), but entries 12/13 admit PROPER and INDULT I-class feasts too, and those arrive via adjustments.sexp-style overlays -- this architecture's own advertised extension path. A diocesan patronal feast landing in Holy Family's window would have made the inversion live immediately: the I-class feast displaced and transferred to the next day, reproduced and confirmed before this fix, reverted after. Fixed by rescaling every band branch to the real RG 91 entry number times ten (unclassified untouched at max_int) instead of the bare 1..28, reserving genuine headroom immediately before each entry for a movable sub-rank -- not an arbitrary rescale: RG 91's own text records a "primum mobilia, deinde fixa" split at three rows, not only entry 14 (entry 12's own ninth sub-item, entry 14, and entry 20), so this leaves room for the other two without a second rescale if either ever gets a live witness. entry_14_movable_band now derives from entry_14_fixed_band - 1, tied together so they cannot drift apart. Added a synthetic I-class end-to-end test reproducing the exact counter-example that found this: a universal I-class candidate inside Holy Family's own 7-13 January window is now observed and does not transfer, with Holy Family itself falling to RG109(a)'s ordinary privileged-Sunday-commemoration path, the same treatment any genuine feast outranking an ordinary Sunday gets.
* precedence(ef): RG91 e14 "primum mobilia" + RG112(a) inseparable exclusionLukasz Kasprzak2026-08-131-7/+101
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Two related fixes, both needed for Holy Family to actually observe correctly on the seven years it coincides with the fixed Commemoration of the Baptism of the Lord (13 January): 2008, 2013, 2019, 2030, 2036, 2041, 2047. band's entry 14 ("Festa Domini II classis") gated on sanctoral origin only, so a movable Class2 Lord feast had no row in the table at all. RG 91 entry 14's own text says otherwise: "primum mobilia, deinde fixa" -- movable first, then fixed. entry_14_movable_band gives Holy Family (the one movable candidate this codebase builds with subject Lord) a value strictly better than the fixed half's own literal 14, negative so it can never collide with a real table position -- without it, the two would tie at 14 and fall to Precedence.resolve's own alphabetical tie-break, which picks the WRONG side ("commemoration-of-the-baptism-of-the-lord" sorts before "ef-time-after-epiphany-sunday-1"). disposition gets a new branch for RG 112(a) (Caput XVI, "De Commemorationibus"): the Office, Mass or commemoration of a mystery of one Divine Person excludes a commemoration of another mystery of the SAME Divine Person. Winner and loser both subject Lord -> Omit, not Commemorate -- without it, Holy Family observing correctly still left the Baptism admitted as an ordinary Class2 commemoration under RG111(b), which the primary text does not allow. Confirmed by a MORE SPECIFIC primary source than RG 112(a) alone: the Holy Family Mass propers' own note, found on both photographic scans, word for word, immediately after the Postcommunio -- "Si festum S. Familiae occurrerit die 13 ianuarii, Missa dicitur de festo S. Familiae, sine commemoratione Baptismatis D.N.I.C., et sine commemoratione dominicae." The electronic transcription carries neither this rubric nor RG 112(a)'s own worked example -- another instance of its documented defect, not merely absent from one check. Still expected red: the lectio differential (2005-2050) now shows a new, real divergence on those seven 13-January-Sunday dates -- lectio has no Holy Family at all, so it still shows the fixed Baptism observed there, unlike colitur now. The oracle's own M-series entries also still need widening for the observed-identity axis added two commits ago. Both are the next commits.
* docs: three comments that outlived the rules they describedLukasz Kasprzak2026-08-121-5/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | All three are the project's own "correct code, wrong explanation" shape, found by the final review of the RG 113 work. No behaviour change. test_rite_ef.ml's registered Alcotest label said "Thomas of Villanova observed, Maurice commemorated" while the test asserts the Ember Wednesday is observed, Thomas is the sole commemoration and Maurice is omitted -- the opposite of two of its three assertions. The body's own doc comment was right; only the name a test run prints was wrong. validate.ml's lead-in still said origin is reconstructed as Sanctoral uniformly because the EF admit "reads only rank and slug, never origin". That stopped being true in ea22ad2: admit now orders by band, and band reads origin via is_temporal, so a temporal-origin commemoration relabelled Sanctoral would be scored on the wrong table entry. The code below already recovers the origin exactly; only this comment lagged. precedence_ef.ml's band guard justified itself by citing celebration.mli as saying a demoted feast retains its rank for RG 111's admission-COUNT purposes. celebration.mli says the opposite -- it names the ORDERING use the guard removes. The guard is right for a reason it did not give: rank stays load-bearing through RG 111(b)'s "de festo II classis" floor, which is what excludes these entries from a II-class Sunday's slot. Both the citation and celebration.mli's own now-stale line are corrected, each recording what it previously claimed.
* fix(rite-ef): band has no table entry for a bare commemoration, everLukasz Kasprzak2026-08-121-12/+74
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fix round 1 on the commemoration-identity/tie-break work: the "genuine same-band tie" M17 adjudicated as open was not a tie at all. RG 91's table enumerates only "dies liturgici" (real feasts) -- entry 24's own text is "Festa III classis, in calendario Ecclesiae universae inscripta" -- so a Celebration.t.status = Commemoration_only candidate (a saint reduced to a bare commemoration) has no row in the table to begin with. Precedence_ef.band used to read rank alone, so it silently lent such a candidate the same table entry as a genuine Feast of its own rank; the calendarium's own 22 September row confirms the distinction in its own notation ("S. Thomae de Villanova ... III classis. / Commemoratio Ss. Mauritii et Soc. Mm." -- Thomas carries a class number, Maurice carries none). Fixed at the source, not by adding a status tier to compare_precedence: band now checks status first, ahead of every rank-keyed branch, and returns unclassified for any Commemoration_only candidate. M17 deleted (not re-adjudicated) -- 22 September now resolves identically on both sides, with no divergence left to name. Blast radius measured independently (a temporary git worktree at the pre-fix commit): 4451 days change across the whole 1583-9999 domain, exactly 4 verified shapes -- 3576 x maurice-and-companions-martyrs -> thomas-of-villanova and 282 x eleutherius -> philip-neri (admitted set changes), 502 x appollonia/cyril-of-alexandria and 91 x dorothy/titus (order only, independently confirmed against the calendarium's own listing convention). Zero days change who is observed. Further swept the whole domain for a genuine "two different candidates on the identical real table entry" residual -- the shape RG 113 truly gives no instruction for -- and found it empty: of 109201 same-rank ties domain-wide, 83950 now resolve by band alone and the remaining 25251 are exclusively two Commemoration_only candidates tied at unclassified, never two real feasts. The residual admit still breaks alphabetically is real, but narrower than previously documented. The "66 days" figure is reconciled, not merely disputed: 599 is the tie population, 65 (whole-comparator: 67) is the real admitted-set decision count within it (independently reproduced against the pre-Task-B binary), 149 is order-only. Every one of the 65 real decisions traces to the same Commemoration_only/Feast root cause as Maurice/Thomas. Also: validate.ml's admission fixed-point check recovers a commemoration's real origin (by matching its slug against the day's own temporal office) instead of reconstructing every candidate as Sanctoral, since band -- unlike EF's own admit -- does read origin; precedence_ef.ml/.mli's motivating example and blast-radius claims corrected to no longer rest on the fixed Maurice/Thomas case; test_identity_rank_corroboration's own population count corrected now that 22 September (and 21 other Feast-status matches) became reachable; its rank-agreement pin documents exactly what it does and does not prove. Register (§4, §6.1, §6 checklist) and CLAUDE.md corrected in place, including the RG 113 first-sentence gap this exercise surfaced but did not close, recorded as a new open item. 275 -> 276 tests (with the exhaustive sweep), all green.
* fix(kernel,rite-ef): admit orders commemorations by RG 113's table of ↵Lukasz Kasprzak2026-08-121-50/+64
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | precedence, not slug Precedence_ef.admit broke a same-rank tie among commemoration candidates alphabetically by slug -- a deterministic engineering convention with no rubrical citation. RG 113's own second sentence, primary-source-verified against two independent scans and previously uncited in the register (only "commemoratio de Tempore fit primo loco" was quoted before), gives the real rule: "in admittendis et ordinandis aliis commemorationibus, servetur ordo tabellae praecedentiae" -- admitting and ordering commemorations both run on the rite's own table of precedence (band's 28-entry table), not RG 8's coarse four-class rank. Precedence.resolve now computes each commemoration candidate's own band value once, generically, and hands it to rules.admit as a third tuple element (Precedence.rules.admit's signature changed accordingly, ditto Precedence_ef.admit; every rule-record stub in the test suite updated to match). Precedence_ef.admit's own compare_dignity is replaced by compare_precedence, ordering by band then slug; a residual tie within one identical band value still falls back to slug, since RG 113 gives no further instruction there -- documented as a still-uncited engineering convention, not dressed up as a rubric. RG 98 ("in paritate autem Officium prius impeditum praecedit") was considered as a candidate authority for that residual and rejected: it governs the transfer queue order among several simultaneously-impeded I-class feasts (Caput XIII), a different operation in a different chapter from RG 113's commemoration admission (Caput XVI); nothing in the primary text connects the two. Blast radius measured against the pre-change binary across the entire 1583-9999 domain (not only 2005-2050): the admitted-commemoration-slug set is byte-identical, day for day, before and after this change. The fix corrects the citation and mechanism, not the answer, on this codebase's current data -- both of the task brief's named examples (22 Feb Chair-of-Peter/Lent-vs-Paul, 22 Sept Maurice-vs-Thomas-of- Villanova) are confirmed present and unchanged in both streams. A new test (RG113: admit picks by precedence order, not slug, when they disagree) proves admit actually consults the passed-in precedence value with a synthetic pair whose slug order and precedence order disagree -- teeth a same-band-only regression test could not have caught, since every real collision found in the domain happens to agree on both axes. 271 -> 272 tests, all green; COLITUR_EXHAUSTIVE_SWEEP=1 unaffected.
* docs(rite-ef): correct a false band-value comparison in the RG16(a) commentLukasz Kasprzak2026-08-121-4/+25
| | | | | | | | | | | | | | | | | | | | Fix round 1 review, MINOR finding (item 4). Both precedence_ef.ml and test_precedence_ef.ml claimed the loser-side Class2 conjunct held because 'entry 6's own band value (6) is lower than every entry [3, 11-14]' -- false on its face (6 is not lower than 3) and, worse, the claim proves the opposite of what it was cited for: if a band-3 candidate really did contest a Class1 Sunday, the lower number would win, meaning the Sunday would lose, not beat it as claimed. The conclusion itself was never wrong, only the justification. Against entries 11-14 (sanctoral-origin Lord feasts) the numeric argument holds (6 < 11-14). Against entry 3 (Epiphany, Ascension, Trinity, Corpus Christi, Sacred Heart, Christ the King) it is not numeric at all but structural: every band-3 celebration is temporal-origin, and Precedence.resolve takes exactly one temporal candidate per day, so a band-3 Lord feast IS that date's own single temporal candidate, never a second one contesting a separately-produced Sunday -- there is no band comparison to make in the first place. Comment-only; no behaviour change.
* fix(rite-ef,kernel): follow the oracle on the Purification; admit reads the ↵Lukasz Kasprzak2026-08-121-7/+39
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | day's own Sunday-ness, not observed Fix round 1 review, two findings landed together because each golden pin's correctness depends on both. CRITICAL (item 1): reverts this branch's own first-pass retag of the Purification (2 February) from Lord back to Bvm -> Lord. The calendarium titles it 'B. Mariae Virg.', but missalemeum -- this project's designated EF oracle -- treats it as taking an occurring II-class Sunday's place outright, commemorations empty, exactly RG16(a)'s own festum Domini treatment (2020-02-02, 2014-02-02, independently fetched). Control, 2019-09-08 (the Nativity of the BVM, an ordinary Marian feast, on a Sunday): the Sunday observed, the feast merely commemorated -- the opposite pattern, proving the Purification's own oracle treatment is deliberate, not a gap. RG16(a) alone, on the untouched data, would have matched the oracle character for character; retagging Bvm is what moved colitur away from it on 1200 domain-wide days. The user has ruled: follow the oracle. Genuine primary-text counter-evidence (RG120(b), the colour rule grouping 2 February under 'B. Mariae Virg.', a category separate from 'Domini') is recorded in the register, not discarded -- a different project could reasonably rule the other way on the same evidence. most-holy-name-of-mary stays retagged Bvm; that one was never disputed. Removes the now-unneeded C12 lectio allow-list entry (data/ef/ expected-divergences.sexp, test_differential.ml): with the Purification Lord again, colitur matches lectio's own class = lord on every affected date, no divergence to allow-list. IMPORTANT (item 2): Precedence.rules.admit gains a ~temporal parameter -- a genuine kernel signature change, unlike RG16(a) itself. RG111(b)'s own Sunday rank floor ('one commemoration, namely of a II-class feast') used to be detected by reading observed's own slug for a Sunday marker, which silently assumed observed IS the day's temporal-cycle office. RG16(a) breaks that assumption on purpose: a Feast of the Lord standing in for an impeded Sunday 'cum omnibus iuribus et privilegiis' keeps the day a dominica II classis for RG111(b) too, even though the FEAST, not the Sunday, is observed. Before this fix an unrelated saint (Pope Sixtus II et al., 6 August, Class3) was wrongly admitted into the freed slot on every one of 1178 domain-wide days. Oracle-confirmed directly: 2023-08-06 (a Sunday) shows him displaced, commemorations empty; 2026-08-06 (an ordinary Thursday) shows him admitted -- being a Sunday is exactly what excludes him. admit now reads Sunday-ness off ~temporal (the day's own temporal-cycle candidate, passed through from Precedence.resolve unchanged) instead of observed. Validate's own admission fixed-point invariant updated to pass the same real temporal candidate through. Both golden pins in test_golden.ml were promoted from actual colitur day output without independently consulting the rubric or the oracle first -- a real defect the review caught. Re-derived from both before re-pinning: 2028-08-06 and 2025-02-02 now pin comms=[], no commemoration at all, matching missalemeum exactly in both cases.
* kernel(rite-ef): apply RG16(a) -- a Feast of the Lord leaves the impeded ↵Lukasz Kasprzak2026-08-121-7/+72
| | | | | | | | | | | | | | | | | | | | | | | | Sunday uncommemorated Caput III "De Dominicis", RG 16(a): a Feast of the Lord, I or II class, occurring on a II-class Sunday takes the Sunday's own place with all its rights and privileges -- of the Sunday, therefore, no commemoration is made. band's entry 14 already ranked such a feast above the Sunday correctly; disposition had no exception for the collision, so the impeded Sunday fell through to the ordinary RG 95/109(a) commemorate-or-omit catch-all and was wrongly admitted as a privileged commemoration. Adds a branch to Rite_ef.Precedence_ef.disposition, gated on all four of: loser is temporal-origin, loser rank Class2, loser carries the Sunday slug marker, winner rank Class1-or-2 with subject Lord. No signature change -- disposition already receives the winner (RG 33's own vigil-omission branch already reads it); each conjunct is proved independently load-bearing by a dedicated disposition_cases row, including one real-data case each for the winner's subject and rank conjuncts, and a defensive synthetic case for the winner rank conjunct's currently-unreachable Class3 shape. A new end-to-end resolve-level test (2028-08-06, the Transfiguration) proves the real band/disposition pipeline together, checking the Omit reason string distinguishes this from admit's own admission-limit cut.
* docs: close the final review's four documentation residuesLukasz Kasprzak2026-08-121-5/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | precedence_ef.mli said "there is no fifth, unclassified case" after the same commit renumbered the disposition list from four cases to five; the count is now six. precedence.mli's physical-equality obligation described the failure mode as counting a drop "a SECOND time (once because it is genuinely absent, once because its identity no longer matches)" -- the same condition stated twice. What actually happens to a rebuilt candidate record is that the celebration surfaces in BOTH commemorations (the copy) and omitted (the original), one admission double-reported. precedence_ef.ml carried the same muddled sentence, which is where the kernel's copy came from; both now say it plainly. vocab.ml/.mli referenced {!Rite_ef.rite_ef.ml} -- a filename inside an odoc reference, which is malformed. Now plain [Rite_ef.rite]. README documented only `dune test`, so the exhaustive 1583-9999 Validate sweep was discoverable only by reading test_validate.ml's own comment. With no CI in this repo, that line is what stands between a committed artifact and one anyone runs. No behaviour change: `colitur day` output is byte-identical across 1583, 1900, 1902, 2008, 2011, 2026, 2038 and 9999 (2921 days, both domain edges). 259 tests by default, 260 with the sweep.
* kernel+rite-ef: correct stale plan-relative deferrals (item 7, part 2)Lukasz Kasprzak2026-08-121-5/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Several comments described work as "arriving with Plan 3" or "waiting for Plan 3" that either shipped without it or refer to the wrong future plan number, all now false in ways that would mislead the next reader: - temporal_ef.ml (two places) and precedence_ef.ml said the Major Litanies (25 April, RG 80) "arrive with Plan 3's sanctoral". Plan 3 shipped, in this branch, without them; register §6 tracks this as a plain open item with no plan committed to build it, and now says so. - temporal_ef.ml said the Sacred Triduum's "own named offices are a Plan 3 sanctoral addition". Wrong on two counts: Plan 3 shipped without adding them, AND a proper office for I-class FERIAS was never a sanctoral matter in the first place (RG 21 defines "feria" to exclude Sundays/feasts, not the reverse). 2026-04-02/03/04 still resolve to the ordinary Passiontide ferial fallback's own generic slugs (ef-passiontide-2-{thursday,friday,saturday}), confirmed against real output; register §6 now records this as its own open item. - temporal_ef.ml said the Rogation-Wednesday commemoration (Ascension Vigil day, entry 21) "waits for RG 108-111" -- both the precedence framework and RG 108-111 exist now; the Wednesday's own commemoration is still never constructed, but for a different, still-real reason (no candidate is wired for it), not a forward dependency. Fixed at both of this comment's two occurrences in the file. - vocab.ml/vocab.mli's `seasons` field doc said "Validate's contiguity check reads this" -- false since validate.ml's "seasons" check switched to Rite.t.season_runs in this branch (rite-supplied, to support a season appearing in more than one run, which the modern form's Ordinary Time needs and EF does not). - vocab.ml/vocab.mli's `ranks` field doc said "it is not a precedence relation until Plan 3 defines one" -- Plan 3 did define one (RG 111's dignity ordering), but as its own small, separately-hardcoded function in precedence_ef.ml, not one derived from this field; corrected to say so precisely rather than leaving a forward-looking claim unresolved. - The lectionary bootstrap (reading citations, Liturgical_day.t's own `citations` field) is called "Plan 3" at slug.ml, vocab_ef.ml, and three places in temporal_ef.ml, but "Plan 4" at liturgical_day.mli (whose own doc comment -- "always empty until Plan 4" -- is the authoritative one: the SANCTORAL bootstrap is Plan 3 and shipped; the LECTIONARY bootstrap is a separate, later Plan 4). All six corrected to say Plan 4, cross-referencing the Plan 3/4 distinction at the first (slug.ml) occurrence so the reasoning is not duplicated six times. No behaviour change: every edit here is a comment/documentation correction. Verified byte-identical `colitur day` output across 1583, 1900, 1902, 2008, 2011, 2026, 2038, 9999. 259/259 tests green.
* docs(citations): migrate register line-number pointers to stable anchorsLukasz Kasprzak2026-08-121-19/+18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 68 "register line N" pointers in tracked code and data cited the register's line numbers directly. The register has moved since: line 334 (cited six times as RG 91 entry 8) is now rose/colour prose; lines 375-376 (cited as "RG 109 leaves Advent/Lent Ember ordinary") are now RG 26, the paragraph that refutes that exact reading; line 374 (cited as RG 109(a)) is now RG 25's Latin; line 378 (RG 111) is blank. expected-divergences.sexp even wrote "RG 91 line 332" three times, as though the line offset were part of the rubric's own identity. Since docs/research/rules-register.md is gitignored, no reader of the public repo could resolve any of these, and -- since the register has moved on its own copy too -- neither can the author's. Replaced every pointer with an anchor that survives editing: the RG paragraph/entry number itself (already present in nearly every case, since the citation text already names "RG 91 entry N" or "RG 109(a)" next to the stale line number -- the line number was redundant, not load-bearing) plus a "§4" or quoted-subsection-heading pointer into the register for readers who want to locate the fuller discussion. Also corrected one genuinely stale content error found while migrating its anchor: test_precedence_ef.ml's RG33 disposition-cases comment still said "a I/II-class vigil impeded by any Sunday" -- the pre-Task-16 mistranscription the register itself corrects to II/III class; fixed the prose alongside its citation, since leaving a wrong RG-class claim next to a freshly-verified anchor would be worse than the stale line number it replaced. Covers lib/rites/rite_ef/precedence_ef.ml (18), precedence_ef.mli (already fixed with item 1), test/test_precedence_ef.ml (44, including two instances that only word-wrapped "register\nline N" across a line break and so did not match a same-line grep), and data/ef/expected-divergences.sexp (5, including three "RG 91 line 332" instances). All 68 original pointers resolved -- none needed guessing; every citation's target rule was already named in the surrounding prose. No behaviour change: every edit is a comment/citation/data-note change. Verified byte-identical `colitur day` output across 1583, 1900, 1902, 2008, 2011, 2026, 2038, 9999. 259/259 tests green.
* kernel(rite-ef): replace unearned/retracted citations with verified onesLukasz Kasprzak2026-08-121-7/+18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Four citation problems, all resolved against the primary scans (docs/research/*.pdf via pdftotext): 1. temporal_ef.ml's Ember-day date-derivation comment still carried a retracted note claiming the scans have no numbered-paragraph statement of the rule. Register §3a corrected this in an earlier commit (the search used the genitive "Quatuor Temporum"; the rubric heading is the nominative "Quatuor Tempora") and the register's own words warn "a false 'not in the source' note is worse than no note" -- the code still carried the retracted note verbatim. Replaced with the verified citation and the primary Latin. 2. temporal_ef.ml cited RG 71 for "Advent I is the Sunday nearest 30 November". RG 71 is a season-boundary citation only ("a I Vesperis dominicae I Adventus..."); it does not say which Sunday opens the season. The actual rule is RG 20 (Caput III, "De Dominicis"): "Dominica I Adventus ea est, quae cadit die 30 novembris vel est ipsi proximior" -- verified against the scan and added to the register. Behaviour was always correct; only the citation was borrowed. 3. RG 88 ("de Litaniis minoribus nihil fit in Officio") is cited five times across code and tests, load-bearing twice (why Rogation days take their season's ordinary ferial class; why privilege_of lets them fall through to Ordinary), but appeared nowhere in the register. RG 67 and RG 69 were likewise cited at expected-divergences-missalemeum.sexp (M11) without register backing. All three verified against the scan and added to the register's §4 (Octaves / Rogations subsections). 4. Two citations flagged for re-verification, both CONFIRMED accurate against the primary scan (word for word): - precedence_ef.ml's RG 32 "si impeditur, commemoratur" (the sole textual basis for treating a vigil as always-commemorated once RG 33 doesn't omit it outright) -- the register previously stated RG 32 only as "same pattern as RG 31", not verbatim; the full sentence is now in the register too. - precedence_ef.ml's RG 111(b) full sentence (the sole textual basis for the shipped Sunday rank-floor fix) -- the register previously carried only the fragment "de festo II classis"; the full sentence is now there. - temporal_ef.ml's RG 91 entry 7 "feria IV cinerum et II, III et IV Hebdomadae sanctae" (the sole justification for stopping the I-class ferias at Wednesday) was also checked and matches the scan exactly; left as-is (already correctly cited), noted in the report. Bonus finding while re-verifying RG 20: RG 17(d), same chapter, states "festum D. N. Iesu Christi Regis, celebrandum dominica ultima mensis octobris" -- primary-source confirmation that Christ the King falls on the last Sunday of October. This was the register's one oracle-backed-but-not-primary-verified rule (CLAUDE.md's own carried-item language); it no longer is. Updated temporal_ef.ml's christ_the_king comment and closed the item in register §6. No behaviour change: every edit here is a comment/citation change to already-correct code. Verified byte-identical `colitur day` output across 1583, 1900, 1902, 2008, 2011, 2026, 2038, 9999. 259/259 tests green.
* kernel(precedence-ef): fix precedence_ef.mli's stale RG33/RG26/RG111(b) contractLukasz Kasprzak2026-08-121-4/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The .mli's disposition doc still said a Class1-or-Class2 vigil is Omit (RG 33) -- the pre-Task-16 mistranscription the register corrects at its RG 33 entry. The .ml has read Class2 || Class3 since commit 079e332; the .mli never caught up. It also named only vigil_suffix, when the vigil test the code actually runs also checks vigil_prefix (the shape the sanctoral bootstrap's four real vigils use); omitted RG 26's Class4 temporal-ferias-are-never-commemorated branch entirely, then asserted the listed cases 'exhaust every representable shape', which was false as written; and omitted RG 111(b)'s 'de festo II classis' rank floor from admit's doc, describing only the privilege-override half of that rule. Fixed all four: the vigil-omission bullet now names Class2/Class3 and both slug conventions; the missing RG 26 branch is now documented, folding the exhaustiveness claim into an accurate five-branch count; admit's Sunday case now states the rank floor as a second, independent condition. The same stale RG 109(e) reading this interface carried ('leaves the Advent and Lent Ember sets ordinary') also survived as the stated reason september_ember_prefix exists, in the .ml, about 330 lines from the already-corrected privilege_of comment it contradicts. Fixed there too: September is broken out because it sits outside RG 109(e)'s three named seasons entirely, not because Advent/Lent Ember needs excluding from (e) -- it does not, per privilege_of's own corrected comment. No behaviour change: both fixes are doc-comment-only edits to already- correct code (precedence_ef.ml's disposition/admit implementations were fixed in an earlier commit; only the .mli's prose and one earlier .ml comment lagged).
* kernel(precedence): fix round 1 -- RG23-26 govern ferial commemoration, not ↵Lukasz Kasprzak2026-08-121-75/+129
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG109 Review round 1 (F1, Critical): the commemoration-eligibility fix from the previous commit silently dropped II-class Advent and Lent Ember ferias when impeded, while ordinary (lower-solemnity) ferias of the same seasons kept their commemoration -- backwards on any reading. Reproduced: 1900-12-21 (an Advent Ember Friday) lost its commemoration entirely; 2026-12-21 (an ordinary Advent feria the same week) kept its. F2 (Important, the direct cause of F1): the branch's own justification mis-stated RG 109 as an exhaustive list of the only temporal circumstances that generate a commemoration. RG 109 is headed "Commemorationes privilegiatae sunt commemorationes" and closes "Omnes aliae commemorationes sunt commemorationes ordinariae" -- it sorts commemorations that already exist into two HONOUR classes (RG 108's differing liturgical hours), and says nothing about which offices have the right to be commemorated at all. That right belongs to Caput IV, "De feriis" (RG 21-27), never opened by the original pass: RG 24 (II-class ferias): "si vero impediuntur, commemorari debent" -- if impeded, MUST be commemorated. Not optional. RG 25 (III-class ferias): same mandate. RG 26: every feria not named in 23-25 is IV class, and IV-class ferias are NEVER commemorated -- the one exclusion RG 21-27 actually states. The omission branch is now gated on `rank = Class4` (RG 26) directly, not on `privilege_of = Ordinary` -- the old gate happened to reach the right answer for IV-class ferias (RG 26 also excludes them, for a reason the old citation did not give) and the wrong one for II/III- class Ember ferias RG 109(e) did not name by letter. RG 109(e) itself is also corrected: its bare "feriis Adventus, Quadragesimae et Passionis" previously excluded the Advent and Lent Ember sub-days by analogy with (d)'s separate September carve-out. RG 91's own TABLE needs an explicit "exceptis feriis Quatuor Temporum" at entries 22 and 25 to keep Ember days from being double- listed against their own entry 18 -- an exception that would be unnecessary drafting if "feriae Adventus"/"feriae Quadragesimae" did not already include their Ember sub-days by default. RG 109(e) carries no such exception, so it is read at that same default, inclusive scope: the Advent and Lent Ember ferias are privileged under (e), not merely ordinary-but-commemorable. (d)'s own existence is unaffected -- September Ember days sit outside Advent/Lent/Passiontide under any reading, so (d) remains necessary regardless. Verified: 1900-12-21 and 1902-02-22 now correctly commemorate their Ember ferias; 2026-12-21 and 1902-02-24 (ordinary ferias) unchanged. Blast radius re-measured against the prior commit, 1900-2100: 102 civil days changed, every one an Advent/Lent Ember (or Ember-vs- Joseph-collision) day regaining its commemoration, nothing else. Validate re-swept exhaustively, 1583-9998: 0 failures. F6: two privilege-boundary test rows that had been bent to expect the bug's own output (Commemorate -> Omit) are restored to what RG 24/25 actually require, now Commemorate(Privileged) given the RG 109(e) correction above -- these are the rows that should have caught F1. F7: admit_cases had no witness for RG 111(b)'s rank floor that wasn't already Class2, so reverting that filter only reddened the oracle suite, never this file. Added a row (II-class Sunday, sole candidate an ordinary Class3) that fails without the filter and passes with it. F9: RG 122 cited alongside RG 128(b) for Holy Thursday's white -- states the same fact affirmatively ("Demum adhibetur color albus, feria V Hebdomadae sanctae...") rather than as an exception to violet.
* kernel(precedence): three RG-verified EF precedence bugs, found via oracleLukasz Kasprzak2026-08-121-35/+180
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Task 16's missalemeum oracle comparison (2026-2027) surfaced three distinct precedence-engine bugs, each confirmed against the primary 1962 Missale Romanum text and cross-checked against the oracle: 1. RG 33 (vigil omission) was transcribed backwards. The primary text reads "Vigilia II AUT III classis penitus omittitur" (a II OR III class vigil is entirely omitted on any Sunday or I-class feast) -- not "I aut II" as the register and this module's own rank check (Class1 || Class2) previously had it. I-class vigils (Nativity, Pentecost) can never actually lose in this engine (band always ranks them above anything that could coincide with their dates), so the Class1 half was dead code; the real bug was that Class3 (St Lawrence's vigil, the sole III-class vigil) was MISSING, so it fell through to an ordinary commemoration instead of RG 33's mandatory omission whenever 9 August landed on a Sunday. 2. RG 93/95/109/113 read together: an ordinary, non-privileged TEMPORAL-cycle office (a bog-standard green-season feria, a plain Advent/Lent Ember day, a Minor Rogation day) has no standing to be commemorated at all when impeded -- RG 109's six-item list is a CLOSED set of the only temporal circumstances that generate a commemoration, not a floor under which anything ordinary still gets one. The engine previously commemorated the losing feria itself in this situation; confirmed wrong against ~190 independent missalemeum days (2026-2027) showing zero commemorations for the exact shape. Vigils are explicitly excluded from this new rule -- RG 31/32 give them their own "if impeded, commemorated" mandate, independent of RG 109's list. 3. RG 111(b)'s Sunday admission slot is restricted to "de festo II classis" -- a rank restriction, not merely the best available ordinary candidate. A III/IV-class ordinary saint competing for a II-class Sunday's single commemoration slot had no such restriction applied before; confirmed wrong via St Hyginus (11 Jan, Class3) losing to Holy Family, which missalemeum shows entirely displaced, never commemorated. All three fixes are pure disposition/admission changes -- they never touch band, so the observed day (season/slug/rank/colour) is unaffected in every case; the lectio differential (which never compares commemorations) stays green untouched. test_precedence_ef.ml updated throughout: two previously-wrong test expectations corrected (the RG33 III-class-vigil boundary row, the IV-class-feria totality row), three privilege boundary rows sharpened from "commemorated but unprivileged" to "omitted entirely" now that temporal+ordinary means omission, and a new contrast row added to keep the SANCTORAL side of rule 2 covered separately from the TEMPORAL side.
* rite(ef): the Annunciation's RG96 exception is conditional, not unconditionalLukasz Kasprzak2026-08-121-30/+58
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The register was transcribed faithfully but was itself wrong: RG 96's Attamen (a), primary-source-verified from the scans and now corrected in the register, reads 'festum Annuntiationis B. Mariae Virg., quando est transferendum post Pascha, transfertur ... in feriam II post dominicam in albis' -- the Monday-after-Low-Sunday seat applies ONLY 'quando est transferendum post Pascha', when the feast is to be transferred PAST EASTER. The unconditional transcription made the exception fire on every impeded Annunciation regardless of cause. transfer_target now computes the general RG 96 target first, for every candidate, and overrides to the Monday after Low Sunday only when that general target itself falls after Easter Sunday -- testing the rubric's own condition directly rather than re-deriving a date-proximity rule from first principles. Confirmed against three real years the review named: 2007, 2012 and 2057 all previously sent the Annunciation to Easter + 8 (16 April, 16 April, 30 April respectively) when the correct, now-produced target is the next free day before Easter (26 March in each case -- Passion Sunday in 2007/2012, Lent III Sunday in 2057). Verified with actual CLI output for all three, before and after. Also cites RG 96 Attamen (b), the same primary-source passage, as the direct authority for All Souls' own move to the following Monday when impeded by a Sunday -- previously inferred from RG 91 entry 8's parenthetical plus the general walk, which happened to produce the right date; now stated directly. Rewrote the two existing Annunciation unit tests, whose synthetic occupants no longer trigger the (now correctly conditional) exception, and added a 2057 regression test using the real Temporal_ef.temporal as occupant plus a real-data cram pin -- both mutation-verified against the unconditional reading.
* rite(ef): clamp the RG96 search at the domain ceilingLukasz Kasprzak2026-08-121-6/+29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | search_from could walk up to 400 days past origin before Calendar's own ~start ~stop clamp is ever consulted, and nothing stopped it probing occupant on a date past 31 December 9999 -- occupant chains through the real EF rite's temporal, which calls Computus.gregorian_easter, not total outside 1583..9999 (it Date.makes and failwiths on Error). Not reachable with the shipped sanctoral data alone, but reachable through the project's own primary extension path: an overlay adding an I-class feast on 25 December leaves nothing but Class2 Nativity-octave days for the rest of civil year 9999, so the unguarded search reached 1 January of year 10000 and crashed there with 'computus: year 10000 out of range 1583..9999'. 9999 is an in-range year and the kernel's contract is 'never raises on in-range input'. search_from now also stops, without probing occupant again, once it passes Date's own domain ceiling -- the same 'return a finite date, let Calendar's own out-of-range handling record it, never pretend to have found something admissible' contract the existing step-count guard already follows. Two new tests, both mutation-verified to actually reproduce the crash when the guard is removed (see the task report): a precedence_ef.ml unit test using the real Temporal_ef.temporal as occupant (a synthetic occupant can never discriminate this, since it never calls Computus itself), and a Calendar-level integration test reproducing the exact overlay-based scenario the review found.
* cli: colitur day <year> dumps resolved liturgical daysLukasz Kasprzak2026-08-121-5/+107
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Assembles Rite_ef.context (lib/rites/rite_ef/rite_ef.ml[i]): temporal, anchors and vocab from Temporal_ef; rules from Precedence_ef's band, disposition and admit; season_runs = Vocab_ef.seasons; transfer_target newly implemented here. transfer_target (RG 96): the next following day that is not I or II class, with the Annunciation's own exception (Monday after Low Sunday). Terminates by a structural step bound on its internal search, independent of Calendar's own round guard, which bounds rounds across a year, not one call's walk; documented as an obligation on rite.mli's transfer_target field, which did not previously state it. Fixes the vigil-naming mismatch Task 7's review predicted: the sanctoral bootstrap names its vigils with a vigil-of-X prefix (lectio's own convention), while Precedence_ef's is_vigil only recognised the temporal cycle's own X-vigil suffix. Both are now recognised, fixing RG 91 entries 21/26 and RG 33's vigil omission for the four affected celebrations. Verified by unit test and by mutation-testing the fix (reverting it fails exactly the new rows) and against real output across several years. Suppresses data/ef/sanctoral.sexp's vigil-of-christmas via a new overlay, data/ef/adjustments.sexp: it is the same celebration as the temporal cycle's own ef-nativity-vigil, both dated 24 December. colitur day <year>: one line per civil-year day, temporal and sanctoral fully resolved through Layer, Overlay, Precedence_ef and Calendar -- the first CLI path exercising the whole Plan 3 pipeline against real data. Verified the All Souls transfer chain (Tasks 7-8-11) end to end against real output for both a Sunday year (2025, lands on 3 Nov) and a non-Sunday year (2026, observed directly on 2 Nov).
* rite(ef): an impeded I-class Sunday commemorates, not transfersLukasz Kasprzak2026-08-111-11/+25
| | | | | | | | | | | | | | | | | | | | | | | | | disposition's Class1 branch was unconditional on rank, so an impeded I-class Sunday (Advent/Lent/Passiontide/Low Sunday) currently transferred like a feast. RG 95 (register lines 323, 363) restricts the right of translation to I-class FEASTS -- RG 91's own table lists Sundays as a separate row (entry 6, line 332) from feasts (entries 11-13, lines 337-339) -- and RG 109(a) (line 374) lists "of a Sunday" as a privileged commemoration category, which presupposes an impeded Sunday stays put rather than moving to another day. Excludes is_sunday_slug losers from the Transfer branch so they fall through to the existing Commemorate (privilege_of loser) branch, which already tags them Privileged via RG 109(a) with no further change. Fires on real dates in the 2005-2050 differential window: 24 December on Advent IV in 2023, 2028, 2034, 2045; 8 December on an Advent Sunday in 2024, 2030, 2041. Verified no previously-passing Transfer assertion used a Sunday-shaped loser (grepped test_precedence_ef.ml, test_calendar.ml -- which uses its own synthetic rite unrelated to Precedence_ef.disposition -- test_colitur.ml, test_validate.ml); confirmed by mutation-reverting the fix and observing exactly the one new test fail, nothing else.
* rite(ef): commemoration privilege and admission (RG 108-111)Lukasz Kasprzak2026-08-111-16/+208
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Precedence_ef.privilege_of classifies a commemoration candidate against RG 109's closed list of privileged commemorations (a Sunday; a I-class day; a day within the Octave of the Nativity; a September Ember day; a feria of Advent, Lent or Passiontide; the Major Rogations in Mass), read entirely off the candidate's own rank/slug/origin, no context needed. Major Rogations (f) is left unimplemented rather than guessed: no producer for the Major Litanies exists anywhere in this codebase yet. disposition's two Commemorate sites now call privilege_of instead of Task 8's interim_privilege placeholder, which is removed entirely (binding and .mli export both gone). Precedence_ef.admit applies RG 111's four admission counts, keyed on the observed day's own class and Sunday-ness: a I-class day admits none except one privileged commemoration; a II-class Sunday admits one, but a privileged commemoration due displaces any ordinary one regardless of dignity; any other II-class day admits one by dignity alone, with no such override; III/IV-class days admit at most two by dignity. Ties break on slug, matching Precedence.compare_by, so the admitted set never depends on input order. Every admitted candidate is a value taken unchanged from the input list, never rebuilt, so Precedence.resolve's physical-equality-based dropped/omitted accounting keeps working -- closing a note left open since Task 2. Tests: RG 109 category rows (one per reachable category, plus boundary rows proving Advent/Lent Ember days and Minor Rogations are correctly excluded), RG 111 admission rows checked on slug identity rather than count, an order-independence check, and three end-to-end integration tests proving the admission limit's drop lands in resolution.omitted rather than vanishing.
* rite(ef): fix false justification in impedes_vigil's commentLukasz Kasprzak2026-08-111-7/+11
| | | | | | | | | | | | | | | | Review finding: the comment claimed every RG 91 entry that can outrank a II-class vigil (entry 21) without being a Sunday is I class 'by the table's own structure (entries 1-13)'. False -- entries 14 and 16-20 (Feasts of the Lord II class, universal/proper/indult II-class feasts, days within the Nativity octave) are all Class2, all outrank entry 21, and none is a Sunday. The code was always correct: impedes_vigil implements RG 33's own two named conditions (any Sunday, or a I-class feast) directly, and does not depend on the band table's numeric ordering at all. Reworded to say so, citing the counter-example entries the review named instead of appealing to a table structure that does not guarantee what the old comment claimed. Comment-only change; no logic, signature, or test changes.
* rite(ef): occurrence dispositions (RG 92-95, 33, 94)Lukasz Kasprzak2026-08-111-0/+95
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Precedence_ef.disposition decides the loser's fate in an occurrence: a Commemoration_only celebration is always commemorated (it can never win or transfer); a I- or II-class vigil impeded by any Sunday or a I-class feast is entirely omitted (RG 33), checked before the generic rule below or the Nativity/Pentecost Vigil could wrongly transfer; any other I-class loser transfers (RG 95 -- only I class has the right of translation); everything else is commemorated, with the admit-or-omit decision left to RG 108-111's admission count (Task 9). RG 94 needs no code: resolve always compares a loser against the day's actual winner, never against a departed sibling, so no commemoration can ride along with a transferred feast in this design. This is the branch that completes Task 7's carried All Souls fix: once it loses to an occurring Sunday, its untouched Class1 rank routes it to Transfer via the generic rule, not a special case. Landing on 3 November is Rite.transfer_target's job, not wired up yet. Commemorate carries an interim Precedence.Ordinary privilege pending Task 9's RG 109 implementation, exposed as interim_privilege for that task to replace. Table-driven tests cover each rule, including RG 33's boundary from both sides and a Commemoration_only loser that is also Class1 and vigil-shaped to pin the branch ordering. Mutation-tested: disabling RG 33, either direction of RG 95's rank condition, or the Commemoration_only priority check each fail exactly the rows built to catch them.
* rite(ef): fix entry 8's Sunday exception and entry 14's over-restrictionLukasz Kasprzak2026-08-111-33/+76
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Review of 436ba75 found two calendar defects and one coupling risk. Entry 8 (All Souls) dropped register line 334's own qualifier, "(yields to an occurring Sunday)" -- it returned 8 unconditionally, so on 2 November falling on a Sunday (2025, 2031, 2036, 2042 in the 2005-2050 differential window), All Souls incorrectly outranked and observed over the Sunday. 2 November is always Time_after_pentecost and never coincides with any other entry's own date, so the only rival this exception ever has is an ordinary entry-15 II-class Sunday; on such a Sunday, band now returns one worse than entry 15's own value rather than the literal 8 -- strictly worse, not merely different, since an exact tie would fall to Precedence.resolve's slug tie-break, which for "ef-all-souls" against a Sunday slug would make All Souls win the tie anyway. Entry 8's own rank is untouched, so Task 8's disposition still sees a true I-class candidate to transfer. Entry 14 (Feasts of the Lord, II class) added a universal-layer restriction the register's line 341 does not carry -- contrast entry 16 at line 342, which explicitly says "not of the Lord"; RG 37c (register line 393) also speaks of "II-class feasts of the Lord" with no universal qualifier. Dropped the layer test: a proper or indult feast of the Lord now bands 14, not 19/20. Also exposes vigil_suffix and ember_prefixes from precedence_ef.mli, matching universal_layer/indult_prefix's existing "colitur convention, not an RG citation" treatment -- both were previously private literals duplicated in the test file, so a rename of temporal_ef.ml's slug format could have drifted silently past both sides agreeing with each other. Two test rows now build their candidate from Temporal_ef.temporal's own real output (entry 18's Lent Ember day, entry 21's Ascension Vigil) instead of a hand-typed slug, closing that specific coupling. Adds the three cheap rows review named as closing the remaining unpinned guards (a temporal-origin Class1 candidate on an unnamed date; a universal Class2 vigil of the Lord; a non-universal Class3 vigil), plus a resolve()-level test proving the Sunday is actually observed over All Souls, not just that band returns the right integer in isolation.
* rite(ef): RG 91 Table of PrecedenceLukasz Kasprzak2026-08-111-0/+173
Precedence_ef.band transcribes RG 91's 28-entry Table of Precedence (rules-register.md §4) for the EF rite: given a day's context and a candidate celebration, returns the table's own entry number, 1-28 (I class 1-13, II class 14-21, III class 22-26, IV class 27-28); lower wins. Every branch carries its entry number and register citation in a comment, checked in the table's own numeric order. Two entries are transcribed as the register states them even though they invert the pattern the rest of the table follows: at III class, 23 (particular calendars) outranks 24 (universal), the reverse of how 11/12 and 14/16/19/20 rank a universal feast ahead of a proper one at I and II class. Sanctoral-origin, layer-decided entries (11-13, 14/16/19/20, 23/24) follow the brief's structural insight: a celebration whose layer is not the universal base is an overlay -- proper, or indult if its layer id also carries the indult prefix. Neither the universal-layer id nor the indult prefix is an RG citation; both are colitur's own data-modelling convention, exposed from the module so whichever task loads the real EF sanctoral overlays can align to them. Vigils (21, 26) are read off the temporal cycle's own -vigil slug suffix rather than gated on origin, since a II/III-class vigil can be either temporal-origin (Ascension, already produced by temporal_ef) or sanctoral-origin (a saint's vigil, no task has loaded yet); Ember days (part of entry 18) are read off temporal_ef's own ember slug prefixes rather than re-derived, since the September anchor is independently flagged there as one of the more contested dates in the calendar. A candidate shape the table has no row for (e.g. a Class1 vigil that is not Nativity or Pentecost, or a Class4 candidate marked as a vigil -- RG 91 has no IV-class vigil either) returns a dedicated unclassified sentinel (max_int) rather than being folded into a same-rank entry it does not belong to. test_precedence_ef.ml is table-driven: one Alcotest.test_case per RG 91 entry (55 rows total, several entries covered by more than one named day so a single missed offset cannot hide behind a passing sibling), each date computed from Computus.gregorian_easter rather than hand-typed, so an arithmetic slip cannot pass by accident.