Skip to content

feat(sdk): Carapace v0.5.0 — catalog sync, gate check, signed receipts#11

Merged
ryan10sa-star merged 2 commits into
mainfrom
feat/carapace-v050-phase-b
May 20, 2026
Merged

feat(sdk): Carapace v0.5.0 — catalog sync, gate check, signed receipts#11
ryan10sa-star merged 2 commits into
mainfrom
feat/carapace-v050-phase-b

Conversation

@ryan10sa-star

@ryan10sa-star ryan10sa-star commented May 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • carapace/catalog.py — CatalogEntry, CatalogState, GateResult dataclasses; fetch_catalog() with ETag/304 support; run_gate_check() five-gate pre-call verifier
  • carapace/receipt.py — create_receipt() (hashes only, optional Ed25519 signing), verify_receipt(), post_receipt() / post_receipt_async() (fire-and-forget, never raises)
  • typescript/src/catalog.ts — same catalog types and functions in TypeScript
  • typescript/src/receipt.ts — receipt helpers via WebCrypto (Ed25519, Chrome 113+/Node 20+)
  • Version bumped to 0.5.0 — pyproject.toml and typescript/package.json
  • 40 new tests — 259 total, all green

Gate check design

Five gates run in order, short-circuit on first failure: catalog_membership → active_status → revocation_clear → clawmark_gate → delegation_valid

Fail-open rules preserved: catalog=None passes all gates; trust_gates_enabled=False passes all gates.

Depends on

Phase A: relayforge-ai/aria-registry#7

🤖 Generated with Claude Code


View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

Python (carapace/catalog.py):
- CatalogEntry, CatalogState, GateResult dataclasses
- fetch_catalog() — ETag-based ARIA catalog fetch with 304 support
- run_gate_check() — five-gate pre-call verification: catalog_membership,
  active_status, revocation_clear, clawmark_gate, delegation_valid
- Fail-open: catalog=None → all gates pass with mode=fail_open
- Observe-only: trust_gates_enabled=False → all gates pass

Python (carapace/receipt.py):
- create_receipt() — SHA-256 hashes only, optional Ed25519 signing
- verify_receipt() — Ed25519 signature verification (returns bool, never raises)
- post_receipt() / post_receipt_async() — fire-and-forget, NEVER raises

TypeScript (typescript/src/catalog.ts + receipt.ts):
- fetchCatalog(), runGateCheck(), catalogGet(), catalogIsActive()
- createReceipt(), verifyReceipt(), postReceipt() via WebCrypto
- Full TypeScript types exported from index.ts

Bumped version to 0.5.0 (pyproject.toml + typescript/package.json).
40 new tests, 259 total passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 20, 2026 01:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to release Carapace SDK v0.5.0 by adding ARIA catalog sync + local gate checks and introducing signed tool-call receipts (with best-effort posting), alongside TypeScript equivalents and version bumps.

Changes:

  • Added catalog sync helpers (ETag/304 fetch + five-gate pre-call verifier) in Python and TypeScript.
  • Added receipt creation/verification + best-effort receipt posting helpers in Python and TypeScript.
  • Bumped SDK versions to 0.5.0 and added a new v0.5 Phase B test suite (Python).

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
typescript/src/receipt.ts Adds WebCrypto-based receipt hashing/signing/verification and receipt posting helpers.
typescript/src/catalog.ts Adds catalog types, ETag-based fetch, and five-gate runGateCheck helper.
typescript/src/index.ts Re-exports new v0.5.0 catalog + receipt APIs from the package entrypoint.
typescript/package.json Bumps npm package version to 0.5.0 and reformats keywords.
carapace/catalog.py Adds Python catalog dataclasses, fetch via ETag/304, and a five-gate verifier.
carapace/receipt.py Adds Python receipt hashing/signing/verification plus best-effort HTTP posting.
carapace/__init__.py Bumps version to 0.5.0 and exports new catalog/receipt APIs.
pyproject.toml Bumps Python project version to 0.5.0 and updates description.
tests/test_v05_phase_b.py Adds v0.5.0 tests for catalog sync + receipts (repo-root test suite).
tests/test_v04_features.py Removes the previous v0.4 feature test contents from the repo-root suite.
Comments suppressed due to low confidence (1)

pyproject.toml:15

  • New v0.5.0 features (catalog sync and receipt posting) depend on httpx, but httpx is not listed in this package's dependencies. As a result, fetch_catalog() will raise ImportError at runtime unless users manually install httpx. Consider adding httpx to dependencies (or an explicit extra like carapace-sdk[net]) and documenting it accordingly.
name = "carapace-sdk"
version = "0.5.0"
description = "Portable trust envelope for AI agents — enforcement, expiry, versioning, delegation, epistemic tracking, compliance profiles, escalation workflows, catalog sync, and signed receipts"
readme = "README.md"
requires-python = ">=3.10"
license = "Apache-2.0"
dependencies = [
    "pydantic>=2.0",
    "cryptography>=41.0",
]

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread typescript/src/receipt.ts Outdated
Comment on lines +37 to +41
async function sha256Json(obj: unknown): Promise<string> {
const canonical = JSON.stringify(
obj,
Object.keys(obj as Record<string, unknown>).sort(),
);
Comment thread typescript/src/receipt.ts Outdated
Comment on lines +82 to +89
if (privateKeyBytes) {
const keyPair = await crypto.subtle.importKey(
'raw',
privateKeyBytes,
{ name: 'Ed25519' },
false,
['sign'],
);
Comment thread typescript/src/receipt.ts Outdated
Comment on lines +98 to +114
// Note: WebCrypto Ed25519 importKey('raw') gives a private key only.
// To get the public key hex, the caller should pass it separately or
// derive it from a CryptoKeyPair (generateKey). This is a limitation
// of WebCrypto's Ed25519 API for raw private key import.
publicKeyHex = null;
}

return {
tool_id: toolId,
agent_id: agentId,
call_hash: callHash,
args_hash: argsHash,
result_hash: resultHash,
signature,
public_key: publicKeyHex,
status,
};
Comment thread typescript/src/receipt.ts
Comment on lines +58 to +63
export async function createReceipt(
toolId: string,
args: unknown,
result: unknown = null,
options: CreateReceiptOptions = {},
): Promise<ReceiptPayload> {
Comment thread typescript/src/catalog.ts
Comment on lines +61 to +69
export async function fetchCatalog(
ariaUrl: string,
options: FetchCatalogOptions = {},
): Promise<{ state: CatalogState | null; etag: string | null }> {
const { etag, timeout = 5000, apiKey } = options;
const headers: Record<string, string> = {};
if (etag) headers['If-None-Match'] = etag;
if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;

Comment thread carapace/catalog.py Outdated
Comment on lines +31 to +32
clawmark_breakdown: dict = field(default_factory=dict)
scope_requirements: dict = field(default_factory=dict)
Comment thread carapace/receipt.py
Comment on lines +24 to +32
def create_receipt(
tool_id: str,
args: Any,
result: Any = None,
*,
agent_id: Optional[str] = None,
status: str = "ok",
private_key_bytes: Optional[bytes] = None,
) -> dict[str, Any]:
Comment thread carapace/receipt.py
Comment on lines +112 to +123
async def post_receipt_async(
aria_url: str,
receipt: dict[str, Any],
*,
api_key: Optional[str] = None,
timeout: float = 3.0,
) -> bool:
"""
Fire-and-forget async receipt post. Returns True on success, False on any failure.
NEVER raises — a failed post MUST NOT block the tool call.
"""
try:
Comment thread carapace/__init__.py
Comment on lines +100 to +114
from .catalog import (
CatalogEntry,
CatalogState,
GateResult,
fetch_catalog,
run_gate_check,
)
from .receipt import (
create_receipt,
post_receipt,
post_receipt_async,
verify_receipt,
)

__version__ = "0.5.0"
Comment thread tests/test_v05_phase_b.py
Comment on lines +10 to +18
# ─── Catalog tests ────────────────────────────────────────────────────────────

from carapace.catalog import (
CatalogEntry,
CatalogState,
GateResult,
fetch_catalog,
run_gate_check,
)
…eipts

- TypeScript: fix sha256Json to sort keys recursively (array-replacer dropped nested keys)
- TypeScript: replace privateKeyBytes with keyPair CryptoKeyPair so public_key is populated
- TypeScript: fix ETag normalization to strip W/ weak prefix in catalog.ts
- TypeScript: add DOM lib to tsconfig for CryptoKey/CryptoKeyPair types
- Python: remove unused hashlib/json imports from catalog.py
- Python: add dict[str, Any] types to clawmark_breakdown/scope_requirements fields
- Python: replace 'Lobsters' with 'Agents' in catalog module docstring
- Python: add status validation ('ok'|'error') in create_receipt()
- Python: fix post_receipt/post_receipt_async docstrings to 'best-effort (never raises)'
- Mirror carapace/catalog.py and receipt.py into python/carapace/ for CI/publishing
- Add python/tests/test_v05_phase_b.py (40 tests) mirrored from root tests/
- Bump python package version to 0.5.0
- Add typescript/test/v05_receipts.test.js (17 new tests, 26 total passing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ryan10sa-star ryan10sa-star merged commit da6ef45 into main May 20, 2026
1 of 2 checks passed
ryan10sa-star added a commit that referenced this pull request May 23, 2026
INFRA: dedupe publish workflow + CHANGELOG v0.5.0 — audit #10, #11
@ryan10sa-star ryan10sa-star deleted the feat/carapace-v050-phase-b branch June 14, 2026 21:46
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