[Hackathon] stellarminds-ai: PARC — portable reputation credentials with a recomputing admission gate#63
Open
Sharathvc23 wants to merge 1 commit into
Conversation
…ssion gate Reputation in NEST dies with the run: no plugin exports it, carries it, or verifies it in another trust domain. This adds the parc trust plugin (extending the merged agent_receipts receipt maths), the parc_migration two-domain scenario, and six adversarial validators. - Export: an agent's receipt ledger becomes a W3C-VC-shaped credential (behavioral_merkle_root + nanda-rep/0.2 scores as fixed 6-decimal strings), signed through the ed25519_rotating identity layer with key_id pinned in proof.verificationMethod (vendored did:key encoder, stdlib-only). - Admission: the gate recomputes the root and scores from the carried receipts instead of trusting signed claims — an issuer-inflated, genuinely re-signed score is rejected (score_mismatch). A valid signature is not admission. - Cross-layer: proofs are checked against the issuer's key-rotation window as-of the credential's validFrom tick (stale_key), using genuine rotation records replayed onto the gate. - Ring severance at the border: an inline single-subject ledger is a star graph and cannot show an N-party ring, so the gate re-runs whole-graph collusion severance over the originating domain's published ledger (severed_below_threshold). - Differential proof: with task.config.naive_gate (signed claims trusted) the inflation + ring validators FAIL; under trust: score_average no credentials exist and every validator fails. Registered in _BUILTINS and as a real nest.plugins.trust entry point. 41 new tests (hostile paths per typed reason, Hypothesis properties, 5-seed e2e, byte-identical determinism). make ci-local green.
|
LGTM |
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.
Motivation
Reputation in NEST dies with the run. Every trust plugin holds an in-memory ledger; nothing exports it, carries it, or verifies it in another trust domain — an agent that migrates starts from zero, and a domain that wants to admit a stranger has nothing to check. The merged
agent_receiptsplugin (#26) made reputation evidence-based; this PR makes it portable, and does it by composing two merged submissions rather than adding a parallel scheme: the receipt maths ofagent_receiptsand the rotation windows ofed25519_rotating(#25).Design
trust/parc.py—ParcTrustextendsAgentReceiptsTrust(drop-in for theTrustProtocol) with:build_credential): wraps the subject's receipts as a W3C-VC-shaped document —behavioral_merkle_rootcommitting to the carried receipts,nanda-rep/0.2scores embedded as fixed 6-decimal strings,validFromas a logical tick — signed through the identity layer, with the signingkey_idpinned inproof.verificationMethodasdid:key:z6Mk...#<key_id>(base58btc/multicodec encoder vendored, ~25 lines, stdlib-only).admit): ordered gates, each a typed reason: schema → scoring method → trusted issuer → presenter binding (replay_presenter_mismatch) → freshness → proof with as-of key-window enforcement (proof_invalidvsstale_key) → ledger size → subject binding (foreign_receipts) → Merkle-root recomputation → score recomputation (score_mismatch) → threshold → published-ledger severance (severed_below_threshold).ingest_published_ledger): an inline single-subject ledger is a star graph and structurally cannot show an N-party collusion ring, so the originating domain publishes its community ledger once and the gate re-runsagent_receipts' whole-graph Tarjan severance over it. Stated openly rather than papered over.The headline property: a valid signature is not admission. The scenario's
auditor-xis a trusted issuer that inflates a client's score and genuinely re-signs. The proof verifies; recomputation over the carried receipts rejects it.Scenario (
parc_migration, tier 1): two trust domains in one seeded run. 4 honest agents + a 3-agent wash ring earn receipts in domain A; at the border to domain B: a forger (tampered proof), a replayer (stolen genuine credential), a stale-key credential (signed with A's rotated-out key via the identity layer's adversarialsign_with), and the inflated credential. The factory performs a genuine key rotation and replays the rotation record onto the gate — the proof checks run against real key windows, not scenario-faked ones.Adversarial validators (6, in
VALIDATORS["parc_migration"]): honest admitted (anti-deny-everything guard), forgery →proof_invalid, inflation →score_mismatch, ring →severed_below_threshold, replay →replay_presenter_mismatch, stale key →stale_key. Each asserts the typed reason, not just the denial.Differential proof:
task.config.naive_gate: truemakes the gate trust signed claims (proof still checked) — the inflation and ring validators FAIL while the rest hold. Undertrust: score_averageno credentials can be built and every validator fails. Both asserted in tests across a 5-seed bank.Tradeoffs
agent_receipts' hex-pubkey identity (that is what the carried receipts use — recomputation depends on it); issuers get stabledid:nest:URIs with per-keydid:keypins, so issuer trust survives key rotation. Unifying them would have meant rewriting the merged receipt format.score_tolerance(default 1e-6).max_age_ticks) + rotation windows cover staleness; Merkle inclusion proofs are the natural follow-up and listed indocs/layers/trust.md.What would invalidate this
agent_receipts' thresholds (dense rings ≥3 or mutual pairs, isolated from the anchor): a ring that buys one genuine corroborated edge to an honest anchor agent evades severance.validFromsupplied by the issuer; a compromised current key can backdatevalidFrominto its own window. Rotation bounds the damage window but does not eliminate it.Verify
make ci-local: all 5 checks green (ruff check, ruff format, pyright strict, 777 tests).