spec: @http gains the operation surface; M8 design gaps resolved (#173) - #175
Merged
Conversation
Resolves the three design gaps GH #93 left open for the OpenAPI boundary renderer, now that #170 (PR #174) has landed the doc pack it reads. Decision record: docs/RFC-001-issues.md §#80. Gap 1 — operation surface. @http gains four defaulted parameters: summary, operation_id, tags, security (§5.2, annotations.proto). Binding rules are pinned with them: {name} path segments bind to same-named top-level request fields; remaining fields bind to the query string for bodyless methods and to the request body otherwise; operation_id defaults to <Service>_<Method>, unique by construction; summary falls back to the first sentence of @description. tags and security take list literals of strings, because the grammar admits no repeated parameter type (§5.1 paramType ::= qualifiedIdent) — list-shaped values ride `any` plus a Literal.list (§8.1), verified against the reference parser before the text was written. Security-scheme *definitions* stay in generator config, per the §9.4/#112 argument that keeps deployment topology out of descriptors. The alternative — a generator-owned openapi.* library with zero spec involvement — was considered and not chosen; the cost is recorded rather than elided: OpenAPI vocabulary now lives in the library every port mirrors and the draft describes, and it can only grow additively. What makes it tolerable is that the parameters carry no validation semantics and impose no port obligation beyond carrying them through the §8.1 carrier. No `responses` parameter. Responses are derived — success from the return type, errors from @error_code plus §7 — and authored per-status entries would need a list of message literals: a shape the carrier represents (LiteralValue.literal) but the reference parser rejects at an annotation argument today. Specifying it would put the spec ahead of the toolchain that can express it. Gap 2 — audience/visibility tiers. Taxonomy is protowire.docs.v1.Audience (#170). Artifact filtering only, never descriptor stripping (stripping has spec implications about image completeness and needs its own pass). Tiers come from generator configuration, not a new canonical annotation, because visibility is deployment policy — same reasoning as #112 — with doc-pack topics contributing their own tier so docs and API surface cannot disagree. Transitive inconsistency (public reaching internal) is an error: a dangling $ref or a silently inlined restricted definition are both worse than refusing. Gap 3 — availability version. x-since is derived from protoregistry history, omitted when no registry is configured. No canonical @SInCE is added: an authored availability claim is unverifiable and nothing would check it, while the registry already knows. Additive throughout: the v1.2.0 two-argument @http keeps its meaning and no existing schema changes shape, pinned by new fixture 21_http_operation.proto, which compiles the bare form beside fully parameterized uses. No grammar production, extension number, wire, or report change.
This was referenced Jul 25, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First slice of #173: resolve the three M8 design gaps GH #93 left open, so implementation has settled ground. No generator code yet — decisions land as reviewable spec text first, as with #93/#111/#155.
Decision record:
docs/RFC-001-issues.md§#80.Gap 1 — operation surface: enrich canonical
@httpBinding rules are pinned alongside the signature:
{name}path segments bind to same-named top-level request fields; remaining fields bind to the query string for bodyless methods and to the request body otherwise;operation_iddefaults to<Service>_<Method>(unique by construction);summaryfalls back to the first sentence of@description.tagsandsecuritytake list literals of strings because the grammar admits norepeatedparameter type (§5.1paramType ::= qualifiedIdent), so list-shaped values rideanyplus aLiteral.list(§8.1). I verified this against the reference parser before writing the text — the lowered carrier is:Security-scheme definitions stay in generator configuration, per the §9.4/#112 argument that keeps deployment topology out of descriptors that cross org boundaries.
Recorded trade-off. The alternative was a generator-owned
openapi.*annotation library with zero spec involvement (gnostic-style). It was considered and not chosen; the cost is written into the record rather than elided: OpenAPI vocabulary now lives in the library every port mirrors and the IETF draft describes, and the surface can only grow additively from here. What makes it tolerable is that the parameters carry no validation semantics and impose no port obligation beyond carrying them through the §8.1 carrier — a port that renders no REST surface parses them and interprets nothing.No
responsesparameter. Responses are derived — success from the method's return type, errors from@error_codeplus the §7 report model, which the settled schema half already maps. Authored per-status entries would need a list of message literals: the carrier represents that shape (LiteralValue.literal), but the reference parser rejects it at an annotation argument today, so specifying it would put the spec ahead of the toolchain that can express it. Revisit when the parser gap closes and demand exists.Gap 2 — audience/visibility tiers
Taxonomy is
protowire.docs.v1.Audiencefrom #170. Three sub-decisions:--audience <tier>emits only elements at or below the tier; descriptors are never rewritten. Stripping has spec implications — what a conformant consumer may assume about an image's completeness — and needs its own design pass, which nothing yet demands.PUBLIC), not a new canonical annotation: visibility is deployment policy, the same reasoning that rejected@encryptedin Schema-level encryption / key-reference annotation — @encrypted(key_ref) (deferred from §6.7) #112. Doc-pack topics anchoring an element contribute their tier, so documentation and API surface cannot disagree.PUBLICelement whose closure reaches anINTERNALone fails generation, naming both ends — a dangling$refor a silently inlined restricted definition are both worse than refusing.Gap 3 — availability version
x-sinceis derived from protoregistry history (first registered revision containing the element), omitted when no registry is configured. No canonical@sinceis added: an authored availability claim is unverifiable and nothing in the toolchain would check it, whereas the registry already knows. Org-namespaced@sincestays user-space and is ignored.Additivity
Every added parameter is defaulted, so
@http("GET", "/orders")keeps its v1.2.0 meaning and no existing schema changes shape. New fixture21_http_operation.protopins it by compiling the bare two-argument form beside fully-parameterized uses, a named subset after the positional pair, and a{name}template. No grammar production, extension number, wire, or report change;annotations.protostays parseable by any v1.2 parser.Full suite green, including the positive corpus byte-stability check that now covers the new fixture.
Follow-ups
pxf openapiis the next slice on cmd/pxf: pxf openapi — OpenAPI boundary renderer over the lowered image + doc pack (RFC-001 #080, M8) #173.LiteralValue.literalrepresents it. That gap is what keptresponsesout of this revision. I have not filed it — say the word and I will.Refs #173. Doc pack input: #170 / PR #174.