test(runtime): 把「谁在服务 /data 与 /discovery」钉成事实,用证据挡住 #4073 的默认值翻转 - #4192
Merged
os-zhuang merged 1 commit intoJul 30, 2026
Merged
Conversation
…flip on evidence #4073's retirement plan — flip `registerStandardEndpoints` to `false`, observe a release, delete `registerDiscoveryAndCrudEndpoints` — rests on the whole surface being DUPLICATE supply. Booted for real (real HonoServerPlugin + dispatcher + `createRestApiPlugin`, real listener, `serve.ts` registration order), that holds for only one half: rest=true flag=ON → /api/v1/data/account 401 (mounted, #2567 gate fired) rest=true flag=OFF → /api/v1/data/account 404 (nothing serves it) rest=false flag=ON → 401 rest=false flag=OFF → 404 `/discovery` is the opposite and is safe: it cedes on an explicit `kernel.hasPlugin(rest|dispatcher)` check (#4018), so the dispatcher's computed payload answers either way — order-independent, verified both ways here. `/data/:object` has no such check. Its shadowing was asserted purely on "REST registers first and wins", and that is not what the listener does. Flipping the default would turn the path into a 404 rather than handing it to REST. Narrower than it may read, and the file says so: REST is mounted with a minimal service set, so this proves "nothing in these compositions serves /data once the flag is off", not "REST never serves it". That is still enough to block a default flip that assumes otherwise — and if a fully provisioned REST does mount it, the assertion that fails is the signal to re-read #4073, which the message says inline. No production code changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016gEeLZ4oTeSXG6fKG1r3vd
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckNo hand-written docs reference the 0 changed package(s). ✅ |
os-zhuang
marked this pull request as ready for review
July 30, 2026 15:05
os-zhuang
added a commit
that referenced
this pull request
Jul 31, 2026
… composed host (#4260) #4192 (mine) concluded that turning `registerStandardEndpoints` off makes `/api/v1/data/:object` a 404, and blocked #4073's retirement on it. Wrong, and wrong in the same shape the issue has already been corrected for twice. That test mounted `createRestApiPlugin({})` against a STUB `objectql` service. REST generates its CRUD from the object registry, so it needs a real engine — driver plus registered objects — and its own `api.api` config. Under-provision it and it serves nothing; the 404 was a fact about the harness, not about REST. `packages/client/src/client.environment-scoping.test.ts` had the answer the whole time: it boots `registerStandardEndpoints: false` and asserts `GET /api/v1/data/task` → 200, served by REST, with a comment saying that is the point. Reproducing that provisioning: /api/v1/data/task?top=5 flag ON == flag OFF /api/v1/discovery flag ON == flag OFF /.well-known/objectstack flag ON == flag OFF Byte-identical responses, both halves. The surface is duplicate supply, and the flip is a no-op for any host mounting REST or the dispatcher — every composed deployment, `os serve` included. The test now compares the two positions instead of asserting a status, because a status is exactly what misled the previous version: `/data/task` answers 404 `OBJECT_NOT_FOUND` — the ENGINE's answer, reached through a working route — where a routing miss would be `{"error":"Not found"}`. Parity does not depend on telling those apart, and a separate assertion pins that the compared routes are live so parity cannot be satisfied by two identical misses. What this does NOT do is flip the default. That remains a real change for a BARE host mounting neither, which is the composition the flag was written for — an API decision, not one a test should make. It is now unblocked and evidenced, which is what #4192 wrongly denied it. No production code changes.
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.
#4073 的退役计划是:
registerStandardEndpoints默认翻false→ 观察一个 release → 删除registerDiscoveryAndCrudEndpoints。前置拆分已经完成(#4144 把三条/me/*挪出了这个门),所以下一步本该是翻默认值。我去做这一步,先验证它是不是计划所说的 no-op。不是。
实测
真实
HonoServerPlugin+ 真实 dispatcher + 真实createRestApiPlugin,真实监听端口,按serve.ts的注册顺序装配:GET /api/v1/data/account这个面的两半,性质完全不同:
/discovery+/.well-known/objectstack—— 安全。 它们靠kernel.hasPlugin(rest|dispatcher)显式 cede(plugin-hono-server 的 registerStandardEndpoints 静态 discovery 硬编码整张路由表 —— 与 D12 "按注册计算" 的两个真 discovery 面不一致 #4018),与注册顺序无关,所以无论 flag 开关,应答的都是 dispatcher 计算出的 payload。本 PR 两个方向都验证了。/data/:object—— 不安全。 它没有 cede 判断。它的"被遮蔽"完全建立在"REST 先注册先赢"这一条推断上,而真实监听器上不是这样:翻掉默认值不会把这条路径交给 REST,而是让它变成 404。所以本 PR 只做一件事
不翻默认值。加上说明这一点的测试,断言当前矩阵,让下一次尝试必须正面回应它,而不是重新推导一遍那个假设。无任何生产代码改动。
/data那两条断言的失败信息直接写了下一步该干什么:边界(文件里也写了,免得被过度解读)
REST 在这个 harness 里只配了最小服务集(
objectql+auth)。真实os serve还有 metadata/protocol 等服务,REST 可能要等这些解析完才挂/data。所以本 PR 证明的是**「flag 关掉后,这些装配里没有任何东西服务/data」**,不是「REST 从不服务/data」。但这已足以挡住一个假设了相反前提的默认值翻转 —— 而且如果完整供给的 REST 确实会挂上这条路径,那条断言就会失败,那正是该回头重读 #4073 的信号。
这也正是 #4073 自己订正过一次的那类错误("我当时查的是谁传这个选项,没查谁依赖这个默认值")—— 这次是"查的是谁声称提供,没查真实监听器上谁应答"。
关联
#4073、#4018(cede 机制)、#2567(匿名闸门,401 的来源)、#4144(前置拆分,已合并)。
🤖 Generated with Claude Code
https://claude.ai/code/session_016gEeLZ4oTeSXG6fKG1r3vd
Generated by Claude Code