Repository navigation
Description
Ruling
Drew (2026-10-31 ~20:19 CDT), on route pool selection:
allow round robin to accept weight but instead of all of them even or all of them by weight, evenly go through each priority so lowest weight even until all fail then second lowest evenly and so on
Semantics to implement
In a round-robin pool, weights stop being proportional shares and become priority tiers:
- Targets with equal effective weight form one tier. Within the active tier, selection rotates evenly across dispatches (the existing per-session draw + stickiness, restricted to the tier).
- Selection falls through to the next tier only when every member of the current tier has failed or is unavailable for that dispatch's candidate walk (not ready, already tried, gate-closed, cooling, quota-gated — the existing eligibility rules decide membership as today).
- All-equal weights (or no weights; unset weight still defaults to 1) collapse to a single tier, which is exactly today's plain even round-robin. Unweighted pools do not change behavior.
orderedmode is untouched.
Tier order: higher weight = earlier tier (interpretation, flagged)
Drew's wording says "lowest weight" first, but the fleet's pools already use weight as preference, larger = preferred:
- the GPT pools put alternate at weight 2 over main at 1 precisely so alternate burns first;
- luna-plan puts the Go leaves at 3/2 above the rest;
- the DeepSeek plan pool uses a weight-100 guard to keep plan doors ahead of PAYG.
A literal lowest-first reading would invert every one of those pools. This issue therefore implements descending order (highest weight is the first tier). If Drew reverses the call, the change is the tier sort comparator and nothing else.
The tier key is the target's effective pre-demotion weight: configured pool weight after scheduled rules, user preferences, and learned adjustments — the same layers tracedWeightOf already computes, stopping before the demotion layer.
Interaction with quota demotion
Demotion today scales the effective weight by 0.01, which under tiering would smear a demoted heavyweight into the middle tiers (100 x 0.01 = 1 ties it with nominal 1s). Rule instead:
- While demoted (>=
quota.demoteAfterquota errors insidequota.windowMs, per target or per serving credential as today), a leaf sits in a demoted tier below every non-demoted tier, whatever its configured weight. Demoted leaves still order among themselves by weight, and they still serve as last resort when nothing else is left. - A nested group counts as demoted only when every currently eligible leaf under it is demoted; a mixed group stays in its nominal tier and its own walk applies the same rule one level down.
- The 0.01 factor itself is unchanged for
orderedandweightedmodes, whose ranking keeps using the final effective weight exactly as today.
weighted mode: left as-is
weighted remains the proportional mode (random draw by ratio) for pools that genuinely want shares. The ruling redefines round-robin only; removing the only proportional mode is not part of it.
Acceptance criteria
Tests in the model-route suite cover at least:
- Single-tier pools rotate evenly, as today.
- Two-tier strict fall-through: the second tier is never drawn while any first-tier member is ready; it engages once every first-tier member has failed / left the candidate set, within a single dispatch walk and across dispatches.
- Within-tier rotation persists across dispatches (successive sessions cycle through the tier, not the pool).
- An unset weight lands in the same tier as weight 1.
- A quota-demoted leaf sorts below all non-demoted tiers regardless of nominal weight, and serves again as last resort.
- A nested route reference participates as a tier member with its group weight.
No config changes; selection logic and its tests only.
Activity
feat(core): round-robin weights are priority tiers, not shares (#1122)
dezren39 commentedon Nov 1, 2026
Feeder triage evidence (issue-sweep-rotating, enqueue-only — this run does not fix):
Checked on current main
c4ad56aaea3542e561e481918f59091b38f2134b(gh api):packages/core/src/model-route.ts:39— selection modes areordered/round-robin/weighted.selectSessionTarget(:745) — theround-robinbranch (:757ff) is smooth weighted round robin: scores accumulate each candidate's weight and the highest score wins, i.e. weights act as proportional ratios today. That is exactly the behavior this ruling replaces — there is no tier grouping, no within-tier even rotation, and no strict fall-through anywhere in selection.tracedWeightOf(:1197-1223) — layers are base → scheduled → prefer → adjustment → demotion, where demotion isweight * DEMOTED_FACTORwithDEMOTED_FACTOR = 0.01(:1132). The issue's tier key (effective pre-demotion weight) is the trace'sadjustmentlayer, which already exists and is recorded per selection (feat(core): per-layer weight attribution in the route decision log (design #587, phase 2) #589) — the tiering change can key off it without new weight plumbing. The demoted-tier rule (below all non-demoted tiers, regardless of nominal weight) is not representable in the current 0.01 scaling, as the issue notes (100 × 0.01 = 1 ties with nominal 1s).packages/schema/src/config/model-routes.ts:285-287— the config annotation describes round-robin as "rotates per new session" and does not mention weights; no config-shape change is needed for tiers.Verdict: the gap is present on current main; round-robin weights are proportional shares today, not priority tiers.
What "done" looks like (for the triage lane): confirm this diagnosis, pin the tier semantics against the dispatch candidate walk (tier key = pre-demotion traced weight; demoted tier last; nested group demoted only when every eligible leaf is demoted; session stickiness preserved within tier), and promote to a fix packet covering the issue's six acceptance tests.
orderedandweightedstay untouched. The descending-order interpretation is flagged in the issue itself — surfacing it in the triage note suffices; it is a one-comparator change if Drew reverses it.Enqueueing a triage packet from this evidence (task id in the follow-up agent note).
dezren39 commentedon Nov 1, 2026
Queued by the triage feeder (issue-sweep-rotating): triage packet enqueued as task 4820 in queue
repo-health-opencode-pilot(deduperepo-health:v1:triage:developing-today/opencode:issue:1122). Evidence comment: #1122 (comment)dezren39 commentedon Nov 1, 2026
agent-note:v1
state: done
Agent: repo-worker-opencode (openchamber scheduled lane)
Session/ID: task 4820
Outcome: Already done on pickup: issue closed; PR #1124 merged as 6aae7cc. No competing implementation or follow-up task created.