Skip to documentation

SDK and error contracts

Tools reference

Tools reference Five node scripts, no dependencies. Two run in this repository ( generate , check ); one is the harness they both lean on ( conformance ); two run against other trees ( no handrolled envelope , find implementations ). Every

Tools reference

Five node scripts, no dependencies. Two run in this repository (generate, check); one is the harness they both lean on (conformance); two run against other trees (no-handrolled-envelope, find-implementations). Every output line below is captured from a real run.

codegen/generate.mjs

node codegen/generate.mjs [--check]

The only thing allowed to read the catalogue at build time. Writes the four generated modules — rust/src/codes.rs, python/wisent_errors/codes.py, js/codes.mjs, swift/Sources/WisentErrors/Codes.swift — and prints one line per target, written or unchanged:

unchanged  rust/src/codes.rs
unchanged  python/wisent_errors/codes.py
unchanged  js/codes.mjs
unchanged  swift/Sources/WisentErrors/Codes.swift

--check writes nothing: a target whose bytes differ prints DRIFTED instead, followed by

generated code does not match the catalogue; run codegen/generate.mjs

and exit 1. Generated files are committed, so a consumer needs no build step and drift is a diff, not a mystery.

ci/check.mjs

node ci/check.mjs

Everything that must hold before the package ships — four checks, each earned by a specific way the fleet's error handling failed. The healthy run, verbatim:

ok    generated code matches the catalogue
ok    schema and catalogue name the same codes
ok    schema and catalogue name the same severities
ok    the failure point pattern is stated once
ok    every golden envelope obeys the schema
ok    runtimes agree (11 case(s) + 45 vocabulary row(s), 0 failing)

all checks passed

Exit 0; any failing check prints FAIL with the detail indented under it, ends with <n> check(s) failed, and exits 1. Check 3 is a hand-rolled schema validation over exactly the fields failure.schema.json uses — required keys, no unknown keys, the failure-point grammar (a malformed point is allowed only when context records wisent_errors.failure_point: malformed), derived fields re-derived from the catalogue, and no empty service/impact/detail strings. What each failure looks like is in the runbook.

tests/conformance.mjs

node tests/conformance.mjs

Proves the four runtimes are one behaviour. It builds the Rust and Swift emitters itself (cargo build --quiet --bin emit, swift build) — a harness that reports RUNTIME MISSING on a fresh clone teaches people to read past that line — then has every runtime emit every golden case in tests/conformance/cases.tsv and dump the derived vocabulary probed by tests/conformance/table.tsv, comparing everything against the expected column and against each other. Healthy output is one ok line per case naming the runtimes that agreed, one for the vocabulary, and the summary:

ok    credential-refused  (js, python, rust, swift)
...
ok    derived vocabulary  (45 rows, js, python, rust, swift)

11 case(s) + 45 vocabulary row(s), 0 failing

Failure vocabulary: FAIL <case> with the expected and differing lines, RUNTIME MISSING <label> when an emitter could not run, TABLE DIFFERS <label> vs <reference> with up to five differing rows, TABLE MISSING <label> -- <why>. Exit 0 only when nothing fails. One caveat worth knowing: the trailing ok derived vocabulary line records only that all four runtimes dumped a table — TABLE DIFFERS lines above it are the verdict, and they are counted in the summary.

ci/no-handrolled-envelope.mjs — the guard

node ci/no-handrolled-envelope.mjs <path> [<path>...]

Run by consumers against their own tree. Reports every line outside this package that writes a failure_point or error_code key — quoted or bare, key (:) or assignment (=) — in .rs .py .mjs .js .ts .tsx .jsx .go .swift .sh files, skipping node_modules target .git dist build .venv __pycache__ vendor. Clean:

no hand-built envelope in /tmp/toy-shelf

exit 0. Findings, captured against a toy tree:

2 site(s) name an envelope key outside the package:
  /tmp/toy-shelf/serve.mjs:14  failure_point: 'shelf.store.read',
  /tmp/toy-shelf/serve.mjs:15  error_code: 'store_down',

Each needs a reason. Building an envelope here means the derived fields can be
wrong, so build it with wisent-errors instead. Three answers are legitimate and
common: an operator-visible log line whose format is already parsed, a field
declaration, and another API's own `error_code` -- Azure has one, and this guard
cannot tell it from ours. Read the line before believing the count.

exit 1. No path given: the usage line and exit 2. It reports sites, not verdicts — read the line before believing the count.

ci/find-implementations.mjs — the census

node ci/find-implementations.mjs [<root>...] [--unadopted-only]

Default root: the parent of this repository. Two passes. The literal scan finds files quoting infra_down (the one code that is not an English phrase) plus at least four of the seven codes as string literals — that calibration reproduced exactly the nineteen implementations found by hand and nothing else. The manifest sweep reads package.json, Cargo.toml, Package.swift, pyproject.toml, setup.py, requirements.txt for a dependency on the package and extracts the pinned sha near the package name. Checkouts of one remote are merged; a file that no longer restates the vocabulary at origin/HEAD demotes its checkout to stale, and a checkout with no remote at all is detached — neither counts against the census. Captured against a toy fleet (one legacy clone, one adopted repository):

RESTATES  toy-fleet/toy-legacy  (1 file(s))
         src/failure.mjs  names 7/7

declares  toy-fleet/toy-adopted  pin b01a0c9c

1 checkout(s) declare a dependency on the package.
1 still quote four or more codes as literals: 1 restate the taxonomy, 0 are stale or detached copies of one that does not, 0 are part-migrated and name the package too.

Row labels: adopted (quotes codes but also names the package — part-migrated), RESTATES (a live copy of the vocabulary), stale, detached, and declares rows for the manifest sweep (pin unpinned when no sha is found and the dependency is not workspace = true). Exit 0 only when no live checkout restates the taxonomy. What neither pass can find, stated so nobody trusts the tool further than it goes: a module that generates or interpolates the code strings instead of writing them out.

Where they run

check (which runs generate --check and conformance) gates this repository; the guard and the census run against consuming trees — adoption strategy in integration, a worked migration in walkthrough-adoption, the healthy gate run in walkthrough-conformance.