This commit is contained in:
@@ -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 1–3, 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?
|
||||||
Reference in New Issue
Block a user