Add draft API design guide and conformance tooling - #17
Open
jeremi wants to merge 19 commits into
Open
Conversation
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Rule 20.2 mandates a GovStack Spectral ruleset; this ships its draft in-repo so BB spec editors and agents get mechanical verification instead of a checklist. 125 default rules plus 8 opt-in strict heuristics across OpenAPI 3.1 and AsyncAPI 3.0, a driver adding the 20.1 base validators, file-layout checks and 20.3 exception handling, per-rule coverage for all 166 guide rules in coverage.yaml (machine-checked), golden reference specs, and a composite GitHub Action with a guarded template workflow. Guide pages updated to point at the ruleset. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
v0.2 is no longer a pure restructuring of v0.1: this adds new normative rules and strengthens existing ones, so version-history now says so plainly rather than claiming presentation-only changes. Substantive additions: api/index.yaml surface inventory and coverage dispositions (4.5, 4.6); 201-vs-202 creation semantics and mandatory response schemas (7.21); W3C Trace Context in place of X-Request-Id (8.4); the revision-11 Structured Field RateLimit contract (8.7); transport-neutral GovStackAsyncError (11.8); the RFC 9700 OAuth baseline with the password grant forbidden outright (13); a required Idempotency-Key on non-idempotent POSTs (14.1); and detached JWS ES256 with RFC 8785 canonicalization, dropping the v0.1 HMAC fallback (16.8). Resolves OPEN-7-A, OPEN-7-B, OPEN-15-C, OPEN-15-D and OPEN-20-A. OPEN-15-A is resolved in-draft but is marked v1.0-blocking and still needs committee ratification. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Gives the template a worked contract instead of the stale swagger.json and swagger.yaml stubs, which are removed. api/index.yaml is the canonical API registry, api/coverage.yaml maps normative interface requirements, and api/common/ carries the shared OpenAPI and AsyncAPI component files that rules 2.8 and 3.8 pin. The common files are drafts vendored from an incubation repository and are not ratified GovStack artifacts yet. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Adds --mode and api/index.yaml discovery to the driver so a run covers every declared surface rather than a single file, and extends coverage to the rules added in this cycle. New functions cover baseline and creation responses (7.14), successful response schemas (7.21), W3C Trace Context (8.4) and logical channel IDs (17.2). s08-requestIdCorrelation.js is removed with the X-Request-Id rule it enforced. Every rule keeps a fail/pass fixture pair and a coverage.yaml entry; the golden reference specs still lint clean. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Replaces the prose spec template with a generic reference domain carrying stable BB-TPL-* requirement identifiers, so the traceability and conformance structure is demonstrated rather than described. This commit is deliberately last and touches only committee-owned template content. Drop it to ship the API design guide work on its own. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
…stack.global The guide used org.govstack.* as the reverse-DNS root for event types, channel ids and error identifiers, and docs.govstack.org as the error registry host. Neither matches the project's actual domain: govstack.org is not owned by GovStack and docs.govstack.org does not resolve. Reverse-DNS of govstack.global is global.govstack. docs.govstack.global resolves and serves the documentation site. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Seven passages cited "the 2026 cross-BB audit of all 15 Building Blocks"
as a citable artifact and attached counts to it ("at least 9 BBs"). No
such document is published, so a reader cannot check any of it.
Each passage now states the provenance a reader can verify for themselves
(the published BB API specifications) and drops the unverifiable counts.
The substantive observations are unchanged.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
3.1 pinned asyncapi to exactly 3.0.0, rejecting 3.1.0, the current published AsyncAPI 3 version. Linting the golden AsyncAPI spec re-declared as 3.1.0 produces exactly one finding, govstack-3.1 itself: every other rule in the ruleset passes unchanged, so the pin was the only obstacle. 3.1 now mirrors 2.1's forward-qualification wording, naming the versions this guide and ruleset version qualify and requiring a later version to be qualified explicitly before use. The govstack-3.1 pass fixture moves to 3.1.0; 3.0.0 stays covered by tests/golden/asyncapi-golden.yaml. Also narrows govstack-18.2-openapi to oas3_1 and govstack-18.2-asyncapi to aas3. Both are substantive rules, not version gates, so the broad formats they declared did not match the house style used by every other rule of that kind. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
17.4 required each channel parameter's "schema" to be documented. The AsyncAPI 3 Parameter Object has exactly default, description, enum, examples and location, with additionalProperties: false, in both 3.0.0 and 3.1.0. A parameter carrying a schema field is therefore not a valid AsyncAPI document, so the rule as written could not be satisfied. 17.4 now requires what the format can express: a non-empty description for routing semantics, enum for closed value sets, examples otherwise. The linter already enforced description as a stand-in; that is now a faithful implementation of the rule rather than a proxy, and the comments saying otherwise are updated. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
9.7 required every enum value to be SCREAMING_SNAKE_CASE, which forbade six value sets the guide itself mandates: 17.11 delivery guarantees, 17.13 capability values, 11.5 error codes, 16.3 event types, 10.9 BCP 47 tags and 12.7 sort keys. A BB modelling any of them as an enum could not satisfy both rules. 9.7 now scopes the requirement to BB-defined states and lists the carve-outs with links. The linter follows for the five that are distinguishable by shape. Sort keys are lowerCamelCase field names, indistinguishable from the mis-cased state names the rule must keep catching, so they stay a false positive recorded in the rule comment and the coverage note rather than a hole in the pattern. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
5.1 required a /v{N}/ prefix on every path and 18.2 required a major version
in every path key, but 5.9 mandates an unversioned /health. A BB satisfying
5.9 broke both. The linter already carved out /health and /ready with a
comment saying why, and 18.2's function only ever checked paths that already
carry a prefix, so the guide text was the only thing asserting the
contradiction. Both rules now state the exemption.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
…ements The guide restated three CFR-derived constraints more loosely than the CFRs themselves state them. A specification that extends the CFRs may tighten or elaborate a requirement but must not weaken one, and all three of these are classified IMMUTABLE, so the looser wording was not a permissible variation. - 1.3 replaces the "precedence is unsettled" punt with the framework's actual rule, and points at the citation convention used below. - 10.2 requires UTC with the Z designator rather than any RFC 3339 offset, per govstack-cfr-data#req-2. - 13.7 requires negotiated TLS 1.3 or higher, per govstack-cfr-security#req-1. - 10.11 is new: UTF-8 text encoding, per govstack-cfr-data#req-1, with govstack-10.11-openapi and govstack-10.11-asyncapi enforcing that no declared media type or contentType names another charset. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Seventeen ruleset fragments cited <SCRATCHPAD>/linter-conventions.md, a document that exists nowhere in the repository. The conventions it described are the ones the linter README already documents, so the references now point there. ruleset.yaml claimed s03-s20 were empty skeletons and named the guide version without its -draft suffix; both were true during the initial build and neither is now. strict.yaml loses the same build-scaffolding prose. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Two rules a reviewer hits early could not be satisfied as written. 11.7 requires a common error catalogue "defined in govstack-openapi-common.yaml and reused", but that file carried the codes only as literals inside response examples, seven of the nine, with nothing referenceable. It now defines CommonErrorCode, including the missing alreadyExists and unimplemented, and 11.7 names the schema so "reused" has something to point at. 16.8 signs the complete structured CloudEvent and has verifiers reconstruct it from the received body, but nothing required structured content mode on the webhooks surface. In CloudEvents binary mode the body is only `data`, so the signature was unverifiable. 16.2 now requires application/cloudevents+json there, matching what 17.6 already requires of AsyncAPI, and govstack-16.2-structured enforces it. The two remaining verification inputs, key discovery on transports with no subscription control plane and the replay-window bound, are genuine committee decisions rather than drafting errors, so they are declared as OPEN-15-H and marked inline at 16.8 and 16.9 instead of being invented here. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
An outside team applied the guide to a non-BB project and reported eight
issues. Six were real: rules that could not be satisfied as written, or
carve-outs the linter did not honour.
- 5.9: health is carried by the status code. Declare both 200 and 503; the
200 body is plain application/json, minimal, and must not expose
system-internal detail. Drops draft-inadarei-api-health-check, an expired
Internet-Draft that never became an RFC (resolves OPEN-4-B).
- 5.10: the standard unversioned endpoints are read-only, so they cannot be
used to smuggle a business resource outside /v{N}/.
- 9.7: name the real enum carve-out, values drawn from an IANA registry
(JOSE and COSE algorithms and curves, media types), not health vocabulary.
- 12.1: a collection that bounds every array it returns with maxItems may be
returned unpaginated.
- 13.2: accept an http bearer JWT scheme. A resource server that validates
tokens issued elsewhere would misdescribe itself declaring an oauth2 flow.
The 5.10 path set now lives in one module, functions/lib/standardEndpoints.js,
replacing three inline copies that had already drifted apart.
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
jeremi
marked this pull request as ready for review
August 10, 2026 08:29
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.
Summary
This PR introduces a reviewable draft of the GovStack API design guide and its supporting conformance tooling.
It:
govstack.globalThe template repository declares
noApibecause it does not itself define a Building Block API. Authors replace that declaration when creating a Building Block with one or more API surfaces.Why
GovStack needs a shared API design baseline that is practical to adopt and honest about what automated validation can prove. Earlier iterations imposed premature requirements and allowed validation results to imply more coverage than the linter actually provided.
This draft separates normative requirements from preferred conventions, records where automated checks are only partial proxies, and keeps context-dependent requirements available for human review.
The related CFR discussion is tracked in cfr-architecture issue 7.
Template impact
The existing specification content, version history, attribution, functional requirements, workflows, and test plan remain unchanged.
The focused template integration:
api/index.yamlwith an explicitnoApideclarationapi/swagger.*placeholdersspec/8-service-apis.mdto describe the inventory, coverage, and validation workflowComplete reference OpenAPI and AsyncAPI documents live with the linter tests instead of turning this template into a fictional reference Building Block.
Review focus
Reviewers are especially invited to assess:
Validation
npm testinapi-design-guide/linter: 204 tests passednoApideclarationpython3 tools/build_rules_index.py --check: 171 rules, generated index currentpython3 tools/check_links.py: 30 files, 496 links, and 188 anchors checkedgit diff --check origin/main...HEAD: passed