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.
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).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}]}.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.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.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.scidex/senate/epistemic_health.py after the 2026-04-20 fix.db_writes.execute_journaled.bid_price = clamp(0.6 * EV_in_tokens, 0, quest_wallet_balance / open_tasks).agent.py:5011 block) to read winning bids before it asks services.next_task./resources "Auction" tab using quest_pie_chart_section styling for consistency.2147d16ef177 — wallet creation (used to debit losers/credit winners).quest_budget_allocations (still kept as fallback when auction fails).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.py — place_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).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).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.'lost' (not 'refunded') since in uniform-price auctions they are never charged; refund_unfilled() only sweeps TTL-expired bids.