feat(openapi): enforce required query params, add --query escape hatch - #76
Open
dspangen wants to merge 2 commits into
Open
feat(openapi): enforce required query params, add --query escape hatch#76dspangen wants to merge 2 commits into
dspangen wants to merge 2 commits into
Conversation
dspangen
force-pushed
the
feat/required-query-params
branch
from
August 24, 2026 16:24
05b370b to
ee9ddc1
Compare
Spec-required query params were registered as ordinary optional flags, so a missing one only surfaced as a server 400 after a round trip. They are now marked required on the cobra flag (and labelled "(required)" in help), so the failure is local and immediate. The reverse gap was worse: when the server requires a query param the spec omits entirely, the operation was uncallable — no flag existed to send it. A repeatable --query key=value flag is now registered on every generated command and merged into the query string alongside the declared flags. Keys are sent verbatim so the server sees exactly what was typed, repeating a key sends every value (array params), and a key that duplicates an explicitly-set declared flag errors instead of silently picking one. Constraint: `omni <cmd> --schema` must stay zero-friction (no args, no token, no API call), but cobra validates required flags before RunE, so the existing RunE/Args short-circuit could not cover them Constraint: --query must never panic flag registration on a spec that declares a param slugifying to "query" Rejected: mark required only when "--schema" is absent from os.Args | untestable in-process and couples flag wiring to process argv Rejected: clear the required annotation in PreRunE | leaves the requirement relaxed for any later invocation on the same command object; PreRunE now rewrites the annotation to the correct value every run instead Rejected: last-one-wins when --query duplicates a declared flag | silently drops a value the user explicitly asked for Confidence: high Scope-risk: moderate Directive: --query is registered after spec params and body-shorthand flags and guarded by a Lookup; keep that ordering so a future flag named "query" degrades rather than panics Not-tested: real server behavior for repeated --query keys on a param the API does not treat as an array Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014TwwKSAsAGPBToNb4iUe5s
MarkFlagRequired only proves a flag was supplied, so `omni content search --q=` passed local validation and then had the empty value dropped when the query string was built — the request went out with no ?q= at all and earned exactly the server 400 this feature was meant to eliminate. Required query params are now validated against the assembled query string at the start of RunE, after --query extras are merged, so every path into the parameter is covered. A value under either the spec spelling or the flag spelling satisfies it, mirroring how --query conflicts are detected. TestSpecCoverage calls RunE directly and so bypasses cobra's own required-flag check; it now sets a dummy value for each required query param, which is what surfaced the five real spec operations affected (content search, ai-eval runs-list, models dbt-sync, models yaml-delete, query wait). Constraint: the check must run after --query merging, or the escape hatch could supply a value the validator can't see Rejected: reject empty strings at flag-parse time via a custom pflag Value | would also block legitimately empty optional params, which the API accepts Rejected: send required params even when empty | trades a clear local error for an opaque server 400, the exact failure being fixed Confidence: high Scope-risk: narrow Directive: keep checkRequiredQueryParams downstream of applyExtraQueryParams; ordering is load-bearing Not-tested: servers that treat an explicitly empty required param as valid Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014TwwKSAsAGPBToNb4iUe5s
dspangen
force-pushed
the
feat/required-query-params
branch
from
August 25, 2026 16:01
ee9ddc1 to
f26bdd3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two query-param gaps fixed on generated commands:
required flag(s) "q" not set,(required)in help, and an empty value like--q=is also rejected) — previously a missing one cost a full round trip to a server 400.--query key=valueescape hatch sends params the spec doesn't declare — previously such operations were simply uncallable (one audited incident burned 45k tokens before giving up). Keys go out verbatim; conflicts with an explicitly set declared flag error instead of silently picking one.omni <cmd> --schemastill works with zero flags — required-flag enforcement is toggled off for schema runs.Details: semantics, the --schema design note, and verification
What changed
MarkFlagRequiredand labelled(required)in their flag usage. Missing one fails locally with cobra's standardrequired flag(s) "q" not set. AcheckRequiredQueryParamspass inRunEalso rejects explicitly empty values (--q=,--q "") against the assembled query string, so the escape-hatch spellings are covered too.--query key=value(StringArray) escape hatch. Values merge into the query string alongside declared flags.--query tag=a --query tag=b→tag=a&tag=b), for array-shaped params.--querykey that duplicates an explicitly set declared flag is ambiguous and errors rather than silently picking one. Both spellings are caught (--query connectionId=and--query connectionid=both conflict with--connectionid). If the declared flag is unset,--querymay supply its value.invalid --query value "nope": expected key=value.--queryis registered after spec params and body-shorthand flags, behind aLookup(...) == nilcheck, so an operation that declares a param slugifying toquerykeeps its own flag instead of panicking pflag (same defensive pattern as--field/--depth).omni agent-helpdocuments both behaviors.The
--schemainteraction (design note)Cobra validates required flags in
execute()afterPreRunEbut beforeRunE, so the existing--schemashort-circuit (which wrapsArgsandRunE) could not cover them —omni <cmd> --schemawould have started failing on operations with required query params, breaking zero-friction discovery.Approach chosen: a
PreRunEthat rewrites theBashCompOneRequiredFlagannotation for this invocation —"false"when--schemais present,"true"otherwise. It's registered only when the operation actually has required query params.Rejected alternatives:
--schemais absent fromos.Args— untestable in-process (the test binary's argv is not the command's) and couples flag wiring to process argv.Verification
make build— clean;make test— all packages pass.internal/openapi/generate_test.go: required param missing → client-side error +(required)in usage; required param present → in query string; explicitly empty required values rejected end-to-end (--connectionid=,--connectionid "") and via a table test over the assembled query (both spellings, multi-value, optional-empty-is-fine);--querymerges extras incl. repeated and empty values; malformed--queryerrors;--queryconflicting with a set declared flag errors (both spellings); no conflict when the declared flag is unset; a spec param namedquerykeeps the flag;--schemaworks with no flags while the same operation still enforces the required param without--schema.content search,ai-eval runs-list,models dbt-sync,models yaml-delete,query wait):🤖 Generated with Claude Code
https://claude.ai/code/session_014TwwKSAsAGPBToNb4iUe5s