From 7ac8a25700c9d930eaaa4f9895665248dac32c52 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 12 Aug 2026 10:26:11 +0200 Subject: docs(citations): migrate register line-number pointers to stable anchors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- test/test_precedence_ef.ml | 97 +++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 48 deletions(-) (limited to 'test/test_precedence_ef.ml') diff --git a/test/test_precedence_ef.ml b/test/test_precedence_ef.ml index efbdb04..a0e1db1 100644 --- a/test/test_precedence_ef.ml +++ b/test/test_precedence_ef.ml @@ -49,45 +49,45 @@ let off n = D.add_days easter n (* (description, date, candidate, expected RG 91 entry). *) let cases = - [ (* Entry 1 -- register line 327: Nativity, Easter Sunday, Pentecost Sunday. *) + [ (* Entry 1 -- RG 91 entry 1 (§4): Nativity, Easter Sunday, Pentecost Sunday. *) ("1 Nativity", mk 2026 12 25, cand "ef-nativity", 1); ("1 Easter Sunday", off 0, cand "ef-easter-sunday", 1); ("1 Pentecost Sunday", off 49, cand "ef-pentecost", 1); - (* Entry 2 -- register line 328: Sacred Triduum. Thu-Sat of Holy Week, + (* Entry 2 -- RG 91 entry 2 (§4): Sacred Triduum. Thu-Sat of Holy Week, NOT entry 7 (which stops at Wednesday -- see entry 7 below). *) ("2 Holy Thursday", off (-3), cand "ef-holy-thursday", 2); ("2 Good Friday", off (-2), cand "ef-good-friday", 2); ("2 Holy Saturday", off (-1), cand "ef-holy-saturday", 2); - (* Entry 3 -- register line 329. *) + (* Entry 3 -- RG 91 entry 3 (§4). *) ("3 Epiphany", mk 2026 1 6, cand "ef-epiphany", 3); ("3 Ascension", off 39, cand "ef-ascension", 3); ("3 Trinity", off 56, cand "ef-trinity", 3); ("3 Corpus Christi", off 60, cand "ef-corpus-christi", 3); ("3 Sacred Heart", off 68, cand "ef-sacred-heart", 3); ("3 Christ the King", T.christ_the_king 2026, cand "ef-christ-the-king", 3); - (* Entry 4 -- register line 330. Sanctoral-origin: neither feast is part + (* Entry 4 -- RG 91 entry 4 (§4). Sanctoral-origin: neither feast is part of temporal_ef's movable cycle. *) ( "4 Immaculate Conception", mk 2026 12 8, cand ~origin:P.Sanctoral ~subject:Sub.Bvm ~layer:PE.universal_layer "ef-immaculate-conception", 4 ); ("4 Assumption", mk 2026 8 15, cand ~origin:P.Sanctoral ~subject:Sub.Bvm ~layer:PE.universal_layer "ef-assumption", 4); - (* Entry 5 -- register line 331. *) + (* Entry 5 -- RG 91 entry 5 (§4). *) ("5 Nativity Vigil", mk 2026 12 24, cand "ef-nativity-vigil", 5); ("5 Octave day (Circumcision)", mk 2026 1 1, cand "ef-circumcision", 5); - (* Entry 6 -- register line 332. *) + (* Entry 6 -- RG 91 entry 6 (§4). *) ("6 Advent Sunday", T.advent_start 2026, cand "ef-advent-sunday-1", 6); ("6 Lent Sunday", off (-42), cand "ef-lent-sunday-1", 6); ("6 Passion Sunday (I Passiontide)", off (-14), cand "ef-passion-sunday", 6); ("6 Palm Sunday (II Passiontide)", off (-7), cand "ef-palm-sunday", 6); ("6 Low Sunday", off 7, cand "ef-low-sunday", 6); - (* Entry 7 -- register line 333: Ash Wednesday and Mon/Tue/Wed of Holy + (* Entry 7 -- RG 91 entry 7 (§4): Ash Wednesday and Mon/Tue/Wed of Holy Week ONLY -- Thu-Sat are entry 2 above, not this entry. *) ("7 Ash Wednesday", off (-46), cand "ef-ash-wednesday", 7); ("7 Monday of Holy Week", off (-6), cand "ef-holy-monday", 7); ("7 Tuesday of Holy Week", off (-5), cand "ef-holy-tuesday", 7); ("7 Wednesday of Holy Week", off (-4), cand "ef-holy-wednesday", 7); - (* Entry 8 -- register line 334. 2 Nov 2026 is a Monday (verified + (* Entry 8 -- RG 91 entry 8 (§4). 2 Nov 2026 is a Monday (verified independently below the table), so this row is the plain case. The register's own qualifying case -- "yields to an occurring Sunday" -- gets its own row and its own end-to-end test after this table (2 Nov @@ -101,31 +101,31 @@ let cases = [test_all_souls_yields_to_sunday] below; this row pins the specific integer [band] returns. *) ("8 All Souls (yields to a Sunday, 2 Nov 2025)", mk 2025 11 2, cand ~origin:P.Sanctoral ~layer:PE.universal_layer "ef-all-souls", 16); - (* Entry 9 -- register line 335. *) + (* Entry 9 -- RG 91 entry 9 (§4). *) ("9 Pentecost Vigil", off 48, cand "ef-pentecost-vigil", 9); - (* Entry 10 -- register line 336: both range boundaries, to guard the + (* Entry 10 -- RG 91 entry 10 (§4): both range boundaries, to guard the off-by-one an inclusive Easter-offset window invites. *) ("10 Easter octave, day+1", off 1, cand "ef-easter-1-mon", 10); ("10 Easter octave, day+6", off 6, cand "ef-easter-1-sat", 10); ("10 Pentecost octave, day+50", off 50, cand "ef-pentecost-1-mon", 10); ("10 Pentecost octave, day+55", off 55, cand "ef-pentecost-1-sat", 10); - (* Entry 11 -- register line 337. *) + (* Entry 11 -- RG 91 entry 11 (§4). *) ( "11 Universal I-class feast", mk 2026 6 29, cand ~origin:P.Sanctoral ~subject:Sub.Saint ~layer:PE.universal_layer "ef-ss-peter-paul", 11 ); - (* Entry 12 -- register line 338. The one non-base-layer case the brief + (* Entry 12 -- RG 91 entry 12 (§4). The one non-base-layer case the brief asks for explicitly: same date/rank/subject as 11, only the layer differs, so this row isolates the layer test as the deciding factor. *) ( "12 Proper I-class feast (non-base layer)", mk 2026 6 29, cand ~origin:P.Sanctoral ~subject:Sub.Saint ~layer:"diocese-warsaw" "ef-local-patron", 12 ); - (* Entry 13 -- register line 339. *) + (* Entry 13 -- RG 91 entry 13 (§4). *) ( "13 Indult I-class feast", mk 2026 6 29, cand ~origin:P.Sanctoral ~subject:Sub.Saint ~layer:(PE.indult_prefix ^ "local-grant") "ef-indult-feast-1", 13 ); - (* Entry 14 -- register line 341, deliberately UNQUALIFIED (contrast - entry 16, line 342, which explicitly says "not of the Lord"). *) + (* Entry 14 -- RG 91 entry 14 (§4), deliberately UNQUALIFIED (contrast + entry 16, which explicitly says "not of the Lord"). *) ( "14 Feast of the Lord, II class", mk 2026 7 1, cand ~origin:P.Sanctoral ~rank:V.Class2 ~subject:Sub.Lord ~layer:PE.universal_layer "ef-precious-blood", @@ -138,21 +138,21 @@ let cases = cand ~origin:P.Sanctoral ~rank:V.Class2 ~subject:Sub.Lord ~layer:"diocese-warsaw" "ef-local-feast-of-the-lord", 14 ); - (* Entry 15 -- register line 342: an ordinary Sunday not named at entry 6 + (* Entry 15 -- RG 91 entry 15 (§4): an ordinary Sunday not named at entry 6 -- Septuagesima is II class (RG 11-12 names only Advent/Lent/ Passiontide/Easter/Low/Pentecost as I class). *) ("15 II-class Sunday (Septuagesima)", off (-63), cand ~rank:V.Class2 "ef-septuagesima-sunday", 15); - (* Entry 16 -- register line 342. *) + (* Entry 16 -- RG 91 entry 16 (§4). *) ( "16 Universal II-class feast, not of the Lord", mk 2026 1 20, cand ~origin:P.Sanctoral ~rank:V.Class2 ~subject:Sub.Saint ~layer:PE.universal_layer "ef-some-saint", 16 ); - (* Entry 17 -- register line 343: days WITHIN the Nativity octave (26-28 + (* Entry 17 -- RG 91 entry 17 (§4): days WITHIN the Nativity octave (26-28 Dec are Stephen/John/Innocents -- sanctoral, not this entry; 1 Jan is entry 5's Octave DAY, not this entry either). *) ("17 Nativity octave, 29 Dec", mk 2026 12 29, cand ~rank:V.Class2 "ef-nativity-octave-day-5", 17); ("17 Nativity octave, 31 Dec", mk 2026 12 31, cand ~rank:V.Class2 "ef-nativity-octave-day-7", 17); - (* Entry 18 -- register line 343-344: Advent 17-23 Dec ferias AND the + (* Entry 18 -- RG 91 entry 18 (§4): Advent 17-23 Dec ferias AND the Ember days of Advent/Lent/September share this one entry. The second row is deliberately a Lent date (season Lent, NOT Advent) to prove the Ember-slug path fires on its own, not merely because it also happens @@ -164,17 +164,17 @@ let cases = rather than a hand-typed "ef-lent-ember-wed" -- closes review finding 3's coupling concern for the Ember prefixes specifically. *) ("18 Lent Ember Wednesday (from Temporal_ef.temporal)", off (-39), of_temporal (off (-39)), 18); - (* Entry 19 -- register line 344. *) + (* Entry 19 -- RG 91 entry 19 (§4). *) ( "19 Proper II-class feast", mk 2026 1 20, cand ~origin:P.Sanctoral ~rank:V.Class2 ~subject:Sub.Saint ~layer:"diocese-warsaw" "ef-local-saint-2", 19 ); - (* Entry 20 -- register line 345. *) + (* Entry 20 -- RG 91 entry 20 (§4). *) ( "20 Indult II-class feast", mk 2026 1 20, cand ~origin:P.Sanctoral ~rank:V.Class2 ~subject:Sub.Saint ~layer:(PE.indult_prefix ^ "local-grant-2") "ef-indult-feast-2", 20 ); - (* Entry 21 -- register line 345 (RG 28-34). Two rows: the Ascension + (* Entry 21 -- RG 91 entry 21 (§4, RG 28-34). Two rows: the Ascension Vigil is the one II-class vigil temporal_ef already produces today (temporal-origin); the Assumption Vigil stands in for the sanctoral-origin case no task has loaded data for yet -- proving @@ -194,12 +194,12 @@ let cases = cand ~origin:P.Sanctoral ~rank:V.Class2 ~subject:Sub.Lord ~layer:PE.universal_layer "ef-precious-blood-vigil", 21 ); - (* Entry 22 -- register line 347-348 (corrected: ends at Palm Sunday, not + (* Entry 22 -- RG 91 entry 22 (§4) (corrected: ends at Palm Sunday, not Passion Sunday). Both a Lent and a Passiontide feria, clear of Ash Wednesday, Holy Week and the Ember days. *) ("22 Lent feria", off (-41), cand ~rank:V.Class3 "ef-lent-1-mon", 22); ("22 Passiontide feria", off (-12), cand ~rank:V.Class3 "ef-passiontide-1-tue", 22); - (* Entry 23 -- register line 349. NOTE the table's own order here is the + (* Entry 23 -- RG 91 entry 23 (§4). NOTE the table's own order here is the REVERSE of 11/12 and 14/16/19/20 above: entry 23 (particular calendars) is numbered BELOW entry 24 (universal), so a proper III-class feast outranks a universal one -- transcribed as the @@ -207,13 +207,13 @@ let cases = ( "23 Proper III-class feast (non-base layer)", mk 2026 6 30, cand ~origin:P.Sanctoral ~rank:V.Class3 ~layer:"diocese-warsaw" "ef-local-saint-3", 23 ); - (* Entry 24 -- register line 349. *) + (* Entry 24 -- RG 91 entry 24 (§4). *) ( "24 Universal III-class feast", mk 2026 6 30, cand ~origin:P.Sanctoral ~rank:V.Class3 ~layer:PE.universal_layer "ef-some-saint-3", 24 ); - (* Entry 25 -- register line 350. *) + (* Entry 25 -- RG 91 entry 25 (§4). *) ("25 Advent feria to 16 Dec", mk 2026 12 1, cand ~rank:V.Class3 "ef-advent-1-tue", 25); - (* Entry 26 -- register line 350. *) + (* Entry 26 -- RG 91 entry 26 (§4). *) ( "26 III-class vigil", mk 2026 8 9, cand ~origin:P.Sanctoral ~rank:V.Class3 ~layer:PE.universal_layer "ef-lawrence-vigil", 26 ); @@ -238,12 +238,12 @@ let cases = mk 2026 8 9, cand ~origin:P.Sanctoral ~rank:V.Class3 ~layer:PE.universal_layer "vigil-of-st-lawrence", 26 ); - (* Entry 27 -- register line 352: an otherwise-unoccupied IV-class + (* Entry 27 -- RG 91 entry 27 (§4): an otherwise-unoccupied IV-class Saturday. *) ( "27 Office of the BVM on Saturday", off 62, cand ~rank:V.Class4 "ef-time-after-pentecost-1-sat", 27 ); - (* Entry 28 -- register line 352: the unqualified IV-class catch-all. *) + (* Entry 28 -- RG 91 entry 28 (§4): the unqualified IV-class catch-all. *) ("28 IV-class feria", off 65, cand ~rank:V.Class4 "ef-time-after-pentecost-1-tue", 28); (* Not an RG 91 row at all: a I-class candidate marked as a vigil, which is not the Nativity or Pentecost (entries 5/9, the only I-class @@ -264,7 +264,7 @@ let cases = [not is_temporal] guard's role in the entry-25 mutation test recorded in the task report). *) ("unclassified: I-class temporal candidate on an unnamed date", mk 2026 7 15, cand "ef-unnamed-day", PE.unclassified); - (* RG 91's own vigil list (register lines 381-384) stops at III class -- + (* RG 91's own vigil list (§4, "Vigils / octaves / Rogations / Sunday classes") stops at III class -- there is no IV-class vigil for entry 28's ferial catch-all to absorb. *) ( "unclassified: IV-class candidate marked as a vigil", mk 2026 6 20, cand ~rank:V.Class4 "ef-second-mystery-vigil", PE.unclassified ) @@ -298,7 +298,7 @@ let test_all_souls_yields_to_sunday () = (S.to_string resolution.P.observed.P.cel.Cel.slug) (* Task 8: [disposition] -- what happens to the day's LOSING candidate (RG - 92-95, 33, 94; register lines 316-325, 381-384). Table-driven like [band]'s + 92-95, 33, 94; §4). Table-driven like [band]'s own [cases] above, one row per rule, each checked against a description of which register clause it pins. [disposition] takes no context (see precedence.mli's [rules.disposition]), so "is the winner a Sunday" is read @@ -320,7 +320,7 @@ let an_ordinary_sunday = cand ~rank:V.Class2 "ef-time-after-pentecost-sunday-11" let disposition_cases = - [ (* RG 95 -- register line 323-325: only I-class feasts transfer; a + [ (* RG 95 -- §4, "Occurrence": only I-class feasts transfer; a II-class feast loses to a I-class day and is COMMEMORATED, not transferred. Paired with the next row (a I-class loser, same shape of winner) so the discriminating factor is provably the LOSER's own @@ -334,14 +334,14 @@ let disposition_cases = cand "ef-nativity", cand ~origin:P.Sanctoral ~layer:PE.universal_layer "ef-local-i-class-feast", "Transfer" ); - (* Fix round 1 (post-Task-9 review): RG 95 (register lines 323, 363) + (* Fix round 1 (post-Task-9 review): RG 95 (§4, "Occurrence" and "Transfer/translation") restricts the right of translation to I-class FEASTS -- RG 91's own - table lists Sundays as a separate row (entry 6, register line 332) - from feasts (entries 11-13, lines 337-339) -- so an impeded I-class + table lists Sundays as a separate row (entry 6) + from feasts (entries 11-13) -- so an impeded I-class Sunday must NOT transfer, unlike the plain I-class feast row above: same [Class1] rank, same kind of winner, the ONLY difference is that - this loser's slug carries [PE.sunday_marker]. RG 109(a) (register - line 374) confirms this from the other direction: "of a Sunday" is a + this loser's slug carries [PE.sunday_marker]. RG 109(a) (§4) + confirms this from the other direction: "of a Sunday" is a privileged commemoration category, which presupposes an impeded Sunday stays put rather than moving to another day the way a feast does. Sourced from [Temporal_ef.temporal]'s own real output (Advent I @@ -356,8 +356,9 @@ let disposition_cases = cand ~origin:P.Sanctoral ~layer:PE.universal_layer "ef-immaculate-conception", of_temporal (T.advent_start 2026), "Commemorate(Privileged)" ); - (* RG 33 -- register line 383-384: a I/II-class vigil impeded by any - Sunday or a I-class feast is entirely OMITTED, not commemorated. The + (* RG 33 -- §4, "Vigils / octaves / Rogations / Sunday classes": a II- or + III-class vigil impeded by any Sunday or a I-class feast is entirely + OMITTED, not commemorated. The vigil is sourced from [Temporal_ef.temporal]'s own real output (as [of_temporal]'s existing callers above do), not a hand-typed "ef-ascension-vigil", so a drift in temporal_ef's vigil-slug @@ -456,7 +457,7 @@ let disposition_cases = RG 95's transfer, not after. Its expected privilege is [Privileged], not [Ordinary]: this loser's [rank] is [Class1] (the default [cand] leaves unless overridden, deliberately kept here for the - branch-order proof above), and RG 109(b) (register line 374-375, "of + branch-order proof above), and RG 109(b) (§4, "of a I-class day") makes any [Class1] commemoration privileged regardless of how it reached [Commemorate] -- Task 8's placeholder [interim_privilege] used to hide this (always [Ordinary]); Task 9's @@ -542,7 +543,7 @@ let disposition_cases = "Commemorate(Ordinary)" ) ] -(* Task 9: [privilege_of]'s RG 109 categories (register lines 374-377), +(* Task 9: [privilege_of]'s RG 109 categories (§4, "Commemorations"), exercised through [PE.disposition]'s [Commemorate] payload -- [privilege_of] itself is private, so this is the only vantage point a test outside precedence_ef.ml has on it. Each row below is built to match ONLY the one @@ -560,14 +561,14 @@ let disposition_cases = correctly NOT conflated with it, which is the strongest claim available without inventing an unfounded slug convention. *) let privilege_cases = - [ (* (a) register line 374: "of a Sunday". [an_ordinary_sunday] is Class2, + [ (* (a) RG 109(a) (§4): "of a Sunday". [an_ordinary_sunday] is Class2, not Class1, not within the Nativity octave, not an Ember day, not a feria of Advent/Lent/Passiontide -- matches (a) alone. *) ( "(a) an ordinary Sunday commemoration is privileged", cand "ef-nativity", an_ordinary_sunday, "Commemorate(Privileged)" ); - (* (c) register line 375: "of days within the Octave of the Nativity" -- + (* (c) RG 109(c) (§4): "of days within the Octave of the Nativity" -- sourced from [Temporal_ef.temporal]'s own output (29 Dec 2026, Class2, "ef-nativity-octave-day-5"), not a hand-typed slug, for the same coupling-safety reason the file's own [of_temporal] rows use it @@ -577,7 +578,7 @@ let privilege_cases = cand "ef-nativity", of_temporal (mk 2026 12 29), "Commemorate(Privileged)" ); - (* (d) register line 375-376: "of September Ember days" -- 23 Sep 2026 is + (* (d) RG 109(d) (§4): "of September Ember days" -- 23 Sep 2026 is the September Ember Wednesday (independently derived from [Temporal_ef]'s own third-Sunday-of-September rule: first Sunday of September 2026 is the 6th, +14 days = 20th, +3 = 23rd), sourced from @@ -593,7 +594,7 @@ let privilege_cases = cand "ef-nativity", of_temporal (mk 2026 9 23), "Commemorate(Privileged)" ); - (* (e) register line 376: "of ferias of Advent, Lent and Passiontide" -- + (* (e) RG 109(e) (§4): "of ferias of Advent, Lent and Passiontide" -- two rows, one per season named, both from [Temporal_ef.temporal]'s own generic ferial fallback, neither a Sunday, Ember day, or within the Nativity octave. *) @@ -666,7 +667,7 @@ let privilege_cases = "Omit" ) ] -(* Task 9: [PE.admit] -- RG 111's admission counts (register line 378), +(* Task 9: [PE.admit] -- RG 111's admission counts (§4, "Commemorations"), given commemorations ALREADY tagged with their real privilege (as [PE.disposition] now tags them -- see [privilege_cases] above). Every candidate/privilege pair here is built directly, not routed through @@ -719,7 +720,7 @@ let slugs_of admitted = List.map (fun (c, _) -> S.to_string c.P.cel.Cel.slug) admitted let admit_cases = - [ (* RG 111 (register line 378): "I class: none save one privileged." *) + [ (* RG 111 (§4): "I class: none save one privileged." *) ( "I-class day, only an ordinary commemoration due -> none admitted", observed_class1, [ (ordinary_hi, P.Ordinary) ], @@ -928,7 +929,7 @@ let test_ii_class_sunday_privileged_witness_admitted_end_to_end () = [ ("ef-some-saint", "omitted: admission limit reached") ] (List.map (fun (c, reason) -> (S.to_string c.P.cel.Cel.slug, reason)) resolution.P.omitted) -(* Completes Task 7's carried fix (register line 334): on a real Sunday +(* Completes Task 7's carried fix (RG 91 entry 8, §4): on a real Sunday landing on 2 November, All Souls does not merely lose (that was Task 7's [band] fix, proved by [test_all_souls_yields_to_sunday] above) -- it must be TRANSFERRED, not commemorated and not omitted. All Souls is I class -- cgit v1.3