Skip to content

fix(lint,runtime,core): 槽查找护栏认出分体声明形态 —— 越清扫越显得干净的那个盲区 (#4251) - #4373

Merged
os-zhuang merged 2 commits into
mainfrom
claude/4251-selector-4-and-http-server-exemption
Jul 31, 2026
Merged

fix(lint,runtime,core): 槽查找护栏认出分体声明形态 —— 越清扫越显得干净的那个盲区 (#4251)#4373
os-zhuang merged 2 commits into
mainfrom
claude/4251-selector-4-and-http-server-exemption

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

#4361。B2 回帖里我把这件事的代价说小了 —— 说"代价只是一条选择器"。不是。 这个 PR 先纠正那个判断,再落地。

为什么它不能等批次做完

基线的单调性校验禁止往祖父名单里 key。所以每落地一个批次,就有一批这种形状的站点从"还能被名单兜住"变成"lint 覆盖了这个文件、而且一声不吭" —— 光 B2 就把 plugin-security/security-plugin.ts 推进了这个状态。

一个越用越显得干净的棘轮,就是 #4342 换了身衣服的同一种失败。 而且每多发一个批次,修它就更贵。

它是一条规则,不是第四条选择器 —— 这才是本次的发现

esquery 能匹配 AssignmentExpression:has(CallExpression[…]),但无法判断被赋值的标识符解析到哪个声明。于是它会连带命中这条工作线正要产出的、写对了的形式:

let i18nService: II18nService | undefined;
i18nService = ctx.getService('i18n');      // 完全正确,裸选择器照样报

今天全仓有 8 处这样的正确代码(runtime/app-plugin.tsservice-automationmetadata-protocolplugin-audit)。把它们判成违规,等于用 lint 惩罚正确代码,反过来把人推回 any

要区分就得做作用域解析 —— 便宜、不需要类型信息(所以仍然不进 KNOWN RESIDUAL 等的那趟 typed-lint),但它是一条规则,不是一条选择器。

实测:16 处真实站点全部命中,8 处形似的正确写法 0 误报。

规则复用同一条 SLOT_LOOKUP_ANY_MESSAGE,所以 check:slot-lookup 不需要知道存在第四种形状就能一起计数。

规模

基线 140 → 169 站点,文件数不变仍是 37 —— 其中 29 处本来就躲在祖父名单文件里,纯属不可见

另有 16 处无法被祖父名单兜住,本 PR 全部类型化:

文件
runtime/app-plugin.ts 5
cloud-connection/{runtime-config,marketplace-proxy}-plugin.ts 3
core/fallbacks/authored-translation-sync.ts 2
plugin-security/security-plugin.ts 2
platform-objects/src/plugin.ts 2
runtime/http-dispatcher.tsruntime/domains/ai.ts 各 1

没有新增任何基线 key —— key set 依然只减不增。

顺带记下两处

  • IHttpServer 没有 getRawApp(),而且是刻意的:契约是框架无关的,raw app 是 Hono 自己的句柄。所以逃生口收成一个具名成员,而不是整个查找塌成 any
  • ObjectQL 的 _defaultBodyRunner / _defaultActionRunner 根本没有公开读取口 —— 引擎用 (this as any)._defaultBodyRunner = runner 挂上去,不发布任何 reader,于是"是不是已经有另一个 AppPlugin 装过了"除了直接伸手够那个字段之外无法回答。而 getHookMetricsRecorder() 恰恰就是为 metrics recorder 的同一个问题存在的。已声明出来而不是用 any 洗掉,并记在 The service-lookup any rule misses getService<any>(...) — 80 sites erase the slot contract, 3 of them inside the rule's own scope #4251

范围调整

原计划一并做的 ① 撤销 http.server 豁免没有放进来。这个 PR 已经是"规则 + 16 处修复 + 基线重算",再塞一项会让验证面糊掉。① 单独一个 PR,它本来也独立。

验证

  • pnpm check:slot-lookup 强制模式:✓ 169 unswept site(s) in 37 file(s), none new;baseline key set verified against c54c822: no files added
  • eslint --no-inline-config 全部改动文件 + eslint.config.mjs —— 干净
  • runtime / core / cloud-connection 在 type-check DEBT 名单里(无 typecheck 脚本),因此走 clean-HEAD 基线对比:改动文件内 0 个 tsc 错误,整包错误数前后完全一致(18 / 91 / 13)
  • runtime 974 tests / 68 filescore 437 / 27platform-objects 254 / 8plugin-security 677 / 32 —— 全绿

🤖 Generated with Claude Code

…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>
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 31, 2026 9:36am

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling labels Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 5 package(s): @objectstack/cloud-connection, @objectstack/core, @objectstack/platform-objects, @objectstack/plugin-security, @objectstack/runtime.

46 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/actions-as-tools.mdx (via @objectstack/core)
  • content/docs/ai/knowledge-rag.mdx (via @objectstack/core)
  • content/docs/ai/natural-language-queries.mdx (via @objectstack/core)
  • content/docs/api/client-sdk.mdx (via packages/runtime)
  • content/docs/api/index.mdx (via @objectstack/runtime)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime)
  • content/docs/automation/webhooks.mdx (via @objectstack/core)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx (via packages/core, packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/cli.mdx (via @objectstack/plugin-security)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/core)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime)
  • content/docs/kernel/cluster.mdx (via @objectstack/runtime)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/core)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/core)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/plugin-security)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/core, @objectstack/plugin-security)
  • content/docs/kernel/services.mdx (via @objectstack/core)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authentication.mdx (via @objectstack/core, @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/core, @objectstack/plugin-security, packages/runtime)
  • content/docs/permissions/explain.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/plugin-security)
  • content/docs/plugins/anatomy.mdx (via @objectstack/core)
  • content/docs/plugins/development.mdx (via @objectstack/core)
  • content/docs/plugins/index.mdx (via @objectstack/core, @objectstack/plugin-security)
  • content/docs/plugins/packages.mdx (via @objectstack/core, @objectstack/platform-objects, @objectstack/plugin-security, @objectstack/runtime)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/core)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/core, @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/core, @objectstack/runtime)
  • content/docs/protocol/kernel/metadata-service.mdx (via @objectstack/cloud-connection)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/core)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cloud-connection, @objectstack/core, @objectstack/plugin-security, @objectstack/runtime)
  • content/docs/releases/v12.mdx (via @objectstack/core)
  • content/docs/releases/v15.mdx (via @objectstack/core)
  • content/docs/ui/audience-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/dashboards.mdx (via @objectstack/plugin-security)
  • content/docs/ui/setup-app.mdx (via @objectstack/platform-objects)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…ne (#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>
@os-zhuang
os-zhuang merged commit d92c72d into main Jul 31, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/4251-selector-4-and-http-server-exemption branch July 31, 2026 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant