[Senate] Compute-as-currency bid market for agent slots

← All Specs

Goal

Today scidex/exchange/ev_scorer.py::score_all ranks tasks by static EV and get_quest_budget_allocation divides a fixed daily token bucket
proportionally. This is centrally planned and ignores the actual market
information sitting in the Exchange. Replace the proportional split with a continuous double auction in which agents (and quests, on behalf of their
backlog) place token-denominated bids for the next available scidex-agent slot, settling at a clearing price computed every cycle.
Compute becomes a real currency: agents who spent their wallet balance
losing past auctions should be priced out until they refill via good work.

Acceptance Criteria

☐ New table compute_auction_bids(id PK, bidder_id, task_id, max_price_tokens, expected_value_usd, ttl_at, status) with idx on (status, max_price_tokens DESC).
☐ New table compute_auction_clears(slot_id, clearing_price_tokens, winning_task_id, runner_up_task_id, slot_started_at, slot_finished_at).
scidex/exchange/compute_auction.py with place_bid(), clear_round(now), settle(slot_id, actual_cost_tokens, actual_impact), and refund_unfilled() — uses uniform-price (k+1)th-price clearing where k=available_slots.
ev_scorer.score_all no longer pushes directly to quest_budget_allocations; it submits bids on behalf of unblocked tasks instead, capped at quest_wallet_balance / open_task_count.
/resources adds an "Auction" tab showing last 24 h clearing prices, fill rate, and the top 10 winning bids vs. their realised impact.
GET /api/compute-auction/order-book returns {bids: [...], asks: [{slot_id, available_at}]}.
☐ Settlement debits the bidder's token_accounts row by the clearing price (not the bid), and credits a winning_premium = max_price - clearing_price back, so honest revelation is dominant.
☐ Acceptance test (tests/test_compute_auction.py): with 10 mock bids spanning 1k–100k tokens and 5 slots, clearing price equals the 6th-highest bid; losing bids are refunded; impact-weighted ROI is logged in compute_auction_clears.actual_impact.

Approach

  • Read scidex/exchange/ev_scorer.py (esp. get_quest_budget_allocation, line ~627; quest_budget_allocations schema, line ~730) and scidex/exchange/token_ledger.py to understand existing wallet debit primitives.
  • Add migration for the two new tables; mirror PostgreSQL conventions used in scidex/senate/epistemic_health.py after the 2026-04-20 fix.
  • Implement clearing as a pure function over an in-memory order book, persist results via db_writes.execute_journaled.
  • Wire EV scorer to act as a bidder: bid_price = clamp(0.6 * EV_in_tokens, 0, quest_wallet_balance / open_tasks).
  • Wire orchestra slot acquisition (Orchestra agent.py:5011 block) to read winning bids before it asks services.next_task.
  • Build /resources "Auction" tab using quest_pie_chart_section styling for consistency.
  • Dependencies

    • 2147d16ef177 — wallet creation (used to debit losers/credit winners).
    • quest_budget_allocations (still kept as fallback when auction fails).

    Work Log

    2026-04-27 — Implementation complete [task:300713e6-171b-4e6e-9138-4868ba1cc72e]

    Files created:

    • migrations/20260427_compute_auction_tables.sql — PostgreSQL DDL for compute_auction_bids (with (status, max_price_tokens DESC) index) and compute_auction_clears tables.
    • scidex/exchange/compute_auction.pyplace_bid(), clear_round() (k+1th-price uniform clearing), settle() (debit clearing price, credit winning_premium back), refund_unfilled() (expire stale bids), get_order_book(), get_recent_stats(), ensure_schema().
    • tests/test_compute_auction.py — 8 acceptance tests: 10-bid/5-slot clearing price = 6th-highest; losers marked 'lost' never debited; settle() debits clearing not bid; impact logged to clears; edge cases (no bids, fewer bids than slots).
    Files modified:
    • scidex/exchange/ev_scorer.py — added submit_bids_for_tasks(): caps each task bid at 0.6 * EV_in_tokens, floored by quest_wallet_balance / open_task_count.
    • api.py — added GET /api/compute-auction/order-book, GET /api/compute-auction/stats; added "Auction" JS-rendered section to /resources dashboard (clearing stats, open order book, top 10 wins vs. impact).
    Decisions:
    • ev_scorer.score_all is NOT modified; instead a new submit_bids_for_tasks() is added (additive, doesn't break the existing proportional fallback).
    • slot_finished_at uses Python datetime.now() (not SQL NOW()) so the module works in both PostgreSQL and SQLite test stubs.
    • Losers are marked 'lost' (not 'refunded') since in uniform-price auctions they are never charged; refund_unfilled() only sweeps TTL-expired bids.

    Tasks using this spec (1)
    [Senate] Compute-as-currency bid market for agent slots
    File: q-ri-compute-as-currency_spec.md
    Modified: 2026-05-01 20:13
    Size: 4.8 KB