diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/test_oracle.ml | 146 | ||||
| -rw-r--r-- | test/test_precedence_ef.ml | 21 | ||||
| -rw-r--r-- | test/test_rite_ef.ml | 44 |
3 files changed, 156 insertions, 55 deletions
diff --git a/test/test_oracle.ml b/test/test_oracle.ml index 07a5634..2624664 100644 --- a/test/test_oracle.ml +++ b/test/test_oracle.ml @@ -107,18 +107,25 @@ entries; RG 110's inseparable-Peter/Paul commemoration is unimplemented code, a real feature this task did not build) -- honestly verdicted [missalemeum] (colitur is short a feature or a row, not right), never - silently absorbed as if colitur were correct. THREE entries (M11, M13 - and, since Task B/ef-rg16a, M17) are [verdict open] -- CORRECTED, final - fix wave, item 7: this comment previously said "one entry (M13)", - missing M11, whose own verdict was changed from [colitur] to [open] in - fix round 1 (see M11's own entry below for why) but this summary was - never updated to match; M17 (the RG 113 same-band tie-break residual, - register §6.1) is a genuinely NEW open item, not a stale-comment fix. - ONE entry (M15) carries its own fourth verdict, [unresolvable] -- not a - rubric dispute or a data gap either engine is wrong about, but a LIMIT - of this comparator itself (see M15's own entry). All are adjudicated as - unresolved/unresolvable, not resolved either way -- the brief's own - explicit permission ("say so as an open item") used for real, not + silently absorbed as if colitur were correct. TWO entries (M11 and M13) + are [verdict open] -- CORRECTED, final fix wave, item 7: this comment + previously said "one entry (M13)", missing M11, whose own verdict was + changed from [colitur] to [open] in fix round 1 (see M11's own entry + below for why) but this summary was never updated to match. Task B + (branch ef-rg16a) briefly added a THIRD, M17 (the same-band tie-break + between Maurice and Thomas of Villanova, 22 September) -- CORRECTED, + fix round 1 of that same task: M17 was itself wrong. The "tie" was + manufactured by {!Precedence_ef.band} lending a [Commemoration_only] + candidate the same table entry as a genuine [Feast] of its own rank + (RG 91's table has no row for a bare commemoration at all -- fixed in + [band] itself, not here); once fixed, 22 September resolves cleanly on + both sides and M17 was deleted, not merely re-adjudicated. ONE entry + (M15) carries its own fourth verdict, [unresolvable] -- not a rubric + dispute or a data gap either engine is wrong about, but a LIMIT of this + comparator itself (see M15's own entry). All remaining OPEN entries are + adjudicated as unresolved/unresolvable, not resolved either way -- the + brief's own explicit permission ("say so as an open item") used for real, + not defaulted past. See the task report for every entry's full reasoning and primary-source citation. *) @@ -655,30 +662,43 @@ let m15_dates = already tracks). Only 2026 shows here -- 2027's Friday of Passion Week IS 19 March, M13's own date, where the identity axis cannot even be reached (M13's own rank/colour mismatch already excludes that day from - count-matched identity comparison). *) + count-matched identity comparison). + + NOTE for whoever builds the office (fix round 1, coordinator finding 7): + 27 March 2026 is a III-class day, where RG 111(d) admits TWO + commemorations, not one -- yet missalemeum admits only the Seven Sorrows + and DISPLACES John Damascene entirely (its own "displaced" list carries + his title that day), not merely drops him to second place. Implementing + the Seven Sorrows candidate naively (as one more ordinary III-class + commemoration competing for the day's two slots) will not reproduce + this: John Damascene would still win one of the two admitted slots by + dignity/band, giving colitur TWO commemorations where missalemeum shows + one. Whatever privilege or precedence the Seven Sorrows commemoration + carries must itself explain the exclusion, not just the admission -- + register §6's own open item for this office should carry this caveat + forward. *) let m16_dates = [ "2026-03-27" ] -(* M17 -- Task B: the SAME-band residual tie-break (docs/research/rules- - register.md §4's own "RG 113" entry, and §6.1's "RG 113 same-band - residual" record) made visible for the first time by identity - comparison. 22 September 2027 (September Ember Wednesday): colitur - admits "St. Maurice and Companions, Martyrs" (Commemoration_only, - Class3); missalemeum shows "St. Thomas of Villanova" (Feast, Class3) - instead -- both land on {!Precedence_ef.band} entry 24 (III-class - universal feasts), a genuine tie RG 113 gives no further instruction for - (its own text only reaches "servetur ordo tabellae praecedentiae", the - TABLE order; nothing in the primary text breaks a tie WITHIN one table - entry). colitur's own residual tie-break (alphabetical by slug, §6.1's - own uncited-convention record) picks "maurice..." over "thomas..." purely - because 'm' < 't' -- no rubrical warrant either way, so this is NOT - adjudicated colitur or missalemeum: verdict OPEN, the same explicit - permission the brief gives M11/M13 ("say so as an open item rather than - absorbing it"), register §6.1. Only 2027 falls in this window with this - EXACT collision -- 2026's 22 September is an ordinary (non-Ember) - Tuesday, so Thomas of Villanova simply wins the day outright on both - sides (colitur: observed; missalemeum: title) with Maurice commemorated - alongside him identically on both -- no tie to observe that year. *) -let m17_dates = [ "2027-09-22" ] +(* M17 was DELETED, fix round 1 (Task B): the "genuine tie" it adjudicated + as [open] was itself wrong. 22 September (any year the September Ember + Wednesday falls on the 22nd -- 2027 in this window): colitur used to + admit "St. Maurice and Companions, Martyrs" (Commemoration_only, Class3) + where missalemeum shows "St. Thomas of Villanova" (Feast, Class3) -- + NOT because RG 113 runs out of instruction between two same-rank + candidates (the framing this entry used to carry), but because + {!Precedence_ef.band} used to lend a [Commemoration_only] candidate the + SAME table entry (24) as a genuine [Feast] of its own rank, manufacturing + a tie the primary text never creates: RG 91's own table enumerates only + "dies liturgici" (entry 24: "Festa III classis..." -- FEASTS), and the + calendarium's own 22 September row confirms it in its own notation -- + "S. Thomae de Villanova Ep. et Conf., III classis. / Commemoratio Ss. + Mauritii et Soc. Mm." -- Thomas carries a class number, Maurice carries + none. Fixed at the source ([band] itself now returns [Precedence_ef + .unclassified] for any [Commemoration_only] candidate, docs/research/ + rules-register.md §6.1's own corrected account) rather than here: 22 + September now resolves identically on both sides with no allow-list + entry needed at all -- removed, not re-adjudicated to a different + verdict, since there is no longer a divergence to name. *) let layer_m_reason (c : colitur_row) (o : oracle_row) diffs = if diffs = [] then None @@ -704,7 +724,6 @@ let layer_m_reason (c : colitur_row) (o : oracle_row) diffs = Some "M13" else if List.mem c.c_date m15_dates && diffs = [ Comm_identity_unresolved ] then Some "M15" else if List.mem c.c_date m16_dates && diffs = [ Comm_identity_mismatch ] then Some "M16" - else if List.mem c.c_date m17_dates && diffs = [ Comm_identity_mismatch ] then Some "M17" else None (* ---------------------------------------------------------------------- *) @@ -862,23 +881,36 @@ let test_layer_m_counts_match_citations () = combination would break it) that stays honest about what remains unverified. + WHAT THIS DOES NOT PIN (coordinator finding 8, fix round 1, honestly + named rather than left implicit): the [oracle_rank = colitur_rank] + branch accepts ANY genuine agreement, including one this check cannot + independently verify is the CORRECT rank -- a regression that silently + flipped some entry's [rank] from [Class3] to [Class4] would land in the + agreement branch and pass cleanly if missalemeum's own id happened to + read 4 for that entry too (data drift on one side coinciding with data + drift on the other is not ruled out by this check, only coincidence + independent of any real cause is). This test pins "no third pattern + appears", not "every individual rank is correct" -- a narrower, still + genuinely useful claim (see the [> 50] population guard below, which + confirms the pinned shape is actually exercised at scale, not vacuously + true over an empty or trivial set), and this comment says so rather than + letting the assertion's own name imply more than it checks. + [Feast]-status candidates get the ORIGINAL, unrestricted check (any - disagreement at all is unexpected) -- but this window's own data never - actually offers a [Feast]-status LOSING candidate whose identity is - independently clean (checked: 0 in the 2026-2027 fixture -- a [Feast] - candidate here either wins its own day outright, in which case it is - never a commemoration at all, or the one day where it does lose, - 22 September 2027/Thomas of Villanova, is ITSELF the M17 tie-break - mismatch and so is excluded by the [identity_diff = None] guard before - ever reaching this check). Kept anyway, not deleted: a real disagreement - would still be reported the moment one becomes reachable (a wider oracle - window, or a data change), and this project's own vacuity catalogue - flags "an assertion true by construction" as a defect shape to avoid, - not "an assertion whose population happens to be empty in the one - fixture available" -- the CHECK still does real work when its input is - non-empty; it is the DATA, not the code, that is currently silent here. *) + disagreement at all is unexpected). CORRECTED (fix round 1, coordinator + finding 1): this comment previously claimed this branch was unreachable + in the 2026-2027 window (checked: 0) because its one candidate, Thomas + of Villanova on 22 September, was M17's own mismatch -- WRONG, once + traced further: M17 itself was wrong (see {!Precedence_ef.band}'s own + fidelity fix, register §6.1), and fixing it made 22 September resolve + cleanly on both sides, reachable here after all. Measured, not assumed: + 22 Feast-status commemorations are now examined by this branch (not + only Thomas of Villanova -- every OTHER genuinely clean Feast-status + match in the window reaches it too, which the earlier version of this + comment did not check for before asserting "0"). All 22 agree. *) let test_identity_rank_corroboration () = let oracle, colitur = compare_streams () in + let feast_checked = ref 0 in let feast_mismatches = ref [] in let commemoration_only_checked = ref 0 in let commemoration_only_surprises = ref [] in @@ -896,6 +928,7 @@ let test_identity_rank_corroboration () = | Some oracle_rank -> ( match List.find_opt (fun (_, _, _, n) -> n = Some title) c.c_commemorations with | Some (slug, colitur_rank, Cel.Feast, _) -> + incr feast_checked; if colitur_rank <> oracle_rank then feast_mismatches := Printf.sprintf "%s: %s oracle-id-rank=%d colitur-rank=%d" c.c_date slug @@ -921,14 +954,21 @@ let test_identity_rank_corroboration () = o.o_commemorations o.o_commemoration_ids) oracle colitur; Alcotest.(check (list string)) - "Feast-status matches: oracle id-rank agrees with colitur's own rank (none reachable in this window, \ - see this test's own comment; the check still runs)" - [] (List.rev !feast_mismatches); + "Feast-status matches: oracle id-rank agrees with colitur's own rank" [] (List.rev !feast_mismatches); Alcotest.(check (list string)) "Commemoration_only-status matches: every one fits the KNOWN oracle=4/colitur=3 convention gap -- any \ other combination would be a genuine, new surprise" [] (List.rev !commemoration_only_surprises); - (* Vacuity guard for the branch that IS populated in this window. *) + (* Vacuity guard: BOTH branches must actually run now. CORRECTED (fix + round 1, coordinator finding 1): the [Feast] branch used to be + unreachable in this window (checked: 0) because its one candidate, + Thomas of Villanova on 22 September, was M17's own mismatch (excluded + by the [identity_diff = None] guard above). Fixing {!Precedence_ef + .band}'s Commemoration_only fidelity (register §6.1) made that day + resolve cleanly, so it is reachable here too -- this guard now expects + at least 1, not merely documents the branch as dormant (measured: 22 + Feast-status commemorations now examined, up from 0). *) + Alcotest.(check bool) "the Feast-status population actually examined is non-trivial" true (!feast_checked > 0); Alcotest.(check bool) "the Commemoration_only population actually examined is non-trivial" true (!commemoration_only_checked > 50) diff --git a/test/test_precedence_ef.ml b/test/test_precedence_ef.ml index ca623d2..2935e40 100644 --- a/test/test_precedence_ef.ml +++ b/test/test_precedence_ef.ml @@ -267,7 +267,26 @@ let cases = (* 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 ) + cand ~rank:V.Class4 "ef-second-mystery-vigil", PE.unclassified ); + (* Task B fix round 1 (coordinator finding 1): RG 91's table enumerates + only "dies liturgici" -- a [Cel.Commemoration_only] candidate is + never a row in the table at all, regardless of what rank it would + otherwise band to. [Class1]/universal-layer is deliberate: absent + the status guard this would band to entry 11, the FIRST, highest- + priority real entry any sanctoral candidate can reach, so this + proves the guard is checked BEFORE and overrides every rank-keyed + branch, not only the low-priority ones an accidental placement + might happen to catch. Real-world witness: "maurice-and-companions- + martyrs" (data/ef/sanctoral.sexp, 22 September, Class3, + Commemoration_only) used to band to entry 24 alongside the genuine + Class3 feast "thomas-of-villanova" -- test_oracle.ml's own former + M17 allow-list entry, deleted once this fix made the divergence it + named disappear. *) + ( "unclassified: a Commemoration_only candidate has no row in RG91's \ + table at all, even at Class1", mk 2026 5 20, + cand ~origin:P.Sanctoral ~status:Cel.Commemoration_only ~layer:PE.universal_layer + "ef-some-commemoration-only", + PE.unclassified ) ] (* Review finding 1's end-to-end proof: on a real Sunday landing on 2 diff --git a/test/test_rite_ef.ml b/test/test_rite_ef.ml index 6fcb25d..2e5d2fd 100644 --- a/test/test_rite_ef.ml +++ b/test/test_rite_ef.ml @@ -298,6 +298,45 @@ let test_search_genuinely_enters_the_window () = "the walked span is at least 8 days -- the octave alone (Easter..Easter+7), not a one-day hop" true (List.length walked >= 8) +(* Task B fix round 1 (coordinator finding 1), end to end with REAL data: + 22 September 2027 is a September Ember Wednesday -- the OBSERVED day is + the Ember office itself ([band] entry 18, RG 91, beats both sanctoral + candidates), and RG 111(c) ("other II class: one") admits exactly ONE + of the two competing losers, "maurice-and-companions-martyrs" + ([Commemoration_only], Class3) and "thomas-of-villanova" ([Feast], + Class3). Before the fix, [Precedence_ef.band] gave Maurice the SAME + table entry (24) as Thomas, so the residual slug tie-break picked + Maurice ('m' < 't') and OMITTED Thomas -- contrary to the calendarium's + own 22 September row ("S. Thomae de Villanova Ep. et Conf., III + classis. / Commemoratio Ss. Mauritii et Soc. Mm.": Thomas is the one + WITH a table entry) and to missalemeum (test/test_oracle.ml's own + former M17 allow-list entry -- oracle "commemorations": Thomas, + "displaced": Maurice -- deleted once this fix made the divergence + disappear). This is the SAME date the oracle harness itself checks, + pinned here too so a regression shows up at the OCaml level, not only + via the fixture comparison. *) +let test_maurice_thomas_band_fidelity_end_to_end () = + let layer = real_layer () in + (* [Calendar.year]'s own liturgical-year convention (Advent-anchored, see + calendar.ml's [year_bounds]): the label [y] spans December of civil + year [y] through November of civil year [y+1], so 22 September 2027 + is reached via [Cal.year ... 2026], not 2027 -- the same + [y-1]/straddling indexing test_oracle.ml's own header comment already + documents for exactly this reason. *) + let days = Cal.year Rite_ef.context layer 2026 in + let day = Array.to_list days |> List.find (fun d -> Date.compare d.LD.date (mk 2027 9 22) = 0) in + Alcotest.(check string) "the September Ember Wednesday office itself is observed (band entry 18)" + "ef-september-ember-wed" (slug_of day.LD.observed); + Alcotest.(check (list string)) + "St Thomas of Villanova (band entry 24, a real table row) is the sole commemoration" + [ "thomas-of-villanova" ] + (List.map (fun (c, _) -> slug_of c) day.LD.commemorations); + Alcotest.(check (list string)) + "St Maurice and Companions (Commemoration_only, unclassified -- no table row) is omitted, not \ + commemorated" + [ "maurice-and-companions-martyrs" ] + (List.map (fun (c, _) -> slug_of c) day.LD.omitted) + let suite = ( "Rite_ef (real data: overlay-in-effect, domain-ceiling)", [ Alcotest.test_case "the overlay suppression is observably in effect" `Quick @@ -311,4 +350,7 @@ let suite = Alcotest.test_case "transfer_target skips the whole Easter octave from inside Holy Week" `Quick test_transfer_target_skips_the_whole_easter_octave; Alcotest.test_case "the search genuinely enters the window (not vacuous)" `Quick - test_search_genuinely_enters_the_window ] ) + test_search_genuinely_enters_the_window; + Alcotest.test_case + "band fidelity end-to-end: Thomas of Villanova observed, Maurice commemorated (2027-09-22)" `Quick + test_maurice_thomas_band_fidelity_end_to_end ] ) |
