Skip to content

Trust layer: verifiable capsule receipts with CCF write-receipt anchoring - #200

Merged
Skyrider3 merged 23 commits into
projnanda:mainfrom
StevenMih:hackathon/stevenmih-ledger-anchored
Jul 15, 2026
Merged

Trust layer: verifiable capsule receipts with CCF write-receipt anchoring#200
Skyrider3 merged 23 commits into
projnanda:mainfrom
StevenMih:hackathon/stevenmih-ledger-anchored

Conversation

@StevenMih

Copy link
Copy Markdown

Trust layer: verifiable capsule receipts with CCF write-receipt anchoring (capsule-emit-nanda)

cc @Skyrider3 @dhve — reopening the trust-layer work from #54#177, rebuilt
on the CCF-native write-receipt format you pointed us toward. Grateful for the
patient reviews. Details on the structural changes below.

Re-opens the work from #54#177 (closed by @Skyrider3), rebuilt with a fundamentally
different anchoring architecture: instead of an on-trace hash chain (which is self-authored
evidence — the plugin controls the seal events), the committed fixtures are CCF / Azure
Confidential Ledger write receipts
obtained out-of-band from an independent transparency
service. The graded run replays these offline — zero network, filesystem, environment, or
clock access in the verdict path.

Every rejection point from #177, addressed

1. "The plugin is never installed/registered in CI."
capsule-emit-nanda is a declared root dependency; plain uv sync installs and registers
it. uv run nest run scenarios/receipt_reputation_capsule.yaml runs end-to-end.

2. "The adversarial validator never runs."
validate_receipt_reputation_anchored is registered in VALIDATORS under a new
receipt_reputation_capsule scenario type. Each signature-valid receipt observed on the
trace must have a matching pre-committed CCF write receipt that verifies offline against the
pinned service identity. Proven:

  • Capsule scenario → PASS (all 29 receipts anchored, CCF write-receipt verified offline).
  • agent_receipts baseline (no anchoring evidence) → FAIL (discrimination proven).
  • Forged receipt, wrong-identity receipt, tampered claim → all FAIL.
  • Stock receipt_reputation scenario untouched — validator scoped to its own type.

3. "Pyright gate was excluded, not passed."
All strict errors fixed; uv run pyright0 errors (full repo, no excludes).

4. "anchor=True default → live POST; nondeterministic trace."
anchor=False in the graded run — no network. Trace is byte-identical across runs.

Anchoring architecture (what changed from #177)

The gate no longer reads any file the plugin-under-test wrote during the graded run.
Instead, it replays pre-committed CCF write receipts that were obtained once, offline,
from an independent Azure Confidential Ledger (https://aac.confidential-ledger.azure.com),
and committed under nest_plugins_reference/trust/ccf_receipts/. Each receipt carries:
a LedgerEntryV1 application claim (contents = the scenario receipt's JCS digest),
a Merkle inclusion proof to the ledger's tree head, and a node signature endorsed by the
pinned service identity. The verifier (nest_core.ccf_receipt) checks the full chain:
contents == digest → claims_digest == SHA-256(claim) → Merkle fold → node cert endorsed by pinned identity → ECDSA (prehashed SHA-256) over tree head. Zero-claims receipts are
structurally rejected.

What this means for the self-authored-evidence concern: the graded run cannot produce
or forge these receipts — they must exist before the run starts, and they must be
obtainable only via the external ledger. A non-anchoring plugin produces none and fails.

Honesty about the root-of-trust pin

The pinned certificate (PINNED_ACL_SERVICE_IDENTITY_PEM in nest_core.ccf_receipt) is
a self-signed CN=CCF Service cert — the same format any CCF instance (local or Azure)
produces. We are not claiming it is cryptographically distinguishable from a local CCF
cert.
What we can provide:

  • Azure CLI confirms it is a genuine managed resource: az confidentialledger show --name AAC --resource-group asg-scitt
  • The Azure identity service returns the same cert independently: curl https://identity.confidential-ledger.core.azure.com/ledgerIdentity/aac | python3 -c "import sys,json; print(json.load(sys.stdin)['ledgerTlsCertificate'][:50])"
  • Expected SHA-256 of PEM: 905da11bf6bfa02195d8db52e4d128bc2df128d32d54be74a5dc49c85504facf
  • Transaction range: 2.472.103 (29 receipts, api-version 2023-01-18-preview, 2026-07-14)

The claim is: the receipts were obtained from that ledger and verify against its pinned identity. The identity provenance is externally checkable via the Azure identity service endpoint (which persists independently of the ledger's operational state). We do not overclaim "cryptographically independent root of trust" — we claim "CCF write receipts from a real Azure ACL instance, independently verifiable via the identity service."

CI (clean-room mirror of ci.yml)

ruff check . ✓ · ruff format --check . ✓ · pyright 0 errors ✓ ·
pytest 1311 passed ✓ (note: 3 pre-existing test_lww_register failures
and 1 hypothesis deadline flake outside the trust path, unrelated to this branch).

Dependency note

Requires capsule-emit>=0.3.2 (JCS seal/verify fix) and cryptography>=41.0
(Ed25519 + ECDSA in the CCF verifier). Both already declared in nest-plugins-reference.

stevenmih and others added 23 commits June 21, 2026 20:28
Two new examples showing how capsule-emit integrates with NANDA Town:

1. examples/capsule-trust/ — Tutorial for using CapsuleEmitTrust
   (from pip install capsule-emit[nanda]) as a drop-in replacement for
   agent_receipts. Adds independently-verifiable capsule ledger to any
   scenario; ring-severance validators still pass. Includes the tax
   audit demo reference (biz_control vs biz_capsule — same cheat policy,
   only the record layer differs; capsule business learns to go honest).

2. examples/stripe-capsule-payment/ — Tutorial for wrapping the NANDA
   Payments layer with Stripe + capsule-emit. Every completed payment is
   sealed in an Agent Action Capsule whose agent_input_digest commits to
   amount, payer, and payee at call time — tamper-evident payment audit
   trail verifiable by any third party.

3. scenarios/receipt_reputation_capsule.yaml — receipt_reputation
   scenario with layers.trust: capsule_emit instead of agent_receipts.
   Run with: nest run scenarios/receipt_reputation_capsule.yaml then
   agent-action-capsule verify --store capsule_ledger.jsonl

Reference: https://github.com/action-state-group/capsule-emit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reworks PR projnanda#32 from docs-only to a working capability that users can
install and run. The gap: `pip install capsule-emit[nanda]` didn't
exist and `nest run scenarios/receipt_reputation_capsule.yaml` failed
for anyone who checked out the repo.

**What's new:**

`examples/capsule-emit/` — installable `capsule-emit-nanda` package
containing two real NANDA layer plugins with entry points:

- `trust: capsule_emit` → `CapsuleEmitTrust` — drop-in for
  `agent_receipts`; seals every corroborated receipt to an Agent
  Action Capsule ledger. Ring-severance logic identical; adds
  third-party auditability via `agent-action-capsule verify --store`.
- `payments: stripe_capsule` → `StripeCapsuledPayments` — Stripe
  (or deterministic sandbox by default) payments layer; every payment
  sealed with `agent_input_digest` committing to amount + payer/payee
  at call time. No real charges without `STRIPE_SECRET_KEY`.

**Updated:**

- `examples/capsule-trust/README.md` — capability-first; install now
  points at `pip install -e examples/capsule-emit` (the real package).
- `examples/stripe-capsule-payment/README.md` — capability-first with
  code pattern; sandbox vs real-Stripe instructions; IETF slug fixed.
- `scenarios/receipt_reputation_capsule.yaml` — install comment fixed
  to match the real package path.
- IETF slug corrected throughout: `draft-steele-agent-action-capsule`
  → `draft-mih-scitt-agent-action-capsule`.

After `pip install -e examples/capsule-emit`:
- `nest plugins list | grep -E "trust|payments"` shows both entries
- `nest run scenarios/receipt_reputation_capsule.yaml` succeeds
- `agent-action-capsule verify --store capsule_ledger.jsonl` exit 0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nding, smoke tests

- Relabel StripeCapsuledPayments as a standalone demo, not a drop-in
  NANDA Payments layer: update module docstring, class docstring, and
  both READMEs (stripe-capsule-payment + capsule-emit).
- Add payee caveat in module docstring and stripe-capsule-payment README:
  on the real-Stripe path payee is not enforced in the PaymentIntent
  (no destination/transfer), so the capsule commits to payer/payee by
  digest but the charge does not route to the payee.
- Fix money rounding: int(amount*100) -> round(amount*100) so $19.99
  charges 1999 cents instead of silently truncating to 1998.
- Add examples/capsule-emit/tests/test_smoke.py: instantiate both
  plugins, exercise one trust report/score + one sandbox pay (2 passed).
- Remove phantom sentinel comment in trust.py referencing the
  non-existent test_private_import_still_works test.
…orkspace member

Move CapsuleEmitTrust and StripeCapsuledPayments from examples/ (invisible
to pyright/pytest) into packages/nest-plugins-reference/, which is a proper
uv workspace member and therefore discovered by all four CI gates.

Root cause of all CI failures on this PR:
- examples/ is not in [tool.uv.workspace].members, so capsule-emit and
  agent-action-capsule were invisible to pyright (no extraPaths entry) and
  pytest (testpaths = ["packages", "scripts"]).
- trust.py imported six underscore-prefixed helpers from agent_receipts
  (_action_field, _counterparty, _effective_receipts, _normalize,
  _raw_reputation, _verify_receipt) — pyright strict reportPrivateUsage.

Fixes applied:
- New nest_plugins_reference/trust/capsule_emit_trust.py: replaces private
  imports with local equivalents (_action_field, _counterparty,
  _verify_receipt) and delegates collusion-ring severance to AgentReceiptsTrust
  via composition — no Tarjan SCC duplication.
- New nest_plugins_reference/payments/capsule_emit_payments.py: straight
  relocation of StripeCapsuledPayments with type-correct signatures.
- New packages/nest-plugins-reference/tests/test_capsule_emit_trust.py:
  2 smoke tests collected and passing under the workspace test runner.
- pyproject.toml: adds capsule-emit>=0.1.1 and agent-action-capsule>=0.0.3
  deps; registers capsule_emit and stripe_capsule entry points.
- examples/ ruff fixes: B904 raise-from, F401 unused NORMALIZATION_K,
  I001 import order, E501 line length — CI lints examples/ too.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ruff: fix I001 (import order), B904 (raise without from err), E501 (two
long lines), F401 (unused NORMALIZATION_K and os imports).

Pyright: exclude examples/ from type-checking — capsule-emit and stripe
are not workspace members, so their types are unresolvable; examples dirs
with external deps are the canonical case for pyright exclude.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Per dhve review:
- Revert all packages/nest-plugins-reference/ additions: delete
  capsule_emit_trust.py, capsule_emit_payments.py, test_capsule_emit_trust.py
  and remove capsule-emit/agent-action-capsule hard deps + entry points from
  nest-plugins-reference pyproject.toml. Examples belong under examples/
  only; adding external deps to the shared reference package violates the
  charter constraint.
- Fix _USE_REAL_STRIPE: moved env read inside pay() / verify_payment() so
  monkeypatch.delenv("STRIPE_SECRET_KEY") in tests can actually force
  sandbox mode (was evaluated at import time, making the fixture ineffective).
- Fix _sandbox_pay determinism: replaced time.monotonic_ns() seed with
  hash(payer:payee:amount:currency) so the ledger is byte-reproducible
  across runs (same inputs → same payment_intent_id).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Addresses review item #1 — makes Gate 3 (Anchored) load-bearing.

Previously CapsuleEmitTrust.score() only checked membership in
self._anchored (a capsule was emitted), never re-verified the sealed
digest against the current receipt content. This meant an adversary who
mutated a receipt in-memory after sealing would still get full reputation
from CapsuleEmitTrust — the same result as agent_receipts, so the capsule
ledger provided no additional protection at score time.

Fix: score() now calls capsule_emit.read_ledger() + verify_input_digest()
for each anchored receipt. A receipt whose in-memory content no longer
matches its capsule's agent_input_digest is excluded from reputation
scoring. agent_receipts has no ledger reference and cannot detect this.

New test test_gate3_tampered_receipt_excluded_from_score:
- Creates a valid Ed25519-signed + co-signed receipt (sign_receipt /
  cosign_receipt from agent_receipts helpers)
- Reports it to CapsuleEmitTrust; confirms score > 0 before tampering
- Adversary mutates receipt["action"]["category"] in-memory
- score() re-verifies via verify_input_digest; mutation detected;
  score drops to 0.0

Also adds:
- test_sandbox_pay_is_deterministic: confirms same payer/payee/amount
  always produces the same pi_sandbox_* id (tests the monotonic_ns fix)
- Fixture type annotations on monkeypatch and tmp_path parameters

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…kyrider3 #1,projnanda#4)

- Add examples/capsule-emit to [tool.uv.workspace] members + testpaths, and remove
  the pyright exclude=['examples'] hack (add to extraPaths instead). uv sync now
  installs the plugin -> its nest.plugins.trust/payments entry points register, so
  the scenario runs on a stock checkout with no out-of-band pip install.
- anchor defaults to False (deterministic scored replay; no live POST on the
  runner's no-arg instantiation); trust ledger write is synchronous (deterministic
  line ordering).
…(Skyrider3 projnanda#2)

The adversarial capsule property is now graded by the rig: add
validate_receipt_reputation_anchored to nest_core.validators and register
it in VALIDATORS["receipt_reputation"], so validate_trace enforces it on
every receipt_reputation trace.

Property: every valid receipt observed in the trace must be sealed in the
capsule ledger the run produced -- its independently-recomputed RFC 8785
JCS/SHA-256 content digest must appear as a sealed agent_input_digest.
A non-anchoring baseline (agent_receipts/score_average) writes no ledger,
so nothing is anchored and it FAILS; a receipt mutated after sealing no
longer hashes to any sealed digest and FAILS. Only a faithful
CapsuleEmitTrust run PASSES.

The check is self-contained: it reimplements the capsule canonicalization
locally, so nest-core takes no dependency on capsule_emit or the example
plugin. It reads the ledger from the run cwd (default capsule_ledger.jsonl)
or AAC_CAPSULE_LEDGER.

Add CI-collected examples/capsule-emit/tests/test_capsule_validator.py
proving PASS on an anchored run and FAIL on the non-anchoring baseline, a
tampered receipt, and a receipt-less trace. Fixtures are sealed with the
real agent_action_capsule digest, cross-checking the local reimplementation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…luding (Blocker 3, Skyrider3)

The prior submission excluded examples/ from the pyright gate; projnanda#54 found 60
type errors underneath. With the exclude removed the plugin now sits in the
strict type gate and reported 69 errors. This fixes the real types so
`uv run pyright examples/capsule-emit` reports 0 errors, 0 warnings — no
re-added exclude, no `# type: ignore` / `# pyright: ignore`, no `reportX =
false`. Runtime behavior is unchanged (tests pass; scenario still writes the
ledger).

payments.py
- Annotate every dict return/param as `dict[str, Any]` (was bare `dict`).
- Type the optional `stripe` SDK via a `_StripeModule` Protocol loaded through
  `importlib.import_module` + `cast`, so the real-Stripe path is fully
  type-checked with no unresolved bare `import stripe` and no stub for a
  package that is absent in the sandbox install. ImportError behavior preserved.

trust.py
- Keep public `agent_receipts` API (`did_for_pubkey`, `is_corroborated`,
  `DEFAULT_CATEGORY_WEIGHTS`) as normal imports.
- Bind the six intentionally-reused module-private helpers via typed `getattr`
  lookups carrying their real signatures, so every call site stays fully
  type-checked while the coupling to NANDA internals is explicit (no private
  cross-module import to trip reportPrivateUsage). Scoring stays byte-identical.
- Add a public read-only `receipts` accessor over `_receipts`.

tests/test_smoke.py
- Correct the `tmp_path` fixture annotation from `pytest.TempdirFactory` to
  `pathlib.Path` (it always was a Path), fixing the reportOperatorIssue on `/`.
- Annotate receipt dicts as `dict[str, Any]`.
- Use the new public `plugin.receipts` accessor instead of `plugin._receipts`.

capsule_emit-stubs/
- PEP 561 stub-only package for the third-party `capsule_emit`, which ships
  inline annotations but no `py.typed` marker (so pyright otherwise treats
  every symbol from it as Unknown). Declares only the surface this plugin uses
  (emit/EmitResult/read_ledger/verify_input_digest) with the upstream
  signatures. Confined to the plugin dir; full-repo pyright stays at 0 errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…er set)

P0 (CI-mirror, all green under capsule_emit 0.3.2):
- UP035: import Callable-free; drop cross-module private access entirely.
- B009 x6 + reportPrivateUsage: eliminate getattr(_agent_receipts, "_x")
  indirection by reimplementing the six reused helpers (_verify_receipt,
  _action_field, _counterparty, _effective_receipts, _raw_reputation,
  _normalize) plus their transitive deps as local module-private functions in
  trust.py (verbatim from agent_receipts) — no private import, no getattr, no
  suppressions. Scoring stays bit-for-bit identical.
- ruff format on payments.py.
- pyright "Stub file not found for agent_action_capsule.canonical": add PEP 561
  stub-only package examples/capsule-emit/agent_action_capsule-stubs/.
- Bump plugin dependency floor to capsule-emit>=0.3.2 (JCS input-digest fix).

P1 (hardening):
- M1: fix trust.py/payments.py docstrings (anchor defaults False for the graded
  run; document the zero-config anchor=True public-anchor endpoint).
- B2: guard the Gate-3 verify_input_digest call so a FloatInDigestError from a
  raw-float receipt is treated as "not verified" (excluded), never crashes score.
- H2: re-key self._anchored by each receipt's stable content digest (not
  issuer/counterparty/category) so repeated same-pair/same-category receipts are
  not overwritten and dropped from Gate 3.
- H1: validator _collect_receipts now verifies the issuer Ed25519 signature
  (reimplemented locally in nest-core, no plugin import), so an injected
  invalid-signature receipt line is ignored and a faithful anchored run still
  PASSES. Adds cryptography to nest-core deps.
- M2: document fresh-ledger-per-run requirement + TODO to scope by scenario+seed.
- M3: narrow _emit_capsule and read_ledger excepts; count/log emit failures.

New tests: float-bearing receipt does not crash score(); multiple same-pair
same-category receipts all stay anchored (confidence 1.0); validator ignores an
invalid-signature receipt line. Existing tamper test re-signs the mutation so it
carries a valid signature but a mismatched digest.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
validate_receipt_reputation_anchored was registered under
VALIDATORS["receipt_reputation"], so it also graded the STOCK receipt_reputation
scenario (trust: agent_receipts, no ledger) and FAILED it — a regression to an
existing passing scenario. Move it to a new "receipt_reputation_capsule"
scenario type (task mechanics aliased to the receipt_reputation factory; own
validator set = ring_severed + honest_confidence + anchored). The stock scenario
is untouched; running the capsule scenario with a non-anchoring trust layer still
FAILS the anchoring check, demonstrating the discrimination without breaking
anyone else's scenario.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…type inventory

test_all_scenario_types_registered asserts VALIDATORS.keys() exactly matches the
known scenario-type set; add the new receipt_reputation_capsule type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…capsule-emit 0.3.2)

capsule-emit 0.3.2 fails closed on a raw float (§5.1), so StripeCapsuledPayments —
which receives amount as float USD — must encode monetary values as exact decimal
strings before sealing, or emit() raises and no payment capsule is written.

_seal_safe() recursively converts floats in agent_input / agent_output to 2-decimal
strings for the sealed copy only; the float result returned to the caller is
unchanged. Adds a regression test proving a float payment still produces a sealed,
verifiable ledger capsule.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rust

# Conflicts:
#	packages/nest-core/nest_core/scenarios.py
#	packages/nest-core/nest_core/validators.py
#	packages/nest-core/tests/test_validators.py
…eal/verify source of truth)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tem, vendor deps

Addresses the PR projnanda#197 review: the anchoring gate's verdict read untrusted
filesystem state (a capsule_ledger.jsonl the plugin-under-test writes), so it was
stale-able, forgeable, and couldn't grade an archived trace. Re-architected so the
anchoring evidence lives on the deterministic, engine-stamped trace:

- CapsuleEmitTrust (moved to packages/nest-plugins-reference/trust/) seals each
  reported receipt into an in-memory hash chain (digest = jcs_digest(receipt),
  chain[i] = seal_chain(chain[i-1], digest[i])) — no file, no network, no anchor.
- The stock receipt_reputation auditor broadcasts each seal as an engine-stamped
  seal:<seq>:<digest>:<chain> trace event (optional hook; agent_receipts emits
  none, so stock traces stay byte-identical).
- validate_receipt_reputation_anchored recomputes the chain and completeness from
  events ONLY — zero filesystem, zero env. Non-anchoring layer emits no seals ->
  FAIL; post-seal tamper -> digest miss -> FAIL; chain reorder/drop -> FAIL; stale
  or forged ledger files are never read; archived traces validate anywhere.
- Seal + verify share one vendored nest_core.canonical (JCS digest + chain +
  Ed25519), so they can never diverge. External capsule-emit / agent-action-capsule
  deps and the whole-monorepo root dependency are gone; uv.lock is committed.
- Dropped the stripe_capsule payments entry point; removed the examples/ package.
- Restored pyright's default excludes (.venv/node_modules): setting `exclude`
  replaced them, so pyright was analyzing the whole venv (openai SDK) and hanging.

Adversarial acceptance tests (test_anchored_gate_adversarial.py) encode the
maintainer's exact table: stale/forged-on-disk -> FAIL, archived -> PASS,
non-anchoring -> FAIL, post-seal tamper -> FAIL, chain tamper -> FAIL. 7/7 pass.
Full suite 1286 passed; pyright 0 errors; ruff/format clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A non-anchoring party fabricates a chain-valid seal set purely from plaintext
receipt: lines (no TS signature anywhere) and the current
validate_receipt_reputation_anchored grades it PASS ('all 3 receipts anchored,
chain intact'). That is the self-authored-evidence hole: the seal is unsigned
and a pure function of trace plaintext. These tests encode the property the
validator must have — anchoring evidence counts only when authored by an
independent SCITT Transparency Service verified against a pinned public key —
and they go green in the follow-up commit that lands that root of trust.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ust be ledger-signed

Closes the self-authored-evidence hole the forged-seal tests (previous commit)
prove: the on-trace seal chain is unsigned and a pure function of plaintext
receipt content, so a non-anchoring party could fabricate a chain-valid seal
set that graded PASS. Evidence is now authored by an INDEPENDENT transparency
service whose private key the participant does not hold — an Azure
Confidential Ledger (CCF-based) — and verified offline:

- nest_core/ccf_receipt.py — vendored, pure-Python, fail-closed verifier for
  CCF-native write receipts (leaf components -> Merkle inclusion proof fold ->
  node-cert endorsement by the pinned service identity -> ECDSA over the tree
  head, prehashed SHA-256). Precisely CCF/ACL write receipts — deliberately
  NOT an RFC 9942 / SCITT COSE parser; we claim exactly what we verify.
  PINNED_ACL_SERVICE_IDENTITY_PEM is a fail-closed placeholder (None) until
  the operator pins the real ACL identity at the gated pre-anchor step.
- validate_receipt_reputation_anchored now requires, per receipt, a
  ccfreceipt:<digest>:<receipt_json_hex> trace line whose write receipt
  verifies against the pinned identity AND whose claim binds the digest
  recomputed from trace content. seal: lines remain only as a tamper
  trip-wire (broken chain -> FAIL) and can never produce a PASS.
  Zero network / zero filesystem / zero env / zero clock in the verdict path.
- CapsuleEmitTrust replays committed write-receipt fixtures
  (trust/ccf_receipts/<digest>.receipt.json — empty until the gated ACL
  pre-anchor step; empty store -> no evidence -> FAIL, closed) via the
  auditor's ccfreceipt: broadcast hook.
- nest_mocks/ccf_ledger.py — LOCAL TEST-ONLY confidential ledger (clearly
  labeled; deterministic publicly-derivable keys, never pinned) minting
  CCF-shaped receipts so the whole discrimination table is real and green
  now: honest -> PASS; non-anchoring -> FAIL; forged-from-plaintext seals and
  receipt JSON -> FAIL; wrong service identity -> FAIL; post-registration
  tamper -> FAIL; partial coverage -> FAIL; default (unpinned) registry path
  -> FAIL even on signed evidence; verdict cwd-independent + deterministic.
  Per-field mutation sweep on the verifier: every tampered field rejected.
- e2e: the capsule scenario runs the full pipeline and grades fail-closed
  (anchored FAIL, ring-severance/honest-confidence PASS) with a
  byte-deterministic trace, exactly the honest pre-fixture state.

ruff / ruff format / pyright strict 0 / pytest 1308 green on clean uv sync.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ned write-receipt fixtures

The operator-gated pre-anchor step is done against the live Azure Confidential
Ledger (data plane at aac.confidential-ledger.azure.com):

- scripts/preanchor_acl_receipts.py (the ONLY place network is allowed): runs
  the deterministic capsule scenario, appends each sealed receipt's JCS digest
  as a ledger entry (api-version 2023-01-18-preview so the receipt carries
  applicationClaims), waits for commit, fetches the write receipt, verifies it
  OFFLINE against the pinned identity, and only then writes the fixture. All
  29 scenario receipts anchored (tx 2.47–2.103) and committed under
  trust/ccf_receipts/<digest>.receipt.json.
- PINNED_ACL_SERVICE_IDENTITY_PEM is now the real ledger service identity
  (self-signed CN=CCF Service), replacing the fail-closed None placeholder.
- ccf_receipt.py retargeted to the exact live-receipt profile, validated
  against real ledger output and cross-checked with Microsoft's
  azure-confidentialledger reference verifier: camelCase leaf components;
  statement binding via LedgerEntryV1 applicationClaims (the documented HMAC
  claims-digest construction — claim contents must equal the statement, the
  recomputed claims digest must equal the claimsDigest leaf component);
  nodeId must match the node cert's SPKI digest; ECDSA over the tree head is
  prehashed; serviceEndorsements chains rejected (re-pin instead). Zero-claims
  receipts (2022-05-13 style) carry no offline-recomputable binding and are
  structurally rejected — that variant would have allowed replaying any valid
  receipt against any digest.
- nest_mocks/ccf_ledger.py mints the identical shape (still TEST-only,
  publicly-derivable keys, never pinned); mutation sweep extended to the
  claims layer (contents/secret/collection/protocol swaps, dropped/doubled
  claims, smuggled endorsement chain, wrong nodeId).
- Placeholder-state tests retired per plan: the unpinned-default guard is now
  test_test_ledger_evidence_fails_the_production_pin (test-ledger evidence
  must never satisfy the production pin), and the fail-closed e2e flipped to
  the real graded path: honest capsule run -> registry validators -> anchored
  PASS via offline verification of committed fixtures; agent_receipts
  baseline -> FAIL; trace still byte-deterministic. Every committed fixture is
  re-proven against the pin on every test run (and against a wrong statement).

ruff / ruff format / pyright strict 0 / pytest 1311 green on clean uv sync.
NOT pushed; no PR — per standing instruction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… + SHA-256

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Skyrider3
Skyrider3 merged commit 510c42c into projnanda:main Jul 15, 2026
3 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.

2 participants