SDK and error contracts
Conformance
Conformance Four runtimes are one behaviour only because a harness proves it, byte for byte, on every change. This page is the proof machinery: the golden cases, the vocabulary probes, the harness that compares runtimes against each other,
Conformance
Four runtimes are one behaviour only because a harness proves it, byte for byte, on every change. This page is the proof machinery: the golden cases, the vocabulary probes, the harness that compares runtimes against each other, and the gate that runs before the package ships.
The gate
node ci/check.mjs
Four checks, each earned by a specific way the fleet's error handling failed:
- generated code matches the catalogue — it runs
codegen/generate.mjs --check; six hand-kept copies drifted, and one lost the vocabulary entirely. - schema and catalogue name the same codes and severities, and state the failure-point pattern once — a schema that disagrees with the table it validates is a second source of truth.
- every golden envelope obeys the schema, derived fields included —
severitychosen at a call site is how the same code came to mean different things in different products. The schema check is deliberately hand-rolled over the fields this schema actually uses rather than pulling in a validator: a package every product must adopt has to be cheap to adopt, and that includes its own CI. - the runtimes agree — it runs
tests/conformance.mjsand reports its summary line.
It prints all checks passed and exits 0, or names the failing checks and
exits 1.
The harness
node tests/conformance.mjs
Each runtime emits every golden case; the harness compares all of them
against the expected column and against each other. The emitters are
tests/emit.mjs (JavaScript), tests/emit.py (Python, run via
/usr/bin/env python3), rust/src/bin/emit.rs (reads the case file on
stdin), and swift/Sources/emit (same). The harness builds the Rust and
Swift emitters itself — cargo build --bin emit and swift build — rather
than requiring the reader to have done it: a harness that reports RUNTIME
MISSING on a fresh clone teaches people to read past that line. The summary
is <N> case(s) + <M> vocabulary row(s), <F> failing, exit 0 only when
nothing fails.
Golden cases
tests/conformance/cases.tsv holds one case per line as tab-separated
key=value pairs, so all the languages can read it without a JSON parser
and the Rust crate stays dependency-free. An optional field is simply
absent, not an empty column. The cases are real: every one is a failure this
fleet produced while the vocabulary lived in six copies — a revoked OAuth
token, a throttled rotation, an unreachable store, a nested refusal carrying
invalid_grant as its cause, a one-segment and a four-segment failure
point, an envelope with no impact and no detail, and two salvage cases
(builder=or_fallback) proving the never-fail path emits identical bytes
too.
Vocabulary probes
Envelope cases prove the shape; tests/conformance/table.tsv proves the
vocabulary itself. Each emitter, asked with --table (the Rust and Swift
emitters additionally read the probe file on stdin), dumps every code's
severity, retryability, outage flag, HTTP status, exit code, and operator
summary, plus:
- statuses — how each interesting upstream status classifies, including 200 and 600: neither is a failure status, and a runtime that classifies them differently from the others is still a disagreement.
- chosen_exit — the exit code a caller brings, so the remap rule is visible: a retryable code must replace it, everything else must keep it.
- trim / word rows — a width and a text per row, comparing both trim rules across runtimes, including the padded, exact-width, and no-space edge cases that earlier versions got wrong.
- member rows — membership asked of untrusted text:
toString,__proto__,constructor,hasOwnProperty,valueOf,prototype, the empty string,AUTH, and the two honest answersauthandinfra_down.
The probes live in a data file all the emitters read, because three emitters carrying their own copy of the question is the same defect as three products carrying their own copy of the answer.
What this proves, and what it cannot
The harness proves the runtimes agree with each other and with the golden column. It cannot prove they agree with what a product was already emitting — only that product's own before-and-after diff does, which is why each migration produced one. The vocabulary the harness defends is catalogue; the guards a consuming repository runs against its own tree are in integration. A healthy run of gate and harness, pasted in full, is walkthrough-conformance; every failure shape, captured from a deliberately broken scratch copy, is in the runbook.