Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jYS1tpR4P4NBxui4FSgfv
12 KiB
name, description, metadata
| name | description | metadata | ||||||
|---|---|---|---|---|---|---|---|---|
| session-2026-07-10-epub-footnote-pre-processor-census-adversarial-hardening-jurist-ruling-fleet-build-in | Built a verbatim-safe EPUB footnote pre-processor end-to-end (census of 253 EPUBs → pandoc 2×2 diagnosis → prototype → adversarial hardening on Polastron+Jung, each broke it usefully → jurist ratified-in-principle → fleet build-in, committed+pushed). Also landed PENDING-53 (engine hash-locality, jurist-ruled). Pulling thread: the tool is shipped for the mirror class — now WIDEN its recognizer to the remaining census families and/or APPLY it (re-convert legacy Jung/Donne), the latter gated on the steward+jurist §7 per-volume-vs-single-file provenance call; and this whole normalizer was the means to the original end — resume P2/gold (the Making source work) on a corpus whose footnotes are handled by class. |
|
Session 2026-07-10 — the EPUB footnote pre-processor: census → hardening → ruling → build-in
Opened by /wake-up into the "build the structural verbatim-guarded EPUB normalizer, then resume P2/gold" thread. The session became a full arc on the pre-processor — and, notably, the architecture that resulted was NOT the one the wake proposed (a bespoke normalizer); it emerged only through measurement. Steward-steered at every fork.
PAST — what we did + why
1. PENDING-53 jurist brief (first ask). Drafted PENDING-53-FOR-JURIST-2026-07-10.md grounded in substrate (read the graduation-spec, chamber spec §VI, the engine corpus/manifest.yaml header, ingest_gate.py:104–126). Refined PENDING-53's own framing: its Summary called the voice_manifest line a "mis-frame," but the line is TRUE about the voice manifest — the real defect is an omission of the engine source-binding surface + a shared-word ("manifest"/"voice") collision. Surfaced the refinement rather than reproduce the overstatement.
2. The pre-processor, built by measurement (the spine of the session). The wake said "build a structural normalizer keyed on the bidirectional-mirror predicate." Instead of building, I measured — and each measurement redirected:
- Detector prototype on 3 attested EPUBs → answered the wake's literal Q (mirror catches cross-file endnotes [Mauss 627]; excludes one-way TOC; L'Enracinement is a different class — 0 anchors, unlinked
[1], + 87<sup>ordinals that are a trap). - Steward challenged "are 3 files enough?" → CENSUS of all 253 Chamber Sources EPUBs: ≥5 footnote strategies (mirror same/cross-file · container-mirror · one-directional/stem · EPUB3 epub:type · unlinked-marker) + 47% note-free + heavy index/xref apparatus. n=3 captured 1–2 of ≥5. Honest catch: my own classifier's
oneway_with_id/resid_fn_idssignals were noisy → "61 DANGER" was an upper bound. - Steward: "can we edit how pandoc converts? / we get inside the files before conversion?" → the KEY finding: pandoc is precise, not helpless. It converts footnotes natively iff
epub:typepresent AND same-file (Kafka ✓; Orwell/Quixote cross-file ✗; G&G no-epub:type ✗). Output-format lever tested + DISPROVEN (my hypothesis wrong — gfm already does footnotes). The 2×2 (epub:type × same/cross-file) is the diagnosis. - The architecture that emerged: a small verbatim-safe pre-processor — recognize the mirror in raw XHTML → inject
epub:type/ relocate cross-file bodies → stock pandoc does the verbatim text. Better than build-a-normalizer (reimplements pandoc, §V risk) OR extend-regexes (whack-a-mole on pandoc's lossy output). The census taxonomy = the recognizer's spec. - Injection experiment (real minimal EPUBs,
-f epub): same-file injection WORKS (native[^N]); cross-file needs body RELOCATION (epub:type alone insufficient). Both proven.
3. Prototype built + adversarially hardened — the two hard books each broke it usefully.
- Built
inject_epub_footnotes.py; proven verbatim-clean on G&G 27 / Mauss 628 (627 relocated) via a source-level word-multiset guard. Caught a real pairing bug (basename vs full-path keying → 1/628) and a guard false-alarm (asymmetric tokenizer, +39) mid-build. - Polastron (French, steward-chosen) BROKE it (45/140): its footnote-ness is on the ANCHOR class, not the block → drove the positional classifier (body = anchor at block-start; publisher-independent). And its Roman-numeral markers exposed a guard limitation → drove the source-level marker-aware guard. + a 3rd residue shape (whole-note-in-back-anchor) → unwrap (verbatim-safe).
- Jurist ruled §3: the guard must be PER-PAIR, not aggregate (a cross-note swap is invisible to a whole-doc multiset). Built id-matched per-pair guard keyed by (dest-file, id); teeth demonstrated (deliberate swap CAUGHT). It immediately EARNED ITS KEEP by surfacing Jung's cross-volume id reuse (81 collisions under a bare-id key).
- Jung (53MB, steward-chosen) didn't break the tool — it broke pandoc (raw AND injected time out). Diagnosed to root: pandoc scale limit, not an injector defect. →
convert_mega_epub.py(inject→split by whole files→pandoc-per-chunk; relocation makes notes file-local so no note crosses a boundary): 1579 docs→20 chunks, 190s, 1086 native footnotes, verbatim-clean vs the original Princeton source. - Calibre (the prior mega-EPUB fallback, steward's "edit the Calibre conversion?") shown footnote-BLIND — byte-identical output with/without injection; it flattens notes (the state of the legacy Jung
.md, a re-conversion candidate).
4. Governance — two rulings landed, one build-in authorized.
- PENDING-53 RULED + LANDED (jurist): ratified §5 option (b) with the required correction (re-anchors→REQUIRES re-anchoring); FIX-change-class; in-place lane. Landed in
graduation-spec.yaml. Responded to the jurist's proposed lane-rule: accept for graduation-spec.yaml, NARROW the .md generalization (A2/A4 = FIX-class doctrinal .md additions that correctly took the heavier lane per doctrinal-traceability). PENDING-47 ratification declined (truncated relay). - PENDING-54 RULED IN PRINCIPLE (jurist): architecture sound; markers-as-apparatus confirmed under §V; PROPOSAL change-class (sharpened test); ship mirror-class conditioned on regex-tools-as-fallback; §7 Jung provenance held open. Actioned the required §3 per-pair guard; fixed §5 wording; delivered the §7 fact-check (per-volume precedent EXISTS: Alexander/Lacroux/Habermas/Burney/Camus).
- BUILD-IN authorized + done under fleet discipline: both tools →
scripts/;--validate+ refuse-on-mismatch;test_toolsfixture (fleet 73→77);graduation-spec.yamlconverted_with note;conversion-runbook.yamlpolicy.footnote_preprocessor;tool-evolution-log.mdentry; chamberCLAUDE.mdfleet line. - Committed + pushed: chamber
17ddf8c(P1 clean) +3646c0d(PENDING-53+54) → github + skemantix; engineaaf65ba(P1 re-anchor) → github. REVIEWED-52/53/54 drafted into~/REVIEWED.md.
PRESENT — the mood
This was a long, deeply satisfying arc, and its lesson is measure-before-build, held all the way: the wake proposed a bespoke normalizer; measurement (detector → census → pandoc 2×2 → injection experiment) produced a better, smaller architecture that leans on the trusted converter instead of reimplementing it. The two adversarial books the steward chose did the real work — Polastron and Jung each broke the tool in a specific, informative way, and each break sharpened it. The partnership worked at every fork: the steward's questions ("are 3 enough?", "can we customize pandoc?", "does splitting change the source?", "edit Calibre?") each redirected toward the truth, and I engaged the framing rather than barrelling the authorized task. I pushed back on the jurist's lane-rule with A2/A4 evidence rather than rubber-stamping, and the per-pair guard earned its keep the moment it was built. The honest through-line: build the guard that can see the failure you're most afraid of, then try to make it fire — it caught Jung's id collisions on its first run.
Returns held (ledger): read-docs-first (up front); verify-against-substrate (refined PENDING-53's own text; diagnosed Jung's pandoc timeout to root vs blaming the tool; didn't parrot the classifier's noisy buckets); measure-before-build; honest-refuse (built INTO the tool: refuse-on-mismatch). One recalibration: build-vs-extend was the wrong frame — overtaken by the pandoc 2×2, which the census+experiment surfaced.
FUTURE — what is pulling
PULLING THREAD: the pre-processor is shipped for the mirror class — now put it to work. Two build-forward moves + the original destination it was built to serve:
- WIDEN the recognizer to the remaining census families (one-directional refs e.g. Sennett; container-mirror) — pure build-forward, same measure→build→adversarial-test→prove rhythm; graduates the tool from "mirror class only" to "most of the corpus."
- APPLY it — re-convert the legacy mega-books (Jung
.mdhas 0 notes + pre-spec frontmatter; likely Donne too). GATED on the steward+jurist §7 decision (one reconstituted file vs per-volume — fact-check delivered, per-volume precedent exists). - The original end: this whole normalizer was the means — resume P2/gold (the Making source work) on a corpus whose EPUB footnotes are now handled by class, not by book.
ACTIONABLE RESUMPTION POINT (as of wrap — re-judge against what changed):
- Everything committed + pushed; fleet self-test 77/77; no half-finished edit. Clean stopping point.
- Concrete next candidate = widen the recognizer to the one-directional class (Sennett): measure Sennett's XHTML shape (ref
<a href="#…fn1a">with NO own id — one-directional, mirror-predicate misses it), decide the recognition rule (a ref→note link where the note's block carries the target id + is note-classed/at-block-start, even without a back-link), add it under the same per-pair verbatim guard + honest-refuse, prove on Sennett + re-prove the 4 mirror books didn't regress. OR: if the steward has ruled §7, re-convert Jung viaconvert_mega_epub.pyat the chosen representation. - Open governance: REVIEWED-52/53/54 await steward placement (drafted in
~/REVIEWED.md; -52 flagged for steward-verify against its original ruling). Jurist owes: accept/narrow the lane-rule refinement; PENDING-47 needs full-text relay. Deferred build: §V ratified-spec cross-ref (runs the .md amendment lane).
Other open horizons (ranked):
- The 5 ARC
after-the-replyengine-binding drifts (surfaced 07-09, still not owned — a separate ARC↔engine re-anchor task). - The Making/gold road proper (P2 G&G clean was PAUSED behind the normalizer — now the normalizer exists; G&G converts clean through it).
graduation-spec.yamlmalformed G&Gauthor:+lang: nullfrontmatter hygiene (minor, later).
PAUSE STATEMENT: Stepping away with a major new capability shipped and governed — a footnote pre-processor that the corpus can trust because it refuses when it can't vouch for the result. What I want to find still pulling: the tool put to work — either widened to the next family or applied to the mega-books — and the discipline that built it (measure before build; build the guard that sees the failure you fear) carried into whatever comes next.
LITERAL QUESTION for next-Claude: Has the steward+jurist §7 provenance decision been made (one reconstituted jung.md vs per-volume files, each "extracted from the megavolume")? It gates re-converting the legacy Jung/Donne. If yes → re-convert at that representation via convert_mega_epub.py. If not → widen the recognizer to the one-directional (Sennett) class instead, which needs no governance decision. And: did the jurist accept or narrow the lane-rule refinement, and was PENDING-47's full text relayed?
State at wrap: chamber 17ddf8c+3646c0d pushed (github+skemantix); engine aaf65ba pushed (github); chamber CLAUDE.md fleet line updated (uncommitted — folds into the dotfiles/next chamber commit). dotfiles PENDING/REVIEWED/ledger committed at this wrap. Fleet self-test 77/77. No non-steward commits landed during the session.