zig-js

Verification & evidence

On this page 5

This project's central rule is that a claim is only as good as the artifact behind it. Conformance scores, ABI coverage, performance ratios, and platform support are all backed by checked-in evidence under docs/.data/, regenerated by tools, and gated in CI.

The evidence system

ClaimEvidence artifactRegenerated by
ECMAScript conformancedocs/.data/test262.jsonbun run docs:data -- --from run.txt
WebAssembly conformanceper-profile inventories + wasm-conformance-matrix.jsonhome-tool run tools/wasm-conformance-matrix.ts
Thread corpus coveragepr249-reference-inventory.json, pr249-execution-nogil.jsontools/threads-reference-audit.ts, tools/nogil-corpus-gate.ts
Public / private ABIthe JSON inventories under docs/c-api/, docs/objc-api/, docs/abi/the *-audit build steps
GC relocation coveragegc-relocation-inventory.jsonzig build gc-relocation-inventory-check
Performancedated .md report plus its raw .tsv samplesbenchmark-comparison, tools/benchmark-publication.ts
Platform supportdocs/platforms.mdtools/platform-release-matrix.ts
Release readinessrelease-compatibility-matrix.jsonzig build release-compatibility-check

Public prose in README.md and status pages is generated from these artifacts between HTML markers. Editing the rendered text by hand is reverted by the next generator run and can silently desync a release gate. See the accuracy plan.

CI gate families

ci.yml is authoritative. It runs on pull requests, pushes to main, manual dispatch, and nightly. Each Required Check is its own matrix leg with fail-fast: false, so an unrelated failure cannot mask the threading gates.

  1. Unit suite, sharded — and the same suite under ThreadSanitizer.
  2. Thread corpus, sharded in serialized mode, plus a no-GIL witness case and an execution-inventory witness.
  3. No-GIL corpus gates — a TSan sweep requiring zero engine-state races, and a functional gate against the published baseline, in both Debug and ReleaseSafe.
  4. threadfuzz across six profiles (default, amplified, broad, mid-GC, lifecycle, verify) plus TSan variants. Seeded, so these are deterministic gates rather than flaky stress.
  5. WebAssembly smokes across ten pinned upstream corpora, with converter binaries pinned by commit and SHA-256.
  6. ABI boundary fixtures across Debug / ReleaseSafe / TSan, plus the audits.
  7. test262-parallel — parallel execution introduces no new failures.
  8. Docszig build docs-link-check resolves every internal link and sidebar entry, then bun run docs:build must succeed. The link check is separate because bunpress renders a link to a missing page without complaint.

A manual-only performance workflow runs the macOS/JSC matrix and retains raw samples plus a rendered report as a 90-day artifact. It never gates ordinary CI: hosted-runner timing is evidence to inspect, not an automatic comparison with the recorded reference host.

Promotion rules

Coverage grows by promotion, and promotion has an explicit bar.

  • A PR-249 thread case is promoted only when it passes in its declared mode and finishes inside the no-GIL gate's budget. Several cases are ~20× slower with the GIL off, so passing in GIL mode is not promotion evidence — promoting such a case breaks CI.
  • The no-GIL gate treats a case unknown to the baseline as must pass, so a newly promoted case earns its place rather than inheriting an exemption by being absent from the file.
  • Every non-helper file outside the promoted allowlists must carry either an implementation blocker or a structured terminal disposition. A blocked case that happens to pass a probe is not thereby promoted.
  • An ABI entry moves from pending to implemented only when behaviour tests cover it, not when the declaration compiles.

Adding a gate

When you add a capability, add its gate in the same change:

  1. Produce a machine-readable inventory or report under docs/.data/.
  2. Add a verifier that fails on drift — the pattern used throughout is derive the live set from source, require exact ordered coverage, and fail closed (see gc-relocation-inventory-check).
  3. Wire it into ci.yml as its own leg.
  4. If it affects a public claim, regenerate the marker-delimited README section rather than editing prose.
  5. If it closes a roadmap item, update docs/.data/release-compatibility-matrix.json and re-run zig build release-compatibility-check.

Reading the release matrix

release-compatibility-matrix.json tracks the gates that stand between the current state and a stable release — platform matrix, public C API, Objective-C bridge, inspector, private ABI profiles, and the remaining engine gates (automatic shared-realm compaction, a moving nursery for the multi-age GC, and optimizing-JIT backend/differential evidence).

zig build release-compatibility-check                 # validate the matrix
home-tool run tools/release-compatibility.ts --release      # fail unless every gate is green
home-tool run tools/release-compatibility.ts --update-readme

The README's "What Is Not Implemented" section is generated from that file, and its removal is itself gated. That is the point: the honest list of gaps is maintained by a tool, not by memory.