fix(core,fields,plugin-dashboard): 清掉最后四处裸控制字节,并清空扫描门禁的基线 (objectstack#5450) - #3389
Merged
Merged
Conversation
…tes and empty the baseline (objectstack#5450)
Four source files still carried a raw control character in a string literal, all
four listed in `KNOWN_OFFENDERS` when the gate landed in objectui#3388:
- `packages/core/src/evaluator/listConditional.ts` — U+0000, the composite
dedup key of the one-time evaluation-failure warning.
- `packages/core/src/utils/record-title.ts` — U+0000, the `EMPTY_TOKEN`
sentinel marking an empty titleFormat placeholder.
- `packages/fields/src/widgets/PeoplePicker.tsx` — U+0000, the separator of
the record-id signature the keyboard cursor is keyed on.
- `packages/plugin-dashboard/src/DatasetWidget.tsx` — U+0001, the separator
joining several row dimensions into a pivot row id.
The first three were invisible to content search: grep and ripgrep classified
the whole file as binary and printed no line at all, which is why grepping this
repo for `EMPTY_TOKEN` or `recordsSignature` returned nothing. The fourth is a
different harm — U+0001 never triggers binary classification — but written raw
it is invisible in every editor and every diff, so no reviewer could tell what
the separator actually was.
Two shapes of fix, chosen per site rather than in bulk:
- `listConditional.ts` no longer needs a separator at all. The key is now
`JSON.stringify([label ?? '', source])`, so the label/source boundary is
unambiguous for any input instead of resting on "this character cannot
occur" — the same move objectui#3388 made for the include key.
- The other three keep a byte-identical runtime value and are re-spelled as
escapes. Each has a reason it must not become a printable character:
`EMPTY_TOKEN` is interpolated verbatim into two RegExps and would strip real
text out of titles; the PeoplePicker signature already spelled the very same
separator as an escape twelve lines below; the pivot row id joins arbitrary
dimension values and is a component of the cell-lookup key.
All four `KNOWN_OFFENDERS` entries are deleted in this commit, as the map's
contract requires — `scan()` reports a stale entry as loudly as a new offender,
so the fix and the baseline cannot drift apart. The map is now empty.
No changeset: nothing here is user-visible. Three changes are byte-identical at
runtime and the fourth is an in-memory dedup key for a console warning.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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 objectstack-ai/objectstack#5450
这是什么
四个源文件在字符串字面量里带着裸控制字节,正是 objectui#3388 落地门禁时记进
KNOWN_OFFENDERS的四条基线债:packages/core/src/evaluator/listConditional.tspackages/core/src/utils/record-title.tsEMPTY_TOKEN空占位哨兵packages/fields/src/widgets/PeoplePicker.tsxpackages/plugin-dashboard/src/DatasetWidget.tsx前三个是内容检索黑洞:grep 和 ripgrep 把整个文件判为 binary,一行都不打印。改动前在本仓实测:
第四个不是。U+0001 不触发 binary 判定(门禁注释里已量化过:GNU grep 3.11 / ripgrep 14 上只有 U+0000 会),
DatasetWidget.tsx一直是能被搜到的。它的危害是另一种:字面量里一个谁都看不见的字节 —— 编辑器不显示、diff 不渲染、和写错的邻居无法区分,没有任何 reviewer 能确认这个分隔符到底是什么。两种危害不同,下面的断言也就分了两种形状。改法(逐处判定,不批量套同一招)
1.
listConditional.ts:根本不再需要分隔符。去重 key 改成
JSON.stringify([label ?? '', source])—— label 与 source 的边界对任意输入都无歧义,不再建立在"这个字符不可能出现"的假设上。与 objectui#3388 对 include key 的处置同形。2. 其余三处保持运行时值逐字节不变,只把字节改写成可读的六字符转义(反斜杠 + 小写 u + 四位十六进制)。三处都有各自"不能换成可打印字符"的具体理由,不是图省事:
EMPTY_TOKEN被原样插进两个 RegExp,并且必须是记录值不可能携带的字符;换成可打印分隔符会把真实标题里的字符吃掉。cursorEpoch里本来就是转义写法;这次只是让相隔十几行的两处终于一致。**3. 四条
KNOWN_OFFENDERS条目在同一个 commit 里删除。**基线是棘轮不是跳过名单:scan()对陈旧条目和新违规一样红,所以修复与基线不可能漂移。这个 map 现在是空的,注释里写明了它应当保持空。验证
node scripts/check-control-bytes.mjs全绿,且输出里不再带 "N baselined" 后缀(map 已空)。packages/core packages/fields packages/plugin-dashboard scripts,147 files / 2548 tests 全绿;三个受影响包type-check全绿、lint0 error。反向验证(先定方向,再跑)
两次,方向都在跑之前写死:
**其一 —— 留下陈旧基线条目应当变红,且必须是 stale 而不是 offender。**四条逐个复现,全部命中预期:
其二 —— 把
DatasetWidget.tsx的转义换回裸字节。预期:门禁测试变红,而透视行为测试保持绿。实测正是如此:这一条如实记下,不套模板:转义与裸字节是同一个运行时字符,所以这三处等价改写在行为层面不可能做出 before-green/after-red。能动的只有字节层面的断言;行为测试钉的是"分隔符在语义上仍然把维度隔开",它要变红得是有人改掉分隔符的值(比如换成空串或会碰撞的可打印字符),而那正是它该防的事。
新增测试
scripts/__tests__/check-control-bytes.test.ts:四个文件"无任何控制字节";其中三个原本瞎掉的另加一条真实 grep 断言(要能打印出行,且不得出现binary file matches)。U+0001 那个故意不写 grep 断言 —— 它本来就没瞎过,写了就是编造证据。另加一条:四个文件在基线里都不得再有条目。listConditional:告警去重的两半 —— 同一 (label, source) 只告警一次;两对"拼接起来一模一样"的 (label, source) 必须仍是两条告警(空格分隔符会把它们合成一个 key,这正是"换个可打印字符"这种修法会踩的坑)。record-title:哨兵不泄漏进渲染结果(按码位断言,测试文件里不写任何控制字符),孤立分隔符照常清除,两端都有值的分隔符不被误删。DatasetWidget:原有 buildPivot 用例全部只有一个行维度,那个分隔符从来没被任何用例跑到过(把它改成空串也照样全绿)。补一条两个行维度、且拼接会碰撞的用例。不带 changeset
三处运行时逐字节不变,第四处是内存里的告警去重 key,没有任何用户可见的行为变化 —— 按
.changeset/README.md的 DON'T(internal refactoring with no API changes)免。顺带发现(不在本 PR 修)
buildPivot的 cell key 是用普通空格拼 rowId 与 colId 的,维度值含空格时会静默串格 —— 已单独开 objectstack#5473,按越界即停留在那边。写作纪律
正文、代码注释、commit message 一律以 U+XXXX 或"转义"的措辞描述字节,不贴字节本体;测试与改写脚本里的控制字符一律由数字构造(
String.fromCharCode),避免转义序列在工具载荷里被解码成真字节 —— 这个家族已经有两次事故就发生在"写这条规则的时候"。Generated by Claude Code