You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] the @objectstack/hono catch-all's 409 METADATA_CONFLICT names the current version only in prose: measure whether the hosted runtime's PUT /meta reaches it, and if so carry currentVersion as data (a packages/spec change) #22222
Filing gate: ② a conditional carrier for a question #22141 left open on purpose (class (b): a contract gap that matters only if a first-party host reaches the door). Raised by #22141's dev (PR #22206, open_questions[0] of its os-dev-report 6053751704), answered C by the domain:cli seat (REWORK 6053835755), and given a carrier on the independent contract review's advice (record 6054267983, ③ item 6). Filed by the domain:cli seat (seat post #6024, session_01RWZbGvPFcRKvUqASZtunCU). ⛔ Not a claim. Triage sets the grade and the lane.
Behind the @objectstack/hono${prefix}/* catch-all, a stale If-Match on PUT /meta/:type/:name is now refused 409 METADATA_CONFLICT. The envelope is the dispatcher's own: { success: false, error: { code, message, httpStatus } }.
The current version is named only inside the message sentence. A client behind the catch-all cannot re-pin from the refusal without parsing prose or re-reading the item.
RestServer's door answers the same refusal in MetadataConflictErrorSchema's flat dialect, which carries currentVersion as data. That schema's docblock scopes itself to the REST door, so no declared contract binds the dispatcher's envelope.
The protocol's conflict builder already sets currentVersion on the thrown error, so carrying it is cheap once there is a reason.
The condition, and the change if it holds
Measure first: does the hosted runtime (objectstack-ai/cloud, which imports createHonoApp) route PUT /meta to this catch-all, and on which cloud pin? This was not measurable from the domain:cli session.
If it does: declare currentVersion on the dispatcher's error envelope (an ApiErrorSchema member beside declaredCode / userMessage), and have errorFromThrown carry it. That is a packages/spec change, for the domain:spec seat. ⛔ Not an undeclared error.details member: that would mint a dialect ADR-0112 forbids.
If it does not: close this card. The catch-all then has no first-party caller to serve.
Dedupe
MCP search_issues, repo-scoped: 「dispatcher 409 METADATA_CONFLICT currentVersion error envelope catch-all MetadataConflictErrorSchema」 gives 10 hits; none is this. #22114 (closed) is the REST door's half: it added the version token to the draft read and named the prose-only 409 body there. #22128 is a different 409.
Dedupe words: catch-all 409 currentVersion · dispatcher error envelope current version data · hono meta conflict re-pin
Triage: first grade, priority:p3 · domain:spec · area:api · pm:queue (finding removed). Conditional: measure the hosted route first; build only if it holds
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-08T09:03Z. ⛔ Not a claim, ⛔ not a dispatch.
Triage: lands in packages/spec (ApiErrorSchema) plus the dispatcher's errorFromThrown, if the condition holds ⇒ domain:spec; rationale: every card that touches spec goes to the spec seat.
A source reading toward step 1, not the measurement. objectstack-ai/cloud apps/objectos/server/index.ts (main):
it registers createRestApiPlugin;
it mounts createHonoApp({ kernel, prefix: '/api/v1' })underneath the plugin routes;
its own comment says "the plugin routes win the match against the dispatcher's catch-all /api/v1/* handler".
So on that composition, a hosted PUT /meta likely meets RestServer's door, which already carries currentVersion as data, and not the catch-all. Measure it on a hosted tenant before building: a stale If-Match save, then read which envelope answers. Tenant kernels go through the scoped dispatcher, so the reading must come from a tenant host.
If the catch-all is not reached: close this card, as its step 3 says.
If it is:Clause-②: yes. It is a declared envelope member, ⛔ not an error.details dialect (ADR-0112).
Maintainer-action: take one hosted-tenant reading — on a cloud tenant, save PUT /api/v1/meta/<type>/<name> with a stale If-Match, and record which envelope answers the 409: RestServer's flat MetadataConflictErrorSchema (it carries currentVersion as data) or the dispatcher catch-all's { success: false, error: { code, message, httpStatus } } — done when that reading, with the cloud pin it was taken on, is posted on this card
The decision is already made (triage 6056494314): measure first. If the catch-all answers, build the ApiErrorSchemacurrentVersion member (Clause-②: yes) in domain:spec. If RestServer answers, close this card, as its step 3 says. Nothing here asks for a ruling.
Why no seat can do it: the reading must come from a tenant host, because tenant kernels go through the scoped dispatcher. Spec-lane sessions reach neither a hosted tenant nor objectstack-ai/cloud. The previous seat-2 shift raised this in its maintainer chat, and nothing was recorded on this card. This comment records it.
The source reading triage already took points to RestServer: apps/objectos/server/index.ts mounts createHonoApp beneath the plugin routes, and its comment says the plugin routes win the match. A RestServer answer closes the card with no code.
After the reading lands: the director seat verifies it and removes the label, and the card goes back to pm:queue (catch-all) or closes not_planned (RestServer).
Maintainer-action done: measured on a hosted environment. PUT /meta does not reach the @objectstack/hono catch-all, so step 3 applies and this card closes
Run by the maintainer's session 64cb68a6-01c7-4dc6-acc6-ccb459c90ef2 on the maintainer's instruction in chat, 2026-10-11 (「在托管环境上测一次 409」).
Where it ran:
staging environment os-4s63kc (the maintainer's own acceptance environment);
cloud build d43ce896, from x-objectstack-build-sha on /health;
PUT, same body, If-Match: "hmac-sha256:000…0" (stale)
409{"error":"dashboard/zz_probe_22222 has been modified since you loaded it. The version token sent is not the current version (current is hmac-sha256:caaf…).","code":"METADATA_CONFLICT"}
4
GET
200, content unchanged
5
PUT with the current token
200, seq 1 (identical content, no new head)
6
DELETE, then GET
200seq:2, then 404 (cleaned up)
Which door answered. Two independent signals point to RestServer's door, not the dispatcher's catch-all:
The body is the flat { error, code } dialect, not the dispatcher's { success: false, error: { code, message, httpStatus } }.
Why this is structural, not an accident of the pin.
apps/objectos/server/index.ts (ensureApp) registers the plugin routes on the raw Hono app first. Only after that does it mount createHonoApp({ kernel, prefix: '/api/v1' }) with outer.route('/', inner). By Hono's registration order, the route-manager's PUT /api/v1/meta/:type/:name (rest-route-ledger.ts:250, still present on framework main12b9daf7) wins before the catch-all is consulted.
apps/cloud/server/index.ts mounts the same way.
Answer to the card's two questions:
Does the hosted runtime route PUT /meta to the catch-all?No. It reaches RestServer's door. Measured on staging at pin 56bf27af. Production runs the same mount order, but it was not probed: no production write was made for this card.
Disposition: step 3, "If it does not: close this card". The catch-all has no first-party caller for PUT /meta to serve. No packages/spec change is owed. Closing as not planned.
Side note, not a new card: at this pin the hosted 409 names the current version only in prose. That is the pre-#22126 REST body, and the pin move already queued on cloud#2709 resolves it.
Activity
objectstack-fleet commentedon Oct 8, 2026
Triage: first grade,
priority:p3·domain:spec·area:api·pm:queue(findingremoved). Conditional: measure the hosted route first; build only if it holdsTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T09:03Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/spec(ApiErrorSchema) plus the dispatcher'serrorFromThrown, if the condition holds ⇒domain:spec; rationale: every card that touches spec goes to the spec seat.A source reading toward step 1, not the measurement. objectstack-ai/cloud
apps/objectos/server/index.ts(main):createRestApiPlugin;createHonoApp({ kernel, prefix: '/api/v1' })underneath the plugin routes;/api/v1/*handler".So on that composition, a hosted
PUT /metalikely meetsRestServer's door, which already carriescurrentVersionas data, and not the catch-all. Measure it on a hosted tenant before building: a staleIf-Matchsave, then read which envelope answers. Tenant kernels go through the scoped dispatcher, so the reading must come from a tenant host.If the catch-all is not reached: close this card, as its step 3 says.
If it is:
Clause-②: yes. It is a declared envelope member, ⛔ not anerror.detailsdialect (ADR-0112).objectstack-fleet commentedon Oct 10, 2026
pm:queue→pm:awaiting-maintainer: the one step left is a hosted-tenant reading no seat session can takedomain:specseat 2 (#18549) ·marchtian· sessionsession_016njDy8ozy9B9Ns5Y8kAWEK· 2026-10-10T08:19Z. Thread-read: 6056494314.Maintainer-action: take one hosted-tenant reading — on a cloud tenant, save
PUT /api/v1/meta/<type>/<name>with a staleIf-Match, and record which envelope answers the409:RestServer's flatMetadataConflictErrorSchema(it carriescurrentVersionas data) or the dispatcher catch-all's{ success: false, error: { code, message, httpStatus } }— done when that reading, with the cloud pin it was taken on, is posted on this card6056494314): measure first. If the catch-all answers, build theApiErrorSchemacurrentVersionmember (Clause-②: yes) indomain:spec. IfRestServeranswers, close this card, as its step 3 says. Nothing here asks for a ruling.objectstack-ai/cloud. The previous seat-2 shift raised this in its maintainer chat, and nothing was recorded on this card. This comment records it.RestServer:apps/objectos/server/index.tsmountscreateHonoAppbeneath the plugin routes, and its comment says the plugin routes win the match. ARestServeranswer closes the card with no code.pm:queue(catch-all) or closesnot_planned(RestServer).Generated by Claude Code
hotlong commentedon Oct 11, 2026
Maintainer-action done: measured on a hosted environment.
PUT /metadoes not reach the@objectstack/honocatch-all, so step 3 applies and this card closesRun by the maintainer's session
64cb68a6-01c7-4dc6-acc6-ccb459c90ef2on the maintainer's instruction in chat, 2026-10-11 (「在托管环境上测一次 409」).Where it ran:
os-4s63kc(the maintainer's own acceptance environment);d43ce896, fromx-objectstack-build-shaon/health;.objectstack-sha56bf27af(committed 2026-10-07). That pin predates both feat(meta): the /meta item read serves the version token, If-None-Match: * pins a first write, and the 409 carries currentVersion #22126 (8f2e8081, 34 commits later) and fix(runtime): the @objectstack/hono catch-all's PUT /meta honours If-Match, If-None-Match and ?mode=draft #22206 (3aa0c7b5, 76 commits later).The caller was an environment admin session from the product's own SSO hand-off, using same-origin requests from the browser.
The probe used a scratch item made for it and deleted afterwards:
GET /api/v1/meta/dashboard/zz_probe_22222404(absent)PUTwith noIf-Match200{success:true, version:"hmac-sha256:caaf…", seq:1, state:"active"}PUT, same body,If-Match: "hmac-sha256:000…0"(stale)409{"error":"dashboard/zz_probe_22222 has been modified since you loaded it. The version token sent is not the current version (current is hmac-sha256:caaf…).","code":"METADATA_CONFLICT"}GET200, content unchangedPUTwith the current token200,seq1 (identical content, no new head)DELETE, thenGET200seq:2, then404(cleaned up)Which door answered. Two independent signals point to
RestServer's door, not the dispatcher's catch-all:If-Matchwas honoured. At pin56bf27afthe catch-all does not readIf-Matchat all; fix(runtime): the @objectstack/hono catch-all's PUT /meta honours If-Match, If-None-Match and ?mode=draft #22206 is what taught it, and fix(runtime): the @objectstack/hono catch-all's PUT /meta honours If-Match, If-None-Match and ?mode=draft #22206 is not in the pin. If the catch-all had answered, step 3 would have saved and answered200.{ error, code }dialect, not the dispatcher's{ success: false, error: { code, message, httpStatus } }.Why this is structural, not an accident of the pin.
apps/objectos/server/index.ts(ensureApp) registers the plugin routes on the raw Hono app first. Only after that does it mountcreateHonoApp({ kernel, prefix: '/api/v1' })withouter.route('/', inner). By Hono's registration order, the route-manager'sPUT /api/v1/meta/:type/:name(rest-route-ledger.ts:250, still present on frameworkmain12b9daf7) wins before the catch-all is consulted.apps/cloud/server/index.tsmounts the same way.Answer to the card's two questions:
PUT /metato the catch-all? No. It reachesRestServer's door. Measured on staging at pin56bf27af. Production runs the same mount order, but it was not probed: no production write was made for this card.56bf27aftoday. When cloud's pin moves past feat(meta): the /meta item read serves the version token, If-None-Match: * pins a first write, and the 409 carries currentVersion #22126 (cloud#2709), the same door begins to carrycurrentVersionas data. That door is already the one hosted callers hit, so the version needs no new dispatcher-envelope member.Disposition: step 3, "If it does not: close this card". The catch-all has no first-party caller for
PUT /metato serve. Nopackages/specchange is owed. Closing as not planned.Side note, not a new card: at this pin the hosted 409 names the current version only in prose. That is the pre-#22126 REST body, and the pin move already queued on cloud#2709 resolves it.
Generated by Claude Code