sutra/NANDA evidence← back to sutra
Project NANDA · Best Prava Adapter for the NANDA Town

NANDA proof you can run.

Live discovery endpoints, a registered nest.plugins.payments adapter, and reproducible output from the same purchase on both payment plugins. The discovery documents make sutra reachable; prava_mandates is the adapter being judged.

§1 · Discovery, live

Four endpoints, fetched by your browser, right now.

Not a screenshot, not a cached badge — this component calls each URL below the moment this page finishes loading, from wherever you are reading it. The thread fills as real responses land, while the payment panel below is explicitly reproducible simulator proof—not a claim that a real card was charged.

agent-card.json
agents/sutra.json
agent-facts.json
skill.md

fetching, live, from your browser…

agent-card.json
A2A agent card
check it yourself ↗
fetching…
agents/sutra.json
NANDA agent listing
check it yourself ↗
fetching…
agent-facts.json
AgentFacts document
check it yourself ↗
fetching…
skill.md
REST API, in prose
check it yourself ↗
fetching…
§2 · The adapter

What prava_mandates actually is.

Native discovery. prava_mandates is registered beside prepaid_credits under nest.plugins.payments in pyproject.toml.

Real payment semantics. pay() creates a one-time Prava mandate, locked to one merchant and capped at one amount. See plugin.py.

No pooled agent balance. One agent cannot credit another; funds move from each human’s mandate to the merchant. The conservation test and transcript below prove that boundary.

cd nanda-town-prava && nest plugins list payments
payments:
  - prava_mandates
  - prepaid_credits
cd nanda-town-prava && pytest -q
........................................................................ [ 61%]
.................s............................                           [100%]
117 passed, 1 skipped in 0.37s
§3 · The contrast — the prize argument

The same $186.00 group purchase, on both plugins.

Four named town agents — Soham, Arsh, Dev, Maya — attempt one real pay_group() purchase: a policy of quorum(2 of 3), Dev declining mid-flight, Maya’s backstop mandate absorbing the shortfall. Then the identical purchase is attempted against Nanda Town’s bundled prepaid_credits. Below is the unedited stdout of both runs — read it, don’t take the tiles’ word for it.

$0.00ever pooled inside prava_mandates, this runno_pooled_funds: True
$186.00reached the merchant, despite Dev declining mid-flight18600 == 18600
$186.00pooled inside one agent’s own balance instead — by prepaid_credits, before any merchant is paidSoham’s balance: 0 → 18600
AttributeErrorwhat prepaid_credits raises when asked to run a group purchase at allno pay_group() method exists
cd nanda-town-prava && python scripts/town_scene.py
nanda-town-prava/scripts/town_scene.py — simulated, zero network, zero keys
mode: simulated

=== ACT 0: plugin discovery — a real nest.plugins.payments entry point?
  nest.plugins.payments entry points on this interpreter: {
  "prava_mandates": "nanda_town_prava.plugin:PravaMandates"
}
  [PASS] prava_mandates is a real entry point, not a builtin fallback — resolves to nanda_town_prava.plugin:PravaMandates — nanda_town_prava.plugin:PravaMandates
  PluginRegistry resolves these names for layer='payments': ['prava_mandates', 'prepaid_credits']
  [PASS] the bundled prepaid_credits still resolves too — this plugin adds an option, it does not remove one
  [PASS] registry.resolve('payments', 'prava_mandates') is this package's class

=== ACT 1: the town ==================================================
  Four named agents, one purchase: tickets at velvet-tickets, $186.00.
  Soham organizes. Arsh and Dev are in. Maya isn't going, but she'll
  stand behind the card if the group comes up short.

=== ACT 2: mint the mandates =========================================
  group_id=g_000001  policy=quorum(2 of 3)  cart=$186.00
  each principal's own mandate, capped at their own number:
  Soham    role=payer     status=awaiting_approval cap=6510 charged=0
  Arsh     role=payer     status=awaiting_approval cap=6510 charged=0
  Dev      role=payer     status=awaiting_approval cap=6510 charged=0
  Maya     role=backstop  status=awaiting_approval cap=0 backstop_cap=6000 charged=0
  [PASS] four mandate sessions minted, none approved yet — collecting
  [PASS] every principal's cap is their own — nobody's cap depends on anybody else's

=== ACT 3: the passkey ceremony ======================================
  -> Maya arms her backstop mandate — standing by, not charged yet.
  -> Soham taps his passkey.
  -> Dev has second thoughts mid-flight and DECLINES.
  [PASS] the group is still open after Dev's decline (quorum(2) is still reachable) — collecting
  -> Arsh taps her passkey — quorum(2) is met. The engine decides now.

=== ACT 4: resolution: backstop absorbs, group commits ===============
  Why a backstop and not a requote: _simulator.py implements backstop
  shortfall absorption but not GMP/1 requote rounds (README, Limitations #9).
  A real requote cascade is proven separately, over HTTP, in
  scripts/live_check.py::check_requote and docs/NANDA.md §2.
  Soham    role=payer     status=charged           cap=6510 charged=6510
  Arsh     role=payer     status=charged           cap=6510 charged=6510
  Dev      role=payer     status=declined          cap=6510 charged=0
  Maya     role=backstop  status=charged           cap=0 backstop_cap=6000 charged=5580
  decision: 'policy satisfied; 2 principal(s) charged on their own cards'
  verify_payment -> PaymentStatus.CONFIRMED
  [PASS] group committed despite a mid-flight decline — committed
  [PASS] Dev was never charged
  [PASS] Soham and Arsh were each capped at the number they consented to, not the larger redistributed share — Soham charged=6510 cap=6510
  Maya's backstop_cap was 6000; the shortfall actually drawn from her card was 5580.
  [PASS] Maya's backstop card absorbed exactly the shortfall the other two couldn't cover
  [PASS] the merchant received the full cart — 18600 == 18600
  [PASS] verify_payment is CONFIRMED

  signed-shaped receipt (simulated engine: hash-chained, not Ed25519-signed —
  a real signature from the deployed engine is in docs/NANDA.md §2):
    settlement_disclosure: SIMULATED. No card was charged and no money moved. This receipt was produced by the in-process GMP/1 simulator so the plugin can run with no network and no keys. Amounts shown as charged are what the card network would have been asked to authorize.
    chain_head: 8b2e81e1a85913dde913ccd286405b3e929eb64e4c9dcf15ff5a3312219b426e
      Soham    charged=6510   outcome=charged   hash=b885a230a204… chained-from-prev=OK
      Arsh     charged=6510   outcome=charged   hash=d8e6882f3adf… chained-from-prev=OK
      Dev      charged=0      outcome=declined  hash=09f09843d831… chained-from-prev=OK
      Maya     charged=5580   outcome=charged   hash=8b2e81e1a859… chained-from-prev=OK
  [PASS] the receipt chain is unbroken from the genesis hash to chain_head

  conservation_report():
    authorization_conserved: True
    no_pooled_funds: True
    settlement_conserved: True
  [PASS] authorization_conserved — no unit of authorized headroom invented or lost
  [PASS] no_pooled_funds — no agent's headroom ever exceeds what it started with
  [PASS] settlement_conserved — every captured unit lands at exactly one merchant

=== ACT 5: for contrast: the same decline, no backstop to catch it ===
  -> all_of this time — nobody backstops. Soham and Arsh approve. Dev declines.
  decision: 'policy became unsatisfiable — no card was charged'
  verify_payment -> PaymentStatus.REFUNDED
  [PASS] the group cancels — not partial, not committed — aborted
  [PASS] nobody was ever charged, including the two who already approved — 0
  [PASS] verify_payment is REFUNDED
  In this simulator case the policy fails before commit, so every simulated charge remains zero.
  That is the pre-commit cancellation path shown, not a claim of atomic real-card settlement.

=== ACT 6: the structural property: an agent cannot pay an agent =====
  Arsh's headroom before: 1000
  -> Soham calls payments.pay(AgentId('Arsh'), Money(amount=500), ref) — no error, no refusal exception. Watch what actually happens to Arsh.
  Arsh's headroom after:  1000
  where the 500 actually went: conservation_report()['merchants'] = {'Arsh': 500}
  [PASS] Arsh's own headroom never moved — she was not paid — 1000 == 1000
  [PASS] the 500 was captured against a merchant record named 'Arsh', not credited to agent Arsh's wallet
  [PASS] no_pooled_funds holds — Arsh was not credited by Soham's payment
  There is no rail for agent-to-agent credit on this plugin. Money leaves a card and
  lands at a merchant; it does not land in another agent's simulator balance.

=== ACT 7: the same purchase against the bundled prepaid_credits =====
  -> Can prepaid_credits even express pay_group()?
  hasattr(PrepaidCredits(...), 'pay_group') = False
  organizer.pay_group() -> AttributeError: 'PrepaidCredits' object has no attribute 'pay_group'
  [PASS] prepaid_credits cannot express a group purchase — no such method exists
  -> The only tool it gives you is repeated pay(): each principal pays the
  -> organizer directly, and the organizer forwards the pool to the merchant.
  Soham's own balance before anyone pays in: 0
  Soham's own balance after three principals pay him:  18600
  [PASS] Soham — a coordinator, not a merchant — was credited by three other agents' payments — 18600 == 18600
  Soham then forwards the pool: pay(velvet-tickets, 18600) — no cap, no consent trail per principal, just a balance transfer he was fully able to make alone.

  side by side, the same $186.00 group purchase:
  can express pay_group() at all                          :
      prepaid_credits : no — AttributeError
      prava_mandates  : yes — pay_group()
  who holds funds before the merchant is paid             :
      prepaid_credits : the coordinator's own simulator balance (18600 credits)
      prava_mandates  : nobody — cards only
  an agent credited by another agent's payment            :
      prepaid_credits : yes — Soham, +18600
      prava_mandates  : never
  could Soham unilaterally spend the pooled 18600 himself :
      prepaid_credits : yes, trivially
      prava_mandates  : no rail
  per-principal consent enforced by                       :
      prepaid_credits : nothing — it's one balance transfer
      prava_mandates  : a mandate cap per principal, enforced at the card network

==================================================================
all checks passed
cd nanda-town-prava && python scripts/baseline_diff.py
the same contrast at marketplace scale — 100 agents, byte-identical traces

=== the only difference between the two scenarios =================
  - # SPDX-License-Identifier: Apache-2.0
  - # Marketplace scenario: buyers and sellers exchange goods.
  - description: "50 buyers and 50 sellers trading products with varying prices."
  -   payments: prepaid_credits
  -   trace: ./traces/marketplace.jsonl
  + description: "50 buyers and 50 sellers, paying on real card mandates instead of a pooled ledger."
  +   payments: prava_mandates # <- the only change from the baseline
  +   trace: ./traces/prava.jsonl

=== prepaid_credits — the built-in pooled ledger ==================
{
  "plugin": "PrepaidCredits",
  "agents": 100,
  "starting_total_in_simulator": 100000,
  "final_total_in_simulator": 100000,
  "agents_ending_richer_than_they_started": 49,
  "value_credited_to_agents": 16675,
  "value_debited_from_agents": 16675,
  "receipts": 266,
  "value_that_left_a_card": 0,
  "value_that_reached_a_merchant": 0,
  "merchants_paid": 0
}

=== prava_mandates — real card mandates ===========================
{
  "plugin": "PravaMandates",
  "agents": 100,
  "starting_total_in_simulator": 100000,
  "final_total_in_simulator": 83325,
  "agents_ending_richer_than_they_started": 0,
  "value_credited_to_agents": 0,
  "value_debited_from_agents": 16675,
  "receipts": 266,
  "value_that_left_a_card": 16675,
  "value_that_reached_a_merchant": 16675,
  "merchants_paid": 49,
  "authorization_still_on_hold": 0
}

  conservation_report():
  {
    "reserved": 17629,
    "captured": 16675,
    "released": 954,
    "outstanding": 0,
    "merchant_credited": 16675,
    "authorization_conserved": true,
    "no_pooled_funds": true,
    "settlement_conserved": true,
    "headroom_consistent": true,
    "headroom_drift": {},
    "agents_credited_by_others": [],
    "merchants": "<49 merchants, 16675 total>"
  }
  largest merchant credits: [('seller-9', 620), ('seller-22', 583), ('seller-15', 476)]

=== the traces ====================================================
  traces\marketplace.jsonl: 513030 bytes, 2200 events
  traces\prava.jsonl: 513030 bytes, 2200 events
  sha256 baseline: dd6cdb7a631e153a3ed9260ddb5fc6a0178f95d76960788f20ac839fcf000edf
  sha256 prava   : dd6cdb7a631e153a3ed9260ddb5fc6a0178f95d76960788f20ac839fcf000edf
  byte-identical : True

=== upstream validators, over both traces =========================
  marketplace_no_double_sell
    prepaid_credits: PASS — checked 266 sales
    prava_mandates : PASS — checked 266 sales
  marketplace_all_responded
    prepaid_credits: PASS — all 500 requests answered
    prava_mandates : PASS — all 500 requests answered
  marketplace_price_agreement
    prepaid_credits: PASS —
    prava_mandates : PASS —

  identical results: True
  all pass         : True

=== what actually changed =========================================
                                                prepaid_credits   prava_mandates
  value moved between agents in the simulator             16675                0
  agents ending richer than they started                     49                0
  value debited from agents                               16675            16675
  credits still pooled inside the simulator              100000            83325
  value that left a real card                                 0            16675
  value that reached a merchant outside                       0            16675
  distinct merchants paid                                     0               49
  payments executed                                         266              266

=== assertions ====================================================
  [PASS] both traces are byte-identical
  [PASS] both traces pass the same upstream validators identically
  [PASS] prepaid_credits conserves value INSIDE the simulator — 100000 == 100000
  [PASS] prepaid_credits moved value between agents — 16675
  [PASS] prava_mandates credited NO agent from another agent's payment — 0
  [PASS] prava_mandates moved every unit out of the simulator — 16675 == 16675
  [PASS] prepaid_credits moved nothing to any merchant
  [PASS] prava_mandates leaves no authorization on hold
  [PASS] prava_mandates: authorization_conserved
  [PASS] prava_mandates: no_pooled_funds
  [PASS] prava_mandates: settlement_conserved
  [PASS] prava_mandates: headroom_consistent

all assertions hold
§4 · Reproduce it

One command. Same repo, your machine.

Requires Python ≥3.12 (nanda-town-prava/pyproject.toml). No account, no API key, no network call — simulated mode is an in-process GMP/1 engine that emits the same JSON shapes as the deployed one.

cd nanda-town-prava pip install "nest-core[plugins]" && pip install -e ".[dev]" python scripts/town_scene.py
run the testscd nanda-town-prava && pytest -q
confirm discoverycd nanda-town-prava && nest plugins list payments
marketplace scalecd nanda-town-prava && python scripts/baseline_diff.py