Skip to content

feat(cycles): offline verifier for the Cycles rail, release 4.3.0 - #27

Merged
aeoess merged 3 commits into
mainfrom
feat/cycles-offline-verifier
Oct 15, 2026
Merged

aeoess merged 3 commits into
mainfrom
feat/cycles-offline-verifier

Conversation

@aeoess

@aeoess aeoess commented Oct 15, 2026

Copy link
Copy Markdown
Member

Adds the Cycles budget-authority rail to the Python SDK, offline path only, as a port of agent-passport-system 8.0.0 behaviour. The Python SDK had no payment rails before this.

New module agent_passport.v2.payment_rails.cycles, also exported from the package root:

  • sign_cycles_permit_receipt, sign_cycles_release_receipt, sign_cycles_denial
  • verify_cycles_permit_receipt, verify_cycles_release_receipt, verify_cycles_denial, synchronous, options evidence, expected_signer, now, ttl_seconds
  • map_cycles_denial_to_foundation with the ErrorCode and DecisionReasonCode tables ported entry for entry

With a supplied envelope the checks run in the TypeScript order: content hash binding, the envelope's own Ed25519 signature, then the 8.0.0 correspondence check for permit and release (stage and reservation_id only). Denials get no correspondence check. Malformed receipts and envelopes return a structured failure and do not raise.

Evidence

  • tests/cross_impl/cycles-correspondence-vectors.json is vendored byte for byte from agent-passport-system ababe0f (#237), all 13 cases pass. The test also re-signs each vector receipt and re-signed envelope from the published test seeds and matches the TypeScript signatures byte for byte.
  • 103 tests ported from cycles.test.ts for the offline path.
  • Mutation check: with the correspondence function forced to matched, the 9 negative correspondence vectors fail and the 4 others pass.
  • python -m pytest tests/ -q: 2753 passed, 9 skipped before, 2899 passed, 9 skipped after.

Boundary

Out of scope: the async DID variants, the evidence fetch and resolver path, did:cycles and JWKS key resolution, and signer authority. Differences from TypeScript, all listed in the CHANGELOG: stricter RFC 3339 parsing of issued_at, input capture for denials as well, a fail-closed bound of 200 nesting levels and 200000 values, and TypeError for wrong-typed options.

Version 4.3.0 is in its own commit.

Port of the agent-passport-system 8.0.0 Cycles rail, offline path only.
Adds receipt and denial types, map_cycles_denial_to_foundation with its
constant tables, sign and verify for permit, release and denial, and the
envelope checks (hash binding, envelope signature, 8.0.0 correspondence).
Malformed, non-JSON, deeply nested and self-referencing input returns a
structured failure and does not raise.

Not ported: async DID variants, fetch and resolver path, did:cycles and
JWKS key resolution, signer authority.

Signed-off-by: Tymofii Pidlisnyi <tima@aeoess.com>
Vendors cycles-correspondence-vectors.json byte for byte from
agent-passport-system ababe0f and asserts all 13 cases, plus byte for byte
re-signing of every vector receipt. Ports the offline tests from
cycles.test.ts and adds Python fail-closed tests.

Signed-off-by: Tymofii Pidlisnyi <tima@aeoess.com>
Adds the 4.3.0 changelog entry for the Cycles offline verifier.

Signed-off-by: Tymofii Pidlisnyi <tima@aeoess.com>
@aeoess
aeoess merged commit a9fe8c2 into main Oct 15, 2026
4 checks 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