fix(registry): per-model solo-TPS quality caps + pooled-KV admission (postmortem layer 6)#524
Conversation
…r 6) The quality-concurrency cap consumed resolvedDecodeTPS(p) — the provider- LEVEL registration benchmark — for every model on the box. Mixed boxes benchmarked on gpt-oss (58-93 tok/s) therefore granted gemma caps of 12-23 where gemma's real solo rate (10-18 tok/s) warrants 1-2, and the coordinator marched 8-11 concurrent gemma requests onto exactly the boxes that collapse past batch 3 (2026-07-06 postmortem §3.2). The cap now resolves each model's OWN static solo rate: - Solo-gated sample store (solo_tps.go): RecordSolo/SoloMedian beside the existing 50-sample ring. Heartbeat ingest records a slot EWMA as solo ONLY when the whole box has ≤1 running+waiting request across ALL slots (the allowance is the sample-generating request itself) — mixed-box samples stay honest. The existing Record/Median (fleetMedianTPS → TTFT estimation) keeps its deliberately load-inclusive semantics, untouched. - Resolver resolvedSoloModelTPSLocked, fallback chain: per-(model,chip) solo median at ≥ EIGENINFERENCE_QUALITY_CAP_SOLO_MIN_SAMPLES (default 5) → cross-chip pooled solo median → EIGENINFERENCE_MODEL_SOLO_TPS_SEED (model=tok/s CSV; cold-start answer, the registry is restart-wiped) → resolvedDecodeTPS(p) unchanged. Rates stay STATIC (never under-load EWMA) so the cap cannot feedback-collapse; solo gating preserves that. - Kill switch EIGENINFERENCE_QUALITY_CAP_PER_MODEL_TPS (default true); false restores resolvedDecodeTPS(p) at every wired site exactly. - The DecodeTPS<=0 dedicated-only guard now applies only to the provider- level fallback: a per-model rate (solo median/seed) is model-specific by construction and caps even without a registration benchmark. resolvedDecodeTPS call sites, each decided deliberately: SWITCHED to the solo resolver (quality-cap inputs, all through the single entry hasConcurrencyHeadroomForModelCapResolvedLocked): - scheduler.go routing-snapshot headroom (snap.hasHeadroom) - scheduler.go quickCapacityCheck preflight concurrency gate - scheduler.go providerCanAdmitLockedEx final admit re-check (already Resolved; now per-model internally) - registry.go ModelCapacitySnapshot public-capacity headroom (already Resolved; now per-model internally) - warm_pool_controller.go warmSaturated gate (already Resolved) - warm_pool_controller.go warm-target decode samples: soloDecodeTPS now comes from the solo resolver so warm targets and admission caps cannot disagree; the observed-EWMA chain moved to a new serviceDecodeTPS that feeds only the E[S] service-time estimate (load-inclusive on purpose). KEPT provider-level (TTFT-estimation / cost-model / scoring semantics): - scheduler.go snap.decodeTPS (TTFT + cost estimates, effectiveDecodeTPS) - scheduler.go resolvedModelTPSLocked base (observed-EWMA cost chain) - scheduler.go resolvedPrefillTPS fallback (decode × ratio-12) - registry.go ModelCapacitySnapshot effectiveTPS (capacity-feed rate) - utilization.go FleetCapacity.DecodeTPS aggregate - warm_pool_controller.go cold-candidate score heuristic The unused explicit-rate hasConcurrencyHeadroomForModelCapLocked was deleted (golangci-lint unused); effectiveMaxConcurrencyForModelLocked stays as the explicit-rate wrapper. Regression tests (fail with the resolver mutation reverted; verified): the exact postmortem mixed box (benchmark 93, gemma solo 14, floor 15 → gemma cap 2, gpt-oss cap 23; kill switch off reproduces the old 23), solo ingest gating through real heartbeats, fallback-chain order, min-sample floor, seed parsing (malformed entries skipped), restart cold-start via seed, warm-pool solo/service rate split. New envs (documented in docs/operations/coordinator-deploy.md): EIGENINFERENCE_QUALITY_CAP_PER_MODEL_TPS, EIGENINFERENCE_QUALITY_CAP_SOLO_MIN_SAMPLES, EIGENINFERENCE_MODEL_SOLO_TPS_SEED.
… the shared budget freeMemoryAdmits admitted against the per-slot ActiveTokenBudgetMax with only SAME-MODEL coordinator pending counted. But a slot max is not a private budget: every slot on a box reports its own committed tokens plus the SAME shared KV headroom (see providerTokenBudget). Two co-resident models could therefore double-spend the one shared pool inside the ~30s heartbeat gap — a burst admitted against model A's slot was invisible to model B's stale slot max until the next heartbeat. Fix (kept minimal around freeMemoryAdmits for the pending budget-clamp branch to merge next to): - pooled_admission.go: providerPooledTokenBudget reconstructs the whole-box pool from the slots via the proven providerTokenBudget (committed sums across slots; shared headroom counted exactly once), plus an all-slots committed baseline that mirrors committedTokenBudget (max(used+queued, maxTokensPotential) per slot) so heartbeat-reflected requests are not double-counted against coordinator pending. - routingSnapshot gains pendingMaxTokensAllModels (the pending-token accumulator WITHOUT the model filter) and the pooled budget, populated by both snapshot builders (dispatch + preflight). - Budget admission is now: fits the per-slot budget (unchanged — the slot max still encodes the model's own context limits) AND fits the pool with every model's coordinator-pending tokens charged. Single-model providers are arithmetically unchanged (the pool reduces to the slot's own budget; boundary pinned byte-for-byte in TestFreeMemoryAdmitsSingleModelUnchanged, including the maxTokensPotential-dominates case). Legacy providers without token budgets never reach the pooled check. Inert under DEDICATED partitioning (no co-resident dispatch); live before the open-pool flip. Regression tests (fail with pooledBudgetAdmits mutated out; verified): burst model A to the whole pool through the REAL reservation path, then a model B request within the heartbeat gap is rejected; co-resident request WITHIN pool headroom still admits; 6th same-model request past the slot budget still rejects; pure-function double-spend + boundary tables; pooled-budget reconstruction arithmetic (shared headroom once, negative floors, budgetless slots ignored).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This diff makes purely capacity-accounting changes to the provider registry's TPS sampling and token-budget headroom logic; it does not materially strengthen or weaken any security control in the threat model. Trust boundaries touched
Threat assessment
New attack surface / observations1. At line ~4706: s.pooledBudgetRemaining != 0The comment documents that 2.
SEC-* findings resolved by this PRNone. Open findings SEC-007, SEC-034, SEC-011, SEC-004, SEC-012, SEC-017, SEC-021, and others remain unaddressed. SummaryNo security mitigations are added, removed, or weakened. The diff is a scheduling/capacity correctness fix. The only items worth a second look are the 🔐 Threat model: |
ethenotethan
left a comment
There was a problem hiding this comment.
Automated Code Review — Layr-Labs/d-inference#
Verdict: REQUEST_CHANGES
Security — 2 finding(s)
- 🔵 [INFO]
coordinator/registry/concurrency_cap.go:46-65— Environment variable parsing lacks validation for malicious input- Suggestion: Add input validation and sanitization for environment variables before parsing
- 🔵 [INFO]
coordinator/registry/concurrency_cap.go:143-162— CSV parsing vulnerable to injection through model names- Suggestion: Validate and sanitize model names in CSV parsing to prevent injection attacks
Performance — 1 finding(s) (1 blocking)
- 🟡 [MEDIUM]
coordinator/registry/scheduler.go:1079-1089— Unbounded token accumulation in pendingMaxTokensAllModels without pre-allocation- Suggestion: Pre-allocate pendingMaxTokensAllModels based on len(p.pendingReqs) to avoid repeated slice growth:
snap.pendingMaxTokensAllModels = make([]int, 0, len(p.pendingReqs))or accumulate directly as int without intermediate slice operations
- Suggestion: Pre-allocate pendingMaxTokensAllModels based on len(p.pendingReqs) to avoid repeated slice growth:
Type_diligence — 1 finding(s) (1 blocking)
- 🟡 [MEDIUM]
coordinator/registry/concurrency_cap.go:139— map[string]float64 lookup without ok check in qualityCapOvercommitForModelLocked- Suggestion: Use two-value assignment: if overcommit, ok := qualityCapOvercommitByModel[strings.ToLower(model)]; ok { return overcommit }
Additive_complexity — 3 finding(s) (2 blocking)
- 🔵 [INFO]
coordinator/registry/concurrency_cap.go:37-40— qualityCapOvercommitByModel and modelSoloTPSSeed both use parseModelFloatMap but have separate variables- Suggestion: Consider consolidating the parsing logic or using a generic map type to reduce duplication of similar functionality
- 🟡 [MEDIUM]
coordinator/registry/pooled_admission.go:1-77— New pooled admission system adds significant complexity with overlapping responsibility to existing per-slot checks- Suggestion: Consider if this could be integrated into existing admission logic rather than adding a parallel system
- 🟡 [MEDIUM]
coordinator/registry/solo_tps.go:1-107— Entire new solo TPS tracking system duplicates existing TPS registry functionality with different gating logic- Suggestion: Evaluate if the existing TPS registry could be extended with gating flags rather than creating a parallel tracking system
7 finding(s) total, 4 blocking. Verdict: REQUEST_CHANGES.
🤖 Automated review by Centaur · DAR-186
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c397dc46ea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
strconv.ParseFloat accepts NaN/+Inf/Infinity spellings, and NaN slips past the v <= 0 filter (NaN comparisons are always false). A seed or overcommit entry like "gemma=NaN" then flows into qualityConcurrency / int(math.Ceil(qc * overcommit)) as an implementation-defined integer conversion, silently strangling the model to cap 1. parseModelFloatMap now skips non-finite values like every other malformed entry.
…ve request The heartbeat ingest gated solo sampling on the BOX being uncontended (soloSampleEligible, total running+waiting <= 1) but then recorded EVERY slot with a nonzero ObservedDecodeTPS. An idle co-resident slot keeps re-reporting its stale decayed EWMA, so with model A serving the box's one request, model B minted a duplicate 'solo' sample per ~30s heartbeat from a single long-past observation — reaching the min-sample trust floor with no real measurement and deriving B's quality cap from a rate no request produced. A fully idle box likewise minted samples from thin air. Now a slot is sampled only when it owns the box's one active request (NumRunning+NumWaiting > 0); a fully idle box records nothing. The load-inclusive Record path (TTFT estimation) is unchanged.
…s co-resident models The pooled gate reconstructed the shared KV pool by summing slot TOKEN counts, but co-resident models spend the ONE byte pool at different KVBytesPerToken rates (a 26B model's token costs ~10x a small model's), so tokens are not a common unit: the token pool is denominated by the largest per-slot free-token view (the smallest-KV model's), and a small-KV pending burst that fits token-wise can exhaust the byte pool while a big-KV co-resident request still passes the gate (90k small-KV tokens = 0.9 GB pending, +3k big-KV tokens = 0.3 GB reads as 93k <= 100k and admits into a 1 GB pool). providerPooledTokenBudget now additionally reconstructs the pool in bytes (per-slot tokens x that slot's KV rate, shared free byte headroom counted once), the routing snapshot carries byte-normalized all-models pending, and pooledBudgetAdmits checks in bytes when every unit is normalizable: all budget slots report a KV rate, every pending request's model has one, and the incoming request's own rate is known. Any gap (legacy provider, cold pending model) falls back to token accounting byte-for-byte — the single-model and legacy boundary tests pin that. Snapshot pending/pool assembly is deduplicated into fillSnapshotPendingAndPool, shared by the dispatch snapshot and the queue preflight.
…path The pooled gate only ran inside the resident-slot budget branch (activeTokenBudgetMax > 0). A request for a model with NO budget slot on the box (cold, not loaded) skipped it entirely and fell through to the memory-estimation path — so in-gap pending on a resident model was invisible to it, and the cold request double-spent the same shared KV its post-load serving will occupy. freeMemoryAdmits now also runs pooledBudgetAdmits on the budget-less path whenever any resident slot reports a token budget (pool.total > 0). A cold model has no reported KV rate, so the check runs in token units; legacy providers with no budget slots at all are untouched (pool.total == 0 admits unconditionally, pinned by TestFreeMemoryAdmitsLegacyProviderUnchanged).
…ission gate enforces ModelCapacitySnapshot summed per-slot budget headroom straight off the heartbeat, so a co-resident box whose shared pool was fully coordinator-pending to model A still advertised model B's stale slot (used 0 / max 10k) as remaining budget and counted the provider routable — capacity the dispatch path's pooledBudgetAdmits rejects, luring upstream routers into 429s during the heartbeat gap. Phase 1 now reconstructs each provider's pooled remaining (token units, mirroring the admission gate's committed-baseline charge of all-models pending); phase 2 clamps every per-slot headroom contribution by it and treats an exhausted pool (0, distinct from the -1 legacy sentinel) as no budget headroom for every model on the box — cold ones included, matching the cold-slot pooled gate.
|
Review round addressed @ethenotethan — ready for re-review.
|
ethenotethan
left a comment
There was a problem hiding this comment.
Automated Code Review — Layr-Labs/d-inference#
Verdict: REQUEST_CHANGES
Security — 1 finding(s)
- 🔵 [INFO]
coordinator/registry/concurrency_cap.go:164— Missing input validation on math.IsNaN and math.IsInf checks- Suggestion: The parseModelFloatMap function checks for NaN and Inf values but doesn't validate that strconv.ParseFloat succeeded before calling these functions on potentially invalid float64 values
Performance — 1 finding(s) (1 blocking)
- 🟡 [MEDIUM]
coordinator/registry/pooled_admission.go:73-116— providerPooledTokenBudget creates unbounded map allocation inside loop without pre-allocation- Suggestion: Pre-allocate kvBytesPerToken map with capacity len(slots) before the loop to avoid repeated map growth
Type_diligence — 1 finding(s) (1 blocking)
- 🟡 [MEDIUM]
coordinator/registry/concurrency_cap.go:164— math.IsNaN and math.IsInf calls missing import for math package- Suggestion: Add 'import "math"' to the imports section or use qualified calls if math is imported elsewhere
Additive_complexity — ✅ No issues found
3 finding(s) total, 2 blocking. Verdict: REQUEST_CHANGES.
🤖 Automated review by Centaur · DAR-186
…ty-caps # Conflicts: # coordinator/registry/scheduler.go
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 942429fa98
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
ethenotethan
left a comment
There was a problem hiding this comment.
Automated Code Review — Layr-Labs/d-inference#
Verdict: COMMENT
Security — ⚠️ SKIPPED
Error: OpenRouter HTTP 402: {"error":{"message":"Insufficient credits. Add more using https://openrouter.ai/settings/credits","code":402}}
Performance — ⚠️ SKIPPED
Error: OpenRouter HTTP 402: {"error":{"message":"Insufficient credits. Add more using https://openrouter.ai/settings/credits","code":402}}
Type_diligence — ⚠️ SKIPPED
Error: OpenRouter HTTP 402: {"error":{"message":"Insufficient credits. Add more using https://openrouter.ai/settings/credits","code":402}}
Additive_complexity — ⚠️ SKIPPED
Error: OpenRouter HTTP 402: {"error":{"message":"Insufficient credits. Add more using https://openrouter.ai/settings/credits","code":402}}
✅ All four passes clean. No issues found.
🤖 Automated review by Centaur · DAR-186
Byte-mode pooled admission multiplies heartbeat token counts (clamped to ~10B) by slot.KVBytesPerToken, which is unbounded. A garbage/absurd rate overflows int64 to negative used/total bytes, breaking admission (a negative pool total rejects everything, or with a negative left side admits everything). Add maxKVBytesPerToken (16 MiB/token, ~160x gemma's real rate so legitimate rates pass untouched) and clampKVBytesPerToken; apply it in providerPooledTokenBudget (map store + all three byte products) and at the two scheduler snapshot sites that read slot.KVBytesPerToken. The pending-byte normalization reads from the now-clamped pool map, no change needed there. Regression test: a slot with KVBytesPerToken=MaxInt64/2 no longer wraps used/total bytes negative and admission fails closed.
…fallback The solo quality-cap resolver keyed by ChipFamily alone, lumping an M4 Max with an M4 Pro (3-4x apart in decode throughput), and SoloMedianAllChips pooled every chip's samples into one median. A fast, sample-heavy chip could then raise a slow box's cap — over-admission, the exact collapse this PR prevents. Add chipClassKey (family|tier, byte-for-byte #526's prefillChipClass), key RecordSolo ingest and the resolver's primary lookup by class (the load-inclusive Record stays family-keyed for fleetMedianTPS). Rewrite SoloMedianAllChips to return the MIN of per-class medians (never a fast-chip-dominated pooled median) plus the total sample count, so the cross-class fallback can never exceed the slowest class's typical rate. SAFETY INVARIANT: the resolver never hands a slow box a rate faster than its own class demonstrated; worst case it under-caps a fast box (safe). Tests (revert-verified): min-of-class semantics, same-class primary, cross-tier isolation, conservative fallback, cold-start, and an end-to-end heartbeat-driven no-cross-tier-over-cap check.
…lback On a byte-reconstructable mixed-KV box, pooledBudgetAdmits and pooledRemainingTokens collapsed to TOKEN accounting whenever the incoming request's own KV rate was 0 (a cold/absent slot), even though the resident pool is byte-reconstructable. A large-KV cold request was then under-charged against the small-KV token view of the pool and could double-spend the shared KV. Track pool.maxKVBytesPerToken (max clamped resident rate) and, in the byteMode && pendingBytesKnown branch, price a cold request (rate 0) at that max rate instead of falling through to tokens. Fall through to token accounting ONLY when !byteMode or !pendingBytesKnown. Single-KV and no-byte-mode paths are arithmetically unchanged. pooledRemainingTokens applies the SAME cold-rate substitution so the capacity feed stays equivalent to the gate. Tests (revert-verified): cold mixed-KV request charged in bytes (rejects an over-pool burst the token fallback admitted), single-KV boundary unchanged, and an admits<->remaining equivalence sweep across byte/cold/ token/pending-unknown paths.
The cold-slot pooled gate (scheduler.go) and the capacity feed (registry.go) comments still described the pre-fix behavior where a cold request (no reported KV rate) fell to token accounting. After the Fix 3 cold-rate substitution, a byte-reconstructable pool prices cold requests in bytes at the box's max resident rate in both the gate and the feed. Comment-only; no behavior change. (Flagged by both PR #524 reviewers.)
ethenotethan
left a comment
There was a problem hiding this comment.
Automated Code Review — Layr-Labs/d-inference#
Verdict: COMMENT
Security — ⚠️ SKIPPED
Error: OpenRouter HTTP 402: {"error":{"message":"Insufficient credits. Add more using https://openrouter.ai/settings/credits","code":402}}
Performance — ⚠️ SKIPPED
Error: OpenRouter HTTP 402: {"error":{"message":"Insufficient credits. Add more using https://openrouter.ai/settings/credits","code":402}}
Type_diligence — ⚠️ SKIPPED
Error: OpenRouter HTTP 402: {"error":{"message":"Insufficient credits. Add more using https://openrouter.ai/settings/credits","code":402}}
Additive_complexity — ⚠️ SKIPPED
Error: OpenRouter HTTP 402: {"error":{"message":"Insufficient credits. Add more using https://openrouter.ai/settings/credits","code":402}}
✅ All four passes clean. No issues found.
🤖 Automated review by Centaur · DAR-186
Refresh #526's stacked base onto the final-round #524 (fix/per-model-quality-caps): KV-rate overflow clamp, chip-CLASS solo keying + min-of-class cross-chip fallback, byte-priced cold requests, and cold-path docs. registry.go ModelCapacitySnapshot composition holds both concerns: below-floor providers are dropped from the public capacity feed AND per-model pooled remaining is byte-aware with cold-byte pricing. scheduler.go auto-merged clean. Composition guard TestModelCapacitySnapshotFlooredByteModeComposition still green under #524's cold-byte pricing.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1a4d25e83c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
ethenotethan
left a comment
There was a problem hiding this comment.
Automated Code Review — Layr-Labs/d-inference#
Verdict: REQUEST_CHANGES
Security — 4 finding(s) (1 blocking)
- 🟡 [MEDIUM]
coordinator/registry/pooled_admission.go:47— maxKVBytesPerToken constant may be insufficient for legitimate use cases- Suggestion: Consider making this configurable or document the rationale for 16 MiB limit
- 🔵 [INFO]
coordinator/registry/pooled_admission.go:95-105— Integer overflow protection relies on saturation at MaxInt64- Suggestion: Add explicit overflow checks before multiplication
- 🔵 [INFO]
coordinator/registry/concurrency_cap.go:164-170— parseModelFloatMap filters NaN/Inf but may miss edge cases- Suggestion: Consider using math.IsNaN and math.IsInf consistently throughout codebase
- 🔵 [INFO]
coordinator/registry/solo_tps.go:41-44— RecordSolo accepts empty chipClass parameter- Suggestion: Add validation to reject empty chipClass parameter
Performance — 3 finding(s) (2 blocking)
- 🟡 [MEDIUM]
coordinator/registry/pooled_admission.go:101-107— Potential overflow in addPooledKVByteCharge multiplication without bounds checking- Suggestion: Add explicit overflow check before multiplication: if tokens > (math.MaxInt64-total)/rate { return math.MaxInt64 }
- 🟡 [MEDIUM]
coordinator/registry/pooled_admission.go:195-210— Multiple overflow-prone multiplications in pooled budget reconstruction- Suggestion: Use addPooledKVByteCharge helper for all token*rate calculations to prevent overflow
- 🔵 [INFO]
coordinator/registry/concurrency_cap.go:164— Map allocation without size hint in parseModelFloatMap- Suggestion: Pre-allocate map with estimated size: out := make(map[string]float64, len(pairs))
Type_diligence — 4 finding(s) (4 blocking)
- 🟡 [MEDIUM]
coordinator/registry/concurrency_cap.go:164-167— math.IsNaN and math.IsInf checks without proper error handling for strconv.ParseFloat- Suggestion: Add explicit type assertion check for the ParseFloat result before using math.IsNaN/IsInf, or handle the error case more explicitly to ensure v is a valid float64
- 🟡 [MEDIUM]
coordinator/registry/pooled_admission.go:104-107— Integer overflow check uses division without verifying divisor is non-zero- Suggestion: Add explicit check for rate > 0 before the division: if rate <= 0 { return total }; if tokens > (math.MaxInt64-total)/rate { return math.MaxInt64 }
- 🟡 [MEDIUM]
coordinator/registry/pooled_admission.go:271-274— Map access without checking if key exists in kvBytesPerToken- Suggestion: Use safe map access pattern: if rate, ok := pool.kvBytesPerToken[pr.Model]; ok { ... } else { rate = resolvedPooledKVBytesPerToken(...) }
- 🟡 [MEDIUM]
coordinator/registry/pooled_admission.go:315-318— Map access without checking if modelRate key exists- Suggestion: Add bounds check or use safe map access pattern for pool.kvBytesPerToken[modelRate] lookup
Additive_complexity — 5 finding(s) (2 blocking)
- 🔵 [INFO]
coordinator/registry/concurrency_cap.go:37-80— Multiple new environment variables added for per-model TPS configuration- Suggestion: Consider consolidating these configuration options or providing a single configuration file approach instead of multiple environment variables
- 🟡 [MEDIUM]
coordinator/registry/pooled_admission.go:1-331— Entire new file with complex pooled admission logic duplicating existing admission patterns- Suggestion: Consider refactoring existing admission logic to accommodate pooled budgets rather than creating parallel admission paths
- 🟡 [MEDIUM]
coordinator/registry/solo_tps.go:1-156— New solo TPS tracking system parallel to existing TPS registry- Suggestion: Consider extending the existing TPSRegistry with solo tracking capabilities rather than creating a separate parallel system
- 🔵 [INFO]
coordinator/registry/scheduler.go:1234-1268— fillSnapshotPendingAndPool duplicates pending request aggregation logic- Suggestion: Extract common pending request aggregation into a shared helper method
- 🔵 [INFO]
coordinator/registry/concurrency_cap.go:185-241— soloModelTPS struct with single field and complex resolver chain- Suggestion: Consider simplifying the resolver chain or using a more direct approach for rate resolution
16 finding(s) total, 9 blocking. Verdict: REQUEST_CHANGES.
🤖 Automated review by Centaur · DAR-186
Dismissed after all associated threads were addressed or resolved on later commits. The PR is now at 85817ad, independently reviewed, and the final coordinator race suite, vet, build, and required checks pass.

Per-model solo-TPS quality caps and pooled KV admission
Problem
The 2026-07-06 Gemma serving incident exposed two coordinator-side admission failures.
First, the quality-concurrency cap used
resolvedDecodeTPS(p), the provider-level registration benchmark, for every model on a mixed-model box. A box benchmarked on gpt-oss at 58-93 tok/s therefore granted Gemma caps of 12-23 even though Gemma's own 10-18 tok/s solo rate warrants approximately 1-2 concurrent decodes. The coordinator concentrated 8-11 Gemma requests on boxes that collapse beyond small batches.Second,
freeMemoryAdmitstreated each model slot's token budget as private and counted only same-model pending work. In reality, every slot exposes its own committed tokens plus the same physical KV-cache headroom. Co-resident models could spend that shared pool twice during the heartbeat gap, and token-only accounting could not compare models with different KV bytes per token.Review of the accumulated byte and chip-class follow-ups found three final gaps:
What changed
Per-model quality caps
TPSRegistry. Heartbeats record a solo sample only when the whole provider has at most one running-or-waiting request, and only for the slot that has an actual running decode. Idle slots and queued-only slots cannot repeatedly contribute retained EWMA values.ChipFamily|ChipTier) so an M4 Max rate is not treated as an M4 Pro rate. Cross-class transfer uses the minimum per-class median rather than a sample-weighted fleet median.resolvedSoloModelTPSLockedas the static rate source for quality caps. The final resolver order is: trusted same-class median; minimum cross-class median bounded above by the configured seed when one exists; the seed when no cross-class median is trusted; then the prior provider-level benchmark behavior. Same-class organic evidence still supersedes the seed, while faster-class data cannot widen an unsampled class above its configured cold-start estimate.NaN, and infinite values in the shared per-model float-map parser.EIGENINFERENCE_QUALITY_CAP_PER_MODEL_TPS=falseas the kill switch that restores the provider-level benchmark behavior.Shared KV-pool admission
providerPooledTokenBudgetto reconstruct one provider-wide pool from all backend slots. Live used capacity adds across slots; shared free headroom is counted once; committed potential is retained only as the pending de-duplication baseline.int64accounting.pooledBudgetAdmitsnow charges every coordinator-pending model before admitting a new request.resolvedPooledKVBytesPerToken. A resident model keeps its clamped reported rate; a cold model with no resident slot usesmax(400,000 B/token coordinator default, highest resident rate), clamped by the existing 16 MiB/token overflow ceiling. The same policy prices both the incoming cold request and already-pending cold work, so an unknown large-KV model cannot borrow a smaller resident model's rate or disable byte accounting.addPooledKVByteCharge, and division-based admission comparisons, so a large pending or incoming charge rejects instead of wrapping anint64product.freeMemoryAdmitsandModelCapacitySnapshot; another model's pooled headroom cannot widen it. Positive-budget co-residents remain usable, and zero-budget slot rates remain available for pending and capacity math.pooledRemainingTokensso/v1/modelsand/v1/models/capacityexpose the same byte-aware pooled headroom that admission enforces.Commit history
9b69fee7c397dc46ac482fe0ef179d083ba518ccba8ad3685edbe165942429famasterinto the branchcd7039cc1ddb69db34b733088f0a28b81a4d25e896b3dc298872e7445e5024f8master, including #527 capacity-rate accounting85817ad2The final merge preserves #527's capacity-rate lifecycle accounting and this PR's pooled-admission and capacity-snapshot behavior without conflicts.
Behavior: Before and after
flowchart TB subgraph Before["Before"] A1["Gemma request reaches mixed-model provider"] --> B1["Cap uses provider-level gpt-oss benchmark"] B1 --> C1["Gemma receives an over-wide concurrency cap"] C1 --> D1["Batch grows and per-request decode collapses"] E1["Co-resident model requests"] --> F1["Per-slot token checks count same-model pending only"] F1 --> G1["Both models spend the same KV headroom"] H1["Cold large-KV model has no resident slot"] --> I1["Request and pending work borrow resident KV rates"] I1 --> J1["Shared pool is undercharged"] K1["Slow chip class has no samples"] --> L1["Fast-class samples run before conservative seed"] L1 --> M1["Slow class can receive a fast-class cap"] N1["V2 model reports positive KV rate and zero budget"] --> O1["Zero is treated as legacy omission"] O1 --> P1["Co-resident pooled headroom admits a known-full model"] end subgraph After["After"] A2["Gemma request reaches mixed-model provider"] --> B2["Cap uses static model and chip-class solo rate"] B2 --> C2["Concurrency stays near the model quality floor"] E2["Co-resident model requests"] --> F2["Per-slot limit plus provider-wide byte pool"] F2 --> G2["All-model pending work is charged once"] H2["Cold model has no resident slot"] --> I2["Resolve conservative cold-model KV rate"] I2 --> J2["Use the same rate for incoming and pending work"] K2["Chip class has no trusted same-class median"] --> L2["Bound cross-class transfer by the operator seed"] L2 --> M2["Fallback remains conservative until local samples exist"] N2["V2 model reports positive KV rate and zero budget"] --> O2["Treat zero as authoritative model-local capacity"] O2 --> P2["Admission and capacity reject it without blocking positive-budget models"] endCode: Before and after
flowchart LR subgraph BeforeCode["Before"] H1["Heartbeat"] --> R1["Record load-inclusive TPS"] R1 --> D1["resolvedDecodeTPS provider rate"] D1 --> C1["effectiveMaxConcurrencyForModelLocked"] S1["snapshotProviderLockedEx or quickCapacityCheck"] --> F1["freeMemoryAdmits"] F1 --> P1["Per-slot budget plus same-model pending"] Z1["Positive KV rate plus zero max"] --> U1["Falls through as budget unavailable"] U1 --> F1 end subgraph AfterCode["After"] H2["Heartbeat"] --> G2["soloSampleEligible plus NumRunning"] G2 --> R2["TPSRegistry.RecordSolo by model and chip class"] R2 --> D2["resolvedSoloModelTPSLocked"] D2 --> C2["hasConcurrencyHeadroomForModelCapResolvedLocked"] C2 --> W2["routing, preflight, final admit, capacity feed, warm pool"] S2["snapshotProviderLockedEx or quickCapacityCheck"] --> A2["fillSnapshotPendingAndPool"] A2 --> B2["providerPooledTokenBudget"] A2 --> K2["resolvedPooledKVBytesPerToken"] K2 --> O2["addPooledKVByteCharge saturates pending bytes"] B2 --> F2["freeMemoryAdmits plus pooledBudgetAdmits"] K2 --> F2 B2 --> P2["pooledRemainingTokens"] K2 --> P2 P2 --> M2["ModelCapacitySnapshot"] Z2["Positive KV rate plus zero max"] --> Q2["knownZeroTokenBudget"] Q2 --> F2 Q2 --> M2 endConfiguration
EIGENINFERENCE_QUALITY_CAP_PER_MODEL_TPStruefalserestores the provider-level rate at every cap site.EIGENINFERENCE_QUALITY_CAP_SOLO_MIN_SAMPLES5EIGENINFERENCE_MODEL_SOLO_TPS_SEEDbuild-id=tok/svalues, matched case-insensitively. For an unsampled class, broader organic data is capped at this seed; trusted same-class samples still take precedence.These settings are parsed at coordinator startup. Pooled admission has no feature flag.
At the single integrated coordinator deployment, the planned seed remains:
Remove the interim
EIGENINFERENCE_QUALITY_CONCURRENCY_OVERCOMMIT_BY_MODEL=gemma-4-26b-qat-4bit=0.15at that same integrated deployment; this PR supersedes it.Test coverage
The current diff contains focused regression coverage for:
ModelCapacitySnapshotequivalence in token and byte modes.Readiness regressions added to the final head:
TestPooledFirstColdRequestUsesConservativeDefault: an incoming cold large-KV request usesmax(400,000 B/token default, highest resident rate)rather than the maximum resident rate alone; public pooled remaining uses the same policy.TestPooledPendingColdRequestKeepsByteAccounting: already-pending cold work is normalized with the same conservative default policy and cannot force token-mode or optimistic resident-rate accounting for the next request.TestQualityCapSeedBoundsCrossClassTransfer: an unsampled slow chip class remains capped by the operator seed even when a faster class has enough organic samples.TestResolvedSoloModelTPSFallbackChain: trusted same-class organic samples still supersede the cold-start seed after reaching the sample floor.TestPooledKnownZeroBudgetRejects: a single Engine V2 positive-rate/zero-max slot is known-full, while a true legacy slot remains unconstrained.TestPooledZeroBudgetResidentRateStaysSymmetric: a mixed provider retains the zero-budget resident's reported rate across pending, admission, and capacity; that model rejects even with abundant pooled headroom while its positive-budget co-resident still admits.Final verification:
-racego test ./... -race -count=1go vet ./...go build ./cmd/coordinatorgofmt -lon changed Go files andgit diff --checkbroadcast_shapes: incompatible(5,1)/(20,1)and(3,1)/(6,1)shapes). Currentmasterat9b1d3b02failed the same test with the same MLX fatal error in run 29045836408; the PR run is 29048151439. This coordinator-only PR does not modify the provider, MLX submodules, or E2E tests.Merge and release sequence
This PR is merge group A, not a coordinator deployment unit.
mastersync, review threads, and final checks are complete.Do not partially deploy #524, #525, or #526. Do not deploy the new coordinator before the complete one-engine v0.7.5 provider release has been published, validated, and canaried.
At the eventual integrated deployment, verify mixed-box Gemma caps, per-chip-class sample counts, pooled-budget rejection reasons, public capacity/admission symmetry, and gpt-oss TTFT/TPS. The quality-cap rollback is
EIGENINFERENCE_QUALITY_CAP_PER_MODEL_TPS=false; pooled admission requires rolling back the integrated coordinator artifact.Review notes
master, including fix(routing): correct capacity-rate window accounting #527, is merged at5e5024f8; final verification ran on descendant85817ad2.Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.