# 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; ratification of this contract by the repository maintainer supplies that approval for these two artifacts. 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. Revision 2 (luna review F1–F5): the generation model now defines its complete input — a declared route-metadata layer every production route must carry, with the generator failing closed on any route lacking extractable metadata, and the migration of today's local-DTO, inline-typed, and raw-handler routes named as implementing-PR scope (F1). The §7.2 inventory is closed over the real surface: raw framework mounts, delegated surfaces, conditional/tier-gated controllers, SSE, and Socket.IO events in both directions, with an explicit delegation/exclusion list (F2). The `ENDPOINTS.md` no-duplication rule is reattributed as a new disclosed policy with a structured entry format and a mechanical checker (F3). Witnesses are added or made executable for 3.1 validity, family coverage in `ENDPOINTS.md`, per-entry required content, and the retirement equivalence algorithm (F4). §8 discloses every untraced binding rule, and the SITEMAP approval claim is restated in the sitemap's own terms (F5). 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 (however registered), SSE routes, and Socket.IO events (both directions) the artifacts describe. 3. **Drift**: any difference between an artifact and the production surface it documents — an undocumented live route or event, a documented phantom, or a divergent schema/auth/error description. 4. **Delegated surface**: a mounted path prefix whose request handling is delegated wholesale to an embedded third-party engine (for example an auth engine's own route tree): the Gateway registers the mount; the engine defines the routes. ## 2. Artifact contract 1. **`OPENAPI.yaml`** is one file, valid OpenAPI 3.1 (witness §7.6), 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, in a structured entry format: one entry per endpoint family, carrying (a) the family's behavior summary, (b) its operations referenced by `operationId` link into `OPENAPI.yaml` — never by restated definition, (c) the authentication requirement, (d) the permission/authorization rule naming the owning contract (contract 2 for chain authorization, the SOT for workspace membership), (e) error semantics including the contract 5 §4.2 taxonomy, and (f) Socket.IO event entries (both directions) for event families. `ENDPOINTS.md` MUST NOT contain request/response schema definitions for any operation that exists in `OPENAPI.yaml` (mechanical rule: no `requestBody`/`responses`/ schema-fragment blocks for such operations — witness §7.5). This no-duplication rule and the entry format are new policy disclosed in §8 (the `docs/API/README.md` boundary as written binds guide books, not `ENDPOINTS.md` itself). 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 by a deterministic repository script whose input is a **declared route-metadata layer**: every production HTTP/SSE route carries machine-extractable metadata — route decorators plus typed request/response schemas (the contract 5 §4.1 shared DTOs where the operation is a mapped tool family; declared per-route schemas elsewhere) and its error-code set. **The generator fails closed:** a production route lacking complete extractable metadata is a generation error, never a silently omitted or partially emitted operation. Today's local-DTO, inline-typed, and raw-handler routes therefore migrate to declared metadata in the implementing PR — that migration is in the implementing PR's scope, and §7.2's independent inventory is the cross-check that no route escaped it. 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 and §7.3 content witnesses. ## 4. Coverage obligations 1. **Closure over the real surface.** Coverage extends to every production route however registered: framework-decorated controllers and gateways AND raw framework mounts registered outside them (the bootstrap's own route/hook registrations), SSE routes, and conditionally registered (deployment-tier-gated) controllers — documented in the union, each conditional route marked with its condition. **Delegated surfaces** (§1.4) are documented as delegated-surface entries naming the mount, the delegating engine, and that engine's own contract — not re-documented route-by-route. **Socket.IO events are covered in both directions:** subscribed (inbound handler) events and server-emitted events. Test-only and development-only surfaces are excluded via an exclusion list that is explicit in the generation script and enumerated in `ENDPOINTS.md`, never implicit. The exclusion and delegation lists are new policy disclosed in §8. 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` entry 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's equivalence algorithm. 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. (The deletion-in-reviewed-PR form and the interim-consumer restriction are disclosed in §8.) ## 6. Phase timing 1. The artifacts, the metadata migration (§3.1), 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` entry in its implementing PR. 4. The phase placement and rollout sequencing in this section are disclosed in §8. ## 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. A second control proves the generator's fail-closed rule (§3.1): a fixture route stripped of its metadata makes generation fail, not emit a partial document. 2. **Coverage witness:** an independent surface inventory — static enumeration over `apps/` production code, tests excluded (the A5 §1.2 inventory style), covering framework-decorated controllers and gateways, raw mount/hook registrations in the bootstrap path, SSE routes, conditional registrations (evaluated per deployment profile and unioned), and delegated-surface mounts — equals the documented set in both directions: no undocumented live route, no documented phantom, each conditional route carrying its condition, each delegated surface present as a delegated-surface entry. Socket.IO events are inventoried in both directions — inbound subscription handlers by handler scan, server-emitted events by emit-call scan over production code — and compared to `ENDPOINTS.md`'s event entries in both directions. Additionally, every HTTP route family in `OPENAPI.yaml` has an `ENDPOINTS.md` entry, and every `ENDPOINTS.md` operation reference resolves to an existing `operationId` — both directions, mechanical. 3. **Content and taxonomy witness:** every `ENDPOINTS.md` entry carries the §2.2 required fields — behavior, operation links, authentication requirement, owning-contract link, error semantics — presence-checked mechanically against the structured entry format; 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` under a defined equivalence algorithm: both documents canonicalized (references dereferenced, keys sorted), then per path — structural schema equality, security/authentication requirement equality, and documented error-code set equality — with permissions compared against the covering `ENDPOINTS.md` entries, and the comparison emitting the exact per-path differences on failure. A repository-wide reference scan shows no remaining consumer (including generated clients) resolves the legacy file. 5. **Boundary witness:** `ENDPOINTS.md` contains no schema definition for any operation that exists in `OPENAPI.yaml` — mechanically: no `requestBody`/`responses`/schema-fragment block attached to a linked operation, and every operation mention is an `operationId` link (§2.2's structured format makes this checkable); the witness proves it can fail by a control run against a mutated copy containing an inline schema block. 6. **Validity witness:** `OPENAPI.yaml` parses and validates as OpenAPI 3.1 under a named validator run in CI; the witness proves it can fail by a control run against an invalidated copy. ## 8. Drafting additions (PRD §12.1 disclosure) The two artifacts, their roles, and the retirement verification dimensions 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, the declared route-metadata layer with its fail-closed generator, the metadata migration scope, and the 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 and the delegated-surface documentation form (§4.1). 4. The Socket.IO placement rule (events in `ENDPOINTS.md`, no pseudo-paths) and the both-direction event coverage (§2.1, §4.1). 5. The no-oracle documentation requirement (§4.2). 6. The `ENDPOINTS.md` structured entry format and its no-duplication rule with the mechanical boundary witness (§2.2, §7.5). 7. The committed-repository-file rule — neither artifact exists only in CI (§2.3). 8. The normative-direction rule — generation documents, never ratifies (§3.2). 9. The retirement deletion-in-reviewed-PR form and the interim-consumer restriction (§5.2), and the §7.4 equivalence algorithm. 10. The §6 phase placement: implementing-PR-after-ratification, the drift gate as a required trunk check from first commit, and the build-first documentation sequencing. ## Ruling request Ruling requested (one decision): shall `OPENAPI.yaml` be generated from Gateway source through a declared, fail-closed route-metadata layer 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, and fail-closed metadata makes incompleteness a build error) — or hand-authored contract-first, with code conformance to the hand-written contract enforced by witnesses instead?