aboutsummaryrefslogtreecommitdiff
path: root/CLAUDE.md
blob: cb8b0f46023210920f0a34a4730d08a9e6bb2f47 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# colitur — working context for Claude

Read this first, then skim the two authoritative docs it points to. This file
orients a fresh session; the specs hold the exhaustive detail.

## What colitur is

*computus liturgicus* + Latin `colitur` ("He is worshipped"). A **safe,
highly-tested, deterministic OCaml engine** that computes and validates
**liturgical calendars** for multiple rites and emits universal, template-driven
output. It computes the **day identity** (season, week, cycle, observed
celebration with rank/colour/flags, commemorations, transfers) and the day's
**reading citations** (references like `Jn 3:16`, never Bible text), correct all
the way to year **9999**.

Starts with the Roman **EF (1962)** and **OF** forms; the architecture generalizes
to any deterministic rite (Byzantine, Ambrosian, pre-Trent) as future modules.

**Sibling projects** (same author, `~/git/projects/`): **lectio** (Go; the shipped
OF+EF readings engine, 0-error vs references 2005–2050 — colitur bootstraps its
data from lectio and uses lectio as a differential oracle), **dlectio** (offline
Android app over lectio), **clectio** (tiny C build). colitur is a **standalone**
tool, not part of lectio.

## The authoritative docs (read these)

- **Design:** `docs/superpowers/specs/2026-07-30-colitur-design.md` — the full,
  approved design (scope, kernel+rites+overlays architecture, data model, output,
  the 5 validation layers, phasing, success criteria). **This is the contract.**
- **Rules register:** `docs/research/rules-register.md` — every temporal/precedence
  rule the engine computes against, each citing its normative paragraph. The **EF
  rubrics are primary-source-verified** against the 1962 Missal (RG 91 Table of
  Precedence full 28 entries, occurrence RG 92–95, commemorations RG 108–111,
  vigils/octaves/Rogations/Sunday-classes, seasons RG 71–77). OF side cites UNLYC.
- **Plans:** `docs/superpowers/plans/` — `…-plan1-computus-skeleton.md` (done).
- **Primary scans:** `docs/research/*.pdf` — the 1962 Missale Romanum (Latin) and
  the *Rubricarum instructum* motu proprio. `docs/` is **gitignored** (research +
  copyrighted scans stay off the public repo).

## Binding decisions (do not relitigate)

1. **Source of truth = the 1962 Missale Romanum + its Rubricae Generales.**
   Divinum Officium, missalemeum, gcatholic are **comparison oracles only** — any
   **divergence from a reference is flagged LOUDLY** in validation, never silently
   swallowed.
2. **Scope is strictly the 1962 Missal** (1960 rubrics + 1955 Holy Week). Every
   addition (2020 *Quo Magis*/*Cum Sanctissima*, any community's proper) is an
   **overlay**, never core.
3. **Data is bootstrapped from lectio** (0-error vs missalemeum), then validated by
   **rigorous property + differential testing over a large RANDOM sample across the
   whole 1583–9999 range** — not only 2005–2050.
4. **EF and OF are peer rite modules** — a form is never an overlay of another form.
   Each has its own `temporal` + `precedence` **code** and its own **data**; they
   share only the kernel.
5. **Build EF end-to-end first** as the pilot vertical slice (it is the harder,
   more idiosyncratic form, and its rules are already fully researched), learn from
   it, *then* add OF as the second module to prove the `RITE` abstraction generalizes.

## Architecture (one screen)

Rite-agnostic **kernel** + **rite modules** (plug in via a signature) + **data
overlays**.

- **Kernel** (`lib/kernel`, pure, total, bounded 1583–9999): `Computus` (Gregorian
  + Julian Easter + anchors), `Date` (proleptic Gregorian arithmetic), `Overlay`
  (ordered layer-merge algebra: field-level add/suppress/replace/edit, last-writer-
  wins, `empty` = identity), `Precedence` (general resolver parameterized by a
  rite's ruleset → observed day + commemorations + transfers; deterministic,
  terminating), `Calendar` (orchestrator), `Validate` (the invariant/property harness).
- **Rite module** (`lib/rites/<rite>`) satisfies:
  ```ocaml
  module type RITE = sig
    val id         : string
    val temporal   : Date.t -> Temporal.t   (* season, week, cycle, movable feasts — CODE  *)
    val precedence : Precedence.rules        (* rite ranking + resolution          — CODE  *)
    val sanctoral  : Calendar.layer          (* fixed-date base calendar           — DATA  *)
    val lectionary : Lectionary.t            (* slug/day → citations               — DATA  *)
  end
  ```
  Temporal + precedence are **code** (auditable, property-tested); sanctoral +
  lectionary are **data** (`.sexp`, bootstrapped from lectio). `Rite_ef` then `Rite_of`.
- **Result type** `LiturgicalDay` = { date; rite; season; week/cycle; observed
  (slug, names, rank, colour, flags); commemorations; transfer; citations } — the
  single stable schema for all output.
- **Output**: one schema → CSV / JSON / S-expression, rendered by a **logic-less
  Mustache-family template engine** (user supplies the target-language template;
  the engine never executes code). Unix-composable CLIs: `compute | render`, `table`.
- **Data format**: **S-expressions** (`sexplib`/`ppx_sexp_conv`) — the OCaml type
  *is* the format, parse/print auto-derived, no hand-written parser.

## Validation (the "sure bet" pillar — 5 layers)

1. **Types** — illegal states unrepresentable (closed variants for ranks/colours/
   seasons; dates validated at construction; resolution total).
2. **Property (QCheck), year-independent** — hold for every year 1583–9999: exactly
   one observed day per date; year covered once, no gaps; seasons contiguous; Easter
   a Sunday in [Mar 22, Apr 25]; movable feasts at correct Easter-offset weekday;
   overlay merge deterministic + `empty` identity; sexp round-trips. **This is how
   confidence extends past the oracle horizon (~2050).**
3. **Differential vs lectio** — every day 2005–2050 agrees (season, rank, observed,
   citations).
4. **Oracle cross-check** — vs missalemeum (EF) / litcal (OF) in lectio's `sources/`.
5. **Golden regression** — landmark + known-tricky years pinned.

## Current state (Plan 1 DONE — verify with `git log`)

Branch **`ef-pilot-plan1`**, ~6 commits. The Computus **walking skeleton** is built
and green:
- `lib/kernel/date.ml[i]` — `Date`: opaque rata-die (Howard Hinnant civil↔days, as
  in lectio); `make ~year ~month ~day : (t,string) result` (validates, 1583..9999);
  `year/month/day/weekday/to_rata/of_rata/add_days/compare`.
- `lib/kernel/computus.ml[i]` — `gregorian_easter`, `julian_easter`, and anchors
  `ash_wednesday/palm_sunday/ascension/pentecost/corpus_christi`.
- `bin/main.ml` — CLI `colitur easter <year>` (prints Easter + anchors; bad year → exit 2).
- `test/` — alcotest unit + qcheck property + a `cli.t` cram test. All green.
- Build: dune 3.0, **OCaml 5.2.0 project-local opam switch** (`./_opam` already
  present), deps `dune alcotest qcheck qcheck-alcotest`, `cram enable`,
  `generate_opam_files`. License **AGPL-3.0-or-later**.

`sexplib`/`ppx_sexp_conv` and a Mustache lib are **not yet added** — they arrive
with the data model in Plan 2/3.

### Build & test
```sh
eval $(opam env)          # activate the project-local switch (run from this dir)
dune build
dune test
dune exec colitur -- easter 2026
```

## What's next

- **Plan 2 — kernel data model & resolution.** `LiturgicalDay` schema; `Overlay`
  (the layer-merge algebra); the `Precedence` framework (rite-parameterized
  resolver); the **EF `temporal`** (seasons per RG 71–77 incl. Septuagesima + the
  cycle); the `Validate` harness. Add `sexplib`/`ppx_sexp_conv`. Each piece
  property-tested. **Brainstorm → writing-plans → execute.**
- **Plan 3 — EF end-to-end (the pilot).** The EF rite module: `temporal` +
  `precedence` **code** from the register's RG citations (RG 91 table, occurrence
  RG 92–95, commemorations RG 108–111, transfers RG 95–102); sanctoral + lectionary
  **data** bootstrapped from lectio; **plus a minimal output path** (CSV + one
  template) so it produces a real table. Differential vs lectio + oracle vs
  missalemeum green 2005–2050; deep-tail edges checked vs the Missal PDFs.
  **Capture the lessons.**
- **Then**: OF rite module (proves `RITE` generalizes) → full output/rendering →
  hardening (property sweep to 9999, golden pins, first tag).

Still-open research residuals are listed in the register §6 (EF reading-selection
rules; Christ-the-King/Holy-Family placement; data audit) — verify-while-coding,
not blockers.

## How to work here

- **Superpowers workflow**: `brainstorming` → `writing-plans` → `executing-plans`
  or `subagent-driven-development`. Present a design and get approval before coding.
  Plans live in `docs/superpowers/plans/`, specs in `docs/superpowers/specs/`.
- **TDD**, bite-sized tasks, a commit per task on the feature branch (never straight
  to `main` without consent).
- **Every temporal/precedence rule carries a source citation** (RG/UNLYC paragraph)
  in a comment — grep-able, matching the register.
- **Kernel is total & deterministic**: no wall-clock, randomness, or environment
  reads; fallible construction returns `result`/`option`, never raises on in-range
  input; years outside 1583–9999 rejected at the boundary.
- **Commits**: conventional-commit style, subject + body only. **No AI/tool trailer
  of any kind** (the author considers them noise in a public repo).
- **License header**: files may carry a short SPDX `AGPL-3.0-or-later` line.
- `docs/` is gitignored — design/research/scans stay local; only code + README +
  LICENSE + this file are tracked.