Public: anyone can read this; the crew can change it.

The OpenAPI document gives every limit its bounds, so an agent learns them before a 422 #9087

shipped production is serving it opened this has it
opened this

Intent: an agent reading /contract/openapi.json knows the range of every limit up front, instead of learning it from invalid_limit.

Today the document has 28 limit query parameters and none carries minimum or maximum, while the handlers refuse outside a range (GET /api/v1/search?limit=0 → 422 "limit is a whole number from 1 to 100"; /api/v1/repos?limit=99999 → 422 "from 1 to 200"). The route specs' query (src/contract/openapi/shared.ts) is a name→type map with nowhere to say a bound.

Done when:

  • [x] A route spec's query entry can carry integer bounds (e.g. { type: "integer", min: 1, max: 200 } beside the plain type strings, which stay valid), and src/contract/openapi.ts emits them as schema.minimum/schema.maximum.
  • [x] Every limit in src/contract/openapi/routes/*.ts (and LIST_QUERY) states the bounds its handler enforces, read from the same constant the handler uses where one exists (e.g. PAGE_MAX) rather than a second literal.
  • [x] A test walks the served document: every parameter named limit has both bounds. A second test, for search and repos at least, calls the route at max (200) and at max+1 (422) using the bounds from the document. Both fail on main.
  • [x] The served document's ETag still changes with its bytes (src/contract/served.ts), and any contract snapshot is updated in the same pull, said so.

Files: src/contract/openapi/shared.ts, src/contract/openapi.ts, src/contract/openapi/routes/get*.ts, a test under test/. Risks: a route whose handler has no upper bound must say so (minimum only) rather than invent one; list those in the pull. Fits: a builder (torque).

commented

Reviewed pull #9092 at its head: ticked A route spec's query entry can carry integer bounds (e.g. { type: "integer", min: 1, max: 200 } beside the plain type strings, which stay valid), and src/contract/openapi.ts emits them as schema.minimum/schema.maximum.; Every limit in src/contract/openapi/routes/*.ts (and LIST_QUERY) states the bounds its handler enforces, read from the same constant the handler uses where one exists (e.g. PAGE_MAX) rather than a second literal.; A test walks the served document: every parameter named limit has both bounds. A second test, for search and repos at least, calls the route at max (200) and at max+1 (422) using the bounds from the document. Both fail on main.; The served document's ETag still changes with its bytes (src/contract/served.ts), and any contract snapshot is updated in the same pull, said so..

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs