approval-engine/adapters/go/approvalfact/README.md
tegwick 3485415b82 Add producer-owned Go approval fact validation and canonical vectors
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 16:25:54 +02:00

3.4 KiB

Approval fact data adapter

Provider-owned pure Go module for Access's Approval B2 source reader. No network, credentials, subprocess, policy evaluator, server or consume mutation exists here. Python approval_engine.binding remains the authoritative native format.

API:

  • CanonicalBinding(rawJSON) returns native five-field canonical UTF-8 bytes and sha256 digest; extra binding metadata is excluded.
  • ValidateClaim(rawClaim, Expected, now) validates one exact human/PDP-path claim against independently owner-derived Expected.NativeBindingJSON, exact approval ID and actual Access approval-free PDP digest.
  • MatchObserved(submitted, observed) requires two validated facts at the same captured instant and identical nonfreshness authority facts. No request is rewritten. Fact.RawJSON() returns a detached original byte copy; deadlines preserve each input's own freshness and approval expiry.

Fact means validated data, never authenticated provider origin. Access must fetch provider bytes through its independently admitted fixed origin/identity, then wrap this data in its own unforgeable source handle. A caller-supplied claim cannot become source truth merely by passing this helper. Access remains the single evaluator and must bound decision/operation/caller lifetimes separately. PEP consume CAS and live one-shot journal remain required before any effect.

Expected native act bytes must preserve the actual owner/compiler/normalization representation. Marshaling float64-decoded CheckRequest maps loses 1.0/1 and large integers. Raw submitted resource is sufficient only when Access proves the active registry cannot override that target and applies its exact existing normalization. Otherwise authoritative raw enrichment/compiler evidence is needed. This helper supplies no fallback or invented restricted numeric domain.

The strict parser retains integer/floating lexical types, arbitrary integer magnitudes, finite IEEE-754 float semantics and valid Unicode scalar values. Canonical float/string formatting follows Python source, including negative floating zero, exponent switching/padding, HTML and U+2028/U+2029. Duplicate object keys, nonfinite/overflow numbers, invalid UTF-8 and lone surrogates refuse. Inputs are bounded to 1 MiB and 128 container levels. Timestamp precision is at most nanoseconds with strict zoned RFC3339; current producer emits whole seconds. These explicit parser/resource limits fail closed, never normalize authority.

go test -race ./... checks the portable producer vectors, typed fact pairing, strict JSON/Unicode and exact deadline semantics. From the owner repo root, python3 scripts/check_go_approvalfact.py runs a deterministic 14,114-case development-only differential corpus against the actual Python producer, including random finite IEEE bit patterns, exponent boundaries/subnormals and Unicode. It uses a test-only local oracle file; production imports no oracle or Python runtime. Sample conformance is evidence, not a formal proof over all JSON.

The module pins Go 1.26.7 to match the existing Access consumer toolchain. testdata/owner-vectors.json is an unchanged portable copy of the Approval owner fixture, SHA256 dfb0a8810cd91847d7af6a7af6a51607a67a66fad7b86fc57365308c36bd9323. Transport cases requiring HTTP remain the Access adapter's tests; this module checks their duplicate/nonfinite bodies only. Import/deployment/native identity admission and positive policy gates require separate owner evidence.