Skip to content

shield-swap: agent onboarding & lifecycle — one-verb journeys, self-provisioning credentials, packaged agent guide#58

Merged
iamalwaysuncomfortable merged 30 commits into
masterfrom
feat/agent-lifecycle
Jul 16, 2026
Merged

shield-swap: agent onboarding & lifecycle — one-verb journeys, self-provisioning credentials, packaged agent guide#58
iamalwaysuncomfortable merged 30 commits into
masterfrom
feat/agent-lifecycle

Conversation

@iamalwaysuncomfortable

@iamalwaysuncomfortable iamalwaysuncomfortable commented Jul 16, 2026

Copy link
Copy Markdown
Member

What this is

Everything a stress-test participant's agent needs to drive shield-swap end to end from a chat prompt: pip install shield-swap-sdk, read python -m aleo_shield_swap, and the full journey — account setup, invite redemption, credential provisioning, airdrop, concurrent private swaps, and collecting earnings — just works. Proven live on testnet: the gated e2e test takes a brand-new account through the complete lifecycle (including 2 concurrent private swaps with distinct blinded identities and both outputs claimed) in ~2 minutes.

Tier 1 — the lifecycle verbs

  • ShieldSwap.from_profile() — on-disk profile (~/.shield-swap/, $SHIELD_SWAP_HOME): key material (created, or imported via SHIELD_SWAP_PRIVATE_KEY(_FILE) so keys are never pasted into a conversation), credentials, and an append-only journal.
  • onboard(invite_code=...) — stage-list-driven registration (lifecycle.REGISTRATION_STAGES is the single definition, built to change): authenticate → redeem → credentials self-provision (Provable consumer+key via keyless POST /consumers, durable ss_… DEX token via POST /api-tokens; env vars as override; live facade refreshed in place) → airdrop (background job, 429-tolerant) → funded (private records via scanner). Idempotent: a registered, funded account is a reported no-op.
  • status() / get_positions() — one-call re-orientation from disk + chain + API; positions merge the journal with a record scan.
  • swap_many(count=N) — journal-reserved blinded-identity counters (no probe races), per-swap disjoint input records with confirm-and-rescan fallback, route-quoted min-out, broadcast without confirmation wait; every handle journaled before the next swap fires.
  • collect_all() — claims every finalized swap and collects owed LP fees (exact owed×scale requests), never double-claims, tolerates transient network failures, resumable from any session.

Typed self-healing errors throughout (NotRedeemedError: run dex.onboard(invite_code=...) …) — the exception text is the runbook.

Agent surface

  • AGENTS.md — generated from docstrings by codegen/gen_context.py (CI staleness gate), ships in the wheel (python -m aleo_shield_swap prints it; agent_guide() returns it) along with the Claude skill under aleo_shield_swap/skills/. Tier 1 covers the lifecycle plus the conversation flow (two pre-flight questions, ask-what-next options menu, never show raw base units); Tier 2 is the development guide for agents building their own tools.
  • Curated 11-tool shield_swap_tools() / MCP surface; the MCP server binds the local profile.
  • .claude/skills/shield-swap/ in-repo skill for Claude Code sessions here.

Live-verified protocol learnings (each fixed + regression-tested)

  • /route speaks canonical decimal units — base-unit quotes inflated min-out 83× and every swap aborted at finalize (found by diffing a rejected execution against a confirmed swap).
  • DPS payloads nest the transaction under "transaction"; outputs are harvested from the payload so batches don't block on confirmation.
  • Swap deadlines must absorb delegated-proving latency (~3s testnet blocks): default is now 10k blocks.
  • Concurrent swaps from one account must partition input records — the scanner can't see in-flight spends.
  • claim_swap_output must register both token programs with the prover; explicit token_record= no longer skips program registration.
  • ss_… API tokens are tiered (data/trading endpoints only); session JWTs handle /access/*.
  • Includes the refreshed amm-api OpenAPI spec + regenerated models (airdrop is now private-record transfers, 15-min rate limit).

Testing

135 unit tests (all fast/offline), 8 live API tests (SHIELD_SWAP_LIVE=1), and the live exit gate tests/integration/test_agent_lifecycle_live.py (-m live): fresh profile → self-minted invite → self-provisioned credentials → airdrop → funded → 2 concurrent swaps → both claimed → fresh-client resumability. A scripts/rehearsal.py runs the four participant flows as a pre-event check. pyright clean; wheel build verified to ship the guide.

The live exit gate covers all four stress-test flows and passes in ~7 minutes from a fresh account: startup (self-minted invite, self-provisioned credentials, airdrop) → discovery → 2 concurrent private swaps → claims → liquidity (mint → resize both directions → collect owed earnings) → fresh-client resumability. Liquidity live-proofs surfaced and fixed their own bug class: mint/increase/collect only registered token programs when the caller named them.

Also included: the Veil-style conversation flow (pre-flight questions, ask-what-next menu with a developer path, human-units rule), the Tier 2 development guide (client-choice table + integration checklist), the agent guide + skill shipped in the wheel (python -m aleo_shield_swap), and a version bump to 0.2.2 across all three packages.

Known follow-up: the ETH/wUSDCx fee=1 pool rejects all swaps server-side (no successful swap in its history — flagged for the AMM team). Scanner indexing lag after writes is real and documented; the gate and guide model the wait-then-retry pattern.

…ping

Includes the refreshed amm-api OpenAPI spec + regenerated models (airdrop
is now private-record transfers, 429 rate-limited).
…zy body decode, 429 in _check, tolerant airdrop-job build

Live-verified on testnet dev API: 401 mapping, access gating for fresh
accounts, full airdrop job lifecycle (3/3 accepted), api-token tiering.
…nal appends, scanned-position id, atomic profile writes

- onboard() on a fresh profile now works end to end: the credentials stage
  pushes the provisioned DPS key onto the live provider/network client/
  scanner instead of requiring a rebuilt client
- journal appends take the same advisory lock as counter reservation (no
  torn JSONL lines); empty counter reservations are no-ops; malformed
  events are skipped, id-less swaps excluded from pending claims
- scanned PositionNFTs read token_id (the actual record field)
- profile files are written atomically with 0600 from birth; a shared
  record_plaintext helper replaces four copy-pasted extractions
…cript

Registration half verified against the live API: fresh account auth,
self-minted invite redemption (POST /access/generate via the e2e
account), instructive credentials error, JWT persistence. The full
swap/collect gate needs ALEO_E2E_API_KEY/ALEO_E2E_CONSUMER_ID.
…entials stage

Provable API consumer + key via keyless POST /consumers (env vars remain
an override), durable ss_ DEX token via POST /api-tokens; both persisted
to the profile and pushed onto the live facade. Expired session JWTs no
longer count as authenticated; from_profile falls back to the durable
token for the data tier.
…gistration, swap_many quotes before swapping

All three found by walking the participant journey live: the DPS now
nests the transaction under 'transaction'; fresh accounts must re-register
with the scanner once the API key exists; and spot-estimated min-out is
unsatisfiable when the pool fee exceeds the slippage allowance, so
swap_many quotes the route once per batch.
…ant swap deadline

Live-diffed a rejected swap against a confirmed one: our amount_out_min
was 83x too high because /route speaks canonical decimals while swap_many
passed base units. Quotes now convert base->decimal->base via registry
decimals; swap's default deadline widens to 10k blocks (~8h at ~3s
blocks) since DPS latency can outlive 100.
…programs + transient-error tolerance in collect_all

Live-journey findings: concurrent swaps double-spent the single airdrop
record (scanner can't see in-flight spends), claims in fresh processes
lacked the token programs' stacks, and a network blip aborted the whole
collect loop. swap_many now assigns each swap a distinct record (falling
back to confirm-and-rescan when records run out), claim_swap_output
registers both token programs, and collect_all leaves transiently-failed
claims pending for the next run.
… import, human units

The generated guide now opens with the two pre-flight questions (existing
account? invite code?), then an ask-what-next options menu in plain
language, and ground rules (never paste keys in chat, never show raw base
units, don't re-submit slow writes). Profiles import
SHIELD_SWAP_PRIVATE_KEY(_FILE) so existing users keep their account.
…-point quotes, review cleanups

The live gate caught it: swap(token_record=...) skipped registering the
token program, so partitioned batches failed to prove in fresh processes.
Also: canonical-decimal quotes serialize fixed-point (never '1E-8'),
pick_covering_record gains exclude= and swap_many reuses it, env keys are
stripped, dead agent handlers and a dead diagnostic removed.
AGENTS.md is generated into the package (python -m aleo_shield_swap
prints it; agent_guide() returns it), the Claude skill ships under
aleo_shield_swap/skills/, and the wheel smoke test proves both land.
mint/increase/decrease/collect verified live on testnet (position minted
+ journaled, resized both directions, owed earnings collected to zero).
Fixes found doing it: mint/increase/collect now always register the token
programs (auto-selected records skipped registration, same class as the
claim bug), mint journals its position and burn journals the closure at
the client layer, and the live gate + rehearsal script gained a liquidity
phase with retry tolerance for the post-resize scanner lag Veil's runbook
documents.
…hoice table; gate waits for position records to scan

The ask-what-next menu now routes builders (option 3) to the development
guide, which opens with the client-choice table (bot/server, agent
integration, browser dApp -> TS stack) and the integration checklist.
The live gate and rehearsal poll for the freshly minted PositionNFT to
become scannable before resizing — the mint-side twin of the post-resize
scanner lag.
@iamalwaysuncomfortable
iamalwaysuncomfortable merged commit 668e0de into master Jul 16, 2026
18 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