fix(spec,runtime): 槽查找 any 规则补上类型实参形态并把作用域扩到全部 packages(#4251 第一批) - #4321
Merged
Conversation
…iden the lookup guard to all packages (#4251) The #4127/#4214 rule matched ': any' and 'as any' on a lookup result but not the type-argument form getService<any>(...) — the shape the codebase actually used — and its files glob stopped at packages/runtime while the composition roots held the majority of lookups. Both gaps close here: - eslint.config.mjs: third selector for the type-argument form (typeArguments.params.0 = TSAnyKeyword), scope widened to packages/**, http.server added to UNCONTRACTED_SLOTS (three providers, no contract). The 40 not-yet-swept files are grandfathered in SLOT_LOOKUP_UNSWEPT — a visible ratchet enumerated at 180 sites by running the rule with the list emptied; batches remove entries, never add. - The three in-scope runtime src sites are typed. Doing so surfaced the batch's first yield: both addDatasource branches (DefaultDatasourcePlugin parity branch, DriverPlugin.start) probed a method no metadata service implements, so they had never run on any boot — deleted rather than typed against a phantom shape. The inert DriverPluginOptions are tracked in #4320; registerInMemory('datasource', ...) is the actual visibility path. - Contracts declare the evidenced members those sites read, both optional: IDataEngine.getDefaultDriverName/getDriverByName (ObjectQL's driver registry, re-registered as driver.<name> services for os migrate and serve storage detection) and IMetadataService.registerInMemory (MetadataManager's boot-time seeding primitive, #3827). - Runtime test lookups typed as IDataEngine; the five http.server test lookups ride the slot exemption. Verified: pnpm lint clean; spec check:generated all 8 up to date; tests green — spec 7137/277, objectql 1345/85, runtime 954/67, metadata 281/13, plugin-webhooks 25/3. 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
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 119 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
The IDataEngine and IMetadataService contract references enumerate the interface surface member by member, so the two additions (driver registry lookups; registerInMemory) were stale-by-omission — flagged by the docs drift check on #4321. Both interface listings and the per-member sections now match packages/spec/src/contracts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWW5xEALZNU5VBXfGyWPGz
new DriverPlugin(driver, { datasourceName, registerAsDefault }) never did
what it promised: both options configured the start() datasource block that
probed metadata.addDatasource — a method no metadata service implements —
so they were dead weight on every boot since inception. Routing to a named
auxiliary driver never came from the option: it keys off the DRIVER name
(init registers driver.<name>, ObjectQL's discovery loop adopts it, the
engine's lifecycle resolution looks the name up — engine.ts
LIFECYCLE_DATASOURCE), which is why serve's telemetry split worked all
along despite the option doing nothing.
- DriverPlugin constructor narrowed to (driver, driverName?); the options
interface (module-local, never exported from the package root) is gone.
- serve.ts drops the options argument; the telemetry wiring comment now
states the driver-name mechanism explicitly.
- Major changeset for @objectstack/runtime carries the FROM -> TO
migration; behavior is unchanged by construction (the code the options
configured never ran).
Verified: full turbo build green (71 packages); runtime 954/67 and cli
628/64 tests pass; pnpm lint clean.
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 06:39
This was referenced Jul 31, 2026
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>
os-zhuang
added a commit
that referenced
this pull request
Jul 31, 2026
…4382) #4321 put `http.server` in UNCONTRACTED_SLOTS on the ground that "no IHttpServer contract exists". The contract does exist (packages/spec/src/contracts/http-server.ts) and eight call sites were already resolving the slot as getService<IHttpServer>(...) when the exemption was written. An exemption is a claim like any other, and this one rested on a premise nobody checked -- the same shape as the gaps the rule exists to find. Revoked. That surfaced 9 erasures the exemption had been hiding: 7 in files never grandfathered, 2 as count growth inside grandfathered ones, none of which the baseline could legally absorb. All typed to IHttpServer; packages/metadata/src/plugin.ts came out clean entirely, so the baseline ratchets DOWN to 168 sites in 36 files and loses a file. Confirmed and reported, not changed: `http.server` and `http-server` are the SAME instance under two names (plugin-hono-server and qa/node-plugin each register it twice, two lines apart; runtime's config.server path registers only the dotted one) -- removing a registration is a runtime change and belongs with whoever picks the canonical name. And `IHttpServer` is defined TWICE and has already diverged: spec's (15 importers) declares write?()/end?(), core's (8 importers) does not. Spec's is the superset and the one the ledger points at; core's is a stale near-copy that should re-export it, in its own change. Verified: ratchet holds (168/36, none new, no files added vs d92c72d); eslint clean; metadata dts build succeeds; runtime 995/68, client 204/15, metadata 281/13, http-conformance 46/2. 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(#4127 工作线,承接 #4214 的批次模式)。Closes #4320。本 PR 是新清扫线的第一批:规则补全 + 棘轮落地 + 规则现有作用域内的站点全部清零,以及对首个产出(#4320)的收尾。
1. 两个缺口,如 issue 所述
选择器缺口。 原有两个选择器只匹配变量注解(
: any)和as any,而代码库实际使用的形态是类型实参——ctx.getService<any>('data')——80 个非测试站点,零匹配。新增第三个选择器(typeArguments.params.0.type="TSAnyKeyword"),纯 AST,无需类型信息,UNCONTRACTED_SLOTS豁免机制原样沿用。作用域缺口。
files原来止步于packages/runtime。现扩到packages/**—— 不是 issue 建议的"按包点名",理由写进了配置注释:按包圈定会把这次的缺口按包再造一遍;全量作用域 + 逐文件祖父名单,新包生来就在规则之下。2. 棘轮(可见的)
以清空名单跑一遍扩域后的规则做的全量枚举:180 个站点、44 个文件(issue 的 80 只数了非测试的
<any>形态;注解形态和测试文件让它翻倍)。其中 4 个 runtime 文件本批清零,40 个文件进SLOT_LOOKUP_UNSWEPT——集中一处、只减不增、每批删几行的那种名单(--no-inline-config下逃生口本来就只能住在 config 里)。http\.server进UNCONTRACTED_SLOTS:三个 provider,无书面契约,调用方只读getPort()。3.⚠️ 本批的产出:两条从未执行过的数据源注册分支 → #4320 一并收尾
给 runtime 的三个站点补类型时发现:
DefaultDatasourcePlugin的 parity 分支和DriverPlugin.start()的整个函数体都探测metadata.addDatasource——整个仓库没有任何 metadata 服务实现过这个方法(getDatasources同理,唯二引用就是这两个探测点自身)。守卫恒假/恒提前返回,每一次启动都没跑过;DriverPlugin.start()的提前返回甚至连它自己收尾的 debug 日志都一并跳过。处理:删除死代码,而不是给幻影方法编一个本地类型(那是 #4127 编目过的"第二份没人校验的契约")。
registerInMemory('datasource', …)才是现行可见性路径(#3827),它就活在被删分支的上方两行。#4320 的 enforce-or-remove 取证与裁决(第三个 commit):issue 问"遥测是否需要真正的具名数据源可见性"。取证答案:具名辅助驱动的路由从来不经过那个选项 ——引擎按 driver 名路由(
DriverPlugin.init()注册driver.<name>→ ObjectQL 发现循环收编 →engine.ts的LIFECYCLE_DATASOURCE = 'telemetry'在this.drivers里查这个名字),这正是选项一直无效而 serve 的遥测分库一直工作正常的原因。故走 remove:DriverPluginOptions删除(模块内类型,从未从包根导出),构造函数收窄为(driver, driverName?);serve.ts去掉选项实参,遥测接线注释改为明说 driver-name 机制;@objectstack/runtimemajor changeset 携带 FROM → TO 迁移说明;行为零变化(被配置的代码从未运行过)。这正是 issue 预告的"产出不只是外观":
<any>一天在,编译器一天看不见这两条死分支。4. 按证据补的契约成员(全部 optional)
IDataEnginegetDefaultDriverName?/getDriverByName?driver.<name>服务,os migrate(SQL_DRIVER_SERVICES)和 serve 的存储探测都从那里定位 driverIMetadataServiceregisterInMemory?MetadataManager实现(metadata-manager.ts:379),启动期种子原语,GitOps 工件可列出但不落 DB(ADR-0015 Addendum、#3827)Optional 的理由:
IDataEngine还有测试假引擎和远端/虚拟引擎这类不带 driver 注册表的占用者;runtime 调用点本来就用?.探测,补类型后一行未改。测试站点(真实 ObjectQL 引擎)用?./!显式断言该表面存在——缺了就 fail,而不是滑过去。两篇契约参考文档(data-engine.mdx/metadata-service.mdx,docs drift check 点名)已同步。5. runtime 作用域内清零明细
data查找 →IDataEngine;http.server查找 → 槽豁免,零代码改动。验证
pnpm lint(--no-inline-config)@objectstack/speccheck:generatedslot-lookup-type-argument-ratchet.md(spec、runtime patch);retire-inert-driver-plugin-options.md(runtime major、cli patch,含迁移说明)后续批次:按
SLOT_LOOKUP_UNSWEPT逐文件清扫(rest-api-plugin 14 处、auth-plugin 20 处是大头),每批删名单若干行。🤖 Generated with Claude Code
https://claude.ai/code/session_01AWW5xEALZNU5VBXfGyWPGz