Routing Strategies

Markets

Competitive routing with broadcast claims and durable market settlement records.

Market strategies are the clearing-native family: instead of the engine pushing Work to a chosen Worker, workers compete for it, and the winner is chosen by market rules rather than a fixed score. That competition can be a race to claim or a market session that records Bids and settlement outcomes — the same primitives the whole clearing lifecycle is built on, exposed as strategies.

Two market primitives ship today: shark_tank, the broadcast-and-claim strategy behind speed-to-lead, and the market-session assignment layer for recording winners, prices, and Settlement receipts on a routing decision. The same machinery carries Agent RFQ: typed bid terms, buyer-side clearing, authenticated bid submission, the task-spec front door, and award execution all ship today behind the agent_rfq.* gates — see Agent procurement for the call sequence.

StrategyOutputStatus
Shark tanksession-basedAvailable
Market sessions & settlementmarket-clearingAvailable

Shark tank

Capabilities: stateful, explain · Aliases: broadcast_claim

Broadcasts an opportunity to N candidates simultaneously and assigns it to the first one to claim it. It is the claim primitive behind speed-to-lead and ping/post-style competition, driven by the ping/post service.

Why use it. When responsiveness is the selection criterion — you want the recipient who is ready right now, not the one who scores best on paper. Instead of guessing who will act fastest, you let them race. Classic uses: lead distribution where the first agent to grab a lead works it, on-call escalation, and any "whoever's available first" assignment.

How it works. It is stateful — it tracks the open broadcast and the claim race — and produces a session-based output rather than an instant winner: the decision resolves when a claim arrives (or the session times out and falls back). It advertises explain, so the claim outcome is auditable. It is registered by builtin.RegisterBuiltins with a fallback strategy (default smooth_weighted_round_robin) for the no-claim case.

Where it fits. The Select stage, but unlike single-shot strategies its result is a durable claim session. See idempotency for how claims commit exactly once.

Market sessions & settlement

Output: market-clearing

The assignment and settlement layer supports a multi-winner session: participants submit Bids, prices are set, and winners are committed with a settlement receipt — and the outcome is recorded on the Route (Decision) as a MarketDecisionRef.

The reference captures the whole settlement, not just the winner:

FieldMeaning
SessionIDThe market session that produced the decision.
ResultIDThe clearing result.
PolicyHashHash of the clearing/disclosure policy in force.
WinnerCountHow many participants won (multi-winner markets).
SettlementReceiptIDProof the route, connector, and ledger commits happened together.
PricesPer-participant MarketPriceRef — RecipientID, BidID, Amount, Currency, Rule.
BlockerReasonsRedacted reasons a session was blocked, if any.

Lifecycle. Close the market to stop accepting bids, then commit the winner set and settle. Validation on the ref rejects a missing SessionID, a negative WinnerCount, or a price with a negative amount or missing RecipientID.

Where it fits. This is the durable record and commit path a market strategy resolves to.

The market session API

RoutingMarketService drives a session from open to commit. All routes are under /api/routing-markets, scoped by environment_id and session_id.

CallDoes
POST /api/routing-markets:previewDry-runs an open request and returns named blockers instead of a bare 400. Use it first.
POST /api/routing-marketsOpens a session: idempotency_key, routable_id, source, disclosure_policy, timeout_policy, clearing_policy, participants[].
GET /api/routing-markets/{env}/{session}Session, participants, bids, result, receipt.
POST .../{session}:solicitRecords a solicitation attempt on a channel.
POST .../{session}/bidsSubmits or amends a bid. Recipient bids carry amount; worker bids carry worker_id plus typed terms.
POST .../{session}:closeFreezes the bid set and clears it deterministically.
POST .../{session}:commitCommits the winner set; commit_mode: hold escrows for an award, the default pays now.
POST .../{session}:cancelCancels an uncommitted session.
POST .../{session}:replayRe-clears from the stored deterministic_seed and policy hash.

source is a closed set: route, dag_step, batch_allocation_plan, ranked_slate, headless, api, pingpost, simulation, connector_event. Scripted clients use api.

clearing_policy.algorithm is one of the seller-side algorithms (first_price_highest_bid, top_n, threshold, all_above_min, vickrey_second_price, posted_price_acceptance, waterfall_fallback) or a buyer-side profile (reverse_lowest_ask, best_value). Buyer-side policies read budget_micros, currency, weight_price, weight_quality, weight_sla, sla_headroom_ref_ms, and reverse_second_price.

disclosure_policy.scope is digest_only, partial, or full; with partial, allowed_fields lists the task-spec fields a participant may see.

timeout_policy.bid_window is a duration ("900s"); bids after the derived deadline are refused, and expire_on_timeout decides whether the session expires or waits for an explicit close.

Every participant is either a recipient_id or a worker_id, never both. Worker bids additionally require the caller to own the worker.