Skip to content

v0.8.5 — opt-in LayerContract (assume/guarantee) block on attest receipts

Choose a tag to compare

@sattyamjjain sattyamjjain released this 21 May 04:26
· 27 commits to main since this release
757f0d7

Thursday cut on top of v0.8.4. Patch bump — one optional field on the existing receipt schema + one new CLI flag. Schema version stays at v1 (the field is additive; legacy receipts deserialise unchanged). No breaking changes.

Honest framing (called out before the code)

The 2026-05-21 prompt asked for guarantees to be "populated automatically from the policy outcomes already tracked this window (deny-by-default hits, ghost-arg strips, PII masks, validation failures)". That counter store does NOT exist in agent-airlockcost_tracking.py counts tokens, circuit_breaker.py counts per-tool failures, audit.py emits one-way, anomaly.py is a per-event detector, but none aggregate policy outcomes by category over a window.

v0.8.5 ships the derived path instead: per-guard pass_rate is computed from the verdicts: list[ReceiptVerdict] the operator already supplies to build_receipt. Same source of truth as today's receipts; zero new infrastructure.

ADD

# agent_airlock.attest.LayerContract
{
  "guarantees": [
    {"name": "EvalRCEGuard",   "pass_rate": 0.9943, "sample_size": 351},
    {"name": "GhostArgFilter", "pass_rate": 1.0,    "sample_size": 412},
    {"name": "PIIMasker",      "pass_rate": 0.0,    "sample_size": 17}
  ],
  "assumes": ["upstream.tls.tlsv1.3", "upstream.dpop.bound"]
}
  • Guarantee (frozen) — name, pass_rate (validated to [0.0, 1.0]), sample_size (verifiers weight low-N appropriately)
  • LayerContract (frozen) — guarantees: tuple[Guarantee, ...] (sorted by name for canonical-payload stability) + assumes: tuple[str, ...] (free-form upstream-guarantee IDs)
  • derive_contract_from_verdicts(verdicts, *, assumes=()) — pure function
  • Receipt.contract: LayerContract | None = None optional field
  • build_receipt(..., contract=...) new kwarg
  • receipt_from_dict tolerates the new field; legacy receipts deserialise with contract=None

CLI

airlock attest receipt emit \
    --policy-bundle-hash "$BUNDLE_SHA" \
    --inputs-hash "$INPUTS_SHA" \
    --model-id claude-opus-4-7 \
    --verdicts-json verdicts.json \
    --key-file ~/.airlock/keys/test.bin \
    --keyid test-key \
    --contract \
    --assumes upstream.tls.tlsv1.3,upstream.dpop.bound \
    --output receipt.json

--contract (default off, opt-in) embeds the derived block. --assumes requires --contract.

Anchor

arXiv:2605.18672 — "assume-guarantee layer contract" framing. Cited once; no claims about the paper's specific content beyond adopting the terminology.

Honest scope

  • pass_rate is a measured statistic over the sample, not a proof. A 1.0 over 3 samples ≠ a 1.0 over 30,000 — hence sample_size on every Guarantee.
  • The signature attests the operator's declaration of verdicts, not the verdicts' truth. Garbage-in, garbage-out.
  • assumes strings are free-form — agent-airlock doesn't interpret them.

Stats

  • 2,510 tests · 83.42% coverage (gate 82%)
  • CI 7/7 green
  • Receipt schema version unchanged at v1 (additive field)

Install

pip install agent-airlock==0.8.5