Skip to content

refactor(logging): the log escape table restated the control alphabet (BACKLOG #1273, limb 3) - #589

Merged
wshallwshall merged 5 commits into
mainfrom
claude/builder-2-1273-controlchars
Aug 25, 2026
Merged

refactor(logging): the log escape table restated the control alphabet (BACKLOG #1273, limb 3)#589
wshallwshall merged 5 commits into
mainfrom
claude/builder-2-1273-controlchars

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

logging_setup.py re-derived the C0+DEL control-character set as range(0x20) plus a separate 0x7F line, duplicating what controlchars already states once. The two agreed, so nothing was mis-escaped -- the cost was that a later widening applied to one copy wouldn't silently reach the other. Now expressed as the shared alphabet minus TAB. docs/BACKLOG.md untouched.

No behavior change, proved by byte-identity rather than asserted: the translation table compared entry-for-entry against the pre-change table -- identical, 32 entries both sides. mypy strict clean across all 267 source files.

Worth a reviewer's eye: the first version used range(0x80) -- both bounds give identical results today, so every check would have passed. But _is_control_char's docstring names widening to C1 as the deliberate change the shared module exists to make cheap, and an 0x80 bound would silently not follow it -- the escape table would keep the old alphabet while every other call site moved, exactly the drift this limb removes. Changed to range(0x100) and demonstrated, not argued: under a simulated C1 widening the table goes 32 -> 64 entries and 0x85 becomes escaped; restored, back to 32. The cosmetic fix and the real one are indistinguishable by the test suite today.

Mutation-proved, three single-point mutants with distinct red sets: dropping the tab subtraction reds 3 tests; re-hardcoding as _i < 0x20 reds 2 (0x7F screened but not escaped -- restores the exact two-copy drift being removed); disabling the LF escape reds 3, including a pre-existing CRLF-scrub test (confirms existing coverage survives rather than being replaced).

One citation flagged rather than silently fixed: the row names tests/test_logging_setup.py, which doesn't exist -- the module is tests/test_logging.py. Noted in case the row's other claims share the same care.

Verification, explicitly scoped: pytest -k "logging or controlchar", 161 passed / 3 skipped; the two named modules directly, 95 passed. ruff/mypy strict clean. Full suite not run.

… (BACKLOG #1273, limb 3)

`controlchars` exists to state the C0+DEL test once. `logging_setup` then re-derived the
same set as `range(0x20)` plus a separate `0x7F` line -- a second statement of the alphabet
in the module that module was written to eliminate.

The two agreed, so nothing was mis-escaped. The cost is the future-tense one #1239 named and
#1253 acted on: a later widening applied to one copy silently does not apply to the other,
and nothing reports the omission.

Now the table is `_is_control_char`'s alphabet MINUS TAB, with the subtraction written as
one.

MEASURED FIRST, because the row's framing turns on it: controlchars screens 33 code points,
the table escaped 32, and the symmetric difference is exactly {0x09}. Controls: 0x00 in
both, 'A' in neither, C1 excluded from controlchars.

"JUST DOCUMENT IT AS EXCLUDED" IS REFUTED, and the residual block on the row says why. The
`parsing/sniff.py` carve-out earns its separate definition by being BYTE-wise and subtracting
a whole allowlist. This is CHARACTER-wise, escapes CR/LF rather than tolerating them, and
differs by ONE code point. One code point of divergence is a subtraction, not a different
predicate.

RANGE 0x100, NOT 0x80, AND THAT IS THE DIFFERENCE BETWEEN A REAL FOLD AND A COSMETIC ONE. I
wrote 0x80 first. Both bounds give the identical 32 entries today, so no test would have
caught it -- but `_is_control_char`'s own docstring names widening to C1 as the deliberate
change this shared module exists to make cheap, and a 0x80 bound would silently NOT follow
it. The escape table would keep the old alphabet while every other call site moved, which is
the exact drift limb 3 removes. Demonstrated rather than argued: with a simulated C1
widening the table goes 32 -> 64 entries and 0x85 becomes escaped; restored, it returns to 32.

NO BEHAVIOUR CHANGE, AND THAT IS MY MEASUREMENT RATHER THAN THE ROW'S. The verification pass
did not run the tests and flagged that it had not. Byte-identity: the translation table is
compared entry-for-entry against the pre-change table and is IDENTICAL, 32 entries both
sides. `messagefoundry.logging_setup` and `messagefoundry.controlchars` both import clean --
controlchars is a leaf, so no cycle, checked by import rather than assumed.

MUTATION-PROVED, three single-point mutants, each asserting a unique anchor and a changed
file hash before scoring:

    A  drop the tab subtraction        3 red  relationship, tab, and the real-scrub test
    B  re-hardcode as `_i < 0x20`      2 red  relationship and tab -- 0x7F screened, not escaped
    C  stop protecting the LF escape   3 red  INCLUDING a pre-existing CRLF-scrub test

Three distinct red sets. B is the one that matters: it restores exactly the two-copy drift
this limb removes, and the relationship test names the code point that diverged. C reding
`test_configure_stderr_logging_redacts_phi_and_scrubs_crlf` shows existing coverage is intact
rather than replaced.

The new tests pin the RELATIONSHIP, not either set's contents. `alphabet - escaped == {0x09}`
survives a deliberate widening untouched, where an entry count would have to be edited by the
very person who should be told instead.

A CITATION IN THE ROW DOES NOT RESOLVE: it names `tests/test_logging_setup.py`, which does not
exist. The module is `tests/test_logging.py`. Flagged rather than silently redirected.

Verification, with scope: `pytest -k "logging or controlchar"` 161 passed / 3 skipped, and
tests/test_logging.py + tests/test_controlchars.py 95 passed, on .venv/Scripts/python.exe
(CPython 3.14.6 non-freethreaded, seven CI extras). ruff 0.15.22 (== the constraints.lock pin)
check and format --check clean. mypy strict clean over all 267 source files. NOT the full suite.

No test was removed or weakened. The ledger row is not mine to author and is not in this
commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@wshallwshall
wshallwshall enabled auto-merge (squash) August 25, 2026 18:41
wshallwshall and others added 4 commits August 25, 2026 13:59
…ays open

logging_setup.py now imports controlchars and states its own table as that
alphabet minus TAB, proved byte-identical to the pre-change table
entry-for-entry rather than asserted. Verified before writing this note.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@wshallwshall
wshallwshall merged commit 41db720 into main Aug 25, 2026
39 of 40 checks passed
@wshallwshall
wshallwshall deleted the claude/builder-2-1273-controlchars branch August 25, 2026 23:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant