Releases: Alberto-Codes/saucier
Release list
v0.7.0
The 1907 scan reads entry 22 as BROWN SAUCE OR ESPAQNOLE, so no name in that
witness carried the word Espagnole except a derivative's, and the mother bound
to LENTEN ESPAGNOLE with twelve preparations beneath it. The rule that bound it
is true of this book — Escoffier presents a base before its derivatives — and
it never checked the premise underneath: that the base is among the candidates
at all. This release is the guard for the witness where it is not. An entry
that says it is made from Espagnole is not Espagnole.
The scan lost one letter, and a derivative was crowned the mother sauce
The state this tag represents
escoffier-1909 151 sauces, 57 derived, 94 unresolved
escoffier-1907 140 sauces, 51 derived, 89 unresolved
export 293 lines, 271,737 bytes, identical SHA-256 on every run
import --check 2 catalogues and 291 preparations rebuilt. Nothing written.
diff 1907 1909 11 unmatched, 18 parent-changed, 35 ocr-suspected
A mother no longer binds by a name run to a preparation whose opening paragraph
states that mother. The statement test is ADR-0008's own — a whole run of words
inside one sentence of the opening paragraph — now shared by both readers
through a new module, saucier.domain.statement. In 1907 that removes the only
candidate for espagnole, the mother stays uncatalogued in that witness rather
than falling back to a derivative, and Lenten Espagnole takes the parent its
first sentence names.
There are ten mother bindings across the two witnesses. One is the exact name
ESPAGNOLE in 1909, which wins before the guard runs. One is the wrong 1907
binding this removes. The remaining eight are name runs that face the guard and
survive it, because Escoffier opens a base with its quantities rather than with
its name. So the whole change to the parsed data is one field: entry 24's
"parent": null becomes "parent": "espagnole", seven bytes on the 271,730
that v0.6.0 exported. The 1909 census does not move and its JSON is
byte-identical. See
ADR-0018.
Behaviour change: the 1907 Espagnole lookup now refuses
saucier show espagnole --source escoffier-1907 printed LENTEN ESPAGNOLE and
exited 0 through v0.6.0. It now prints no preparation named 'espagnole' and
exits 1. saucier tree espagnole --source escoffier-1907 heads on the bare
concept instead, with Lenten Espagnole among the children rather than above
them. Anything scripted against either command sees that. The commit landed
with a fix title and release-please derived a patch from it; the refused exit
code and the new public module are why this tag is 0.7.0.
Run it
No GPU, no API key, no database, no network. Both source texts are committed.
git clone https://github.com/Alberto-Codes/saucier
cd saucier && git checkout v0.7.0
uv sync && uv run saucier parse
sed -n 1730p corpus/escoffier-1907.txt
uv run saucier tree espagnole --source escoffier-1907
uv run saucier show lenten-espagnole --source escoffier-1907
uv run saucier show espagnole --source escoffier-1907 # refuses, exit 1
0.7.0 (2026-09-10)
Fixes
Chores
- release as 0.7.0 (eb30db4)
v0.6.0
The record for Mornay said it derives from Béchamel and stopped there, two
lines above the sentence that says how. This release reads that sentence, for
one preparation, by hand: six operations in the book's own words, every
quantity the text gives, and every one it withholds left empty rather than
guessed. The check that refuses a misquote also turned up the first confirmed
difference between the 1907 and 1909 printings.
The state this tag represents
escoffier-1909 151 sauces, 57 derived, 94 unresolved
escoffier-1907 140 sauces, 50 derived, 90 unresolved
export 293 lines, 271,730 bytes, identical SHA-256 on every run
import --check 2 catalogues and 291 preparations rebuilt. Nothing written.
show mornay 6 operations, 5 quantities given, 3 unresolved
The census and the interchange stream are unchanged from v0.5.0. A procedure
is a hand record that quotes its witness, not catalogue data, so it neither
adds a sauce nor moves a byte of export. What is new is procedure on
saucier show: each operation prints the verb, its ingredients with the
quantities the text states, and the criteria the text leaves open, marked
unresolved instead of filled in. Every word of it is checked against a run of
words in the source before it prints, and the command refuses rather than
paraphrase. One preparation is recorded so far. See
ADR-0017.
Run it
No GPU, no API key, no database, no network. Both source texts are committed.
git clone https://github.com/Alberto-Codes/saucier
cd saucier && git checkout v0.6.0
uv sync && uv run saucier parse
uv run saucier show mornay
uv run saucier show morn-ay-sauce --source escoffier-1907
sed -n 2437,2446p corpus/escoffier-1909.txt
0.6.0 (2026-09-05)
Features
v0.5.0
The catalogue now leaves the process as one stream, one JSON record per
line, so a shell can read both witnesses without importing this package. The
first reader written for that stream accepted an empty file, then a file
with its last sauce cut off, and every remaining line was valid JSON. This
release is the reader that refuses both, and the jq one-liner that found a
Périgueux the scan resolved and the text refused.
I cut the last sauce off the file. Every line still parsed.
The state this tag represents
escoffier-1909 151 sauces, 57 derived, 94 unresolved
escoffier-1907 140 sauces, 50 derived, 90 unresolved
export 293 lines, 271,730 bytes, identical SHA-256 on every run
import --check 2 catalogues and 291 preparations rebuilt. Nothing written.
The census is unchanged from v0.4.0. What is new is saucier export, which
writes every stored catalogue to standard output as saucier/1 records, and
saucier import --check, which reads the stream back, rebuilds every
catalogue in memory, prints the census, and writes nothing. The reader
refuses an empty stream, a stream cut at a line boundary, an object that
repeats a key, an unknown field, a duplicate id, a bad byte, and a
preparation that cites another fidelity than its catalogue, each with the
line number. The JSON snapshot stays the working store; parse, show,
tree, and diff are unchanged. See
ADR-0016.
Run it
No GPU, no API key, no database, no network. Both source texts are committed.
git clone https://github.com/Alberto-Codes/saucier
cd saucier && git checkout v0.5.0
uv sync && uv run saucier parse
uv run saucier export | uv run saucier import --check
uv run saucier export | head -n -1 | uv run saucier import --check
0.5.0 (2026-09-04)
Features
- adapters: stream catalogues as versioned jsonl (d0ede9d)
v0.4.0
The rule that decides what counts as a sauce had two tests, and the second
could overrule the first. It vetoed 27 entries Escoffier filed in his own
sauce chapters — half glaze and the three roux among them — and two earlier
posts explained the resulting gap as something the book never wrote down.
Entry 23, line 1437, writes it down. This release deletes the clause.
The book spells it out at line 1437. Two of my posts said it never did.
The state this tag represents
escoffier-1909 151 sauces, 57 derived, 94 unresolved
escoffier-1907 140 sauces, 50 derived, 90 unresolved
diff 11 unmatched, 19 parent-changed, 36 ocr-suspected
blind spot 284 entries of the scan the parser cannot yet read
Derived rose by seven, and the seven is three numbers: twelve sauces gained
the parent Escoffier wrote, five admitted entries state one, and ten sauces
resolved at v0.3.0 are unresolved now, on purpose. Cardinal states Béchamel
and lobster butter; the resolver reads names, cannot tell a base from a
finish, and refuses. saucier show prints the candidates it saw beside every
refusal. A preparation is now identified by the line its heading sits on, not
its entry number, which the scan reads twice. See
ADR-0015.
Run it
No GPU, no API key, no database, no network. Both source texts are committed.
git clone https://github.com/Alberto-Codes/saucier
cd saucier && git checkout v0.4.0
uv sync && uv run saucier parse
uv run saucier show cardinal-sauce
uv run saucier tree espagnole
0.4.0 (2026-09-04)
⚠ BREAKING CHANGES
- extraction:
is_saucetakes the title and the chapter test only. The mothers no longer take part in admission.
Features
- extraction: admit an entry on the sauce chapter alone (1fdca5d)
Fixes
- extraction: identify a preparation by its line, not its number (228ecc6)
Documentation
v0.3.0
Post three of the saucier series. A second witness of Escoffier enters the
corpus — the 1907 first printing, photographed and machine-read by the
Internet Archive — and the diff between the two printings produces no facts
about cookery and four classes of fact about the instruments. The number of
sauces the revision supposedly added went twenty, then eight, then none,
each round caught by a person reading output.
I added a second copy of the same book. It told me nothing about the book.
The state this tag represents
escoffier-1909 124 sauces, 50 derived, 74 unresolved
escoffier-1907 115 sauces, 36 derived, 79 unresolved
diff 9 unmatched, 18 parent-changed, 35 ocr-suspected
blind spot 284 entries of the scan the parser cannot yet read
The identifier every previous release printed, escoffier-1907, named the
January 1909 revision all along — its own title page says so. That name now
belongs to the actual 1907 printing, which is the breaking change below. The
counts v0.1.0 and v0.2.0 published are unaffected and still reproduce at
their tags. No diff row is adjudicated: an unmatched row says the diff
found no counterpart, never that the printing lacks one. See
ADR-0013 and
ADR-0014.
Run it
No GPU, no API key, no database, no network. Both source texts are committed.
git clone https://github.com/Alberto-Codes/saucier
cd saucier && git checkout v0.3.0
uv sync && uv run saucier parse
uv run saucier diff escoffier-1907 escoffier-1909
0.3.0 (2026-09-02)
⚠ BREAKING CHANGES
- source:
escoffier-1907now names the 1907 first printing. The catalogue the previous releases published isescoffier-1909.SourceRefgains a requiredfidelity,Cataloguetakes awitnessin place of asource_id,SourceTextreports awitnessin place of asource_id, andescoffier_sourcebecomesescoffier_sources.
Features
- source: read the edition, add the 1907 witness, and diff the two (84eb851)
Fixes
- adapters: mend the entry separator a scanner broke (2abc8d2)
- adapters: mend two more separator shapes the scan uses (387123d)
- extraction: read a wrapped heading whole (5811100)
- services: compare the derivations pairing hid (c0f6e81)
- services: stop claiming a book lacks what the scan hid (d78614d)
Documentation
v0.2.0
Post two of the saucier series. A preparation's parent may now be any
catalogued preparation, not only one of the five mothers. Still no model:
a deterministic resolver reads the statement out of the opening paragraph,
and every new derivation quotes a name the source wrote.
Marrow Sauce finally has a parent. The parser gave up three answers to earn it.
The state this tag represents
sauces 124
derived 50 linked to a stated parent
unresolved 74 state no base in their prose
Derived moves from 29 to 50. The resolver adds 24 derivations and dissolves
three the old rule recorded, one of them caught in peer review. Bordelaise
stays unresolved on purpose. Its opening names half-glaze and never
Espagnole, and a term that encodes a derivation is not a statement of one.
That entry is the bar the eventual model measures against. See
ADR-0008.
Run it
No GPU, no API key, no database, no network. The source text is committed.
git clone https://github.com/Alberto-Codes/saucier
cd saucier && git checkout v0.2.0
uv sync && uv run saucier parse
uv run saucier tree bordelaise
v0.1.0
Post one of the saucier series. A deterministic parser reads Escoffier's A
Guide to Modern Cookery (1907) and returns a catalogue of sauce preparations,
each traceable to a line you can open.
There is no model in this parser. It still told me ice cream was a
sauce.
The state this tag represents
sauces 124
derived 29 linked to a mother
unresolved 95 state no base in their prose
95 is the number to judge this by. Escoffier wrote for a reader who already
knew what a Bordelaise is built on, so he did not write it down. That gap is a
fact about the source rather than a shortfall in the parser, and it is the
measured bar a model has to beat.
An earlier version of this census said 166 and 64. Roughly forty of those were
not sauces: velouté soups, tomato jam, and a vanilla ice cream, all admitted by
a substring test. Thirty of the 64 derivations hung off them. The rule now
reads the chapters Escoffier titles as sauces, and an entry naming two mothers
resolves to neither. See
ADR-0007.
Run it
No GPU, no API key, no database, no network. The source text is committed.
$ git clone https://github.com/Alberto-Codes/saucier
$ cd saucier && uv sync
$ uv run saucier parse
$ uv run saucier tree espagnole
$ uv run saucier show bordelaiseEvery claim carries an entry and a line number in the file on disk:
$ sed -n '1680p' corpus/escoffier-1907.txt
32—SAUCE BORDELAISEBreaking
v0.0.1 reserved the name and carried no working parser, so nothing depended
on this surface. The changelog below lists the API changes in full.
0.1.0 (2026-08-20)
⚠ BREAKING CHANGES
- extraction:
SourceTextimplementations must provideline_offset.CatalogueStore.savereturns the destination.Term.ofis removed,SourceRefis keyword-only, andPreparation.parenthas no default. Recorded line numbers changed by the licence header offset.
Features
- ci: cut releases as drafts, with a pre-flight checklist (a8a7272)
- docs: cite the source and the language standard (c24ddf0)
- docs: draw the pipeline and the release flow (57d9d21)
- docs: give the site a frame that later pages inherit (935ce8e)
- docs: publish the site to GitHub Pages from the docstrings (cff3d1f)
- docs: rebuild the site around the citation, not the hero (5f22281)
- gates: enforce the glossary and the writing system (27cf0f9)
- v01: read Escoffier into a traceable sauce catalogue (555ff5e)
Fixes
- ci: answer the CodeQL findings, and stop one from recurring (d3b6847)
- ci: keep every recorded version in step through a release (bea908c)
- ci: make the docvet gate check files (c46dc3b)
- ci: replace uv-secure with the audit built into uv (ae52b40)
- docs: correct the release diagram and gate the published counts (81a23a0)
- docs: render mermaid on the site too (3f8e4cc)
- extraction: read what counts as a sauce from the source (06d43b8)
- gates: stop the gate scripts reporting success on nothing (6330c18)
- repo: base the ignore file on the canonical Python template (72249fd)
- repo: stop tracking the coverage database (8436b74)