Found while implementing #9436 (which stays open until its own PR lands; nothing here closes it). Measured on main at 4c260cd. Filed unassigned — recording, not starting.
The gap
packages/runtime/src/dispatcher-plugin.ts serves two discovery bodies in the exact shape #9436 was ruled on, and neither is visible to scripts/check-route-envelope.mjs:
| route | site | condition |
|---|
GET /.well-known/objectstack | res.json({ data: await dispatcher.getDiscoveryInfo(prefix) }), ~line 738 | unconditional — this route is dispatcher-owned in every composition (ADR-0076 D11 / OQ#9) |
GET {prefix}/discovery | same body, ~line 765 | registered only when com.objectstack.rest.api is absent (REST-less compositions; otherwise ceded to REST) |
Both are { data } with no success key — one key short of BaseResponseSchema, the same distance the hono adapter's discovery bodies were before #9436's ruling (2026-08-18, option A: envelope them, because machine-read discovery surfaces are the envelope's core constituency and the migration is one key).
Why this is a triage call, not an inherited fix
The #9436 ruling's operative text names only packages/adapters/hono/src/index.ts. The consumer population here is the same — /.well-known/objectstack is the SDK's own discovery fallback probe (connect() in packages/client/src/index.ts reads it), pre-auth, machine-read — so the ruling's reasoning extends naturally, but extending a ruling is not an implementer's move. Note the boundary drawn in #9389 does not cover these either: that exemption is a closed list of SPA-read shell-bootstrap surfaces, and these are not on it.
Reader tolerance is already measured (same sweep as #9436, controls reported there): the SDK unwraps body.data || body; the QA http-adapter discriminates on 'routes' in body; objectui's readers unwrap only when typeof body.success === 'boolean' && 'data' in body. An additive success: true breaks none of them.
Second half: the gate cannot see these sites either way
check-route-envelope.mjs audits three populations: response-envelope write sites, runtime/src/domains/* (returned payload objects), and Hono-context modules listed in PLUGIN_ROUTE_MODULES (judging c.json(...) / ctx.json(...) calls). dispatcher-plugin.ts writes through an express-style res.json(...) on an IHttpServer, which is none of the three — so whichever way the fork is ruled (envelope, or exempt-with-reason), the verdict has no place in the gate table to be recorded until the scan surface grows a fourth population (or these two sites move behind an audited seam).
If the fork is ruled toward the envelope
Two doc pages document the current { data } wrap for the well-known endpoint and would ride the flip: content/docs/api/index.mdx (~line 154) and content/docs/protocol/kernel/http-protocol.mdx (~lines 111–115).
Related: #9436 (the ruling on the hono adapter's mount) · #9389 (the pre-auth exemption boundary, a closed list) · #9559 (rest-server's own envelope conversion; dispatcher-plugin.ts is not in its scope).
Generated by Claude Code
Found while implementing #9436 (which stays open until its own PR lands; nothing here closes it). Measured on
mainat 4c260cd. Filed unassigned — recording, not starting.The gap
packages/runtime/src/dispatcher-plugin.tsserves two discovery bodies in the exact shape #9436 was ruled on, and neither is visible toscripts/check-route-envelope.mjs:GET /.well-known/objectstackres.json({ data: await dispatcher.getDiscoveryInfo(prefix) }), ~line 738GET {prefix}/discoverycom.objectstack.rest.apiis absent (REST-less compositions; otherwise ceded to REST)Both are
{ data }with nosuccesskey — one key short ofBaseResponseSchema, the same distance the hono adapter's discovery bodies were before #9436's ruling (2026-08-18, option A: envelope them, because machine-read discovery surfaces are the envelope's core constituency and the migration is one key).Why this is a triage call, not an inherited fix
The #9436 ruling's operative text names only
packages/adapters/hono/src/index.ts. The consumer population here is the same —/.well-known/objectstackis the SDK's own discovery fallback probe (connect()inpackages/client/src/index.tsreads it), pre-auth, machine-read — so the ruling's reasoning extends naturally, but extending a ruling is not an implementer's move. Note the boundary drawn in #9389 does not cover these either: that exemption is a closed list of SPA-read shell-bootstrap surfaces, and these are not on it.Reader tolerance is already measured (same sweep as #9436, controls reported there): the SDK unwraps
body.data || body; the QA http-adapter discriminates on'routes' in body; objectui's readers unwrap only whentypeof body.success === 'boolean' && 'data' in body. An additivesuccess: truebreaks none of them.Second half: the gate cannot see these sites either way
check-route-envelope.mjsaudits three populations: response-envelope write sites,runtime/src/domains/*(returned payload objects), and Hono-context modules listed inPLUGIN_ROUTE_MODULES(judgingc.json(...)/ctx.json(...)calls).dispatcher-plugin.tswrites through an express-styleres.json(...)on anIHttpServer, which is none of the three — so whichever way the fork is ruled (envelope, or exempt-with-reason), the verdict has no place in the gate table to be recorded until the scan surface grows a fourth population (or these two sites move behind an audited seam).If the fork is ruled toward the envelope
Two doc pages document the current
{ data }wrap for the well-known endpoint and would ride the flip:content/docs/api/index.mdx(~line 154) andcontent/docs/protocol/kernel/http-protocol.mdx(~lines 111–115).Related: #9436 (the ruling on the hono adapter's mount) · #9389 (the pre-auth exemption boundary, a closed list) · #9559 (rest-server's own envelope conversion;
dispatcher-plugin.tsis not in its scope).Generated by Claude Code