Uh oh!
There was an error while loading. Please reload this page.
feat(runtime): envelope the dispatcher's two discovery bodies (#9813) - #9949
Conversation
Inherits the #9436 maintainer ruling (2026-08-18, option A) with its reason intact: machine-read discovery bodies are the envelope's core constituency and the migration is one additive key. Adds success: true to both GET /.well-known/objectstack and the REST-less GET {prefix}/discovery fallback, pins the shape in dispatcher-plugin.routes.test.ts, updates the two documenting pages, and grows check-route-envelope.mjs an enumerated fourth scan population for express-style res.json writes on an IHttpServer (dispatcher-plugin.ts: unenveloped 1, ratcheted to #9936; the discovery walk for the dialect is #9937). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WeN7F6jQFpcqW2BN56RdPa
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ce1fdfac330af599fade5d5d2974d044a2b9f567 && git checkout ce1fdfac330af599fade5d5d2974d044a2b9f567
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ba5709cbd630a4d4aa5ced28402a6c5250bb489e f78a83e0cc05d1425822117f33aca27c81920c56 && git checkout -B drift-repro ba5709cbd630a4d4aa5ced28402a6c5250bb489e && git merge --no-ff f78a83e0cc05d1425822117f33aca27c81920c56
node scripts/docs-audit/affected-docs.mjs --json ba5709cbd630a4d4aa5ced28402a6c5250bb489e
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#9813
Implements the inherited #9436 maintainer ruling (2026-08-18, option A — envelope machine-read discovery bodies, because they are the envelope's core constituency and the migration is one additive key), applied to the runtime dispatcher's two discovery bodies in
packages/runtime/src/dispatcher-plugin.ts. All readings below at headf78a83e0cc.The flip (additive only)
Both bodies located by text (the card's ~738/~765 and the claim's :775/:801 were both stale spellings of the same two sites):
GET /.well-known/objectstack(unconditionally dispatcher-owned) —{ data }→{ success: true, data }.GET {prefix}/discovery— same flip. Its registration condition re-verified live, not assumed:kernel.hasPlugin('com.objectstack.rest.api')still gates it, so the route is the fallback owner in REST-less compositions, not dead.No key removed or moved. Reader tolerance re-measured, not inherited (population stated per sweep):
connect()(packages/client/src/index.ts:532/:557):body.data || body— unaffected.packages/core/src/qa/http-adapter.ts:140): discriminates'routes' in body, else unwrapsbody.data— unaffected. (Its comment describing the dispatcher wrap as{ data }stays literally true of the unwrap logic it explains — thedatakey is still what carries the document — so it was deliberately left untouched rather than widening this PR intopackages/core.)97fba31(control: 156fetch(sites): readers discriminate ontypeof body.success === 'boolean' && 'data' in body— today's bare shape fails that predicate; the flip makes these routes unwrap correctly, the same measurement adapters/hono's two bare{ data }discovery bodies lose their ratchet owner when #9364 lands #9436 reported.well-known/objectstack: 38 hits across 4457 non-dist.tsfiles, all tests/route tables/comments/redirects — no intolerant reader. The single reopening condition (a reader that chokes) did not fire.Pinned in
dispatcher-plugin.routes.test.ts: both handlers answer exactly the top-level key set['data', 'success']withsuccess === true.The gate half — rode the PR, judged small
scripts/check-route-envelope.mjsgrew a fourth scan population for express-styleres.json(...)writes on anIHttpServer— enumerated, not discovered: the scanner's receiver set is now a parameter (Hono pair stays the default), andIHTTP_ROUTE_MODULESnamesdispatcher-plugin.ts, audited through the sameauditPluginRouteModulegrammar. Noexemptentry anywhere (the rejected option B), and no existing counter weakened — the gate before/after readings are in the issue report. A discovery walk for the dialect is real gate-architecture work (fetch's zero-argres.json()READ shares the receiver spelling; 20 candidate files measured) and is filed as follow-up #9937 per the dispatch instruction — #9937 is not addressed here.The new population's scan found one genuinely off-envelope literal body beyond the card's two: the SSE-fallback
res.json({ events }). That is a different consumer population, so the inherited ruling does not reach it — filed as #9936 (which remains open) and pinned asunenveloped: 1, ratchet: #9936, the first-registration path the gate's own NOT-DECLARED text prescribes.Docs
Complete documented set re-swept with a control (12
well-known/objectstackhits across 393 mdx files): the two pages the card named are the set, but with three wrap-documenting spots, not two —content/docs/api/index.mdx(the wrap sentence) andcontent/docs/protocol/kernel/http-protocol.mdx(the wrap sentence + JSON example, and the REST-less callout's envelope parenthetical at ~:224, which the card missed). All three updated.realtime-protocol.mdx:110 shows inner fields with no envelope at all (pre-existing elision, equally true after an additive key) andclient-sdk.mdx:82 documents probing, not shape — both left.Changeset
minoron@objectstack/runtime, ADR-0087 markernot-required (no-migration-prescription)with the measured-reader reasoning inline — mirrors the accepted #9814 pattern.Verification
check:route-envelopebefore: 3 populations, exit 0; after: 4 populations, exit 0, self-test green (new pins: same source reads 0 bodies under Hono receivers andunenveloped 1under express receivers; relayed bodies counted, never judged)../dispatcher-plugin.jsrelatively through vitest): de-enveloping one body → gate exit 1 withunenveloped: found 2, declared 1and exactly the mutated route's pin red (1 failed / 15 passed); restored via checkout from the branch → gate exit 0, 16/16 green.@objectstack/runtime: 176 test files / 2629 tests pass,tsc --noEmitexit 0. Downstream integration:@objectstack/http-conformance(boots a real composition and fetches these routes) 86/86 pass against the rebuilt runtime.node scripts/pm/dispatch-gates.mjs(no hand-fed paths) plus mandatedpnpm lint: all exit 0, details in the issue report.Generated by Claude Code