feat(tooling): 让 #4251 的清扫棘轮真的有执行力 —— 计数基线 + 单调性校验 - #4342
Merged
Conversation
…aseline The sweep list shipped as a bare array of paths in eslint.config.mjs under a comment reading "NEVER add an entry" — a promise nothing checked, which is the exact shape this work line keeps finding (#4320's options configured a block that never ran). ESLint cannot express a ratchet: an ignored file is ignored COMPLETELY, so three moves were invisible. The list becomes scripts/slot-lookup-baseline.json — file -> site count — and is the single source: its keys ARE the config's ignores, its values are what check:slot-lookup enforces. The script re-runs ESLint with the grandfathering lifted and matches reports by the rule's exact message (exported from the config), so the counter cannot drift from the rule; change a selector and it re-measures against it. Each caught move was verified by injection: A. new erasure in a listed file -> count grew 1 -> 2 (pnpm lint: silent) B. listed file cleared, entry kept -> ratchet DOWN, run --update C/D. a file ADDED to the list to mute it -> rejected against the merge base with main. D is the decisive one: a violating new file baselined at its TRUE count passes every count check, and only the key-set comparison catches it. When the merge base is unreadable (shallow clone, baseline new on the branch) the run says so rather than reading as verified — so lint.yml checks out with fetch-depth: 0. 171 unswept sites in 40 files today. Batches sweep files, then --update ratchets the baseline down; it never grows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWW5xEALZNU5VBXfGyWPGz
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
The PR changes tooling and CI only — no publishable package diff — which is exactly the case the Check Changeset gate names as an empty changeset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWW5xEALZNU5VBXfGyWPGz
os-zhuang
marked this pull request as ready for review
July 31, 2026 07:17
os-zhuang
added a commit
that referenced
this pull request
Jul 31, 2026
* fix(lint,runtime,core): slot-lookup guard sees the split-declaration form (#4251) The three selectors from #4321 all key off the erasure and the lookup being in ONE expression. Split them and every selector misses: let ql: any; try { ql = ctx.getService('objectql'); } catch { /* optional */ } Selector 1 needs the call inside the declarator (this one has no init), selector 2 needs `as`, selector 3 needs a type argument. The contract is erased exactly as in `const ql: any = ctx.getService(...)`. Why this could not wait for the batches: the baseline's monotonicity check means a file that leaves the grandfather list can never be re-added, so every batch converted more of this shape from "grandfathered" into "lint covers this file and says nothing" -- B2 alone moved plugin-security/security-plugin.ts into that state. A ratchet that reports a cleaner number the more you sweep is the #4342 failure wearing different clothes. It is a RULE, not a fourth selector, and that is the finding. esquery can match AssignmentExpression:has(CallExpression[...]), but cannot tell which declaration the assigned identifier resolves to -- so it would equally flag the correctly-typed form this work line exists to produce (8 such sites today). That needs scope analysis: cheap, no type information, but a rule. Verified: flags all 16 real sites, none of the 8 lookalikes. Baseline 140 -> 169 sites, file count unchanged at 37 -- 29 were already inside grandfathered files and simply invisible. 16 more could not be grandfathered and are typed here. No baseline key added. Verified: ratchet holds (169/37, none new, no files added vs c54c822); eslint clean on every changed file; tsc on the three DEBT packages (runtime/core/cloud-connection) shows 0 errors in touched files and identical whole-package counts vs clean HEAD (18/91/13); runtime 974/68, core 437/27, platform-objects 254/8, plugin-security 677/32. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(platform-objects): FreshDatastoreEngine extends MigrationFlagEngine (#4251) CI caught what my local run could not: `platform-objects` has no `typecheck` script (type-check coverage DEBT), so its dts build is the only gate, and I had run only its tests. The named surface introduced for the `objectql` lookup declared the two attestation members but not the engine shape `attestFreshDatastore` takes, so the call no longer typechecked. Extending `MigrationFlagEngine` is the right fix rather than widening the call: that interface IS the contract the helper states, and the surface's job is to add ObjectQL's attestation members on top of it. Verified: platform-objects build (CJS/ESM/DTS) succeeds, 254 tests / 8 files pass, eslint clean; core / runtime / cloud-connection / plugin-security dts builds re-run and all succeed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
Refs #4251。#4321(第一批)的直接续作:那一批把清扫名单落进了
eslint.config.mjs,配了一句注释「NEVER add an entry」—— 而没有任何东西检查这句话。这正是本工作线反复抓到的形态(#4320 的选项配置了一段永不执行的代码;#4127 的any看起来和有检查的代码一模一样),所以先把护栏做实,再继续清扫。问题:ESLint 表达不了棘轮
ignores里的文件是被完全忽略的,于是三个动作在纯文件名单下不可见:pnpm lintA 是最要命的:一处新的
getService<any>('auth')写进auth-plugin.ts,搭上既有条目的便车,整条流水线一片绿。做法:基线即单一事实来源
scripts/slot-lookup-baseline.json(文件 → 站点数)同时是:pnpm check:slot-lookup强制的计数。脚本不是另写一套匹配逻辑,而是把 grandfathering 摘掉后重跑 ESLint 本身,再按规则的精确 message(从 config 具名导出)筛报告。所以计数器与规则不可能各说各话:改了选择器,它就照新选择器重新测量。
每一条都做了注入验证
D 是决定性的:计数 1 = 实测 1,任何纯计数逻辑都会放行,lint 也已被 ignores 消音——只有「基线 key 集合对比 merge-base」这一层能抓住它。所以名单只能减,不能增。
merge-base 读不到时(浅克隆 / 基线在本分支才新建)脚本**明说「NOT verified」**而不是默默当作通过——
check:generated的同款做法;为此 lint.yml 的 checkout 加了fetch-depth: 0。现状数字
171 个未清扫站点 / 40 个文件(#4321 里写的 180 是清扫前的读数,这里是清扫掉 runtime 四个文件之后的精确值)。往后每一批:清扫文件 →
pnpm check:slot-lookup --update把基线往下棘 → 提交。验证
pnpm lint(--no-inline-config)pnpm check:slot-lookup无 changeset:本 PR 不改任何已发布包的代码,只动根
package.json脚本、scripts/、eslint 配置与 CI。下一步:auth / session 集群第二批 ——
plugin-auth(20)+plugin-hono-server/current-user-endpoints(10)+plugin-security(1),共 31 处,按IAuthService/ISecurityService切片。#4214 唯一的线上 fail-open 就出在这一族的 session 读取上,是产出概率最高的一批。🤖 Generated with Claude Code
https://claude.ai/code/session_01AWW5xEALZNU5VBXfGyWPGz
Generated by Claude Code