chore(scripts): 门禁扫描面纳入 DEL(0x7f),并转义 login.ts / register.ts 各一枚裸字节 (#5460) - #5479
Merged
Conversation
…C0 set (#5460) #5157 drew this gate's scan surface as "the C0 controls minus tab/LF/CR". DEL (U+007F) is a control character but not a C0 one -- it sits alone past the printable range -- so a set expressed as a contiguous range could not reach it. That the gap was arbitrary rather than considered is shown by where the two remaining raw specimens sat: nine lines below the 0x03 #5157 had just escaped, in the same switch, in both login.ts and register.ts, as the Backspace key literal. The escaped case reads as a key; the raw one renders as nothing and reads as an empty-string case. All three harms #5157 argued for C0 land on DEL verbatim, and the decisive one is that the accident source -- an editing tool materialising an escape into its byte while an author writes about the byte -- does not pick byte values. The binary criterion widens with it, and is load-bearing there: E4 B8 7F AD is the character 中 with a stray 0x7f in it, which a C0-only strip reads as binary, making the byte its own alibi. Measured over all 5457 tracked regular files: zero movement between the text and binary verdicts. Both specimens are escaped to the U+007F escape sequence, which is byte-identical at runtime and already the spelling used by the sibling prompt in cloud/login.ts. Self-test: 34 -> 48 assertions, both directions pinned. The assertion that deliberately held DEL outside the set is inverted rather than deleted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GX3sL71LFq8m2usg6VqTSE
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 21 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This was referenced Aug 5, 2026
os-zhuang
marked this pull request as ready for review
August 5, 2026 13:51
This was referenced Aug 5, 2026
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.
Fixes #5460
前提已核实(rule 6)
按 issue 正文逐条对
origin/main(#5461 合并后,577cd27be)验证:packages/cli/src/commands/login.ts:47、packages/cli/src/commands/register.ts:43,od -c实证为八进制 177。tab / CR / LF / DEL are outside the scanned set and stay green。前提全部成立,按 08-05 12:56Z 裁定实施方案 A(纳入)。
为什么 0x7f 该纳入
#5157 把扫描面定为「C0 控制集去掉 tab/LF/CR」。DEL 是控制字符但不是 C0 —— 它单独坐在 ASCII 表末尾、印刷字符区之后,所以一个用连续区间表达的集合根本够不到它。
这个缺口是偶然而非深思熟虑,最硬的证据就是剩下那两枚裸字节被发现的位置:#5157 刚转义了同一个 switch 里的一枚裸 0x03,往下九行的 Backspace 仍是裸字节。于是转义后的 case 与裸字节的 case 并排:一条读得出是个按键,另一条渲染为空、读起来是一个空串 case。区分二者的只有 ASCII 当年把这个字节放在了 0x1f 的哪一侧。
#5157 对 C0 论证的三条危害,逐条原样落在 0x7f 上(渲染为空 / 两种拼写都搜不到 / 事故源不挑字节值)。
iscntrl与正则的Cc类也都把 0x7f 算作控制字符 —— 「C0」是个更窄的读法。改动
scripts/check-nul-bytes.mjsIS_SCANNED[0x7f] = 1(带注释说明「虽非 C0,但按事故源不挑字节纳入」);脚本头/报错文案的扫描面描述如实改为「ASCII 控制字符」;自测 34 → 48 断言.github/workflows/lint.ymlpackages/cli/src/commands/login.ts/register.ts.changeset/control-byte-gate-scans-del.mdcontrol-byte-gate-scans-all-c0.md先例扫描面现在是
[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]。二进制判据:扩面是承重的,不是顺手对齐
判据是「剔除全部扫描字节后整文件 UTF-8 严格解码」。0x7f 纳入剔除集与 #5157 对 0x01 的论证同构:
E4 B8 7F AD是「中」被塞进一枚 0x7f,只剔 C0 的话解码失败 → 判二进制 → 跳过 → 那枚 0x7f 成了自己的不在场证明。反方向不会出错:扫描集全部0x7f及以下,而合法 UTF-8 多字节序列只由0x80及以上的字节构成。实测全部 5457 个受追踪常规文件,扩面前后文本/二进制判定零变化(#5461 的验收先例):
改前含裸 0x7f 的 7 个受追踪文件:
apps/docs/app/favicon.icodocs/screenshots/architecture.pngdocs/screenshots/automation.pngdocs/screenshots/layers.pngdocs/screenshots/modeling.pngpackages/cli/src/commands/login.tspackages/cli/src/commands/register.tsPNG/ICO 里的 0x7f 不受影响:它们是整文件解码失败才判的二进制,与任何单个字节无关。改后 text 类里 0x7f 归零。
反向验证(方向在跑之前先定)
预判方向:经典的红向 —— 因为两个新样本文件整个都不含 C0 字节,前一版 C0-only 的扫描确实无事可做。两条都按预判走:
(a) 摘掉
IS_SCANNED[0x7f] = 1,自测转红:其中
exactly the 2 binary assets skip, got 3这条最值得看:它不是重复计数,而是那个「中」被塞了 0x7f 的样本从文本掉进了二进制 —— 不在场证明当场生效。这正是二进制判据必须同步扩面的实证。(b) 把两个 cli 文件恢复成裸字节,扩面后的门禁判红,行号与 issue 正文逐字对上:
报错并给出处方:
0x7f→ 对应的 U+007F 转义序列。Backspace 行为不变的证明
packages/cli下没有覆盖这个按键处理器的测试(grep只命中三个源文件,无测试文件),按派发口径以字节等价论证,并跑全包测试证明无回归。把两个版本的 case 标签按 TS/JS 解析器的规则求值后比较码点,结果:
[127][127]IDENTICAL AT RUNTIME: true—— 两种拼写求值后都是单个码点 127、长度 1,switch命中完全相同。另一条独立佐证:同包的
packages/cli/src/commands/cloud/login.ts:50本来就用 U+007F 的转义序列拼写同一个按键。仓内三个密码输入实现里,规范拼写早已存在,只有这两个漂移成了裸字节;本次是把它们收回既有惯例,不是发明新写法。事故源在本 PR 里又复现四次
issue 正文记录了它自己的第一版被这个坑绊倒(写着写着落进两枚真的 0x03)。实施过程中又复现四次,每次都被逐字节自扫或工具校验当场抓住:
split(...)的参数里落进一枚真的 NUL(渲染为空,直到Edit工具匹配不上那行才暴露);外加上面那条订正说明里的第五次。这些都不在 issue 的记录里,写在这里是因为它们正是「事故源不挑字节值、也不挑文件类型」的当场实测 —— 也顺带说明为什么本文用
U+007F而不用反斜杠转义。另注一个门禁边界(非本单缺陷,不扩范围): changeset 那三枚 0x7f 落地时,
node scripts/check-nul-bytes.mjs报的是 OK —— 因为门禁扫的是git ls-files的受追踪文件,而新建的 changeset 当时还没git add。git add之后立刻判红。这是门禁既有的、正确的设计(未追踪文件不归它管),提一句是因为它恰好说明AGENTS.md里「除了跑门禁,还要逐字节自扫」那条不是冗余。验证
自测新增了什么
正反两向都钉在代码旁边,外加一条「处方本身可测」:
0x7f与对应转义处方;多字节序列里的 0x7f 判红。原先那条故意把 DEL 钉在扫描面外的断言按裁定反转而非删除:它当年是用来说明这条边界是选出来的而不是漏掉的;这次边界被重新选择,选到了另一边,注释里记下了这次改选的来由。