Created
May 26, 2026 20:59
-
-
Save denniswon/93fa0bc44281a852465657442e75e85f to your computer and use it in GitHub Desktop.
Isaac - Lithic integration
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
| Here's the design, in sections. The four decisions you made are baked in. Flagging upfront: exact Lithic ASA payload field names, | |
| HMAC signature scheme, and the simulate endpoint path are marked [verify vs Lithic docs] — I'll confirm those against Lithic's API | |
| during planning rather than guess them now. | |
| --- | |
| 1. Architecture overview | |
| A new inbound webhook receiver POST /webhooks/lithic-asa is the card-rail analog of the x402 facilitator's executeIntent path. Lithic | |
| calls it in real time for every card authorization; we decide APPROVE/DECLINE within the 2s SLA using the same Rego policy that | |
| governs USDC spend, then fire an async Newton attestation for the crypto-economic audit trail. | |
| Lithic card auth ──POST /webhooks/lithic-asa──▶ [HMAC verify (per-vault asa_webhook_secret)] | |
| │ | |
| [resolve card_token → vault, agent] | |
| │ | |
| [fetch agent spend from indexer]─┤ (synchronous, budgeted) | |
| ▼ | |
| [LocalEvaluator: card-auth Rego input] | |
| │ Allow→APPROVE, Deny/Queue→DECLINE | |
| ┌─────────────────────┼─────────────────────┐ | |
| ▼ ▼ ▼ | |
| [respond ≤budget] [persist auth + latency] [emit auth.approved/declined] | |
| │ | |
| [spawn async Newton attestation] ──▶ compare ──▶ on divergence: | |
| record + emit auth.divergence | |
| Trust model, stated honestly: the synchronous card decision is operator-local Rego (not BLS-attested), because card auth is | |
| real-time. The async Newton attestation provides the crypto-economic backing after the fact — it can't reverse a cleared auth, but it | |
| captures the rail in the audit trail and flags divergence. | |
| --- | |
| 2. D9.3 — ASA receiver (the core, NEWT-1329) | |
| New module src/lithic/asa.rs (decision logic) + a thin handler wired via router() in routes/mod.rs. Steps: | |
| 1. Identify + authenticate — parse card token from the body, look up lithic_cards → vault_address → | |
| vault_lithic_programs.asa_webhook_secret, decrypt (secret_crypto), verify HMAC over the raw body [verify vs Lithic docs: header name | |
| + scheme]. No vault match or bad sig → DECLINE (fail-closed). | |
| 2. Budgeted synchronous decision — wrap HMAC + indexer spend fetch + Rego eval in tokio::time::timeout(~1500ms). Any error or timeout | |
| → DECLINE. (Local eval is <10ms; indexer fetch ~50-100ms — comfortable.) | |
| 3. Outcome mapping — Allow→APPROVE; Deny→DECLINE; Queue→DECLINE (a real-time card auth can't wait for human approval — record the | |
| queue reason but decline). | |
| 4. Persist + respond + emit — write the decision to a new lithic_card_auths table (audit + P95 source), respond to Lithic, emit | |
| auth.approved/auth.declined via the existing D8 emitter. | |
| 5. Async attestation — tokio::spawn the real gateway createTask; compare to the local decision; on divergence persist + emit | |
| auth.divergence. Off the synchronous path entirely. | |
| 6. Metrics — Prometheus histogram of decision latency for the P95-under-2s AC. | |
| Does this section look right before I detail the policy adapter? | |
| --- | |
| 3. D9.4 — Rego card-auth adapter (NEWT-1330, policy-touching — care needed) | |
| The existing agent_neobank.rego is shaped for ERC-20 transfer intents (decoded_function_arguments). A card auth is a different shape | |
| (cardholder agent, merchant, MCC, amount). Proposed minimal, additive change: map a card auth onto the agent's existing per-token | |
| policy — treat the card spend as a spend against the agent's max_daily_spend, with merchant/MCC checked against allowed_recipients | |
| (reused as a merchant/MCC allowlist). Adds a card_auth_allow rule path keyed on a new input.kind == "card_auth" discriminant, leaving | |
| the USDC path untouched. The adapter in Rust builds this input from the ASA payload. Exact param extension (new card block vs | |
| reusing tokens) gets nailed in the spec — but the principle is: no breaking change to the USDC policy, smallest possible card branch. | |
| Is reusing the per-agent token policy (vs a standalone card policy) the right call for the pilot? | |
| --- | |
| 4. D9.5 — Dashboard + demo (NEWT-1331) | |
| - Dashboard: per-vault card list (existing lithic_cards) + an "auth stream" log (new lithic_card_auths) showing decision, reason, | |
| latency, merchant. Follows the neo-industrial design system + existing table patterns. (One check: whether "Lithic" may appear in UI | |
| text or must be functionally framed as "card issuing" — I'll confirm against the dashboard vendor-name rule.) | |
| - CI E2E: synthetic ASA POST (valid HMAC) → receiver → verify → eval → respond → emit → audit assertion, with the gateway wiremocked | |
| (mirrors existing facilitator integration tests; no external dependency). | |
| - Recorded demo: Lithic sandbox simulate-authorization [verify vs Lithic docs: endpoint] for a real ASA round-trip. | |
| --- | |
| 5. Data model + testing | |
| - New migration 014_lithic_card_auths.sql: lithic_card_auths (id, vault_address, card_token, agent_address, amount, merchant/MCC, | |
| decision, reason, latency_ms, attestation_status, created_at). Must be idempotent + added to the hand-maintained run_migrations list | |
| in db.rs (per the lessons-inbox migration trap). | |
| - Webhook taxonomy: add auth.divergence to the event-type CHECK constraint (idempotent migration) — auth.approved/auth.declined are | |
| already in the planned taxonomy. | |
| - Tests: Rust units (HMAC verify, outcome mapping, fail-closed on timeout, divergence detection), Rego units (card-auth | |
| allow/deny/over-limit), the wiremocked E2E. | |
| --- | |
| Net scope: one new module (lithic/asa.rs), an additive Rego branch, one migration + one CHECK update, a dashboard surface, and the | |
| test/demo split. Does this overall shape work, and do you want any section reworked before I write the spec? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment