From edec105858882290323f3422b772ce877e5c1e1b Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 11 Jun 2026 08:45:16 +0200 Subject: [PATCH] Pre-freeze data-plane hardening: FIX 11/12/13 + Nova coverage finding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FIX 11 — reject cross-language-divergent numbers in committed payloads. append_stream_event now rejects non-integer numbers and integers beyond ±(2^53−1) in payload/metadata at ingestion (HTTP 422), so a customer recomputing a commitment in a Go/TS verifier can never read it as tampering. Documented in the protocol spec + all three SDK READMEs; 9 tests. FIX 12 — Nova IVC chain-continuity invariant. record_ivc_epoch now takes a per-stream transaction-scoped advisory lock and fails closed (409) if an epoch does not extend the latest verified epoch's next_state_root or would skip an unproven checkpoint — so two concurrent provers cannot fork Attesto's own lane and a failed proof cannot be chained over. The worker stops the pass on a failed proof (break, not continue) and always backfills the oldest unproven checkpoint first so holes heal. Tests cover both 409 paths plus in-order record + replay. FIX 13 — pin the e2e v1 checkpoint shape. Config now requires PROOFSTREAM_WINDOW_MAX_EVENTS=1 (alongside CHECKPOINT_MAX_WINDOWS=4) when Nova is enabled, and the worker refuses to close an aged checkpoint below the 4-window shape (which would be unprovable). Documented as the deliberate fail-closed v1 behavior; config + worker tests. VERIFY-1 — investigation: the standard production ingestion path (SDK → append_stream_event → persist_stream_event_receipt) does NOT write the nova_e2e boundary metadata the prover requires; no writer exists in backend/app, and _e2e_vector_for_checkpoint requires (not derives) it. So Nova proofs currently cover golden-vector/harness inputs, not live customer receipts — the open Route A/B item. Recorded in CRYPTO_REVIEW_CHECKLIST as a coverage-scope note; no Route A/B implementation in this release. Co-Authored-By: Claude Fable 5 --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index d08a0a1..412df46 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,14 @@ Attesto stores source-system time separately from backend ingest time. `time.Now().UTC()` when omitted, but production integrations should pass the real upstream event timestamp whenever the source system provides one. +## Committed payload number rule + +When events are committed to a Proofstream, payload and metadata numbers must +serialize identically across Python, Go, and JavaScript. Non-integer numbers +and integers beyond ±(2^53−1) are rejected at ingestion (HTTP 422); encode +decimals and large integers as strings (e.g. `{"score": "0.87"}`). This keeps +cross-language commitment recomputation byte-exact (`CanonicalJSON`). + ## Verification Remote verification uses Attesto's public `/v2/verify` API. Offline receipt