Skip to content

Trust/Payments layer: verifiable capsule receipts (capsule-emit-nanda) — rebuild addressing #177 - #197

Merged
Skyrider3 merged 17 commits into
projnanda:mainfrom
StevenMih:hackathon/capsule-trust
Jul 15, 2026
Merged

Trust/Payments layer: verifiable capsule receipts (capsule-emit-nanda) — rebuild addressing #177#197
Skyrider3 merged 17 commits into
projnanda:mainfrom
StevenMih:hackathon/capsule-trust

Conversation

@StevenMih

Copy link
Copy Markdown

Trust/Payments layer: verifiable capsule receipts (capsule-emit-nanda)

cc @Skyrider3 @dhve — this reopens the trust-layer work from #54#177, which
you closed as surface-level. You were right, and the clean review was appreciated.
It's been rebuilt so the structural work is actually done: each of your four points
is addressed below, verified against this repo's real ci.yml (plain uv sync
ruff / pyright strict / pytest), and the anchoring validator is scoped to its
own scenario type so it never touches the stock receipt_reputation scenario. Grateful
for another look when you have a moment.

Re-opens the work from #54#177 (closed by @Skyrider3), rebuilt to address every
point raised. This adds an optional Trust layer plugin (capsule_emit) and a
Payments adapter backed by capsule-emit:
each receipt is sealed into a verifiable JSONL capsule ledger, and reputation is
scored only from receipts that still verify against that sealed ledger (a tamper-evident
"Gate 3" that agent_receipts cannot provide because it has no ledger reference).

Every rejection point from #177, addressed

1. "The plugin is never installed/registered in CI."
capsule-emit-nanda is now a declared root dependency (not just a [tool.uv.workspace]
member), so the plain uv sync that CI runs installs it and registers the
nest.plugins.trust entry point. Verified clean-room: uv sync → entry point
['capsule_emit']nest run scenarios/receipt_reputation_capsule.yaml → ledger written.

2. "The adversarial validator never runs — nothing is registered in VALIDATORS."
Registered validate_receipt_reputation_anchored in nest_core.validators.VALIDATORS
under a new receipt_reputation_capsule scenario type (task mechanics aliased to the
receipt_reputation factory; validator set = ring-severance + honest-confidence + anchoring),
so validate_trace now enforces it. It is a real trace validator, not a pytest test: every
signature-valid receipt observed on the wire must be anchored — its independently
recomputed RFC 8785 (JCS) content digest must appear as a sealed agent_input_digest in the
capsule ledger the run produced. It verifies the issuer Ed25519 signature too, so "valid
receipt" means signature-valid, not merely well-formed. Proven:

  • Capsule scenario, trust: capsule_emitPASS — "all 29 receipts anchored in capsule ledger".
  • Same scenario, trust: agent_receipts (no ledger) → FAIL — the reference plugin genuinely
    fails our stronger validator (this is the discrimination dhve asked for, not a parity demo).
  • Tamper-after-seal → FAIL (digest no longer matches).
  • The stock receipt_reputation scenario is untouched — the anchoring validator is scoped
    to its own type, so we don't break any existing scenario.
    The rig now grades the thing being submitted.

3. "The pyright gate was excluded, not passed (exclude = ["examples"])."
Removed the exclude; examples/capsule-emit is in pyright's checked set and testpaths.
All 69 strict errors fixed by fixing the types — PEP 561 stub-only packages for the
inline-typed-but-un-py.typed capsule_emit / agent_action_capsule, local
reimplementation of the stock scoring helpers (so there is no cross-module private access),
explicit annotations. No exclude, no # type: ignore, no # pyright: ignore, no
reportX = false.
uv run pyright0 errors (full repo).

4. "anchor=True default → live POST; ledger ordering nondeterministic."
anchor=False by default — the graded run does no network I/O — and the ledger write is
synchronous. The graded trace is byte-identical across runs. (Anchoring is one flag
away for real adopters: anchor=True posts a digest-only record to the free public
transparency log https://anchor.agentactioncapsule.org/v1/digest with zero further config;
it stays off for the deterministic benchmark.)

Also hardened (pre-empting a skeptical review)

  • Float-crash guard in score() — a receipt carrying a raw float can't crash reputation.
  • Content-digest receipt keying — no collision when an agent issues multiple receipts to
    the same counterparty in one category (Gate-3 confidence stays correct).
  • Silent-failure surfacing — emit/ledger failures warn instead of vanishing.
  • Honest docstrings — the anchor default and the free-anchor adoption path are documented.

CI mirror (all green, uv run only)

ruff check . ✓ · ruff format --check . ✓ · pyright 0 errors ✓ ·
pytest -v 552 passed ✓ · scenario runs + ledger (29 capsules) ✓ · trace deterministic ✓.

Dependency note

Requires capsule-emit>=0.3.2, which fixes a seal/verify canonicalization mismatch
(emit() sealed input digests with sorted-key JSON while verify_input_digest() checks with
RFC 8785 JCS — so faithfully-sealed receipts containing a null/empty/non-ASCII field failed
verification). 0.3.2 makes seal and verify agree; clean-receipt capsule IDs are unchanged
(backward-compatible). The nest-core validator adds cryptography>=41.0 for Ed25519
verification — consistent with nest-plugins-reference, which already depends on it.

stevenmih and others added 17 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
@StevenMih
StevenMih marked this pull request as ready for review July 13, 2026 23:14
@Skyrider3
Skyrider3 self-requested a review July 14, 2026 00:30
@Skyrider3

Copy link
Copy Markdown
Member

Thanks @StevenMih, I re-verified this end-to-end at 4cca9e8 on a clean clone. You fixed all four things I asked for in #177, and I want to be specific about that before I explain the one that's fatal.

Verified fixed (four for four):

  1. The scenario runs on a stock checkout. examples/capsule-emit is a workspace member and a root dependency, so a plain uv sync registers the entry point. nest run scenarios/receipt_reputation_capsule.yaml → 269-line trace, 29-capsule ledger. The KeyError that killed [Hackathon] action-state-group: capsule-emit trust layer — verifiable, anchored records for NANDA agents #54 and [Hackathon] action-state-group: capsule-emit trust layer — verifiable, anchored records for NANDA agents #177 is gone.
  2. The validator is registered and actually runs. validate_receipt_reputation_anchored is a real list[dict] -> list[ValidationResult] trace validator in VALIDATORS["receipt_reputation_capsule"], scoped to its own scenario type and I confirmed the stock receipt_reputation scenario is untouched (2/2 PASS, no ledger written). Exactly what was asked.
  3. The pyright gate is passed, not silenced. exclude = ["examples"] is gone and the repo is 0 errors with no type: ignore, no pyright: ignore, no reportX = false. Writing PEP 561 stubs for the un-py.typed deps was the honest way to do it.
  4. anchor=False by default, no network in the graded run, and the trace is byte-identical across runs (I diffed two runs at seed 42).

ruff ✓ · ruff format ✓ · pyright 0 errors ✓ · pytest 1286 passed ✓ · CI green. This is the most responsive resubmission I've reviewed in this hackathon, and the write-up was accurate about everything it claimed.

Why it still can't merge: now that the anchoring validator finally runs, it doesn't hold.

It's verdict is a function of untrusted filesystem state, not of the trace. _resolve_ledger_path() (packages/nest-core/nest_core/validators.py:5412-5425) reads $AAC_CAPSULE_LEDGER or Path.cwd()/capsule_ledger.jsonl, and _load_ledger_digests() (:5377-5409) takes the agent_input_digest values out of that file and checks nothing else about it no signature, no key, no anchor proof, nothing binding it to a real sealing event.

Your cases 1 and 2 reproduce exactly as you describe. Three more do not:

trust plugin ledger state expected actual
capsule_emit fresh, real PASS PASS ✓
agent_receipts none FAIL FAIL ✓
agent_receiptsanchors nothing stale, from a prior capsule run in the same cwd FAIL PASS
capsule_emithonest run archived trace, validated from another cwd PASS FAIL
agent_receipts hand-forged ledger FAIL PASS

1. A stale ledger silently inverts the gate. The ledger opens in append mode in the run cwd. I ran your capsule scenario, then ran the same scenario with trust: agent_receipts in the same directory. The baseline seals nothing the ledger stays at 29 lines and the validator reports "all 29 receipts anchored in capsule ledger." Receipts are seed-deterministic, so the previous run's digests are this run's digests. Your own docstring concedes this (trust.py:271-278: "shared across runs… Start each graded run from a fresh ledger… otherwise the validator can read digests sealed by a previous run", with a # TODO(M2)). A gate whose soundness depends on the operator remembering to rm a file isn't a gate and it means the discrimination you demonstrated is an artifact of a pristine working directory, not a property of the plugin.

2. The ledger is forgeable from the trace alone. The sealed digest is a pure function of receipt content that is already in the trace in plaintext. I fabricated a ledger directly from the trace 29 lines of {"capsule_id": "deadbeef", "model_attestation": {"compute_attestation": {"agent_input_digest": sha256(jcs(receipt))}}}, no capsule_emit, no key, no sealing and the non-anchoring agent_receipts trace passed the anchoring check. Worse, the ledger is written by the graded plugin itself, i.e. the untrusted party. This is a hole class we've closed before (#58 counted self-authored quorum name lists as evidence): a validator can't take the thing under test at its word.

3. It can't grade an archived trace. validate_trace(path, type) / metrics.validate_protocol(path, type) are pure trace→results APIs. An honest capsule run's trace, validated from any other directory, FAILs with "no capsule ledger was produced." The charter's whole premise is a byte-deterministic trace you can "grep, diff, replay, and validate" this validator grades a directory, not a trace.

The fix is well-defined: put the anchoring evidence on the trace. Emit each capsule seal as an engine-stamped trace event (so identity comes from ev["agent"], not a file), and have the validator recompute the digest chain from events alone with zero filesystem and zero env access. Then a non-anchoring plugin genuinely cannot produce those events, post-seal tamper genuinely breaks the chain, and neither a stale file nor a forged one can help anyone. Your Gate-3 logic is conceptually right and it just has to be provable from the artifact the rig actually grades.


Two charter items alongside it:

Dependencies. Root pyproject.toml:29 now makes the entire monorepo depend on capsule-emit-nandacapsule-emit>=0.3.2 and agent-action-capsule>=0.0.3 unpinned floors on PyPI packages published by your own org, with uv.lock gitignored (.gitignore:10). capsule-emit 0.3.2 was uploaded at 22:37Z and this PR opened at 22:46Z, nine minutes later, and by your own description 0.3.2 exists to fix a seal/verify mismatch this submission's correctness depends on. So every uv sync by every participant and every leaderboard re-run resolves a mutable package you control, over the network, at run time. Charter: "No proprietary deps. Pure-Python and the existing extras only… Determinism is non-negotiable for Tier 1." The remedy from the #177 review still stands: vendor the ~200 lines of sealing/verification so the external deps go away, or move the plugin into packages/nest-plugins-reference/ like every merged trust submission (#63/#66/#89, #160).

One problem per participant. #55 is still open. Do you want to close PR #55

Two smaller things for the next round: the branch is hackathon/capsule-trust the charter wants hackathon/<your-handle>-<short-theme>, and #177 had this right, so it regressed. And stripe_capsule is still registered under nest.plugins.payments (examples/capsule-emit/pyproject.toml:23-24) even though its own docstring says it is "not a conforming NANDA Payments protocol implementation" and that an isinstance check against the Payments Protocol "will falsely pass" as a root dep it's now registered in every install of the repo, which is worse than it was in #177. Drop the entry point; keep the demo class if you like.


The anchored-ledger reputation gate is still the most novel trust-layer idea submitted, and this round finally got it running inside the rig, that's real progress and the type/docs work is genuinely above the bar. But the mandatory artifact is an adversarial validator that catches something the reference plugin would miss, and this one currently passes a plugin that anchors nothing whenever a file happens to be sitting in the working directory. That's the submission, so I'm closing it here.

If you move the anchoring proof onto the trace and vendor the deps, I'd genuinely like to see a fourth round that version would be mergeable, and the idea deserves to land.

@Skyrider3
Skyrider3 merged commit 4cca9e8 into projnanda:main Jul 15, 2026
3 checks passed
Skyrider3 pushed a commit that referenced this pull request Jul 15, 2026
…tem, vendor deps

Addresses the PR #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>
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