Skip to content

docs(spec): freeze RECEIPT-v1 with golden vectors and version lock - #49

Merged
shreyanshjain7174 merged 1 commit into
mainfrom
docs/receipt-v1-spec
Oct 18, 2026
Merged

shreyanshjain7174 merged 1 commit into
mainfrom
docs/receipt-v1-spec

Conversation

@shreyanshjain7174

Copy link
Copy Markdown
Contributor

Plan

Phase 1 of the AgentGate scale-out prompt: freeze the receipt spec as the code behaves today. No Rust or v2 work starts before this is merged.

What changed

  • docs/spec/RECEIPT-v1.md describes exactly what the code does:

    • the length-prefixed binary hash preimage (fields, order, widths, domain strings, limits, 3,106-byte max);
    • the JCS rule for params_sha256;
    • the JSONL encoding;
    • the export manifest preimage and signature;
    • key ID derivation;
    • the policy decision enum and error-code rules;
    • the delegation-chain element format;
    • genesis linkage;
    • the step-by-step verification algorithm and its rejection reasons;
    • versioning rules.

    §10 has a byte-level worked example produced by the code.

  • 20 golden vectors in pkg/receiptspec/testdata/v1/: valid chains (genesis, multi-receipt, delegation, unicode, boundary values), tampered body, reordered chain, truncated chain (middle and tail), wrong-key signature, bad prev_hash, unknown signer, manifest mismatch and more. A committed generator with fixed keys rebuilds them byte for byte.

  • TestV1GoldenVectors runs every vector through the real ReadJSONL, LoadTrustedKeys and VerifyBundle, under explicit and embedded trust.

  • Version lock. A test hashes the canonical preimages of the ok vectors and compares them against digests the generator never writes. Any encoding change fails it, with a message to bump format_version and write RECEIPT-v2.md.

  • The README and package docs link the spec. Production code is unchanged apart from a 2-line doc comment.

Code and doc differences found (documented, not changed)

  • Record root and raw-size limits differ from DECISION.md.
  • genesis-unicode-max.bin actually holds seq MaxUint64.
  • Empty exports are rejected. This fails closed.
  • Delegation elements are not format-checked. The encoding stays unambiguous and the elements are signed.
  • The verifier does not check manifest metadata, including the manifest signer's validity window. A follow-up PR hardens this without a wire change.

Validation

  • go build ./...: passed
  • go vet ./...: passed
  • go test -race ./...: passed
  • semgrep --config auto --error --quiet ./internal ./cmd ./pkg: passed, no findings
  • Vectors regenerated twice: git diff empty

Review

Reviewed by a second model (Claude Opus 5.5). It recomputed §10's example independently: key, key ID, 183-byte preimage, entry hash, Ed25519 signature and manifest hash all match. It also rehashed every receipt in the valid vectors. Verdict: approved, no spec errors.

Pin deterministic vectors to prevent silent v1 changes.

Signed-off-by: Shreyansh Sancheti <43677304+shreyanshjain7174@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@shreyanshjain7174
shreyanshjain7174 merged commit d740dc6 into main Oct 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant