Skip to content

Align list query parsing with official families - #43

Merged
SaladDay merged 7 commits into
mainfrom
codex/list-query-tolerance
Sep 23, 2026
Merged

SaladDay merged 7 commits into
mainfrom
codex/list-query-tolerance

Conversation

@SaladDay

@SaladDay SaladDay commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Core rejected many list and resource query strings that the official Agents API accepts or rejects differently. This batch aligns the shared list parser and query handling with owned official observations. The pinned baseline is unchanged (SDK 3.13.0 / d7c41ef / agents=v1).

Behavior

  • Unknown query keys are ignored on shared-parser lists and on single-resource routes. Previously they returned 400 unsupported_parameter. Only authentication selects the tenant. Foreign and missing resources stay indistinguishable, and body validation is unchanged.
  • A repeated supported list key still returns 400, now with the observed family fields:
    • Beta lists: invalid_request_error with the duplicate-field message.
    • Skills: duplicate_parameter, param limit/key.
    • Files: unchanged.
  • Limits, by family:
    • Agent, Session, Item and Template lists treat 0 as 1 and values above 100 as 100.
    • Turn, Subagent and Artifact lists still reject values outside 1–100, now with code invalid_request_error.
    • Negative and non-integer Beta limits return the observed deserialization error.
    • Vault and Credential lists keep clamping, including negative values, because the pinned docstring says "clamped between 1 and 100".
    • Skills and Skill versions accept 0–100. Zero returns an empty page whose has_more reports remaining resources. Out-of-range values return integer_above_max_value / integer_below_min_value with param limit.
    • Files range errors carry a null code.
  • A scalar status combined with status[] filters Vaults/Credentials by their union.
  • An explicit empty Files purpose= means no filter.

Decision: the pinned Turn/Item/Template docstrings say "between 1 and 100". Clamping keeps the effective page inside that range, so Items and Templates follow the live service's clamp. Turns keep rejecting because the live service rejects.

Evidence

Campaign scan 1 sent 252 owned official requests across three families, with request IDs retained privately. It included 4 official none Sessions with 6 tiny Turns; every owned official resource was deleted and verified. The matrix, the decisions and the deferred items are recorded in contracts/agents-api/list-query-semantics.md and operation-evidence.md (entry L).

Validation

  • Independent acceptance, written from the requirements only, against real Core HTTP with dedicated PostgreSQL, using raw HTTP plus the pinned SDK 3.13.0: 845 checks, 116 of them through the SDK.
    • On main, every changed row failed and every retained row passed.
    • On the candidate runtime (5e1171b), all rows passed.
    • The checks cover tenant B foreign-equals-missing, and snapshot/row fingerprints showing that no rejected request writes.
  • Go handler and store tests for every matrix row. A PostgreSQL store test covers the Skills zero page. The repository's official-client acceptance passed locally.
  • Server gate on this head: make -o check-web check plus Web typecheck, core-doctor, 287 client tests, 583 Web tests and the build all passed. The Playwright browser cases were not run on the server, because it has no Google Chrome; this skip was approved by the user.
  • Generated files: make openapi regenerates the committed schema byte for byte. There are no SQL changes.
  • No live model run: execution is unaffected.
  • Independent blind review of the full diff by a fresh Claude Code subagent (the user-approved replacement for GPT-6 Astra): no code or security defects. Its in-scope findings (stale docs and missing write-route tests) are fixed in the last three commits, which touch only docs and tests.

Deferred

Not part of this change and registered on the board:

  • The Environment Files list still rejects unknown keys through its own parser.
  • Files limit=abc versus limit=-1 codes are inconsistent.
  • Error order and empty-limit= messages.
  • Malformed non-UUID path IDs return 400 in Core but 404 officially.
  • Metadata/name error fields.
  • Skill sole-version deletion and number reuse.
  • Session delete lifecycle.
  • Whitespace input.
  • Template network forms.

No full protocol compatibility is claimed.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

Unknown list query keys are now ignored, while a repeated supported key
still rejects with each family's observed error: the Beta duplicate-field
deserialization error, the Skills duplicate_parameter code, or the
retained Files rejection.

Agent, Session, Item and Template lists clamp limit 0 to 1 and larger
limits to 100. Turn, Subagent and Artifact lists keep rejecting values
outside 1-100 with the Beta invalid_request_error code. Negative and
non-integer Beta limits use the observed deserialization message; Vault
and Credential lists keep their pinned clamp. Skills accept limit 0 as an
empty page reporting has_more and use the observed integer range codes.
Files range errors have a null code.

A scalar Vault/Credential status combined with status[] filters by their
union, and an explicit empty Files purpose applies no filter.
The official service ignores unrecognized query keys on resource reads,
writes and deletions; a deleted Vault or Agent still returns 404. No
single-resource operation in the pinned SDK sends a typed query
parameter, so the blanket "does not accept query parameters" and
invalid-input rejections are removed from every such handler.

Authentication, tenant scoping and missing/foreign not-found masking are
unchanged: a tenant_id query key is ignored like any other unknown key.
official_list_query.py now replays the batch matrix against real HTTP and
PostgreSQL with the pinned SDK: unknown list keys, family-specific
duplicate errors, per-family limit bounds including the Skills zero page,
the Vault/Credential status union and the Files empty purpose, each as
tenant A and tenant B, plus unknown keys on single-resource reads, event
admission, streams, updates and deletions.

Other acceptance scripts that asserted the former blanket rejections now
assert that unknown keys are ignored without selecting another tenant,
exposing secrets or bypassing body validation.
list-query-semantics.md gains a dated section with the A1-D2 matrix,
the campaign-scan-1 request IDs, the recorded decisions, local choices
for unsampled inputs and the remaining deferrals. operation-evidence.md
registers the evidence and updates the affected list rows; related
contract prose and the CONTRIBUTING list-query paragraph follow the new
behavior. openapi.yaml is regenerated from the updated annotations.
CONTRIBUTING, the contract README, the service README and the Environment
Files contract still described the former blanket query rejection, the
mixed status rejection and the old limit policy. They now describe the
per-family limit policy, the status union and ignored unknown keys.

The list query sections now also state precisely that the Environment
Files list keeps its own strict key parser and validates its query only
after the Environment lookup.
Environment file creation, Artifact deletion, File upload and Skill and
Skill version upload ignore unknown query keys. The new handler tests
show that the body is still validated, that query keys never become
multipart form fields or select a tenant, and that a foreign resource
still returns the same 404 as a missing one without writing.
verify_resource_queries now also uploads a File and a Skill with its
version through the pinned SDK with unknown query keys, checks that a
query purpose or default is not a form field, and that a foreign Skill
version upload returns the same 404 as a missing Skill.
@SaladDay
SaladDay merged commit 4ee0f46 into main Sep 23, 2026
3 checks passed
@SaladDay
SaladDay deleted the codex/list-query-tolerance branch October 7, 2026 06:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant