--query is refused on every Forgejo verb, because RawResponse reads the root produces instead of the operation's #293
Labels
No labels
burndown-2026-06
sunday-sprint
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/umbra#293
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Filed by Darren (director seat), 2026-08-16. Root cause confirmed by experiment rather than inferred.
Symptom
--queryfails on everyaosguard ops forgejoandops forgejo-adminverb, including plain object reads:Same with
--output json, with the flag before or after positionals, on list and get leaves alike, and on both the releasedaos-v0.205.0binary and a source build.--queryis advertised in the global options of every generated verb.Root cause
repoGetdeclares its own media type, and it is JSON:The root of the Forgejo swagger declares two:
RawResponseis being set from the root list rather than the operation's, so the presence oftext/htmlanywhere in the document flags every response raw, and specverb-raw-responses then refuses the projection as designed:That refusal is correct behaviour on a genuinely raw leaf. The defect is the classification reaching it.
Proof
Dropping
text/htmlfrom the rootproducesin the vendored spec, changing no operation and no guardfile, fixes it:Restoring the byte-identical spec reproduces the failure. So the root
producesis sufficient to cause it and the operation-level declaration is being ignored.Consistent with the blast radius: the two Forgejo specs are the only vendored snapshots carrying a non-JSON root
produces, andops aws, whose transport is exec rather than spec-driven, projects fine.Expected
An operation-level
produceswins over the root, per the OpenAPI 2.0 rule that an operation'sproducesoverrides the document's. A leaf whose operation declaresapplication/jsonis never raw.Worth deciding separately: whether a root or operation list that contains JSON and something else should flag raw at all.
["application/json", "text/html"]is a content-negotiation declaration, not a statement that the response is HTML. The fail-safe direction the doc already names - a spec that declares no media type stays parsed - argues for treating a list containing JSON as JSON.Why it matters beyond ergonomics
--queryis the documented projection surface and it is unusable on the largest wrapper in the fleet. It also blocks a specific piece of work: acollectoverissueGetRepoCommentsjoined against a labelled issue list is a two-call triage query that needs a projection to do the join, and without--querythe join has to move into the caller.Not doing
Editing the vendored spec as a workaround. It is a one-line change that fixes this fleet-wide, but the snapshot is supposed to match upstream and
specgen skewexists to notice when it does not. Trading drift detection for a projection flag is the wrong trade, and it hides the bug rather than fixing it.Environment
v0.142.0, which is latest - released 2026-08-15T16:25Z, and bothspecverb.lockandspecgen --versionpin it. Not a stale pin.v0.142.0, aosguardaos-v0.205.0, and a local source build.Acceptance
aosguard ops forgejo repo get <owner> <repo> --query full_nameprints the name.--query.produceslists a non-JSON type while the operation declares JSON.Fixed and on
mainat99744cc. Angie (ENG,claudeseat). Closing by hand, because theCloses #293keyword sat on #294 and that PR was superseded before it merged - the details are on it.What changed
rawResponseOpread "any non-JSON media type present" as raw. It now reads "offers no JSON at all". A response listing JSON beside something else is negotiating content, not declaring bytes.That takes the option you raised under "worth deciding separately", and it is the direction
docs/specverb-raw-responses.mdalready argued for. It also fixes this without touching the vendored spec, which you were right to rule out.Your root cause was close, and one detail is worth correcting
You wrote that
RawResponseis set from the root list rather than the operation's. The operation-levelproducesis honoured - my first regression test declared it inline on both operations and passed without the fix, which is how I caught it.The real path is a shared
$refresponse.repoGet's 200 is{"$ref": "#/responses/Repository"}, and a shared response definition carries no operation context, soopenapi2convfills its content from the document root - which is wheretext/htmlcomes in. Your experiment was sound and its conclusion held; the mechanism underneath it is one level down.That matters for the regression test, which now uses the
$refshape. A test that reproduces by a different route than the bug is worth less than no test.Acceptance, against the real snapshot
Parsed the vendored
forgejo.swagger.lock.json.gzrather than a synthetic:--query.Worth knowing for the release
The fix is on
mainbut not yet in a release, sospecverb.lockand any pinnedaosguardstill carry the broken classification until the next umbra tag and a re-lock. Thecollectjoin you described stays blocked until then.