Skip to content

fix(runtime,metadata-protocol): data 槽位也改为计算,硬编块就此清空 (#4130) - #4141

Merged
os-zhuang merged 1 commit into
mainfrom
claude/core-fallback-i18n-issue-2sdl2a
Jul 30, 2026
Merged

fix(runtime,metadata-protocol): data 槽位也改为计算,硬编块就此清空 (#4130)#4141
os-zhuang merged 1 commit into
mainfrom
claude/core-fallback-i18n-issue-2sdl2a

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #4130 · 接 #4114 / #4089

问题

#4089 让两个 builder 把 metadata 槽位改成读实现自己的 __serviceInfo,同一个 "kernel-provided" 硬编块里就只剩 data 还在自己给自己下判决 —— 两边都无条件写 status: 'available' + handlerReady: true

这句话目前是真的,但真在别的包里data 只有一个 producer(ObjectQLPluginctx.registerService('data', this.ql)),而 plugin-dev 只在槽位为空时才填 stub、却总把 ObjectQLPlugin 当子插件加载,所以它那个 data stub(find() 恒返回 []insert() 发个 id 什么都不存,DEV_STUB_SELF_INFO 里分类为 stub)永远进不来。两个 builder 谁也没验证过这条链 —— 这正是 metadata 那两条硬编在"还大致成立"阶段的同一形状,而且发生在平台最核心的槽位上。

改动

两个 builder 都改成读槽位的 __serviceInfo

  • 真引擎不带标记 ⇒ available + handlerReady: true,与被替换的硬编逐字节相同(不只用 mock 验证,真实内核启动那条也钉了);
  • 自称 stub ⇒ 用它自己的 status / messagehandlerReady: falsereadServiceSelfInfostub 的默认值),于是按 handlerReady 判断的消费者不再把空查询引擎当真引擎。

为什么这里 handlerReady 是算出来的,而 metadata 那边钉死 true —— 两条 entry 各说自己那条路由的实情:/meta 无论槽位里是什么都由 protocol 兜底作答(最后还有一层默认类型表),degraded 实现不会把它卸掉;/data 没有这层地板 —— callData 需要 protocol 服务或 objectql 形状的服务,两者都没有就抛 503,而 stub 能占住 data 槽位的唯一前提恰恰是 ObjectQL 从未注册,也就是 /data 根本没法服务的那种栈。

刻意没做:在 builder 里用 protocol / objectql 重新推导 serveability。discovery 解析服务是不带 scope 的(它没有请求上下文),多内核 host 上这会把 required 的 data 能力报成 handlerReady: false,而按请求 scope 解析其实服务得很好 —— 那比现在这个谎更糟。这个字段也不驱动任何路由:data domain 自己直接解析引擎,isServiceServeable#4058 step 2)只管可选域。

测试

  • packages/runtime/src/http-dispatcher.test.ts — 真引擎(无标记)仍报 available/handlerReady: true/provider: kernel/无 message;plugin-dev 那条真实 marker ⇒ stub + handlerReady: false + message 含 ObjectQLPlugin跨 builder 一致性扩到 data(同一实例交给两个 builder,status/handlerReady/message/route 必须相同)。
  • packages/objectql/src/protocol-discovery.test.ts — metadata-protocol 侧同样两个方向。
  • packages/objectql/src/plugin.integration.test.ts — 真实 ObjectKernel + ObjectQLPlugin 启动后,同一份 discovery 里 data 仍是 available/handlerReady: true/无 message,即"改成计算"没有把真栈的答案改掉。

已跑通:runtime(65) objectql(81) metadata-protocol spec(270) core(26) rest(35) plugin-hono-server(12) plugin-dev metadata hono 全绿;改动文件 eslint 干净,http-dispatcher.ts / protocol.ts 无新增类型错误。

文档 / changeset


Generated by Claude Code

… too, closing the hardcoded kernel block (#4130)

#4089 made both discovery builders derive the `metadata` entry from the
implementation in the slot. `data` was the one entry left that judged itself:
`status: 'available'`, `handlerReady: true`, unconditionally, in both builders.

That was true — by a convention in a different package. ObjectQL is the slot's
only producer (`ctx.registerService('data', this.ql)`), and plugin-dev fills a
core slot only when it is empty while always loading `ObjectQLPlugin` as a child,
so plugin-dev's `data` stub — `find()` returns `[]`, `insert()` mints an id and
stores nothing — never reaches the slot. Neither builder verified any of that.
It is the same shape the `metadata` hardcodes had while they were still "roughly
right", on the platform's most load-bearing capability, and it breaks the moment
a second `data` producer appears or a dev config drops the ObjectQL child.

Both builders now read the slot's `__serviceInfo`:

- a real engine carries no marker ⇒ `available` + `handlerReady: true`, which is
  byte-identical to the hardcode it replaces (pinned on a real kernel boot, not
  just on mocks);
- a self-declared stub ⇒ its own `status` / `message`, and `handlerReady: false`,
  which `readServiceSelfInfo` already defaults for `stub`.

`handlerReady` is derived here rather than pinned `true` as it is for `metadata`,
because each entry says what its own route does. `/meta` answers from the
protocol — down to a last-resort default type list — whatever fills the metadata
slot, so a degraded implementation there does not unmount it. `/data` has no such
floor: `callData` needs the `protocol` service or an objectql-shaped one and
throws 503 without them, and the only way a stub occupies the `data` slot is a
stack where ObjectQL never registered, i.e. exactly the stack where `/data`
cannot serve.

Deliberately NOT done: re-deriving serveability from `protocol`/`objectql` inside
the builder. Discovery resolves services UNSCOPED (it has no request context), so
on a multi-kernel host that could report the required data capability as
`handlerReady: false` while per-request scoped resolution serves it fine — a
worse lie than the one being fixed. Nothing routes off this field either: the
`data` domain resolves its engine directly, and `isServiceServeable` (#4058 step
2) gates the optional domains only.

Tests: both directions per builder, the cross-builder agreement extended to
`data` (same instance ⇒ same status / handlerReady / message / route), and the
real-boot assertion that a live ObjectQL keeps reporting `available`.

Closes #4130

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RfdfmzBq2hdp6gzHaK1S9p
@vercel

vercel Bot commented Jul 30, 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 30, 2026 11:08am

Request Review

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/metadata-protocol, @objectstack/runtime.

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

  • 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/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-protocol)
  • content/docs/concepts/north-star.mdx (via packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • 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/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime)
  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime)

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 marked this pull request as ready for review July 30, 2026 11:19
@os-zhuang
os-zhuang merged commit 0373d52 into main Jul 30, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/core-fallback-i18n-issue-2sdl2a branch July 30, 2026 11:19
os-zhuang added a commit that referenced this pull request Jul 31, 2026
…ory, not spot checks (#3898) (#4306)

The three holes #3898 inventoried are all closed on main — #4082 eliminated
the `_fallback` marker by moving every kernel fallback onto the standard
`__serviceInfo` descriptor, #4114 made both discovery builders compute the
`metadata` slot, #4141 did the same for `data`. What remained was the issue's
suggestion 4: a recurrence gate over the known-fake INVENTORY rather than
per-slot spot checks.

This adds that gate to both discovery builders' suites: iterate
CORE_FALLBACK_FACTORIES (the complete fake inventory now that plugin-dev's
stub table is retired, ADR-0115), register each product into its own slot,
and assert discovery reports it `degraded` — never `available`. Table-driven,
so the next fallback added to the table is gated the day it lands.

cache/queue/job had no per-slot pin before this: dropping their
`svcAvailable(…, svc)` third argument — the exact #4130 regression shape —
was test-invisible. Verified the gate bites by simulating that regression
(`services.cache.status: expected 'available' to be 'degraded'`).

Closes #3898

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Fable 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.

discovery 的 data 槽位仍是硬编 available —— 目前只靠 plugin-dev 的加载顺序约定兜住,不是构造上的保证

2 participants