Skip to content

test(devx): check-nul-bytes 的 --self-test 断言字符类引用面逐字节相等,终结该族漂移 (#5646) - #5680

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-5646-charclass-selftest-assert
Aug 6, 2026
Merged

test(devx): check-nul-bytes 的 --self-test 断言字符类引用面逐字节相等,终结该族漂移 (#5646)#5680
os-zhuang merged 1 commit into
mainfrom
claude/issue-5646-charclass-selftest-assert

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #5646

字符类此前是手抄关系:IS_SCANNED 表是门禁真正扫的东西,而 .claude/agents/os-dev.md「Byte discipline」段的自扫命令行里躺着一份手写副本。该族漂移当日已付两次 —— #5577(自扫类缺 \x7f,门禁侧从 #5460 起早已纳入)与 #5579(危害论证只搬了对 NUL 成立的那条)。#5579散文侧改成「cite the header」(少一层重复),但字符类不能这么办:作者需要一条能直接粘的命令行。所以反向处理 —— 派生 + 断言。

修法

比较是逐字节而非语义:\x0b-\x0c\x0b\x0c 匹配同一批字节,但前者会判红。所以 scannedCharClass() 里的折叠约定(连续 3 字节以上收成区间,1–2 字节逐个写)是承重的 —— 必须有一个规范拼写,而它就是这个函数。为防「emitter 稳定但错」,另加一条:把派生出的类编译成真 RegExp、跑遍 0–255,选中的集合必须与表完全一致。

引用面台账(全仓实测)

git grep 'x00-'git grep 'grep -naP' 全仓共 9 处命中,登记 2 处:

位置 形态 处置
.claude/agents/os-dev.md:311 自扫命令行里单引号包裹的 PCRE 类 登记(锚点:grep -naP 之后的引号串)
scripts/check-nul-bytes.mjs:9 脚本头「Equivalently」后的反引号类 登记 —— 实测这是第三份手抄:#5460 加 DEL 时曾需同步改它
.changeset/control-byte-gate-scans-all-c0.md 扩面前的集合(无 \x7f) 不登记 —— 历史记录,对它所描述的那次变更是正确的;强制等于今天的集合会伪造记录
.changeset/control-byte-gate-scans-del.md 当时的集合 不登记,同上(历史记录类文本)
packages/plugins/plugin-auth/CHANGELOG.md.changeset/isLikelyEmail-no-control-char.md [^\x00-\x7f] 不登记 —— 另一条关于非 ASCII 输入校验的正则,与本集合无关
scripts/check-nul-bytes.mjs:6.github/workflows/lint.yml:98 同一批字节的散文枚举 不登记 —— 是句子而不是可粘贴的类,归 cite-the-header 口径
.claude/skills/pm-dispatch/SKILL.mdscripts/check-workflow-status-functions.mjs:291 只提门禁名/惯例,无字符类 非引用处

取舍口径:只锁受众是 agent 指令、可直接粘贴的活引用;历史记录类文本反而必须允许「过时」。台账写死在脚本里,新增引用处需登记 —— 与仓内 shrink-only 门禁的「显式列表」惯例同构。

提取锚点刻意不含字符类本身:含了的话,它会在正要抓的那次漂移上停止匹配,把「不相等」(能报出两种拼写)降级成「提取不到」(报不出)。

先红后绿(四个方向,均前台实测)

预期方向:引用面被改动即红。四种都是漂移,四种都必须红。

  1. 改错一位(os-dev.md 的 \x7f 改成 \x7e):
    ✗ … .claude/agents/os-dev.md (the byte-discipline self-scan command line) spells the scanned set as [\x00-\x08\x0b\x0c\x0e-\x1f\x7e], but this gate scans [\x00-\x08\x0b\x0c\x0e-\x1f\x7f]. exit=1 → 还原后 56 断言绿。
  2. 复现 docs(os-dev): 自扫字符类补上 DEL,与 #5460 扩面后的门禁扫描面对齐 (#5484) #5577 原形(整段去掉 \x7f):同一条断言判红,报出 [\x00-\x08\x0b\x0c\x0e-\x1f] —— 正是当初漂了数月的那一版。
  3. 提取不到即红(把整条 grep -naP 命令行删掉):
    ✗ … found no character class at the registered anchor (the byte-discipline self-scan command line). Either the class was removed -- then de-register it … Expected to find: [\x00-\x08\x0b\x0c\x0e-\x1f\x7f] exit=1。⛔ 不静默跳过(check:react-declaration-parity 是唯一没接进任何 workflow 的源码审计门禁,且无 MANIFEST 时静默 skip 退出 0 —— 它现在永远不可能红 #4690 反模式)。
  4. 登记文件消失(重命名 os-dev.md 而未去登记):… is a registered character-class reference but could not be read -- restore it, or remove it from CHAR_CLASS_REFERENCES on purpose exit=1。

另两条旁证:未来扩面场景(往表里加一枚字节、两处引用都忘改)一次报出 4 条失败,其中两条分别点名 os-dev.md 与脚本头并给出新的规范拼写;语义相同、字节不同(\x0b-\x0c)照样判红,坐实逐字节口径。

权威方向与 os-dev.md 零改动

脚本 IS_SCANNED 表是权威。实测两处当前已经一致(#5577 修完至今未再漂),所以本 PR 的 os-dev.md 改动为零 —— 文件面只有 scripts/check-nul-bytes.mjs(+175/-0)。若实测到漂移,跟改会朝脚本对齐。

边界

  • self-test 现有断言结构与退出码语义不变,断言数 48 到 56(只增不减)。
  • CI 的 pnpm check:nul-bytes--self-test 再接全仓扫描,所以这条新断言天然进 CI 门禁。
  • 新检查读的是真实的仓内文本(不是临时仓 fixture):标的正是 checked-in 的指令文件本身。仓根由 import.meta.url 解析,cwd 骗不了它。
  • 字节纪律:改动文件自扫零命中;未向任何文件写入裸控制字节,样本一律由字节值在运行时生成。
  • scripts/ 门禁改动,不发布任何包 → 走 skip-changeset 标签路线(⛔ 不写空 frontmatter changeset,空 changeset 会静默卡死已 version 的发布:Release run 全绿,但 npm 和 Docker 什么都没发(17.0.0-rc.2 现在就卡着) #4898)。

Generated by Claude Code

字符类此前在两处手抄:IS_SCANNED 表(门禁真正扫的东西)与 os-dev.md
自扫命令行。该族漂移当日已付两次(#5577 自扫类缺 \x7f、#5579 危害论证
只搬了对 NUL 成立的那条)。

scannedCharClass() 从表派生出 PCRE 字符类,--self-test 断言登记在
CHAR_CLASS_REFERENCES 里的每处引用与之逐字节相等;提取不到也红。
不做散文 codegen:引用文件是手写 prompt,断言只拒绝它们「错」,并在
失败信息里给出该粘贴的确切字符串。
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 5, 2026 11:56pm

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants