docs(openapi): Declare API lifecycle status
Summary
Update operations in api/openapi/v1.yaml to declare x-gitlab-lifecycle: experiment. The extension is how a consumer of https://api.gitlab.com/rest/ learns
the management API is not generally available; the document carried that claim
nowhere else. Vocabulary and placement follow the
API style guide:
operation-level, experiment or beta, and a generally available operation drops
the key rather than declaring a third value.
Two gates keep the sweep complete as operations are added. rule/operation-lifecycle
in api/openapi/redocly.yaml fails lint:openapi on a missing value or one outside
the vocabulary; it sits under the management@v1 entry rather than the root rules
block, so it does not reach gitlab-v1.yaml.
TestContract_EveryOperationDeclaresLifecycle pins the value to experiment, which the
lint rule deliberately leaves open.
gitlab-v1.yaml is untouched: it authenticates the calling service, not an end
user, so it has no consumer to signal maturity to. The pages job renders both
documents, so the asymmetry is deliberate rather than an omission. This is feature
maturity, unrelated to the soft-delete lifecycle that artifact-registry::lifecycle
and ADR-009's lifecycle policies mean by the word. No Bruno or e2e catalog change:
no operation, URL, method, body, or response code moves.
Governing ADRs
ADR-009: API Design relates; this conforms, and no amendment is needed. It governs the API surfaces, endpoint structure, and versioning prefixes, none of which move here — no route added, removed, or renamed, no prefix, auth mode, or pagination rule changed.
ADR-009's two OpenAPI clauses ("payloads live in the corresponding OpenAPI
specifications", and "payload changes do not require ADR updates") are about
payloads and schemas, so they do not cover operation metadata directly; they
establish the sufficient weaker point that the documents' contents are the
codebase's business. No ADR addresses vendor extensions or maturity markers —
grep -ri openapi docs/adr/ returns only those two clauses. Mirror freshness
checked per docs/adr/README.md: no upstream decision commits since the last
local change.
Testing
TestContract_EveryOperationDeclaresLifecycle walks every declared operation and
requires the extension, modeled on TestContract_EveryResponseDeclaresXRequestID
beside it; loadContractDoc runs doc.Validate, so a malformed extension fails
there too.
Related to https://gitlab.com/gitlab-com/gl-infra/api-docs/-/work_items/42