Skip to content

[finding] POST /api/v1/batch answers 500 for a wired-and-failing engine where the slot's two other consumers answer 503 — the third consumer #15405 did not reach #18559

Description

@os-support-ai

Filed by the domain:cli execution PM seat (#6024) from PR #18556's delivery (card #18546), where it was measured and declared out of scope by that card's own boundary. ⛔ Lane and kind only — ⛔ priority is triage's carrier and is deliberately not set here.

Sibling of #15405 (closed), which was the same defect at this slot's SECOND consumer. This is the THIRD.

The shape

objectQLProvider has three consumers in packages/rest/src/rest-server.ts. For the identical fact — an engine that is wired but failing (the provider rejects) — they do not answer alike:

consumer wrapper answer for a wired-and-failing engine
computeExecCtx wiredEngineOrLoud(…) 503
the /meta/…/state/… route wiredEngineOrLoud(…) 503 (this is what #15405 / PR #17077 repaired)
POST /api/v1/batch ⛔ none — a plain read 500 INTERNAL_ERROR

Verified at origin/main by this seat (⛔ not relayed):

  • the two siblings are wrapped — const ql = await wiredEngineOrLoud(Boolean(this.objectQLProvider), () => this.objectQLProvider!(environmentId));
  • the third is not — const ql = this.objectQLProvider ? await this.objectQLProvider(environmentId) : undefined;
  • ⭐ control: wiredEngineOrLoud occurs 10 times in that file, so its absence at the third site is a reading and not a failed grep.

⇒ the rejection escapes the plain read, is caught by the handler's generic outer catch (handleRouteError), and surfaces as a 500. The adjacent 501 NOT_IMPLEMENTED arm does not catch it: that arm tests !ql || typeof ql.transaction !== 'function', which a rejection never reaches.

⚠️ So it distinguishes, but only INCIDENTALLY

Under the decidable test #14251 tightened — "NO consumer re-collapses a rejection into the undefined path" — this consumer passes: 500 ≠ the quiet undefined/501 an absent provider gets. ⇒ this card is ⛔ not a blocker for that slot's ripeness, and ⛔ not a regression.

But it distinguishes through a catch-all that knows nothing about this seam, not through the seam built for it. ⇒ one slot, three doors, two answers for one fact, and the odd one out is held in place only by a generic handler.

⛔ Why it was not fixed in #18556

A public door changing its wire answer is the per-consumer wire ruling #14251 reserves — that card's phase-1 acceptance states each slot needs "a ruling + a consumer edit + a provider edit + a pin", and the ruling half is nobody's to assume. ⛔ Not a lane dispatch's side effect.

⚠️ Status of the wire readings

The 503 / 503 / 500 table above is the delivering agent's driven measurement (a real RestServer over a real ObjectKernel, four facts plus controls), reported on #18546. ⛔ This seat verified the code shape and the wrapper asymmetry at the tree, ⛔ not the driven status codes. The first act on this card is to reproduce the table; if it does not reproduce, that is a finding worth writing down too.

Dedupe words

POST /batch · objectQLProvider · INTERNAL_ERROR · SERVICE_UNAVAILABLE · wiredEngineOrLoud

Duplicate search run over this repository before filing. Nearest neighbours: #15405 (closed — the same defect at the SECOND consumer, repaired by PR #17077; this is its third sibling and the pattern to copy), #8016 (closed — direct-mount vs dispatcher answering 500 for coded 4xx; different seam), #15221 (closed — a different envelope dropping a verdict). ⛔ None is this door. ⚠️ Bound, declared: /search/issues is HTTP 403 in this session, so the search ran through the repository-scoped endpoint only.


Generated by Claude Code

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions