fix(spec): 未知键建议对两侧折叠大小写 —— camelCase 键不再白扣编辑距离 (#4990) - #5363
Merged
Conversation
`findClosestMatches()` 只把输入小写化、候选不做同样处理,于是候选键里每一个 大写字母都要额外付一次编辑距离。叠加 `strictUnknownKeyError` 长度相对的预算 (短键为 2),短 camelCase 键上一个普通笔误就够不着建议:`hideOn` 对 `hiddenOn` 真实距离 2、加大写罚分后 3、超预算返回空;而同一个词写成全小写的 `hiddenon` 反而拿得到建议。 现在打分对两侧做同样的归一化,回显仍用候选原始拼写。另两处附带修正: - 折叠后距离为 0 的候选(只差大小写)不再被 `distance > 0` 丢掉 —— 那是最有 把握的一条建议。过滤改为只排除作者逐字写过的字符串,顺带修掉一个未记录的 同源缺陷:旧实现会把作者写对的键原样回显成「你是不是想写」。 - 折叠后打平时以作者自己的大小写作次级排序(`yxAis` 同距 `yAxis`/`xAxis`)。 325 组真实候选集实测:329 例从「没有建议」变为有建议(328 例正确),0 例失去 建议,31 例改变选中项(30 例更准)。批 13 的逐例 `hideOn` alias 随之退役,实测 值改由 responsive.test.ts 断言保存。`data/object.zod.ts` 的 `suggestKey` 经核查 不同病(本就对两侧小写化),补测试锁定防止分叉。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FTszibd6C8sUCCZnM4VcrL
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 108 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
August 5, 2026 01:24
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 #4990
前提复核
issue 的实测表来自
fe83042,main 已走远。在553a47fda上重跑,四行逐字复现:findClosestMatcheshideOn[]hiddenon["hiddenOn"]hiddenOnn["hiddenOn"]maxLenght["maxLength"]第二行仍是完整刻画:把键写成全小写的作者,拿到的建议比写对大小写、只错一两个字母的作者更好。
改动
打分对两侧做同样归一化(大小写 +
-/空格 →_),回显仍用候选原始拼写。另有两处附带修正,都是同一处过滤器的连带:折叠后距离为 0 的候选不再被丢掉。 原
distance > 0过滤的本意是「别把作者写过的字符串原样回显」,但折叠后「只差大小写」也变成距离 0 —— 而那恰恰是兜底能给出的最有把握的一条建议(hiddenon→hiddenOn)。过滤改为只排除作者逐字写过的那个字符串。这里顺带修掉一个 issue 未记录的同源缺陷,是反向验证时才浮出来的:旧实现在
maxLength这种键上会把作者写对的键原样回显成「你是不是想写maxLength」,因为输入被小写化后与候选距离是 1 而不是 0,过滤器根本没拦住。折叠后打平时,以作者自己的大小写作次级排序。
yxAis折叠后同距yAxis与xAxis(均为 2),作者写下的大写 A 是仅存的证据。严格次级,不可能复活「大小写压过真实编辑」的原缺陷。影响面实测
在全部 325 组真实候选集(从
src/index递归采集每个 ZodObject 的 shape)上,按单字符删除/相邻换位/双字符删除生成 16734 个 camelCase 笔误探针,逐个对比新旧:两处代价如实记录,均为折叠后的真实平局、非排序质量退化:
yxAis旧给yAxis(对)、新给xAxis(错)。折叠距离与次级 cased 距离双双打平,由 shape 声明顺序决定。再加启发式(如「首字母优先」)缺乏原则依据,不做。mxaRows→minRows(应为maxRows),同为双双平局。注意这不是退化:改动前该输入没有任何建议。测试
packages/spec全套 308 files / 7903 tests 全绿(改动前 7895,新增 8 条);pnpm typecheck干净。按消费半径外扩(PR #5046 的教训:规则在哪里被调用,fixture 就可能在哪里):
findClosestMatches还被packages/lint三个 write-validator 调用,packages/services/service-automation断言 spec 产出的报错文案。两者分别跑过:lint 57 files / 1194 tests 全绿,service-automation 相关三个文件 149 tests 全绿。自证测试(issue 称之为本单实质)
「同一个键的全小写形式不应比正确大小写形式得到更好的建议」。这条的编码方式改过一次,值得记录:
issue 字面的写法 —— 比较
suggest(T)与suggest(T.toLowerCase())—— 对旧代码是空转的。旧实现第一步就把输入小写化,两次调用坍缩成同一次,462 个探针上「全部通过」,而缺陷完好无损。真正的不对称不在输入的两种拼法之间,而在声明键的两种拼法之间:同一个笔误,对着
hiddenOn判一个结果,对着hiddenon判另一个,因为只有候选保留了大写、每个大写都向作者收费。这才是标题里的「对 camelCase 键系统性偏弱」。改后的测试锁的是这个:声明键的大小写不得改变对一个笔误的判决。同一语料在旧实现上破坏 462 例中的 55 例,且双向破坏(bordeRradius对着驼峰borderRadius能解析、对着扁平borderradius反而不能 —— 大写恰好帮了忙)。大小写两个方向都不该说了算。反向验证
先定方向再跑。第一次预测部分落空,如实记录:预测「表格测试 + 不变量测试转红,其余为回归护栏」,实际把源文件换回
origin/main版本后 4 条转红,多出来的一条是上文第 1 点里那个未记录的「原样回显」缺陷 —— 它是被测试意外揭露的,不是被预期的。修复后 26/26 全绿。关于两处「同病」排查
data/object.zod.ts的suggestKey(issue 注 1):不同病。 它本来就对两侧都做小写化(editDistance(unknown.toLowerCase(), key.toLowerCase())),声明键的大写从未向作者收费。已补一条测试锁定该性质,防止两个 suggester 日后分叉。ui/responsive.zod.ts批 13 的逐例hideOn: 'hiddenOn'alias:已退役。 对真实完整键集(breakpoint, hiddenOn, columns, order)复测,hideOn现在靠距离本身即可解析。该 alias 的注释记录了实测值,按要求未删除而是转为断言存进responsive.test.ts,并补了hiddenon一例 —— 即当年让旧行为站不住脚的那个对照。注释里那句「fallback 仍够不着」已成假命题,留着比删掉更有害。hidden: 'hiddenOn'保留:它是 objectui 解析结果的拼写,是另一个词,任何编辑距离都够不着。未动的东西
packages/spec/authorable-surface.base.json会被pnpm build的gen:schema步骤重写(改baseRev并净删 110 个 key)。这与本单无关,提交前已git checkout --还原,不在本 PR 内。该行为已有 #5358 在跟,我在那边补了本次的复现数据而没有另开单。Generated by Claude Code