From 1c4de99838b2058bb2e1ccfe40aec076f3fd2fd4 Mon Sep 17 00:00:00 2001 From: os-zhuang Date: Wed, 5 Aug 2026 21:30:56 +0000 Subject: [PATCH] =?UTF-8?q?docs(os-dev):=20=E3=80=8CByte=20discipline?= =?UTF-8?q?=E3=80=8D=E6=AE=B5=E7=9A=84=20binary-file=20=E5=8D=B1=E5=AE=B3?= =?UTF-8?q?=E7=82=B9=E5=90=8D=20NUL,=E5=85=B6=E4=BD=99=E5=AD=97=E8=8A=82?= =?UTF-8?q?=E6=94=B9=E5=BC=95=E9=97=A8=E7=A6=81=E8=84=9A=E6=9C=AC=E5=A4=B4?= =?UTF-8?q?=E7=9A=84=E4=B8=89=E6=9D=A1=20(#5579)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 该段给出的唯一理由是「One raw control byte makes grep treat the whole file as binary: zero matches, no signal」——而这条只对 NUL 成立。在容器内独立复现(样本用 printf 生成,未粘贴裸字节;GNU grep 3.11 + ripgrep 14.1.0): U+0000 grep: binary file matches rg: binary file matches (found "\0" ...) U+0001 grep: 2:searchable line rg: 2:searchable line U+007F grep: 2:searchable line rg: 2:searchable line 即门禁扫描面里除 NUL 之外的每个字节(含 #5460 纳入门禁、#5577 补进自扫字符类的 DEL)都不会让文件被当成二进制。危害只写这一条的后果不是文字不精确:agent 写出一枚 非 NUL 控制字节、自扫命中后去核对指令,会发现唯一被陈述的判据不成立,从而把门禁的红 判成误报。 `scripts/check-nul-bytes.mjs` 脚本头早就把两侧分开论证好了(#5157 段),本次把散文 口径搬过去对齐: - binary-file / zero-matches 那条点名 NUL,并标明是实测结论; - 其余扫描面字节引脚本头写清的三条:渲染为空(代码对每个读者说谎)、两种拼写互不 命中(文件里是字节,不是你会去搜的转义文本)、事故源不挑字节值; - 补一句直接堵住上述推理:「不是 NUL、grep 还能搜到」永远不构成把门禁红或自扫命中 读成误报的理由; - 危害论证指向脚本头「引用它,不要重新推导」,不在此处再抄一遍论证细节。 顺带修同段两处陈旧: - 「this repo has paid four times」的硬编码计数改为免计数措辞——该族已多于四例, #5624 刚因同样的漂移把台账里的 sibling 计数改成不含数字的表达; - 「a `0x01` that `check:nul-bytes` does not scan for (#5157)」的现在时已错:#5157 正是把该字节纳入扫描面的那一单,改为过去时的事实句。 未做(留档而非顺手扩面):单源化——让字符类与危害论证不再手抄多处——是 #5484 正文 留下的方向,本 PR 只修散文口径,不动 `scripts/check-nul-bytes.mjs`、不动 #5577 刚 补的自扫字符类、不动 #5630 刚加的 Toolchain traps 条目。 纪律:全程未向任何文件写入裸控制字节,散文沿用该文件与脚本头既有的 `0x01`/`0x7f` 十六进制写法(不含反斜杠转义,不会被编辑工具 materialise)。 `node scripts/check-nul-bytes.mjs` 绿;改动文件自扫 `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` 无命中;`cat -A` / `od -c` 复核新增 行无意外字节。 `.claude/` 文档-only,无用户可见变更,走 skip-changeset 标签路线。 Fixes #5579 Claude-Session: https://claude.ai/code/session_01GX3sL71LFq8m2usg6VqTSE Co-authored-by: Claude --- .claude/agents/os-dev.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/.claude/agents/os-dev.md b/.claude/agents/os-dev.md index d9b2ae73c1..84fa45e036 100644 --- a/.claude/agents/os-dev.md +++ b/.claude/agents/os-dev.md @@ -270,13 +270,23 @@ backslash-u forms like `\u0000` / `\u0001` — never as raw bytes, in **any** file (source, markdown, fixtures) and in any prompt or tool payload you compose: describe the escape, do not paste the byte. Editing tools materialize escapes into real control bytes precisely when you are writing -*about* them — this repo has paid four times: #4763 (raw NUL in a dispatch -prompt), #4890 (a raw NUL landed in `SKILL.md` **while writing the -no-raw-NUL rule**, outside every gate's scan surface), and PR #5140's two -bytes — a NUL plus, 14 bytes away, a `0x01` that `check:nul-bytes` does not -scan for (#5157). One raw control byte makes grep treat the whole file as -binary: zero matches, no signal, and the rule you just wrote becomes -invisible to every agent that greps for it. Run +*about* them, and this repo has paid for it repeatedly — including #4763 +(raw NUL in a dispatch prompt), #4890 (a raw NUL landed in `SKILL.md` +**while writing the no-raw-NUL rule**, outside every gate's scan surface), +and PR #5140's two bytes: a NUL plus, 14 bytes away, a `0x01` that the +then-NUL-only scan walked straight past — the gap #5157 closed by widening +the scan surface beyond NUL. The harms are argued in the gate script's +header (`scripts/check-nul-bytes.mjs`) — cite it, don't re-derive it. +Measured, only a raw **NUL** makes grep and ripgrep treat the whole file as +binary and report zero matches with no signal, so the rule you just wrote +becomes invisible to every agent that greps for it. Every other scanned byte +(`0x01`, `0x7f`, …) keeps matching line by line, and is rejected for the +three harms that land on the whole set: it **renders as nothing**, so the +code lies to every reader; it is unfindable in **both** spellings, since the +file holds a byte and not the escape text you would search for; and the +accident source **does not pick byte values**. "Mine is not a NUL and grep +still finds my file" is therefore never a reason to read a gate failure or a +self-scan hit as a false positive. Run `node scripts/check-nul-bytes.mjs` before pushing, and when your change so much as *mentions* control characters, self-scan beyond the gate (`grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' `) — the gate's blind