Skip to content

fix: describe the whole API in openapi.json, not the read half - #281

Merged
AKogut merged 2 commits into
mainfrom
feat/complete-openapi
Aug 18, 2026
Merged

fix: describe the whole API in openapi.json, not the read half#281
AKogut merged 2 commits into
mainfrom
feat/complete-openapi

Conversation

@AKogut

@AKogut AKogut commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Closes the last observation from the audit.

What was wrong

/openapi.json was generated from READ_ROUTES, so it advertised 7 endpoints out of 18:

before                     after adds
GET /v1/runs               POST /v1/ingest
GET /v1/runs/{runId}       POST /v1/ingest/junit
GET /v1/tests/{id}         POST /v1/traces
GET /v1/flaky              POST /v1/artifacts/presign
GET /v1/executions/…/rca   POST /v1/tests/{id}/quarantine
GET /v1/health             PUT  /v1/codeowners
GET /v1/export             PUT  /v1/notifications/routing
                           GET  /v1/runs/summary
                           GET  /v1/runs/gate
                           GET  /health, /openapi.json

Everything a client would actually write to was missing, and nothing in the document said a fraction was on offer. Meanwhile the human reference was generated from REST_ENDPOINTS and had all eighteen — two descriptions of one API, free to disagree.

Now

One table, REST_ENDPOINTS, two renderings. Request bodies come from the zod schemas the endpoints already validate against, so the specification cannot describe a body the server would reject.

Schemas are inlined, not named. Passing a name to zodToJsonSchema puts the schema under definitions and leaves a $ref pointing where OpenAPI does not look — I generated it that way first, saw $ref + definitions in the served document, and changed it, because a generated client cannot resolve that. Verified on the live API: zero #/definitions references remain.

Four guards

A specification that drifts is worse than none — it is wrong with authority.

  • every documented endpoint appears in the document
  • every endpoint taking a body describes one
  • the liveness probe is not marked as needing a token — a document that demands auth for /health teaches people to ignore its security blocks entirely
  • every path parameter a URL names is declared, or no generated client can build that URL

The pre-existing assertion that counted paths against READ_ROUTES now checks them against the documented endpoints instead, and a new one keeps every read route in REST_ENDPOINTS.

Verified live

$ curl -s localhost:4000/openapi.json | jq '[.paths[] | keys[]] | length'
18

$ … .paths["/v1/ingest"].post.requestBody…schema | {type, required}
{"type":"object","required":["contractVersion","idempotencyKey","resource","run","executions"]}

$ … .paths["/health"].get.security
[]

62/62 turbo tasks.

AKogut added 2 commits August 18, 2026 12:09
The document was generated from READ_ROUTES, so it advertised seven GET
endpoints out of eighteen. Ingestion, the JUnit path, OTLP traces, artifact
presigning, the run summary, the quality gate, CODEOWNERS, notification routing
and quarantine were all invisible to anything generating a client, and nothing
in the document said a fraction was on offer.

It now comes from REST_ENDPOINTS — the same table the human reference is built
from — so there is one description of the API and two renderings of it, rather
than two descriptions that can disagree.

Request bodies come from the zod schemas the endpoints already validate
against, inlined rather than named: a name puts the schema under `definitions`
and leaves a $ref pointing where OpenAPI does not look, which a generated
client cannot resolve.

Four guards, because a specification that drifts is worse than none — it is
wrong with authority. Every documented endpoint must appear; every endpoint
taking a body must describe one; the liveness probe must not demand a token,
since a document that does teaches people to ignore its security blocks; and
every path parameter a URL names must be declared, or no generated client can
build that URL.
@AKogut
AKogut merged commit 09519db into main Aug 18, 2026
6 checks passed
@AKogut
AKogut deleted the feat/complete-openapi branch August 18, 2026 10:16
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