aboutsummaryrefslogtreecommitdiff
path: root/test/test_names.ml
Commit message (Collapse)AuthorAgeFilesLines
* feat(kernel): movable Date_spec variants, and Rogation WednesdayLukasz Kasprzak2026-08-171-4/+133
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Date_spec carried one variant, Fixed(month, day), and its own header said Sunday- and Easter-relative forms would arrive with the OF sanctoral. They arrive early because two things needed them at once: a user-supplied overlay carrying a local movable feast had no way to express "the first Sunday of October", and Rogation Wednesday's commemoration has been recorded as architecturally blocked since 2026-08-13. That blockage turns out to have been a premise, not a fact. The register concluded the Rogation "is not Commemoration_only sanctoral data by nature... it needs a genuinely THIRD kind of thing this architecture has no name for" -- but the reasoning rested on there being "no civil (month, day) pair to anchor a Fixed entry to". That is a statement about Date_spec's expressiveness. With Easter_offset the entity is ordinary sanctoral data, the identical shape Add major-litanies already ships, differing only in how the date is written. No third channel was needed. The register is corrected rather than left contradicting the code. Two variants: Easter_offset of int, and Nth_weekday of {month; nth; weekday} with negative nth counting from the end. Fixed's sexp representation is untouched, so all 327 sanctoral entries and the whole overlay parse unchanged. Both are re-validated in t_of_sexp through their smart constructors, extending the idiom Fixed already used -- the failure that guards against is invisible, a spec deserialising into something that silently never resolves and a celebration vanishing with no diagnostic. Easter is supplied by the rite, not computed in the kernel. Computus ships Gregorian and Julian both, and picking one here would hard-code a Roman assumption into rite-agnostic code and be silently wrong for a Julian-reckoning rite. Rite.t gains an easter field; Rite_ef supplies the Gregorian one. Layer keeps a split index. Fixed entries stay in the year-independent (month, day) table, which preserves the fast path and the "30 November counted twice in a 371-day span" behaviour validate.mli documents for St Andrew. Movable entries have no year-independent key by construction -- the same spec lands on a different (month, day) each year -- so they resolve per civil year into a rata-die table. index_by_date is removed rather than kept as an alias: two ways to index a layer, one of which silently ignores movable entries, is the trap this change exists to avoid. Two domain-edge defects, both found by the suite rather than reasoning. A liturgical year is Advent-anchored, so resolving civil year y names y +/- 1, and at the edges those are 1582 and 10000, which Computus correctly refuses by raising. The ceiling surfaced through the domain-ceiling test, the floor through `colitur day 1583` failing outright. Fixed once, in Layer.index, the single point that calls the rite's easter -- a clamp repeated per caller would have been two places to get wrong a third time. Rogation Wednesday: RG 87 assigns the Litaniae minores to the Monday, Tuesday AND Wednesday before Ascension (scan1:691); colitur built the first two from the start and never the third. RG 88 keeps it out of the Office, so the Ascension Vigil remains observed. RG 89 routes it through the Major Litanies' rules, but RG 109's closed list names only maiores, so by RG 107 it is an ORDINARY commemoration -- confirmed in the output, not assumed. Name from the Missal's own "feria IV" (scan1:20495-20497), violet to match the Monday and Tuesday offices. Blast radius, full 1583-9999 sweep against the pre-change binary: 2257 days, every one the same shape, zero unclassified, line counts equal both sides. The complement is the informative half -- in the other 6160 years the Rogation does not appear at all, because RG 111 admits one commemoration on a II-class day and an impeded feast takes it under RG 113, a Commemoration_only candidate having no row in RG 91's table. Both shapes are pinned. Allow-lists unmoved: layer 3 compares no commemorations and is blind by construction, and layer 4's 2026-2027 window has a competing feast on both Wednesdays, so the Rogation is capped out in exactly the years the oracle can see. C8 is unchanged, asserted by its own count pin. Not built: Sunday-relative specs, which nothing needs yet, and the --overlay plumbing that would let a user actually supply a local movable feast. Nth_weekday therefore ships with synthetic and property coverage only; inventing a shipped entry to exercise it would be fabricating calendar data. Register: section 6.10.
* kernel(celebration): distinguish a feast from a commemoration-only entryLukasz Kasprzak2026-08-111-0/+15
| | | | | | | The 1960 reform reduced many feasts to a bare commemoration. They keep a rank, because RG 111 orders admitted commemorations by dignity, but they can never be the observed day. Modelled as a separate status rather than a fifth rank: RG 8 fixes the classes at four.
* kernel: loaders never escape as an exception, date-spec validates on loadLukasz Kasprzak2026-08-111-3/+27
| | | | | | | | | | | | | | | | | | | | | | Layer.load narrowed its catch to Sexplib0.Sexp_conv_error.Of_sexp_error, but rank_of_sexp is caller-supplied and may raise anything -- e.g. a hand-written rank parser that calls invalid_arg. Overlay.load already catches every exception from the equivalent call; mirror that here so layer.mli's "never as an exception" promise actually holds. Date_spec.t derived its sexp converters with plain ppx_sexp_conv, unlike Slug and Lang, which hand-write validating parsers specifically so malformed data is rejected at load. (Fixed (month 13) (day 40)) used to deserialise cleanly into a spec that simply never resolves -- a saint quietly vanishing with no diagnostic. t_of_sexp now re-runs the value through the existing fixed validator, the same shape Slug and Lang already use. Covering tests: a Layer.load case where rank_of_sexp raises Invalid_argument instead of Of_sexp_error (would have escaped uncaught before this fix); two Date_spec.t_of_sexp cases (month 13, 31 April) that must raise Of_sexp_error rather than silently constructing an unresolvable spec.
* fix(record): derive headers and to_row from a single columns listLukasz Kasprzak2026-08-111-1/+7
| | | | | | | | | Make alignment impossible: both headers and to_row are derived from a single list of (name, extractor) pairs, so reordering one without the other is impossible. CSV schema cannot silently mislabel columns. Add a meaningful test that pins the header names in order, not just length. This catches column reordering regressions.
* kernel(record): flat all-string canonical output viewLukasz Kasprzak2026-08-111-1/+42
| | | | | | | The boundary where rite-parametric types stop. CSV, JSON and the template engine all render from this one schema, so they never see a type variable. headers/to_row cover the scalar columns; names and citations are variable-arity and wait for the richer encoders in Plan 5.
* kernel: Vocab, Celebration and Temporal parametric typesLukasz Kasprzak2026-08-111-1/+21
| | | | | | | | Rite specificity is carried by type parameters plus a vocab record of operations rather than by functors: the same guarantee that a rite cannot name another rite's season, without threading module plumbing through every kernel module. Celebration takes only the rank parameter, since it has no season field and OCaml rejects a type variable that appears in no field.
* kernel: fix sexp deriving, add missing tests, canonicalize removeLukasz Kasprzak2026-08-111-1/+31
| | | | | | | | | | | | | Use [@@deriving sexp] with open Sexplib0.Sexp_conv instead of hand-rolling converters (fixes non-standard Citation shape and missing field validation). Names.t_of_sexp wraps derived version to enforce canonical sort on load. Add tests: - Names of_list duplicate handling - Names sexp canonical sort guarantee (identical serialization) - Names and Date_spec sexp roundtrips Fix Names.remove to canonicalize output (defensive against non-canonical input).
* kernel: Names, Citation and Date_specLukasz Kasprzak2026-08-111-0/+56
Names is an open language-keyed assoc kept in canonical order so equal name sets serialise identically. Citation carries references only, never text. Date_spec ships the one form the EF sanctoral needs; 29 February is constructible and resolves to None in common years.