Skip to content

ADR 0001 โ€” Canonical contract, versioning, and cross-language conformance

Status: accepted ยท Date: 2026-10-02

Context

Policy semantics must exist once (Rust), while a Go Kubernetes adapter consumes the same contract. The project needs a single wire contract, a way to detect divergence between Rust and Go, and a stable policy digest.

Decision

  1. Canonical types live in Rust (crates/contracts). The versioned JSON Schemas under schemas/v1alpha1 are generated from those types via schemars. A test (committed_schemas_match_types) fails if the committed schemas drift from the code โ€” this is the CI divergence detector.
  2. Schema version is v1alpha1, carried in HardwareSnapshot and PlacementDecision. Breaking changes bump it; additive, backward-compatible fields do not.
  3. Shared conformance fixtures (fixtures/requests/*.json, fixtures/decisions/*.json) are generated by the Rust evaluator. Rust asserts it reproduces every decision; Go decodes the same vectors with unknown-field rejection and round-trips them. Semantic drift fails a test in either language.
  4. Policy digest is sha256:<hex> over a canonical JSON of the normalized policy (recursively sorted keys), not raw YAML bytes.
  5. Go pins a core revision via the lab versions.yaml; it never copies untracked schema fragments. Local dev uses sibling checkout paths.

Consequences

  • Adding a predicate requires: update Rust types + reason code + evaluator, regenerate schemas + fixtures, extend Go structs, re-run both test suites.
  • No separate hand-maintained schema can rot independently of the code.
  • Strict parsing (deny_unknown_fields + duplicate-key rejection) is part of the contract, so unknown security fields and duplicate keys are validation errors.