Commit aacaa01
committed
chore(scripts): the raw-byte gate scans the whole C0 control set, not only NUL (#5157)
`check:nul-bytes` shipped from #4890 scanning 0x00 alone, because 0x00 was the
byte whose harm its own failure message could prove: a raw NUL makes grep and
ripgrep classify the whole file as binary and silently return zero matches.
Measured, that argument really is NUL-specific — GNU grep 3.11 and ripgrep 14.1
report "binary file matches" for a file carrying 0x00 and keep matching normally
for one carrying 0x01 or 0x03 — so this change is not that argument extended by
assertion. It is a second harm that lands on the whole C0 set.
The other C0 controls render as NOTHING wherever a human reads the code. Both
specimens this commit removed from the tree read as an empty string while being
load-bearing:
const key = keyParts.join('<0x01>'); // shows as: keyParts.join('')
return `${object}<0x01>${recordId}`; // shows as: plain concatenation
grep prints the match, the diff prints the line, and review sees `join('')` — an
obviously pointless call a later reader is invited to delete, or a separator-less
composite key a later reader is invited to "fix". Code that lies to every reader
is worse than code grep cannot find, because nothing signals a second reading
exists. Nor can the author search for it: not the escape text (the file holds a
byte) and not the byte (nobody can type it). And the accident source does not
pick byte values — every occurrence in this repo came from an editing tool
materialising an escape while someone wrote ABOUT the byte (#4763, #4890, and
PR #5140, where the caught NUL was fixed and a 0x01 fourteen bytes away was not).
Scanned set is now `[\x00-\x08\x0b\x0c\x0e-\x1f]`: the C0 range minus tab, LF and
CR — the pattern #4890's own manual sweep used before the gate narrowed to NUL.
The binary probe widens with it, and that step is load-bearing rather than
cosmetic tidiness. A control byte CAN break an otherwise-valid multi-byte
sequence: `E4 B8 01 AD` is 中 with a 0x01 spliced into it, and stripping only NUL
leaves that undecodable, so the file is skipped as binary and the 0x01 becomes
its own alibi — the exact circularity this gate exists to break, one byte value
over. Widening cannot err the other way: every scanned byte is <= 0x1f while
valid UTF-8 multi-byte sequences are built only from bytes >= 0x80. Measured over
all 5448 tracked paths, the widened stripping moves zero files between text and
binary.
Six raw control bytes already in the tree are escaped here; the NUL-only gate was
green over all of them. `login.ts` / `register.ts` carried a 0x03 Ctrl+C case
label, `cross-object-rebucket.ts` a 0x01 bucket-key separator (in the comment and
in the `join`), `verify-file-references.ts` two 0x01 in `slotKey`. Escaped
strings are byte-identical at runtime, so no behaviour changes and nothing ships.
The script and its `pnpm check:nul-bytes` command keep their historical names:
those strings are referenced from CI, from other gates' comments and from agent
instruction files, several owned by other in-flight work, and a rename buys a
more accurate name at the price of a half-applied one. The widened semantics are
stated in the script header, the failure message and the CI step instead.
`--self-test` goes 16 -> 34 assertions. The new ones pin the widening in both
directions: every new specimen file contains no NUL anywhere, so the pre-#5157
`buf.indexOf(0)` scan had nothing to find, and reverting the widening turns the
self-test red with 8 failures rather than leaving it quietly green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GX3sL71LFq8m2usg6VqTSE1 parent 01c0bae commit aacaa01
7 files changed
Lines changed: 316 additions & 73 deletions
File tree
- .changeset
- .github/workflows
- packages
- cli/src/commands
- services
- service-analytics/src/strategies
- service-storage/src
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
87 | 98 | | |
88 | 99 | | |
89 | 100 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
| 34 | + | |
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
118 | 118 | | |
119 | 119 | | |
120 | 120 | | |
121 | | - | |
| 121 | + | |
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
| |||
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
131 | | - | |
| 131 | + | |
132 | 132 | | |
133 | 133 | | |
134 | 134 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
107 | | - | |
| 107 | + | |
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
| |||
0 commit comments