summaryrefslogtreecommitdiff
path: root/Makefile
Commit message (Collapse)AuthorAgeFilesLines
* build: verify the upload instead of assuming itLukasz Kasprzak2026-08-211-5/+21
| | | | | | | | | | | | release-tarball chained its steps with ';', so a failed scp or ssh still reached the final echo and it announced a publication that had not happened -- the file was never in the docroot. Every step is now chained with && and the result is checked over HTTP before anything is claimed: the URL must respond and the bytes must untar. Also passes -o ClearAllForwardings=yes, since the i2p port forwards in the ssh config fail when another session holds them and their noise buries real errors.
* build: publish the latest tag, not strictly HEADLukasz Kasprzak2026-08-211-2/+4
| | | | | | | Requiring HEAD to be exactly a tag made the target unusable: the commit that adds the download link to the README necessarily comes after the tag it links to. It now archives the most recent tag and says so when HEAD is ahead of it.
* build: publish one current tarball instead of per-tag snapshotsLukasz Kasprzak2026-08-211-2/+23
| | | | | | | | | | cgit offers snapshots for every tag or for none, so colitur.git now has cgit.snapshots=0 and 'make release-tarball' uploads the tagged archive to a stable URL. Ten tags had meant twenty download links, nineteen of them stale. The target refuses to run from an untagged or dirty tree, so what is published always matches a tag.
* feat(templates): retune ordo.tex to ordo.typ's density, fix ordo.ms's ownLukasz Kasprzak2026-08-201-1/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ordo.tex was 53 pages / 6.9 days-per-page on 2027 against ordo.typ's 27 pages / 13.5 -- the user prefers the tighter Typst booklet. Read ordo.typ's own typographic decisions (base size, the day-number/name/detail-line size hierarchy, box padding, inter-box skip, leading) and matched them: an explicit 9pt/10.5 base (was \normalsize, 10pt), the day number and feast name both 9pt bold (bold distinguishes them, not size, as ordo.typ decided), 7pt weekday, 6.5pt detail lines, sharp-cornered boxes, and needspace amounts re-measured for the shorter boxes. Result: 29 pages / 12.6 days-per-page -- within the "a page or two of 27" target, reached without sacrificing legibility (verified against the rendered PDF, not assumed). The one real gotcha: \fontsize set inside a brace group that closes before the line-ending \\ has no effect on the interline glue TeX inserts for that break -- the glue uses the OUTER scope's \baselineskip, not the just-closed group's. This is exactly the shape of bug the pre-retune box already had (every \fontsize group closed before its own \par), which is why the first retune pass barely moved the page count. Fixed by declaring \fontsize/ \selectfont/\bfseries/\mdseries inline, ungrouped, immediately before the text each governs. Recorded in the file's own header for next time. ordo.ms looked comparatively fine (43 pages) but was rendering on A4, not A5 -- roughly double an A5 page's area, so normalised for area it was already looser than ordo.tex's own pre-retune baseline. Fixed, each found by rendering and reading the real PDF rather than assumed: added -P-pa5 to the Makefile's groff invocation (mirroring grid.ms's existing -P-pa4l); fixed the day box reading the RAW rank/colour strings (class-2, green) instead of the resolved Latin pair (rank_name/colour_name) -- exactly the "printed slugs" defect the ordo rebuild's own commit message named, which this file had regressed to; added -Kutf8 (groff's default input encoding produced visible mojibake on an accented Latin name); tightened fonts/ leading the same way as ordo.tex; found and fixed a stray-blank-line bug present since the file's original authoring (every day/week/month boundary left an accidental blank template line, read by groff as its own extra .sp); found and fixed a genuine print-safety bug (text sitting 0.13mm from the true page edge -- .pl, groff's text page length, is independent of -P-pa5's device paper selection and needed matching explicitly before ms's own FM-based bottom margin would fire at all); and added a .ne guard so a week header can no longer be stranded alone at a page's foot. Net: 43 pages (A4, broken) to 39 pages (real A5, print-safe, real Latin names, correct encoding, zero orphans) -- no numeric target set for this flavour, but no lower number was reachable without leaving one of the above unfixed. ordo.html and every grid.* flavour are untouched, as scoped. Both golden/ordo-2027.{tex,ms} regenerated through the real test harness path (Test_support's loaders + Test_view's en-with-la-fallback view_of), not the CLI, whose own --lang default (la) differs from the harness's and would have pinned content the suite never produces. Full suite green: 503 tests (504 with the exhaustive sweep). make check-templates/check-schema/check-citations all clean.
* feat(templates): ordo booklet and wall calendar in TypstLukasz Kasprzak2026-08-201-8/+23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Adds templates/ef/ordo.typ (A5, one week per page, each day framed with a colour swatch, real names, every fixed string through term.*) and templates/ef/grid.typ (A4 landscape, one month per page, 7 columns, colour-filled cells, Epistle/Gospel sigla), matching what ordo.tex and grid.tex already do. Typst resolves its own table of contents inside a single compile: no pageref/aux-file dance, unlike pdflatex's own two-pass need for ordo.tex. ordo.typ's TOC is one flat heading per week (Month . Week N) rather than ordo.tex's own month-once/weeks-nested layout, since the view model has no first-of-month flag for a template to test and inventing one would be new engine state for a cosmetic grouping. grid.typ deliberately diverges from grid.tex's own partial-fill behaviour for a 5-week month: Typst's row-size list repeats its own last entry for every remaining row, so a two-entry rows spec fills the page completely regardless of week count, where LaTeX's fixed cellh leaves a 5-week month's bottom sixth blank on purpose. Both divergences are documented in the templates' own headers. Two bugs found and fixed while building these against the real typst 0.14.2 binary: two stray hash characters in grid.typ's header comment that were not actually inside a line-comment (would have been parsed as Typst code, not prose); and two lines merging into one wherever they were separated only by a bare newline (still the same soft-wrapped paragraph in Typst, unlike LaTeX's own explicit paragraph break) -- fixed with a trailing backslash to force a real line break without adding inter-paragraph spacing, verified against a full-year render (zero typst warnings across all 365 days of 2027, in both templates). Goldens (test/golden/ordo-2027.typ, test/golden/grid-2027.typ) were generated through the harness's own View.of_days/Template.render_string path, via a throwaway generator, NOT through the CLI: the CLI's default language table differs from the harness's own English-chained-to-Latin table, confirmed live (diffing CLI output against the harness's own render showed exactly the expected language divergence and nothing else) -- the same trap this project has hit before. make check-templates now typesets both templates with the typst binary, using the same SKIPPED-and-exit-0 shape the pdflatex/groff blocks already use when their own tool is absent, verified in both directions: absent (PATH without typst) skips loudly and exits 0, and a deliberately corrupted template fails the target with a non-zero exit and typst's own error text.
* docs(naming): the config man page, and the field referenceLukasz Kasprzak2026-08-201-1/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | colitur-config.5 documents the file's location, the flag > config > default precedence, every setting, and that an unknown key is warned about rather than fatal. Its worked example is a real run against the shipped example overlay, pasted rather than hand-typed -- including one genuine gotcha found while verifying it: overlay/template values are not shell-expanded, so a bare "~/..." written into the config file fails to load; the full path must be written out instead. colitur-templates.5's field reference is updated for the view change -- every field checked against lib/render/view.ml and schema/day-v1.json, not transcribed from memory or an earlier version of this page -- and its worked example is pasted from a real `colitur table` run. Its scope-shadowing warning about {{name.la}} is REMOVED and replaced with a short note that the hazard is now unrepresentable, because name is a plain resolved string with no dotted path left to fall back through. The num collision between a month and a week (both carry num, and a bare {{num}} read from inside a day silently climbs to the week's own value, not the month's) still exists and is demonstrated with a real render, not merely asserted. A man page describing a hazard that was fixed is as wrong as one that omits a real hazard. Two further stale mentions of the removed {{name.la}} hazard, and two places describing the schema as "Latin and English names" rather than one resolved display name, were found in colitur.1 while cross-checking and fixed alongside the primary rewrite; its own CSV example in EMIT was also still the pre-Task-5 column list (name_la/name_en, no *_name columns) and is now the real, verified header. lang/ already installs beside templates/ and schema/ (a prior hotfix); colitur-config.5 is added to install/uninstall/man/doc in the Makefile so `make install`/`make doc` cover it too.
* fix(install): ship lang/ so installed colitur resolves namesLukasz Kasprzak2026-08-191-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | la.ini and en.ini (725 Latin/English liturgical names -- the entire point of the naming-and-config work just merged) had no dune install rule, so make install / dune install never copied them to <prefix>/share/colitur/lang/. bin/main.ml's lang_dir() probes exactly that installed path first, falling back to a build-tree layout that also does not exist for an installed binary -- so every installed user silently got raw slugs (ef-circumcision) and untranslated terms (epistle/gospel) instead of resolved names, with no error at all. The defect existed because nobody had run the installed binary from a directory with no colitur source tree above it: dune exec and dune test always resolve lang/ via the build tree, materialized as a side effect of test/dune's cram deps, so every in-tree check stayed green while the installed artifact was broken. Add lang/dune, following schema/dune's exact pattern: an install stanza placing la.ini and en.ini at <prefix>/share/colitur/lang/, matching where bin/main.ml's lang_dir() already looked. No code change was needed there -- only the missing install rule. Update Makefile's install target help text and summary echo to mention lang alongside ef/templates/schema. Verified end to end: uninstalled, removed lang/dune, rebuilt and reinstalled to reproduce the bug from an outside directory (~/tmp, colitur table showed ef-circumcision/epistle); restored lang/dune, reinstalled, and confirmed the same command now shows the resolved Latin name and rubric terms, that ~/.local/share/colitur/lang/ contains both files, and that colitur emit --format csv shows a real name in the name column. lang/la.ini and lang/en.ini are untouched. Full suite: dune test --force, 495 tests, 0 failures.
* docs(templates): document the ordo booklet's required two-pass buildLukasz Kasprzak2026-08-191-2/+4
| | | | | | | | | | | | | | | A LaTeX table of contents needs two pdflatex passes -- the first pass leaves every entry showing '??', the second resolves the \pageref values. A user hit exactly this and reported it as a bug; the template was fine, the instructions were not. README's rendering example now runs pdflatex twice for ordo.tex (or names latexmk -pdf as the one-shot alternative) and notes the wall calendar needs only one pass, having no cross-references of its own. make check-templates now runs pdflatex twice per LaTeX template too, so the target exercises what a user actually has to do rather than silently passing on a single, incomplete pass.
* fix(tools): harden check_citations.py against its own self-poisoning bugLukasz Kasprzak2026-08-191-7/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Reproduced the defect: reintroducing the exact historical citation bug (pointing class-1's citation back at LT.txt:12459, the value a prior fix round corrected away from) made the tool report "147 citations checked, 0 look wrong". The mechanism was that the corrective comment documenting the old bug quotes the wrong historical value, and the checker pooled every quoted phrase from the whole surrounding comment block, so citing the wrong line matched the comment explaining why it was wrong. Four changes: 1. The word pool for a citation is now scoped to the entry(ies) it is attached to only -- never to quoted text elsewhere in the comment. This is the direct fix for the self-poisoning bug. 2. A citation whose pool has fewer than two distinctive words (Latin liturgical headings are short and stopword-heavy) cannot discriminate the right line from a wrong nearby one. Such a citation is now reported CANNOT VERIFY and fails the target, instead of silently passing. 3. The blanket +-2-line tolerance is gone. A bare "LT.txt:N" is checked at line N only; a heading that genuinely wraps must say so explicitly as "LT.txt:N-M". The allowance moves into the data, where it is visible. 4. The tool gets its own test suite, tools/test_check_citations.py, with a synthetic fixture covering: a correct citation, off-by-one and off-by-three mismatches, an explicit wrap range, a degenerate pool, a PATTERN-marked entry with no citation, and a dedicated regression test for the self-poisoning case itself. Wired into `dune test` via a new (rule (alias runtest) ...) in tools/dune (a plain (test ...) stanza cannot run a Python script), so it runs with the rest of the suite, not only as a `make` target. Added a --file/--lt-file override to check_citations.py so the tool (and its own tests) can point at a fixture without touching the real lang/la.ini or docs/research/LT.txt. Confirmed the "SKIPPED, exit 0" behaviour for a missing docs/research/LT.txt is unchanged. tools/__pycache__/ (a stray artefact of this script, previously untracked and ungitignored) is now in .gitignore. Measured against the current lang/la.ini (another task is still landing its sanctoral entries on this branch): 15 of 275 citations now look wrong and 42 more cannot be verified, both far above the 0 the unhardened tool reported. Not fixed here -- the data pass is separate, once the sanctoral entries land.
* fix(lang): correct two wrong citation lines, add check-citationsLukasz Kasprzak2026-08-191-1/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Two of la.ini's LT.txt:<n> citations pointed at the wrong line -- the Latin itself was right, only the pinned line was wrong: - advent cited LT.txt:8631 ("Tempus Nativitatis"); the real "Tempus Adventus" heading is at 8609. - ef-christ-the-king and [rank]'s own citation both pointed near "Dominica ultima Octobris" (12459) when the text they actually quote, "D.NI NOSTRI JESU CHRISTI REGIS" and "I classis", sits two and three lines further down, at 12461 and 12462. ef-christmas-sunday-0 was marked PATTERN but LT.txt:8644 is the identical string verbatim -- relabelled as a direct citation, not constructed. Added tools/check_citations.py and `make check-citations`: for every LT.txt:<n> citation outside a PATTERN block, confirms a +-2-line window around line n actually contains the Latin text the citation claims, rather than trusting each of the 38 citations by hand. Follows check-schema/check-templates' own precedent -- docs/ is gitignored, so the target prints SKIPPED loudly and exits 0 when docs/research/LT.txt is absent, never a silent pass. The checker's own teeth are proven three ways: replayed against the pre-fix file it independently re-derives both corrections above; a fresh mutation (redirecting one citation to an unrelated line) is caught and reverted; the fixed file passes clean, 147 citations checked, 0 wrong.
* fix(templates): grid.ms wall calendar dropped four of seven columnsLukasz Kasprzak2026-08-191-3/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | pdftotext -layout of the shipped grid.ms showed only 3-4 of 7 columns and roughly a third of each month's day numbers: tbl's plain columns (no w()) size to their widest single entry and never wrap, so a long fallback slug (some run past 40 characters) forced every column that wide, the table ran far past the page, and whatever fell past the physical edge was gone, not merely ugly. groff exited 0 throughout (warnings, not errors), so make check-templates reported OK on a broken artefact. Fixed both halves. (a) The table now fits: true landscape via gropdf's own -P-pa4l (an in-document Xpapersize=a4l escape was tried and rejected -- it does not rotate the page in this groff), ms's own title macro widened back out after narrowing the line length for the title text (a second, independent way the original lost its width, found by reading s.tmac), and every column rewritten as a genuine tbl text-block (T{/T}, not a plain w() cell -- w() alone does not wrap, confirmed against tbl's own generated troff code) so long, hyphenated slugs wrap at their own hyphens instead of forcing the column wider. (b) check-templates now captures groff's stderr per template and fails the target if it is non-empty, rather than trusting groff's exit code. Verified: 0 warnings (was 12), pdftotext -layout shows all 7 columns and every day number for all 12 months (was 3-4 columns, ~12-23 of each month's day numbers). The golden fixture is regenerated: 0 "{{", 12 month headings, exactly one Ianuarius, and each week's block (now spread across several physical lines by the T{/T} wrap) carries exactly 6 tabs joining its 7 cells.
* docs(render): template reference, install rules, typesetting checkLukasz Kasprzak2026-08-191-4/+39
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | colitur-templates.5 documents the four syntax forms, the six flavours and their escaping, and the full view-model field reference. It states plainly that there are no partials, no raw form and no expression evaluation -- a template is data, never a program. It documents two real hazards found during this build, not theoretical ones: the outward scope fallback silently shadowing an inner name/num key with an outer one of the same name (with the safe {{#name}}...{{^la}} idiom), and the engine's lack of host-comment awareness (a {{...}} inside a LaTeX %, groff .\" or HTML <!-- --> comment is still parsed as a tag). It also states the limitation rather than hiding it: AsciiDoc and Markdown are not escaped, so a feast name containing * or _ renders as emphasis. templates/ and schema/ now install into <prefix>/share/colitur/, matching data/ef/, via new install stanzas; colitur-templates.5 installs to man5 beside colitur-overlay.5. Verified against a scratch prefix: the installed binary resolves both from the prefix, not the source tree, when run from an unrelated working directory. make check-templates typesets every shipped template through pdflatex and groff when they are installed, and prints SKIPPED loudly when they are not. Golden tests prove templates render; only this proves they typeset. A silent skip would read as a pass. Fixed a real doc/help drift while here: bin/main.ml's --help still said --overlay was accepted on day and readings only, three commands out of date (emit, table/render and publish all accept it too), disagreeing with the man page's own OVERLAYS section, which carried the identical stale line. Both are corrected; --overlay's own behaviour is unchanged.
* feat(render): XML emitter and schemaLukasz Kasprzak2026-08-191-1/+10
| | | | | | | | | | | | | Element-per-field; attributes carry identity only and there is no mixed content, so a consumer's XPath never has to distinguish the two. Schema validation is an opt-in make check-schema via xmllint, not an in-suite assertion: validating XSD needs an XML library and the dependency list is frozen. It prints SKIPPED loudly when xmllint is absent, because a silent skip reads as a pass. The suite asserts well-formedness properties directly instead. This corrects the design spec, which claimed in-test validation.
* docs(man): colitur-overlay(5), the overlay format in fullLukasz Kasprzak2026-08-181-4/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The overlay format was documented in three partial places -- a paragraph in colitur(1), a block in --help, and the comments inside the shipped example -- none of which was a reference. Someone writing a diocesan calendar had to read all three and infer the rest. Section 5 because an overlay is a thing a user AUTHORS rather than a command they run: it belongs beside fstab(5), not in man1. Covers every directive and every field edit, the six required fields and the two optional ones, all three date specifications including the signed Easter_offset and the negative nth, three worked examples, and the caveats. The subject field gets a note explaining that it is not decoration -- it decides whether a feast displaces an occurring Sunday under RG 16(a). Two things it says that the code says and the old prose did not. There is no Set_status and no Set_date among the field edits, deliberately: changing an entry's status or its date makes it a different celebration rather than an edited one, so Replace is the right directive and the change stays visible in `colitur check` output. And a local feast missing from output has usually LOST its day under the general rubrics rather than failed to load -- the engine applies precedence to overlay entries exactly as to universal ones, which is the first thing an author hits and was written down nowhere. Writing it caught a documentation bug before it shipped: a first draft listed a Set_status edit that does not exist and omitted Remove_name that does. Every documented edit is now cross-checked against overlay.mli. Linked from colitur(1)'s SEE ALSO and its OVERLAYS section, and from --help. The Makefile installs it into man5, removes it on uninstall, and the man and doc targets lint both pages.
* fix(make): release must not abort when the version bump is a no-opv0.1.0Lukasz Kasprzak2026-08-171-2/+9
| | | | | | | | | Cutting a version whose files already carry it -- which is how the first tag went, and what any re-run after a failed gate looks like -- leaves nothing staged, and git commit aborts the target on "nothing to commit" despite everything being in order. The commit is now conditional on something actually being staged, and an existing tag is refused explicitly rather than surfacing as a bare git error.
* feat(cli): --version, a CHANGELOG, and a release targetLukasz Kasprzak2026-08-171-1/+25
| | | | | | | | | | | | | | | | | | | | | | | | Groundwork for tagging. The project had no version anywhere: not in dune-project, not in the binary, no CHANGELOG, no tags. The version lives in two places -- dune-project, which generates colitur.opam, and a constant in bin/main.ml, which is what --version prints. Two rather than one because dune's watermarking only substitutes in a release tarball, so a binary built the ordinary way from a checkout would report a placeholder. The release target rewrites both and then re-checks both, and finally requires the freshly built binary to report the version it just wrote: a release that bumped one and not the other would ship a binary disagreeing with its own package metadata. --version is deliberately not embedded in the help text. cli.t pins help's first line, and a version there would mean editing a test expectation every release for no gain. The release target mirrors lectio's, refusals included: no release from a dirty tree, none without a CHANGELOG entry for that version, none whose version bump silently failed to apply, and `make check` -- the full 1583-9999 sweep, not the sampling suite -- must pass before the tag is created.
* feat(cli): a Makefile, a man page, and --helpLukasz Kasprzak2026-08-171-0/+55
Three things the project had no answer for: how to install it without knowing dune, where to read about it, and what it does when asked. Makefile, same shape as lectio's -- PREFIX ?= $(HOME)/.local, BINDIR, MANDIR, and the '## '-comment help target -- so the two siblings are driven the same way. Every recipe wraps dune in `opam exec --`, which is the actual point of having one here: `make build` works from a plain shell with no `eval $(opam env)` first. install goes through `dune install` rather than a hand-rolled copy, because the binary finds its calendar data relative to its own path; the man page is installed separately to share/man/man1, matching lectio. install and uninstall were both run against a scratch prefix and checked: uninstall leaves zero files behind. PREFIX defaults to ~/.local because that is where lectio installs and where it actually lives on this machine, so colitur lands on an existing PATH with no shell change. An earlier install this session went to ~/opt/colitur, which was me over-applying a rule meant for third-party tools to one of the author's own projects; it has been removed rather than left as a second, staler binary competing on PATH. man/colitur.1 documents the four commands, both output formats and why they differ, COLITUR_DATA_DIR and its refusal to fall back, the data resolution order, exit statuses, and -- deliberately -- the limitations: EF only, Epistle and Gospel only with the chants unbuilt and rejected rather than guessed, and the BVM Saturday Mass-selection gap. A man page that only lists what works is half a man page. Renders clean under `groff -ww -z`, no warnings. --help prints to stdout and exits 0; a usage error prints one line to stderr and exits 2. That is the Unix convention rather than a preference: asking for help succeeded and should be pipeable, being invoked wrongly did not and must not pollute stdout. Both directions are asserted in cli.t, along with a loop confirming every command the help text advertises is one the dispatch actually accepts -- the check that catches help drifting away from the code.