refactor(logging): the log escape table restated the control alphabet (BACKLOG #1273, limb 3) - #589
Merged
Merged
Conversation
… (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
enabled auto-merge (squash)
August 25, 2026 18:41
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
logging_setup.pyre-derived the C0+DEL control-character set asrange(0x20)plus a separate0x7Fline, duplicating whatcontrolcharsalready 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 torange(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 < 0x20reds 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 istests/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.