Files
clawmates/skills/backend/openapi-contract-first.md
T
Omar SobhandClaude Opus 5 4358964c05 fix(skills): every team-template skill binding now resolves
55 of 85 role skill bindings pointed at skills that were never authored,
so 10 of 11 team templates bound a smaller context bundle than their role
prompts assumed. Three roles bound nothing at all (gpu.bench_engineer,
threejs.shader_author, threejs.perf_engineer) while their prompts described
procedures they had no way to read.

The loader comment at team_template_loader.rs:167 already diagnosed this —
snake_case slugs in TOML against kebab-case skill files — and it was
half-fixed: the kebab names were corrected, the snake_case ones left.

It was invisible because both existing tests assert authored ⊆ referenced
(30/30, green) and the second explicitly declines to check the other
direction. So the failing half was the half nobody asserted.

Resolved every name by one of three explicit choices:

  - 23 skills authored where the role genuinely needed the procedure
    (gpu, threejs, research, analysis, frontend, mobile, backend, platform)
  - renames onto authored skills where one existed in substance, including
    the four-near-duplicate cases that collapse onto one real skill
  - 22 aspirational references deleted — a binding an agent cannot read is
    a promise, not a capability

Two tests now hold it. The unit test checks referenced ⊆ authored against
the files. The new integration test runs both loaders in boot order and
asserts the bindings survive the trip through the database, which is a
different question: resolution goes through skills_catalog rows, so a skill
file that exists but fails to ingest still leaves the role empty.

Negative controls: the unit test failed naming all 55; the integration test
fails naming the exact role when one name is reverted.

threejs.shader_author and .perf_engineer gained a second and third skill
after the collapse — pin_in_context pins idx < 2, so a role left with one
skill silently pins less than the policy intends.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-19 07:42:48 -07:00

2.3 KiB

name, description, when_to_use, tags
name description when_to_use tags
openapi-contract-first Designing an HTTP API as a written contract before the handler exists, and keeping the document true afterwards. You are the API designer adding or changing an endpoint.
backend
api

The contract is the deliverable; the handler implements it

Writing the schema first surfaces the disagreements while they are still cheap — what is optional, what the error shape is, what happens on conflict.

Decide these five before writing code

  1. Resource and method. POST /missions creates; PATCH /missions/{id} partially updates. If you need a verb, the resource is probably wrong.
  2. The error shape, once, for the whole API. One envelope everywhere. A client that must handle three error shapes will handle one and log the others.
  3. Which fields are optional, and what absent means. Absent, null and empty are three different things and clients will discover the difference in production.
  4. The status codes you actually use. 201 with a Location for creates, 409 for conflicts, 422 for validation. Returning 200 with {"error": ...} makes every client parse the body to learn what happened.
  5. Pagination, from the first endpoint. Retrofitting it is a breaking change — see api-pagination-day-1.

The document must stay true

A stale spec is worse than none: clients trust it and are wrong. Generate it from the types where the framework allows, and where it is hand-written, make a test fail when handler and document disagree.

The failure mode to design against is a field added to the response and never to the spec. That is invisible until an integrator asks why the documented shape does not match, which is much later and much more expensive.

Compatibility rules

Additive is safe: new optional request fields, new response fields. Everything else is a breaking change, including narrowing an enum, making an optional field required, and changing a field's type — even int to string for an id.

If a break is genuinely needed, version the path. Silently changing a shape and telling clients in a changelog is how integrations fail on a Friday.

Examples are part of the contract

One realistic request and response per endpoint answers more questions than the schema does, and a wrong example is caught immediately by anyone who tries it.