Skip to content

fix(lint,metadata): 撤销 http.server 豁免 —— 它的理由本身是错的 (#4251) - #4382

Merged
os-zhuang merged 1 commit into
mainfrom
claude/4251-http-server-exemption
Jul 31, 2026
Merged

fix(lint,metadata): 撤销 http.server 豁免 —— 它的理由本身是错的 (#4251)#4382
os-zhuang merged 1 commit into
mainfrom
claude/4251-http-server-exemption

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

清单里的

那条豁免的理由是错的

#4321http.server 写进 UNCONTRACTED_SLOTS,理由写的是"不存在 IHttpServer 契约"。该契约存在 —— packages/spec/src/contracts/http-server.ts —— 而且写下这条豁免时,已经有 8 个调用点在用 getService<IHttpServer>(…)

豁免和别的断言一样是一个 claim,而这一条建立在没人核过的前提上 —— 正是这条规则本身要抓的那种形状

撤销之后露出 9 处

从未入列的文件 7
已入列文件的计数增长 2

两种基线都不能合法吸收。全部类型化到 IHttpServer;packages/metadata/src/plugin.ts 因此整个清空,基线下降到 168 站点 / 36 文件,并少掉一个文件。

8 个测试站点调 getPort()(契约上是可选成员),按契约写成 getPort!() —— 它们刚 bootstrap 完自己的 server,这个断言是准确的。

另外两点:已确认,只报告不改

http.serverhttp-server 是同一个实例的两个注册名。 plugin-hono-server 和 qa 的 node-plugin 各自并排注册两行;runtime 的 config.server 路径只注册带点的那个。metadata/src/plugin.ts?? 同时读两个 —— 这就是它一直没暴露的原因。本 PR 不删任何注册 —— 那是运行时行为变更,该由决定规范名的人来做。

IHttpServer 有两份定义,而且已经分叉。 packages/spec/src/contracts/http-server.ts(15 个导入方)声明了 write?()end?();packages/core/src/contracts/http-server.ts(8 个导入方)没有。spec 那份是超集,也是 ledger 指向的那份,所以它是源;core 那份是过期的近似复制,应当改为 re-export。单独一个变更 —— 合并一份重复契约不是 lint 修复。

给写更宽 HTTP 契约的人留一条证据

getRawApp() 现在有了第三个独立消费方(metadata 的 HMR 路由,加上 cloud-connection 的两个)。它刻意不在 IHttpServer 上 —— 契约框架无关,raw app 是框架自己的句柄 —— 所以每个消费方各自具名声明。三个足够用来判断这是不是仍然是对的答案了。

验证

  • pnpm check:slot-lookup 强制模式:✓ 168 unswept site(s) in 36 file(s), none new;no files added(对 d92c72d)
  • eslint --no-inline-config 全部改动文件 —— 干净
  • metadata dts build 成功(该包在 type-check DEBT 名单,build 才是类型门 —— 这是上个 PR 的教训)
  • runtime 995 / 68client 204 / 15metadata 281 / 13http-conformance 46 / 2 —— 全绿

🤖 Generated with Claude Code

#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: 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 10:02am

Request Review

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata.

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

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata)
  • content/docs/kernel/cluster.mdx (via packages/metadata)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/metadata)
  • content/docs/plugins/packages.mdx (via @objectstack/metadata)
  • content/docs/protocol/kernel/metadata-service.mdx (via @objectstack/metadata)
  • content/docs/releases/v12.mdx (via @objectstack/metadata)
  • content/docs/releases/v9.mdx (via @objectstack/metadata)

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.

@os-zhuang
os-zhuang merged commit 10575f3 into main Jul 31, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/4251-http-server-exemption branch July 31, 2026 10:14
os-zhuang added a commit that referenced this pull request Jul 31, 2026
…erver 定为 canonical 并入账 ledger (#4251) (#4393)

* fix(spec,core,cloud-connection,metadata): one HTTP contract, one canonical slot name (#4251)

packages/core/src/contracts/ was a dead near-copy of the real contracts --
zero importers (no relative import, no subpath export, not a tsup entry;
core's barrel has re-exported the spec versions all along) -- and it had
already DIVERGED (spec's IHttpResponse grew write?/end?, IHttpRequest grew
rawBody?; the copy never did). Anyone who grepped into it read a stale
contract nothing enforces -- the both-humans-and-AI failure mode behind
the false http.server exemption (#4382). Deleted; zero-risk by
construction.

`http.server` is the canonical slot name and the ledger now says so:
ServiceSlotContracts gains 'http.server': IHttpServer plus the deprecated
'http-server' alias entry (same instance -- hono-plugin, qa node-plugin
and cloud's two server entrypoints all register both, alias commented
"backward compatibility"). Canonical is the only name on EVERY provider
path -- runtime's config.server path registers no alias, so the three
cloud-connection plugins reading the alias alone found an empty slot
there. All readers now go canonical-first with the alias as a fallback
that dies with the alias registrations; registrations untouched this
release, both sites carry the deprecation note.

getRawApp?(): any joins IHttpServer -- the deliberate framework-handle
escape, declared once with the rationale; four consumers declared it
locally before (cloud-connection x2, metadata HMR, cloud node-server),
and the local RawAppHost / HttpServerWithRawApp types are deleted.

IMetadataService.bulkRegister/bulkUnregister declare the write options
their implementation always accepted (bulkRegister's contract dropped the
MetadataWriteOptions half it intersects in; bulkUnregister declared no
options at all). Same shape as B2's IDataEngine read-methods gap.

Baseline 168 -> 167 (marketplace-install-local's lookup typed while
touched). Ledger test pins both slot entries and the alias equality.

Verified: spec build (dts) + 7192 tests / 281 files; core, metadata,
cloud-connection, plugin-hono-server dts builds; runtime 1001/69, rest
539/36, plugin-auth 579/26, plugin-sharing 226/11, service-settings
196/14, metadata 281/13, hono-server 135/12, http-conformance 46/2;
ratchet holds 167/36 none new; eslint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(cloud-connection,metadata): the canonical-first read needs a per-name try -- getService throws on an empty slot (#4251)

CI caught the shape my local run could not (I built cloud-connection but ran
only metadata's tests -- cloud-connection's own suites mock a kernel that
registers ONLY the alias): `getService` THROWS for an unregistered slot, so

    try { a = getService('http.server') ?? getService('http-server'); } catch {...}

never reaches the alias -- the first name's throw exits the whole try. Split
into a per-name try (readServer helper) in all four readers.

Worth recording: the pre-existing alias-first read in metadata/plugin.ts had
the SAME shape, so its `?? getService('http.server')` fallback never once
fired either -- a decorative fallback, the declared-vs-actual gap this work
line keeps finding, now actually implemented in both directions.

Verified serially (the earlier 6-file FAIL was local vitest concurrency noise
while spec's dts build ran in parallel -- single-file and serial reruns green):
cloud-connection 64/12, metadata 281/13, both dts builds, eslint clean.

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>
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 tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant