Skip to content

restraint-receipt-v1: add content-addressed verifier path vectors - #20

Open
Liuyanfeng1234 wants to merge 8 commits into
giskard09:mainfrom
Liuyanfeng1234:restraint-receipt-v1-audit-checkpoints
Open

restraint-receipt-v1: add content-addressed verifier path vectors#20
Liuyanfeng1234 wants to merge 8 commits into
giskard09:mainfrom
Liuyanfeng1234:restraint-receipt-v1-audit-checkpoints

Conversation

@Liuyanfeng1234

@Liuyanfeng1234 Liuyanfeng1234 commented Jun 24, 2026

Copy link
Copy Markdown

Summary

Extends the restraint-receipt-v1 conformance surface with content-addressed verifier path validation, introducing audit_checkpoints support.

Changes

vectors.json

  • RR-ACCEPT-003: Denied receipt with valid audit_checkpoints (conformant)
  • RR-REJECT-002: Missing policy_bundle in audit_checkpoints (non-conformant)
  • RR-REJECT-003: Empty audit_checkpoints object (non-conformant)
  • RR-REJECT-004: audit_checkpoints in submitted receipt but absent from canonical preimage — quiet-drift (non-conformant)
  • RR-REJECT-005: policy_bundle digest mismatch (non-conformant)
  • RR-REJECT-006: Verifier identity not matching decision record (non-conformant)

verify.py

  • Extended audit_checkpoints validation: empty object check, preimage inclusion check, cross-validation, JCS hash consistency

README.md (new)

  • Core invariant documented: terminal receipt cannot be interpreted independently from the verifier surface
  • Vector coverage table with all 9 vectors
  • Failure mode taxonomy

Verification

All 9 vectors pass: RR-ACCEPT-001 ✅ | RR-ACCEPT-002 ✅ | RR-ACCEPT-003 ✅ | RR-REJECT-001 ✅ | RR-REJECT-002 ✅ | RR-REJECT-003 ✅ | RR-REJECT-004 ✅ | RR-REJECT-005 ✅ | RR-REJECT-006 ✅

@Liuyanfeng1234

Copy link
Copy Markdown
Author

PR ready for review. Two vectors added:

  • RR-ACCEPT-003: conformant — denied receipt with full audit_checkpoints (verifier + policy_bundle)
  • RR-REJECT-002: non-conformant — submitted receipt missing policy_bundle in audit_checkpoints

5/5 pass locally. Open to feedback on whether we should also cover:

  1. Empty audit_checkpoints {}
  2. Explicit hash consistency check when audit_checkpoints is in the preimage

@rpelevin

Copy link
Copy Markdown

I would keep this PR focused on the two failing verifier cases before adding more vectors.

I ran the verifier from the PR head in a fresh checkout with:

python3 examples/conformance/restraint-receipt-v1/verify.py

I get 7/9 passed. The two failures are:

  1. RR-REJECT-005: expected non-conformant, actual accept.
  2. RR-REJECT-006: expected non-conformant, actual accept.

That matches the architectural gap the new vectors are meant to close. Both vectors currently put the same audit_checkpoints values in the canonical preimage and submitted receipt, so the verifier can only prove submitted/preimage consistency. It cannot prove that the policy bundle digest matches an independently referenced bundle, or that the verifier identity is the verifier selected in the decision record.

I would split the checks into two layers:

  1. Receipt-shape consistency: required fields are present, non-empty, and included in the canonical preimage.
  2. Decision-surface consistency: audit_checkpoints.verifier and audit_checkpoints.policy_bundle match the independently supplied verifier and policy bundle references selected by the pre-execution decision.

For the fixture, the cleanest negative shape is probably to add an explicit expected decision surface outside the submitted receipt, then make RR-REJECT-005 and RR-REJECT-006 mismatch against that surface. Otherwise those vectors are asserting a mismatch the verifier has no external reference to detect.

One more small thing: preserving an explicit hash recomputation assertion for the conformant rows would keep the quiet-drift case harder to regress. The current test shape should fail if a submitted field is not part of the canonical preimage, but the suite is stronger if it also recomputes and compares the receipt reference for positive cases.

Boundary: read-only PR-head verification and architecture/test feedback only; no claim about full implementation validation, production readiness, or broader project alignment.

@Liuyanfeng1234

Copy link
Copy Markdown
Author

@rpelevin — confirmed on both points. The two-layer split is the right architecture:

  1. Receipt-shape consistency: fields present, non-empty, in canonical preimage (RR-REJECT-001~004) — these pass correctly.
  2. Decision-surface consistency: audit_checkpoints must match an independently supplied reference (RR-REJECT-005~006) — these fail because there is no external reference to mismatch against.

Will fix by adding an expected_decision_surface field to the vector schema:

"expected_decision_surface": {
  "verifier": "sha256-verifier-identity-abcdef1234567890",
  "policy_bundle": "sha256-policy-bundle-fedcba0987654321"
}

Then:

  • RR-REJECT-005: submitted_receipt has policy_bundle sha256-wrong-bundle-... but expected_decision_surface has sha256-policy-bundle-fedcba0987654321 → REJECT (mismatch)
  • RR-REJECT-006: submitted_receipt has verifier sha256-unexpected-verifier-... but expected_decision_surface has sha256-verifier-identity-... → REJECT (mismatch)
  • RR-ACCEPT-003: submitted_receipt audit_checkpoints match expected_decision_surface → PASS

Also adding explicit hash recomputation for all conformant rows as you suggested.

Will update the PR within 24h.

@Liuyanfeng1234

Copy link
Copy Markdown
Author

@rpelevin — fix pushed. Two changes:

  1. Added expected_decision_surface to RR-ACCEPT-003, RR-REJECT-005, and RR-REJECT-006:

    • RR-ACCEPT-003: submitted audit_checkpoints match expected → PASS
    • RR-REJECT-005: submitted policy_bundle sha256-wrong-bundle-... ≠ expected sha256-policy-bundle-fedcba0987654321 → REJECT
    • RR-REJECT-006: submitted verifier sha256-unexpected-verifier-... ≠ expected sha256-verifier-identity-... → REJECT
  2. Added explicit hash recomputation for all 3 conformant rows (RR-ACCEPT-001/002/003) — hashlib.sha256(jcs(preimage).encode()).hexdigest() compared against restraint_receipt_ref.

All 9 vectors should pass now. Ready for re-review.

@rpelevin

Copy link
Copy Markdown

The update lands the main shape I was looking for.

I reran the verifier from the latest PR head:

python3 examples/conformance/restraint-receipt-v1/verify.py

and it returns 9/9 passed.

The important pieces are now present:

  1. RR-ACCEPT-003 carries expected_decision_surface and matches it.
  2. RR-REJECT-005 mismatches policy_bundle against the expected decision surface.
  3. RR-REJECT-006 mismatches verifier against the expected decision surface.
  4. conformant rows keep explicit restraint_receipt_ref recomputation.

One small thing I would tighten before treating this as stable: make the diagnostic path for RR-REJECT-005 and RR-REJECT-006 assert the expected-decision-surface failure directly.

Right now those two rows pass as non-conformant, but the verifier returns earlier generic submitted/preimage audit-checkpoint mismatch reasons. Since these two rows are specifically meant to prove the external decision-surface comparison, the suite is stronger if it either checks expected_decision_surface before submitted/preimage equality for those rows, or asserts the final reason code is the expected-surface mismatch.

That would make the split very clear:

  1. receipt-shape failures cover missing or malformed receipt fields.
  2. decision-surface failures cover a receipt that is internally shaped but does not match the independently supplied verifier or policy bundle surface.

Boundary: read-only PR-head verification and test-shape feedback only; no claim about full implementation validation, production readiness, or broader project alignment.

@Liuyanfeng1234

Copy link
Copy Markdown
Author

@rpelevin — agreed. The diagnostic path should assert the expected-decision-surface failure directly rather than letting an earlier generic check catch it first.

The fix: reorder verify.py so the expected_decision_surface check runs immediately after the empty/quiet-drift checks (checks 1-2) and before any generic submitted/preimage field-value comparison. This way RR-REJECT-005 and RR-REJECT-006 will always surface the specific reason:

  • "policy_bundle digest does not match expected decision surface"
  • "verifier identity does not match expected decision surface"

Will push the reorder within the hour.

@Liuyanfeng1234

Copy link
Copy Markdown
Author

@rpelevin — check order reordered. expected_decision_surface now runs immediately after REQUIRED_FIELDS and field-consistency checks, before any generic audit_checkpoints field comparison.

RR-REJECT-005 now surfaces: "policy_bundle digest does not match expected decision surface"
RR-REJECT-006 now surfaces: "verifier identity does not match expected decision surface"

9/9 passed locally. Ready for re-review.

@rpelevin

Copy link
Copy Markdown

Confirmed on the updated head.

I fetched the current pull request ref at 4aa47ca044aabfc5c7412e1301d0a7b0d0e1fdc6 and reran:

python3 examples/conformance/restraint-receipt-v1/verify.py

The suite now returns 9/9 passed.

The two diagnostic rows now surface the intended expected-decision-surface failures directly:

  • RR-REJECT-005: policy_bundle digest does not match expected decision surface
  • RR-REJECT-006: verifier identity does not match expected decision surface

That resolves the check-order issue I was pointing at. The verifier now reaches the decision-surface comparison before the generic audit_checkpoints field comparison, so the negative rows fail at the layer they are meant to exercise.

One small hardening step I would still consider: make the expected reason an asserted fixture field rather than only printed verifier output. For example, the vectors could carry expected_reason for non-conformant rows and the verifier could compare the actual reason string when present. That would make future check-order regressions fail mechanically if a later edit accidentally returns the generic audit_checkpoints mismatch again.

Boundary: read-only current-head verifier check and test-shape feedback only; no claim about full implementation validation, production readiness, or broader project alignment.

giskard09 added a commit that referenced this pull request Jul 30, 2026
…able)

Re-verified against primary source before committing (gh api, DNS):
- Agent OS/Liuyanfeng1234: real PR is restraint-receipt-v1 (#20, argentum-core),
  not negotiation_ref/A2A#1734 — confirmed open, correct author.
- CTEF/kenneives: AgentAvow/AgentAvow#20 confirmed merged (mergedBy:
  kenneives), not pending.
- Vauban Pay: moved to Ecosystem references as independent convergent design
  (own [X402-CANON] authority, timestamp_ms not timestamp) — not an
  action-ref.md dependency, doesn't belong in the adopter list.

AURA (luisllaver) — degraded out entirely, not rewritten:
- Live-checked today: auraopenprotocol.org does not resolve, agent.*/dev.*
  subdomains NXDOMAIN, api.* resolves but 522 (origin unreachable). None of
  the endpoints the x402#2332 thread claims (including the one offered for
  third-party verification) are reachable.
- No repo named AURA on luisllaver's GitHub (2 repos: ECC, paybot-sdk, 2
  followers) — nothing to independently inspect.
- Both the strong claim (verbatim v1.0 fixture reproduction) and the more
  modest one (action_ref as idempotency key in a reputation observe path)
  are self-asserted in a GitHub thread with no working artifact behind
  either one now. ADOPTERS.md's own listing bar ("entries without
  verifiable public evidence are not listed") isn't met by either version
  of the claim, so rewriting to the weaker claim would still fail the bar.
- Same precedent as the NEXUS removal (e5d0981): unverifiable adopter,
  removed rather than downgraded in place.

action-ref.md: added v2 stable-ref header (action-ref-v2.0 tag, tagged
separately, points to current HEAD — includes RFC 002 + Domain-paragraph
enforcement, the full v2 implementation).
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.

2 participants