canonical: true
role: decision-lock
locked: 2026-05-18 PM
founder_authorization: "Lock and create super prompt end to end without stopping all founder's permission." — 2026-05-18 PM session
binding: All 12 decisions immutable; supersedes any prior conflicting design proposals
Founder gave explicit batch-lock authorization. The following 12 decisions are now immutable and feed directly into the v4 super prompt + Sprint v1.8 epics (AIN-152, AIN-153, AIN-154, AIN-158, AIN-161).
LOCKED: Wallets table gets nullable agent_id foreign key. agent_id = null → shared pool. Per-agent wallets are primary spend source. Per-agent caps override tenant defaults.
Schema change:
ALTER TABLE wallets ADD COLUMN agent_id uuid REFERENCES agents(id);
ALTER TABLE wallets ADD COLUMN per_call_cap_usd numeric(8,4);
ALTER TABLE wallets ADD COLUMN daily_cap_usd numeric(10,4);
ALTER TABLE wallets ADD COLUMN monthly_cap_usd numeric(10,4);
ALTER TABLE wallets ADD COLUMN paused_at timestamptz;
-- Composite PK supports both per-agent and shared rows
ALTER TABLE wallets DROP CONSTRAINT wallets_pkey;
ALTER TABLE wallets ADD PRIMARY KEY (tenant_id, COALESCE(agent_id, '00000000-0000-0000-0000-000000000000'::uuid));
Implementation: api/ainfera_api/services/spend_policy.py _spent_today extended with agent_id parameter. Drain-proof tests extended for per-agent caps. Migration: migrations/2026_05_19_per_agent_wallets.sql.
LOCKED: Fall through to shared pool by default. Per-tenant config flag wallet_strict_per_agent (default false) flips to fail-strict (HTTP 402 wallet_insufficient without fallthrough). Strict mode useful for budget isolation between agents.
Resolution order:
wallet_strict_per_agent = true → HTTP 402 wallet_insufficient_per_agent