docs: API contract artifacts contract (S2 contract 9)
ci/woodpecker/pr/ci Pipeline was canceled

This commit is contained in:
fred
2026-08-26 19:45:03 -05:00
parent 2a30c68b84
commit f891f78e7b
+169
View File
@@ -0,0 +1,169 @@
# API Contract Artifacts Contract (S2 contract 9)
Status: DRAFT — awaiting ratification (webui-audit S2, contract 9 of 9).
Authority: `docs/API/README.md` declares the single API documentation
boundary: `docs/API/OPENAPI.yaml` as the canonical machine-readable
HTTP/WebSocket contract and `docs/API/ENDPOINTS.md` as the
human-readable endpoint, authentication, permission, and error index —
both declared, neither present (the webui-audit REPORT's prerequisite
9). `docs/SITEMAP.md` records that canonical scope requires maintainer
approval; this contract's ratification is that approval path. Contract
5 (`tool-gateway-mapping.md`) §4 binds the per-operation
request/result/error/audit envelope; this contract binds only how the
two artifacts are produced, what they must cover, and how they are
kept true.
This contract binds the artifact definitions (§2), the production
model (§3), coverage obligations (§4), legacy migration (§5), phase
timing (§6), witnesses (§7), and disclosed drafting additions (§8).
Operation semantics stay with contract 5 and the owning S2 contracts;
documentation placement rules stay with the docs atlas
(`docs/README.md`).
## 1. Definitions
1. **The artifacts**: `docs/API/OPENAPI.yaml` and
`docs/API/ENDPOINTS.md`, exactly as declared by `docs/API/README.md`.
2. **Coverage**: the set of Gateway HTTP routes and Socket.IO events
the artifacts describe.
3. **Drift**: any difference between an artifact and the production
surface it documents — an undocumented live route, a documented
phantom route, or a divergent schema/auth/error description.
## 2. Artifact contract
1. **`OPENAPI.yaml`** is one file, valid OpenAPI 3.1, and the canonical
machine-readable contract for the Gateway's HTTP surface. Socket.IO
events, which OpenAPI cannot express natively, are documented in
`ENDPOINTS.md` and referenced from the OpenAPI description block;
inventing a pseudo-path encoding for them inside `OPENAPI.yaml` is
non-conformant.
2. **`ENDPOINTS.md`** is the human index: per endpoint family, the
behavior, authentication requirement, permission/authorization rule
(naming the owning contract — contract 2 for chain authorization,
the SOT for workspace membership), and error semantics including
the contract 5 §4.2 taxonomy. It links to owning contracts and to
`OPENAPI.yaml`; it does not duplicate endpoint definitions (the
`docs/API/README.md` authoring boundary).
3. Both artifacts are committed repository files, reviewed in PRs like
any contract text; neither is a build output that exists only in CI.
## 3. Production model
1. **Generation (per the ruling).** `OPENAPI.yaml` is GENERATED from
the Gateway source (route decorators plus the shared request/result
DTOs of contract 5 §4.1) by a deterministic repository script; the
generated output is committed, and CI regenerates and byte-compares
it (§7.1). Hand edits to `OPENAPI.yaml` are non-conformant — a
description that cannot be expressed from source annotations goes
into the annotations, or into `ENDPOINTS.md`.
2. **Normative direction.** Generation documents the code; it does not
ratify it. The S2 contracts and their witnesses remain the
normative gates on what the surface may be; the artifacts make the
measured surface visible and machine-checkable. A generated
description of a non-conformant route is drift evidence against
that route's owning contract, not authority for it.
3. `ENDPOINTS.md` is hand-authored (its content — permission
rationale, cross-contract links, event semantics — is judgment, not
extraction), against the §7.2 coverage witness.
## 4. Coverage obligations
1. Every production Gateway HTTP route appears in `OPENAPI.yaml`; every
route family appears in `ENDPOINTS.md`. Test-only and
development-only surfaces are excluded and the exclusion list is
explicit in the generation script, not implicit.
2. Every documented operation carries: its authentication requirement;
its authorization rule by reference to the owning contract; its
error responses drawn from the contract 5 §4.2 closed taxonomy.
Where contract 2's no-existence-oracle rule applies, the
documentation shows authorization refusal and not-found as
indistinguishable on the wire — documenting a distinguishing
response there is a coverage defect, not a documentation style
choice.
3. New surface ships documented: a PR that adds or changes a Gateway
route or event lands with the regenerated `OPENAPI.yaml` and any
needed `ENDPOINTS.md` row in the same PR, enforced by the §7.1
drift gate — there is no "docs to follow" state.
## 5. Legacy migration
1. `docs/openapi-tess.yaml` (17 paths, Tess-scoped) remains labeled a
scoped legacy artifact until the consolidated `OPENAPI.yaml`
demonstrably covers it: the `docs/API/README.md` retirement rule
(verify paths, schemas, authentication, permissions, error
behavior, and generated/client references) is binding, witnessed by
§7.4.
2. Retirement is deletion in a reviewed PR after the §7.4 witness
passes; until then no consumer may treat the legacy artifact as
canonical for anything beyond its own 17 paths.
## 6. Phase timing
1. The artifacts and the generation script are produced by an
implementing PR after this contract is ratified; they are S4-phase
platform work, not part of any S2 ruling PR.
2. From the first commit of `OPENAPI.yaml` onward, the §7.1 drift gate
is a required CI check on the integration trunk; the §4.3
same-PR rule binds every subsequent surface-changing PR.
3. The build-first tool families (A5 ranks, contracts 13, 5, 8) are
documented as they land, under the same rule — the roll-up query,
for example, ships with its OpenAPI operation and its
`ENDPOINTS.md` row in its implementing PR.
## 7. Verification requirements
Binding on the implementing PRs; each witness names its commands,
scanned source roots, and compared files.
1. **Drift witness:** CI regenerates `OPENAPI.yaml` with the
repository script and fails on any byte difference from the
committed file; the witness proves it can fail by a control run
against a mutated copy.
2. **Coverage witness:** an independent route inventory (static
enumeration of Gateway controllers and gateways over `apps/`,
production code, tests excluded — the A5 §1.2 inventory style)
equals the documented path set in both directions: no undocumented
live route, no documented phantom. Socket.IO events are inventoried
the same way against `ENDPOINTS.md`.
3. **Taxonomy witness:** every error response documented in
`OPENAPI.yaml` uses a code from the contract 5 §4.2 closed enums,
and each family's documented codes exactly match the enum in the
shared types package; where the no-oracle rule applies, the
documented refusal and not-found responses are identical in code,
status, and shape.
4. **Retirement witness:** before `docs/openapi-tess.yaml` is deleted,
an automated comparison proves each of its 17 paths is covered by
`OPENAPI.yaml` with equivalent schemas, auth, permissions, and
error behavior, and a repository-wide reference scan shows no
remaining consumer (including generated clients) resolves the
legacy file.
5. **Boundary witness:** `ENDPOINTS.md` contains no endpoint
definition duplicated from `OPENAPI.yaml` (machine-checkable:
no path+verb table row whose content restates the generated
operation instead of linking it), per the `docs/API/README.md`
authoring boundary.
## 8. Drafting additions (PRD §12.1 disclosure)
The two artifacts, their roles, the single-boundary rule, and the
legacy retirement conditions are traced to `docs/API/README.md` and
`docs/SITEMAP.md`. Proposed drafting additions, visible here for
ratification, each severable:
1. The generated-with-committed-output production model and CI drift
gate (§3.1, §7.1) — the ruling below.
2. The same-PR documentation rule for surface changes (§4.3).
3. The explicit exclusion list for test/development surfaces (§4.1).
4. The Socket.IO placement rule (events in `ENDPOINTS.md`, no
pseudo-paths) (§2.1).
5. The no-oracle documentation requirement (§4.2).
## Ruling request
Ruling requested (one decision): shall `OPENAPI.yaml` be generated
from Gateway source with a committed output and a CI drift gate
(recommended — the 45-controller surface already exists, so
generation is the only route that starts true and stays true) — or
hand-authored contract-first, with code conformance to the
hand-written contract enforced by witnesses instead?