#!/usr/bin/env python3 """Normalisation map for `tarbuckle-rejects.jsonl` `why` values. REVIEWED-136 condition A. Fixed and recorded BEFORE the fortnight read, because after REVIEWED-128 condition 2 deletes the corpus this map is the only thing that makes the banked tallies auditable. ⚠ WHY THIS EXISTS. `why` is not content-free by construction. `echoes_soul()` returns `sorted(hit)[0]` — a literal n-gram lifted from the suppressed line, at a 4-word threshold against the sample lines and a 6-word threshold against the soul's prose. Every recital-class reason therefore embeds verbatim text of a line that was never uttered. Normalisation for that class is UNCONDITIONAL and discards the payload; it is not applied on inspection of the values that happen to be present, because the next recital rejection written would leak again. """ import re RE_WORDS = re.compile(r"^(\d+) words$") RE_RECITAL = re.compile(r"^recited the soul: '.*'$", re.S) RE_BANNED = re.compile(r"^banned \\b(\w+)\\b$") def normalise(why: str): """(category, payload) or None if the shape is unknown. Returning None on an unknown shape is the point: a classifier that absorbs everything reports zero residue vacuously. """ if why is None: return None m = RE_WORDS.match(why) if m: # A count is content-free: it says how long the line was, never what it said. return ("word-count", int(m.group(1))) if RE_RECITAL.match(why): # PAYLOAD DISCARDED. The fragment is the suppressed line, verbatim. return ("recital", None) m = RE_BANNED.match(why) if m: # ⚠ THE ONE JUDGMENT IN THIS MAP, AND THE EXECUTOR DOES NOT MAKE IT. # The token is a member of a fixed ban list — a property of the RULE that # fired, not a distinctive phrase composed by the line. Retained on that # reading. Condition A scopes unconditional normalisation to the recital # class and does not reach this one. Flagged for the jurist: if the # reading is rejected, change the payload below to None and re-bank. return ("banned-token", m.group(1)) return None def selftest() -> bool: ck = lambda name, ok: (print((" ok " if ok else " FAIL ") + name), ok)[1] r = [] # must-classify — every shape observed in the corpus r.append(ck("14 words -> word-count/14", normalise("14 words") == ("word-count", 14))) r.append(ck("196 words -> word-count/196", normalise("196 words") == ("word-count", 196))) r.append(ck("banned -> banned-token/must", normalise(r"banned \bmust\b") == ("banned-token", "must"))) r.append(ck("recital -> recital/None", normalise("recited the soul: 'a b c d'") == ("recital", None))) # must-DISCARD — the payload may never carry the fragment through got = normalise("recited the soul: 'is standing about here'") r.append(ck("recital payload is discarded, not passed through", got == ("recital", None))) r.append(ck("recital fragment absent from repr(result)", "standing" not in repr(got))) # must-NOT-classify — without this, residue 0 is vacuous r.append(ck("unknown shape -> None", normalise("something nobody wrote") is None)) r.append(ck("empty -> None", normalise("") is None)) r.append(ck("None -> None", normalise(None) is None)) r.append(ck("near-miss 'words' plural bare -> None", normalise("words") is None)) r.append(ck("near-miss unanchored -> None", normalise("about 14 words long") is None)) return all(r) if __name__ == "__main__": import sys print("normalise.py selftest") sys.exit(0 if selftest() else 1)