Files
esh-pfi-infrastructure/persistent-memory.d/2026-09-17-mccarthy-split-name-leak.md
T

96 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `[2026-09-17]` The leak gate passed with five protagonist names still in every copy
Found during D4 pre-flight, three stages downstream of where it happened. Commit `c559664`.
```
leak gate, 2026-09-17 morning 0 of 75 renameable, 0 of 37 sub-threshold, both controls green
actually present, all 6 copies Bell x2 Chigurh x3 Moss x2 Toadvine x4 Glanton x2
```
## The mechanism
`leak_gate.py` scans `\b(Surface)\b`. **A character inserted inside a name defeats that
pattern outright**, so a mangled occurrence is not merely unrepaired — it is *unrenameable*
by `rename.py` and *unreportable* by the gate, and the gate prints a clean zero over it.
Two extraction artifacts produce exactly that:
```
B ell C higurh M oss T oadvine a small-caps drop cap kept as its own token
Toad-vine Glan-ton a print line-break hyphen kept by the extractor
```
⭐ **Every VISIBLE occurrence had been renamed correctly** — exact-match survivors were 0,
as the gate said. That is what makes this residue invisible to a spot-read: the names are
gone everywhere you look. `Bell` sits in the entity map at 147 capitals, `Glanton` at 365.
This is the third member of a family. lv-bronte's was `_Antigua_` (`_` is a word character,
so `\bAntigua\b` cannot match inside it), found by hand in 2026-09-16 and never generalised.
**The generalisation is the point: any separator inside a name blinds a word-boundary scan.**
## Fixed at three levels, and all three must stay
1. **`build_corpus_mccarthy.py` rules 4 and 5** repair the source text — 32 split initials
with a *lowercase* remainder (rule 1 requires a following ALL-CAPS word and DROPCAP
requires two, so this is the class both leave behind), 5 hyphen-split names by name.
Both carry expected counts so a master change fails the build.
⚠ **Rule 4's letter class is consonants only.** `I` opens **1,966** paragraphs (the
pronoun), `A` opens 143 (the article), `Y` opens 32 (Spanish *y*). Folding any of them
would corrupt 2,141 lines to fix 32 — the same `I`/`A` trap that bit `audit_stoplist.py`.
2. **`leak_gate.py` runs a separator-tolerant pass every time**, with its own positive and
negative controls, and **it fails the gate**. Validated against the pre-fix tree: reports
all five surfaces, exits 1.
3. The exact-match passes are untouched, so the old verdict is reproduced alongside the new.
⚠ **The fragment filter is what makes the new pass usable.** A naive separator-tolerant
scan is dominated by false positives — on Hemingway it returns 21 hits of which **18 are
ordinary text** (`God damn` for the surface `Goddamn` ×14, plus `I run`, `On an`, `Do me`,
`Si le`). The discriminator, with no dictionary: in a genuine split at least one FRAGMENT
is not a word of this corpus. `God` and `damn` occur constantly; `Primi`, `tivo`, `ell`,
`higurh`, `Toad` do not. That one test cleared all 18 and kept all 3 real ones.
⚠ **My first negative control could not pass.** It planted the split nonce in its own probe
text and then asserted the nonce was absent — an alarm wired to itself, failing on every
run. It now hunts the split nonce in the *real* copies. A control that cannot pass is not a
control.
## The shipped corpora, checked with the committed instrument
```
lv-bronte clean of this class (`English women` vs `Englishwomen` is a false positive)
lv-hemingway 3 real: `Primi tivo`, `Pasionar ia`, `Chi cote` — SHIPPED and LIVE
```
**Operator call outstanding** on whether 3 occurrences in 958k words warrant re-gating a
live adapter. Not acted on.
## The chain was recovered, not remembered — and is now written down
There was **no McCarthy runbook**, and the D1→D3 session issued its commands over
non-interactive ssh so no shell history survived. The chain was recovered by rebuilding
candidates and matching sha256 against the artifacts on disk, then pinned:
```
D1 build_corpus_mccarthy.py 6 works byte-identical
D2 entities.py --min-count 5 --fold-clitics --drop-acronyms --min-mid-ratio 0.2 --min-mid 2
D2c apply_gender_overrides.py entities-final.json byte-identical
D3 rename.py --preset mccarthy --scope corpus --min-cap 5 --copies 6 --seed 4919
--holdout-chapter 7 17 all 36 copy files byte-identical
```
⚠ `--min-mid-ratio` is what keeps `Yeah`/`Buenas`/`Shh`/`Sí` out of the map. The map is
**insensitive** to it: any value in [0.05, 0.3] with `--min-mid` 1 or 2 reproduces byte-for-
byte; `--min-mid 3` does not. The original values are unrecoverable and it does not matter —
which is worth saying, because an exact-looking recipe that was never pinned invites a
false claim of reproduction. Full recipe and every deviation: `scripts/mccarthy-corpus/RUNBOOK.md`.
⚠ **D1 must run on nh3-dev** — the builder reads the kvasir catalogue by absolute path and
gx10 has no copy. The previous session's "on gx10" note is true of D2 onward only.
⚠ **No phrase map exists for this corpus**, so the gate's phrase audit does not run at all.
Yarros and Brontë both had one. Not closed.
Rollback: `~/lv-mccarthy/corpus-{clean,renamed}.pre-splitfix` on gx10.
Related: [[2026-09-17-mccarthy-d1-d3]], [[2026-09-17-beat-contamination-leak]],
[[2026-09-17-lv-hemingway-gate]], [[2026-09-17-lv-bronte-gate]].