Trust layer: verifiable capsule receipts with CCF write-receipt anchoring - #200
Merged
Skyrider3 merged 23 commits intoJul 15, 2026
Merged
Conversation
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).
…s+registers it (Skyrider3 #1)
…(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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Trust layer: verifiable capsule receipts with CCF write-receipt anchoring (
capsule-emit-nanda)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-nandais a declared root dependency; plainuv syncinstalls and registersit.
uv run nest run scenarios/receipt_reputation_capsule.yamlruns end-to-end.2. "The adversarial validator never runs."
validate_receipt_reputation_anchoredis registered inVALIDATORSunder a newreceipt_reputation_capsulescenario type. Each signature-valid receipt observed on thetrace must have a matching pre-committed CCF write receipt that verifies offline against the
pinned service identity. Proven:
agent_receiptsbaseline (no anchoring evidence) → FAIL (discrimination proven).receipt_reputationscenario untouched — validator scoped to its own type.3. "Pyright gate was excluded, not passed."
All strict errors fixed;
uv run pyright→ 0 errors (full repo, no excludes).4. "
anchor=Truedefault → live POST; nondeterministic trace."anchor=Falsein 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
LedgerEntryV1application 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 arestructurally 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_PEMinnest_core.ccf_receipt) isa self-signed
CN=CCF Servicecert — 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:
az confidentialledger show --name AAC --resource-group asg-scittcurl https://identity.confidential-ledger.core.azure.com/ledgerIdentity/aac | python3 -c "import sys,json; print(json.load(sys.stdin)['ledgerTlsCertificate'][:50])"905da11bf6bfa02195d8db52e4d128bc2df128d32d54be74a5dc49c85504facf2.47–2.103(29 receipts, api-version2023-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 .✓ ·pyright0 errors ✓ ·pytest1311 passed ✓ (note: 3 pre-existingtest_lww_registerfailuresand 1 hypothesis deadline flake outside the trust path, unrelated to this branch).
Dependency note
Requires
capsule-emit>=0.3.2(JCS seal/verify fix) andcryptography>=41.0(Ed25519 + ECDSA in the CCF verifier). Both already declared in
nest-plugins-reference.