Conformance · AARM Architecture A
Jiffy implements AARM Architecture A
JTP v0.1.0 · spec_version 0.1.0
Jiffy's trust protocol is structured as a Protocol Gateway that classifies every observed action into a five-tier ladder, hashes the caller's context, and chains receipts with sha256. Any party holding the receipts can verify the chain offline, or POST them to a public endpoint and get back a yes/no answer — the signature and chain linkage are byte-deterministic (RFC 8785 JCS) and Ed25519.
Conformance summary
Honest score across 13 conformance items (9 AARM security objectives O1–O9 + 4 structural elements §3.1, §4, §5, §6):
Machine-readable: GET /api/v1/aarm/conformance. Long-form spec: /docs-public/jtp-spec. Both views are sourced from the same JTP_SPEC module so the counts you see here byte-match the manifest.
The five tiers
AARM partitions every agent-observable action into one of five tiers. The boundary that matters most in practice is T3 → T4: the moment an action becomes visible to an actor other than the agent itself. T5 is reserved for actions that cannot be undone with a git-revert or a rollback.
| Tier | Description | Examples |
|---|---|---|
| T1 | Read-only, non-escalating | fs:read, http:GET, git:status |
| T2 | Non-persistent side effects | log:write, metrics:emit, stdout |
| T3 | Local sandbox mutation | fs:write, git:commit (local) |
| T4 | Cross-actor mutation | git:push, slack:post, email:send |
| T5 | Irreversible privileged | dns:change, iam:grant, rm -rf |
The classifier is pure and deterministic — web/src/lib/aarm/tiers.ts — with 83+ pre-classified MCP tool names and a regex fallback. Unknown actions default to Tier 3 with aunclassified flag so the runtime never silently drops an observation into the "safe" bucket.
Clause-by-clause implementation
Every row below points at the live code path — not a roadmap item.
| Clause | AARM requirement | Jiffy implementation | Status | Surface |
|---|---|---|---|---|
| §3.1 | Protocol Gateway placement | JTP pipeline + /api/v1/trust sit between agent runtimes and tool providers. | Met | web/src/app/api/v1/trust/route.ts |
| §3.2 | 5-tier action classification | Pure classifier with 83+ pre-classified action names + regex fallback. | Met | web/src/lib/aarm/tiers.ts |
| §4.1 | Canonical receipt shape | RFC 8785 JCS canonicalization of {v, ts, actor, action, tier, context_digest, prev_hash, chain_seq}. | Met | web/src/lib/aarm/receipt.ts |
| §4.2 | Hash-chained receipts | Each receipt embeds sha256(canonicalize(prev_receipt)); genesis prev_hash is 64 zeros. | Met | web/src/lib/aarm/receipt.ts::verifyChain |
| §4.3 | Ed25519 detached signatures | Receipts signed with the same JTP Ed25519 keyring used for attestations (Sprint 12). | Met | web/src/lib/jtp/sign.ts |
| §4.4 | Offline chain verification | Public POST /api/v1/aarm/verify-chain returns {valid, brokenAt, reason} for any receipt array. | Met | web/src/app/api/v1/aarm/verify-chain/route.ts |
| §5 | Semantic-distance check | Stub shape in place (semanticDistanceStub); real cosine-distance impl lands in a follow-up. | Deferred | web/src/lib/aarm/receipt.ts::semanticDistanceStub |
| §6 | Context accumulation via digest | context_digest = sha256(canonicalize(context)) — semantically equivalent contexts collapse. | Partial | web/src/lib/aarm/receipt.ts::contextDigest |
Example receipt
A receipt never carries the raw context — only a hash. Operators replay the signed bytes against the Ed25519 public key from the JTP JWKS endpoint to verify.
{
"v": "aarm-1.0",
"ts": "2026-04-21T12:00:00.000Z",
"actor": "agent://acme/cursor-session-7c3f",
"action": "fs:read",
"tier": 1,
"context_digest": "4a8f3b…",
"prev_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"chain_seq": 0
}Verifying a chain
Post an array of receipts (raw, or each wrapped as {receipt, hash}) to the public endpoint. The response is a structural verdict; signature verification can be layered on the client using the same Ed25519 public key the JTP endpoints advertise.
POST /api/v1/aarm/verify-chain
Content-Type: application/json
{
"receipts": [
{ "receipt": <receipt_0>, "hash": "<sha256_0>" },
{ "receipt": <receipt_1>, "hash": "<sha256_1>" },
{ "receipt": <receipt_2>, "hash": "<sha256_2>" }
]
}
→ 200 { "valid": true, "length": 3 }
→ 200 { "valid": false, "brokenAt": 1, "reason": "prev_hash_mismatch", "length": 3 }Flag + rollout
AARM addendum fields on JTP attestations are gated by NEXT_PUBLIC_FLAG_AARM_RECEIPTS. The flag defaults off in production until the LiteLLM adapter (Sprint V.9) begins passing tier-classified tool calls through at runtime. Readers that do not understand the new fields continue to verify the JTP signature as before — the addendum sits outside the signed field set on purpose.
What is NOT yet conformant
§5 (semantic-distance threshold) is present as a typed shape (semanticDistanceStub) but does not yet compute a real distance. A follow-up sprint ships the embedding path. The protocol gateway itself is runtime-ready, but receipts are only emitted when the flag is on.