Skip to content

feat(router): add policy-class queues - #10744

Merged
PeaBrane merged 25 commits into
mainfrom
codex/policy-class-queues
Jun 23, 2026
Merged

PeaBrane merged 25 commits into
mainfrom
codex/policy-class-queues

Conversation

@PeaBrane

@PeaBrane PeaBrane commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add startup-only policy-family/cache-bucket queue configuration through --router-policy-config / DYN_ROUTER_POLICY_CONFIG, with strict Rust/serde_yaml validation, exact-model profile replacement, root fallback, and the unchanged no-YAML synthetic default queue.
  • Resolve requested policy family × router-observed uncached-ISL bucket to one physical policy-class queue. A class with both policy_family and cache_bucket is a matrix class; a class with neither is an explicit class that can be selected directly and intentionally bypasses cache-derived classification.
  • Propagate x-dynamo-meta-policy-class through frontend metadata, prefill cloning, standalone routing, Python bindings, and replay without adding live request-body or nvext fields.
  • Give each physical class independent FCFS/WSPT ordering, busy thresholds, immutable token snapshots, counters, DRR quantum/deficit, and per-worker queue limits.
  • Use work-conserving weighted DRR across dispatchable classes, including bounded bulk virtual rounds for oversized requests. Production routing and offline replay share the same policy queue implementation.
  • Remove main's global missing-ISL admission tier and its backpressure protocol/error path. Allow-list requests now obey normal class admission, backlog, ordering, limits, and DRR while worker selection remains restricted to the supplied allow-list.

Baseten Context

The sample at examples/router/policy-class-queues.yaml models standard and latency policy families across router-observed cached and uncached buckets, plus an explicit custom class. Client policy and cache state are independent inputs: ordinary physical-class names cannot bypass cache classification, while a class that omits both binding fields is a trusted explicit override.

Compatibility

The policy YAML is a new startup-only surface in this PR. Earlier draft schema names are intentionally not supported, and the replacement for main's missing-ISL admission behavior is intentionally non-equivalent.

  • The no-YAML path remains one synthetic default queue using the existing router_queue_threshold and router_queue_policy, with no queue limits.
  • Earlier draft YAML fields such as default_policy_class, uncached_isl_policy_class_tiers, explicit_only, and absolute queue-limit fields are absent from the strict schema and fail as unknown YAML fields.
  • Main's router_queue_by_incoming_missing_isl field is removed from KvRouterConfig without a compatibility parser and fails normal router-config deserialization as an unknown field.
  • Queue limits use only request_queue_limit_per_worker, raw_isl_token_queue_limit_per_worker, and cached_token_queue_limit_per_worker. Effective totals are computed from the current discovered endpoint count at admission; worker removal affects future admission but does not evict queued requests.
  • There is no hidden first-stage queue or global cross-class cap. This removes main's worker-scaled global cap, HTTP 429 overload response, and instance-wide overload exclusion.
  • Class-local limit rejection returns typed QueueRejection, HTTP 503, and Python RouterQueueLimitExceeded, exposing the resolved physical class and computed effective total.
  • Model profiles completely replace the root profile, including families, buckets, classes, thresholds, and limits.
  • SLA/TTFT due-time scheduling, hot reload, persistent process-level E2Es, and pre-existing cancellation lifecycle issues remain out of scope.

Validation

  • cargo test -p dynamo-kv-router --lib: 608 passed.
  • cargo test -p dynamo-kv-router --lib --features standalone-selection: 654 passed.
  • cargo test -p dynamo-mocker --lib: 371 passed, 1 ignored.
  • cargo test -p dynamo-llm --lib --no-default-features: 1109 passed, 3 ignored.
  • .venv/bin/python -m pytest components/src/dynamo/common/tests/configuration/test_kv_router_args.py -q: 31 passed.
  • Python and C binding Rust suites: 2 passed in each nested workspace.
  • Strict formatting and clippy passed for KV router, mocker, Python bindings, and lib/llm --no-default-features.
  • Focused regressions cover family/bucket boundaries, explicit precedence, ordinary-class anti-bypass, stale replay cache entries, per-worker limits, actor-local bounded draining, overlap refresh, and allow-list backlog participation with allowed-worker dispatch.
  • Default and mapped 1,000-request Mooncake replays both completed 1,000/1,000 requests with identical simulated duration, TTFT/ITL distributions, request throughput, and cache reuse. Report SHA-256 values: default 126c11116fcaf9990f5a765368ac5456da53b5acfa7b3addf74d41ff197334d4; mapped 86e8bb1ac65d630856de1418fdb0b3ddd4f3686e8ca4f3bf271a804a80ddac52.
  • An adversarial 12-request family/bucket replay completed without warnings or errors. Report SHA-256: 4a7b90ed9944d1f867be551e76dfb82dab630a86882634dfa95506097d601e6a.
  • Alternating release-like 100-iteration timings averaged 6.117s for the synthetic path and 5.973s for the mapped path. Samply showed no classifier or policy-queue function in the sampled hot set.
  • Temporary replay/profiling instrumentation and repository-local diagnostics were removed.

Persistent process-level E2Es remain deferred to a follow-up PR.

Implements a scoped subset of #9755.

PeaBrane added 2 commits June 15, 2026 22:27
Signed-off-by: PeaBrane <yanrpei@gmail.com>
Signed-off-by: PeaBrane <yanrpei@gmail.com>
@github-actions github-actions Bot added feat documentation Improvements or additions to documentation frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` router Relates to routing, KV-aware routing, etc. and removed feat labels Jun 16, 2026
Signed-off-by: PeaBrane <yanrpei@gmail.com>
@github-actions

github-actions Bot commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

PeaBrane added 2 commits June 15, 2026 22:46
Signed-off-by: PeaBrane <yanrpei@gmail.com>
Signed-off-by: PeaBrane <yanrpei@gmail.com>
Signed-off-by: PeaBrane <yanrpei@gmail.com>
@PeaBrane
PeaBrane marked this pull request as ready for review June 16, 2026 06:11
@PeaBrane
PeaBrane requested review from a team as code owners June 16, 2026 06:11
@PeaBrane
PeaBrane requested a review from a team June 16, 2026 06:11
@PeaBrane
PeaBrane requested review from a team as code owners June 16, 2026 06:11

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@coderabbitai

coderabbitai Bot commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds per-request policy-class queuing to the KV router. A new --router-policy-config YAML option defines named policy classes with per-class scheduling policies, queue limits, and busy thresholds. A multi-class deficit-round-robin PolicyQueue replaces the prior single-heap scheduler. The policy_class field is threaded from HTTP headers (x-dynamo-meta-policy-class) and trace data through routing, replay pipelines, metrics (per-class labels), and Python/CLI surfaces; rejections surface as structured 503 responses and a new RouterQueueLimitExceeded exception.

Changes

Policy-Class Queuing Feature

Layer / File(s) Summary
Policy config parsing and multi-class queue primitives
lib/kv-router/src/scheduling/policy_config.rs, lib/kv-router/src/scheduling/policy_queue.rs, lib/kv-router/src/scheduling/mod.rs, lib/kv-router/Cargo.toml, lib/runtime/src/config/environment_names.rs, examples/router/policy-class-queues.yaml
New RouterPolicyConfig/PolicyProfile/PolicyClassConfig YAML parsing with strict validation; PolicyQueue<T> implements multi-class deficit-round-robin with per-class limits and typed QueueRejection. New submodules declared, public types re-exported, serde_yaml dependency and DYN_ROUTER_POLICY_CONFIG constant added.
KvRouterConfig: replace queue-tier field with router_policy_config
lib/kv-router/src/scheduling/config.rs, lib/bindings/python/rust/llm/entrypoint.rs, lib/bindings/python/src/dynamo/_core.pyi, components/src/dynamo/common/configuration/groups/kv_router_args.py, components/src/dynamo/common/tests/...
Removes router_queue_by_incoming_missing_isl; adds router_policy_config: Option<String> + OnceLock-cached policy state; adds policy_profile(), with_policy_model_name(), configured_policy_profile() methods; KvRouterConfigSerde gains deny_unknown_fields; env-var lookup extended; Python constructor updated; Python CLI arg and tests updated.
SchedulerQueue and LocalScheduler refactored to PolicyQueue-backed class-based admission
lib/kv-router/src/scheduling/queue.rs, lib/kv-router/src/scheduling/local.rs, lib/kv-router/src/scheduling/types.rs, lib/kv-router/src/scheduling/selector.rs, lib/kv-router/src/scheduling/policy.rs
Removes SchedulingPolicy generic from SchedulerQueue/LocalScheduler; replaces BinaryHeap+threshold_frac with PolicyQueue<QueuedRequest> and per-class atomic counters; rewrites handle_enqueue and handle_update with class-index resolution, PolicyQueue.enqueue/pop_next, and per-class prefill-busy checks; adds class_queue_stats(); SchedulingRequest gains policy_class; KvSchedulerError gains QueueRejected. Test fixtures updated throughout.
KvRouter, SelectionCore, and KvScheduler wired with policy_class; per-class metrics
lib/llm/src/kv_router.rs, lib/llm/src/kv_router/scheduler.rs, lib/llm/src/kv_router/push_router/..., lib/llm/src/kv_router/prefill_router/query.rs, lib/llm/src/kv_router/metrics.rs, lib/kv-router/src/services/selection/..., lib/kv-router/src/protocols.rs, lib/bindings/c/src/lib.rs
FindBestMatchOutcome::QueueRejected added; find_best_match_details_with_policy_class() introduced; AsyncEngine extracts policy-class metadata; RouterResponse::QueueRejected added to wire protocol; SelectionCore gains *_with_policy_class() methods; SelectionServer reads x-dynamo-meta-policy-class header; SelectionError maps QueueRejected to 503 with structured details; KvScheduler.start gains model_name, builds per-class metric handles; router queue metrics gain pending_cached_tokens, model/policy_class labels, and a handles() API.
RouterQueueLimitExceeded exception and HTTP 503 structured error
lib/bindings/python/rust/errors.rs, lib/bindings/python/src/dynamo/llm/exceptions.py, lib/bindings/python/src/dynamo/llm/__init__.py, lib/bindings/python/src/dynamo/_core.pyi, lib/llm/src/http/service/openai.rs, lib/bindings/python/rust/llm/kv.rs, lib/llm/src/http/service/metadata.rs
RouterQueueLimitExceeded Python exception created via create_exception!, queue_rejection_to_pyerr converts QueueRejection to PyErr; Python fallback defined in exceptions.py; ErrorMessage gains optional details field; find_queue_rejection_in_chain walks error chain to return 503 with structured rejection payload; KvRouter.best_worker Python binding accepts policy_class.
policy_class propagated through trace data model and replay routers
lib/data-gen/src/mooncake.rs, lib/mocker/src/loadgen/types.rs, lib/mocker/src/loadgen/trace.rs, lib/mocker/src/loadgen/driver.rs, lib/mocker/src/common/protocols.rs, lib/mocker/src/replay/offline/components/router.rs, lib/mocker/src/replay/online/router.rs, lib/mocker/src/replay/router_shared.rs, lib/mocker/src/replay/online/live_runtime.rs, lib/mocker/src/replay/offline/state.rs, lib/mocker/src/replay/online/tests.rs
MooncakeRow/TurnTrace/DirectRequest gain policy_class; trace loaders propagate it; OfflineReplayRouter replaces BinaryHeap+threshold with PolicyQueue<PendingRequest>+PolicyProfile; OnlineReplayRouter uses new_with_policy_profile and schedule_with_policy_class_and_block_hashes; ReplayRouter::new returns Result; ReplayScheduler type alias drops RouterSchedulingPolicy generic; replay_policy helper removed.
Python/CLI replay API: model_name and router-policy-config wiring
components/src/dynamo/replay/main.py, components/src/dynamo/replay/api.py, components/src/dynamo/mocker/__init__.py, lib/bindings/python/rust/llm/replay.rs, lib/bindings/python/src/dynamo/_core.pyi, lib/bindings/python/tests/replay/*
run_trace_replay/run_synthetic_trace_replay gain model_name; replay/main.py adds _load_router_config() helper, --router-policy-config/--model-name CLI flags, threads both into all replay entry points and PlannerReplayBridge; PyO3 replay functions and PlannerReplayBridge constructors accept model_name; load_replay_router_config applies with_policy_model_name; Python tests verify forwarding and override behavior.
Documentation
docs/components/frontend/configuration.md, docs/components/router/router-configuration.md, docs/dynosim/runs.md, docs/observability/metrics.md
Documents --router-policy-config/DYN_ROUTER_POLICY_CONFIG in frontend config table; adds Policy-Class Queues section to router-configuration.md; documents policy_class trace field and --model-name in DynoSim; expands router queue metrics section with new gauges, labels, and enablement conditions.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
lib/bindings/python/rust/llm/entrypoint.rs (1)

277-282: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate configs loaded through from_json.

KvRouterConfig.__init__ validates the constructed config, but from_json returns the parsed RsKvRouterConfig directly. That lets router_policy_config supplied via JSON bypass the strict policy YAML validation path until a later startup/use site.

Suggested fix
     fn from_json(config_json: &str) -> PyResult<Self> {
         let inner = serde_json::from_str::<RsKvRouterConfig>(config_json).map_err(|e| {
             PyException::new_err(format!("Failed to parse KvRouterConfig JSON: {e}"))
         })?;
+        validate_kv_router_config(&inner)?;
         Ok(KvRouterConfig { inner })
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/bindings/python/rust/llm/entrypoint.rs` around lines 277 - 282, The
from_json method in KvRouterConfig parses the JSON string into RsKvRouterConfig
but returns it directly without applying the same validation that occurs in the
__init__ method, allowing invalid router_policy_config to bypass validation.
After parsing the JSON with serde_json::from_str and before constructing the
KvRouterConfig return value, apply the same validation logic that __init__ uses
to ensure the inner RsKvRouterConfig is properly validated, including strict
policy YAML validation.
lib/kv-router/src/scheduling/types.rs (1)

48-78: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Classify QueueRejected as overload.

QueueRejected is the new policy-queue capacity/backpressure path, but is_overload() still returns false for it. Any caller using this helper for overload/retry/metrics classification will treat a full policy-class queue as a generic scheduler error.

Suggested fix
             self,
             Self::Backpressure { .. }
+                | Self::QueueRejected(_)
                 | Self::AllEligibleWorkersOverloaded
                 | Self::PinnedWorkerOverloaded { .. }
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/kv-router/src/scheduling/types.rs` around lines 48 - 78, The
is_overload() method in the KvSchedulerError implementation does not classify
QueueRejected as an overload condition. Update the matches! pattern within
is_overload() to include Self::QueueRejected as one of the conditions that
should return true, alongside the existing checks for Backpressure,
AllEligibleWorkersOverloaded, and PinnedWorkerOverloaded variants. This ensures
that callers using is_overload() for classification will correctly treat a full
policy-class queue (represented by QueueRejected) as an overload scenario.
lib/bindings/python/src/dynamo/_core.pyi (2)

1711-1740: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep overlap_score_credit_decay in the Python stub API.

The Rust binding exposes overlap_score_credit_decay in KvRouterConfig.__init__, the property accessors, and with_overrides, but the stub omits it. Valid Python calls are therefore rejected by type checkers.

Suggested stub alignment
         *,
         overlap_score_credit: float = 1.0,
+        overlap_score_credit_decay: float = 0.0,
         prefill_load_scale: float = 1.0,
         router_policy_config: Optional[str] = None,
@@
     `@property`
     def overlap_score_credit(self) -> float: ...
 
     `@overlap_score_credit.setter`
     def overlap_score_credit(self, value: float) -> None: ...
+    `@property`
+    def overlap_score_credit_decay(self) -> float: ...
+
+    `@overlap_score_credit_decay.setter`
+    def overlap_score_credit_decay(self, value: float) -> None: ...
@@
         *,
         overlap_score_credit: Optional[float] = None,
+        overlap_score_credit_decay: Optional[float] = None,
         prefill_load_scale: Optional[float] = None,
     ) -> "KvRouterConfig": ...

Also applies to: 1815-1821

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/bindings/python/src/dynamo/_core.pyi` around lines 1711 - 1740, The
Python stub file is missing the `overlap_score_credit_decay` parameter that is
exposed in the Rust binding's KvRouterConfig. Add the
`overlap_score_credit_decay` parameter to the __init__ method in KvRouterConfig
at the current location, ensuring it is placed with appropriate type hints and
default value alongside the other keyword-only parameters. Additionally, apply
the same change to the property accessors and with_overrides method at lines
1815-1821 to maintain consistency across all exposed interfaces in the stub
file, ensuring type checkers recognize valid Python calls that match the Rust
binding's actual API.

2292-2316: ⚠️ Potential issue | 🟠 Major

Fix positional parameter order in PlannerReplayBridge signatures.

Both __init__ and create_disagg place model_name before arrival_speedup_ratio and trace_block_size, breaking positional compatibility. A call like PlannerReplayBridge(..., router_config, 2.0, 512) now incorrectly binds 2.0 as model_name instead of arrival_speedup_ratio.

Move model_name after the existing numeric parameters or make it keyword-only in both the stub (lib/bindings/python/src/dynamo/_core.pyi lines 2299 and 2313) and the Rust PyO3 signature (lib/bindings/python/rust/llm/replay.rs line 1637 for __init__ and the create_disagg signature).

Suggested stub shape
         router_mode: str = "round_robin",
         router_config: Optional[KvRouterConfig] = None,
-        model_name: Optional[str] = None,
         arrival_speedup_ratio: float = 1.0,
         trace_block_size: int = 512,
+        *,
+        model_name: Optional[str] = None,
@@
         router_mode: str = "round_robin",
         router_config: Optional[KvRouterConfig] = None,
-        model_name: Optional[str] = None,
         arrival_speedup_ratio: float = 1.0,
         trace_block_size: int = 512,
+        *,
+        model_name: Optional[str] = None,
     ) -> "PlannerReplayBridge": ...
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/bindings/python/src/dynamo/_core.pyi` around lines 2292 - 2316, The
PlannerReplayBridge class has parameter order issues in both __init__ and
create_disagg methods where model_name is positioned before the numeric
parameters arrival_speedup_ratio and trace_block_size, causing positional
argument binding to fail. Move model_name to appear after trace_block_size (or
make it keyword-only with a leading asterisk) in both method signatures to
restore positional compatibility. Apply this fix to both the Python stub file
lib/bindings/python/src/dynamo/_core.pyi (for both __init__ at line 2299 and
create_disagg at line 2313) and the corresponding Rust PyO3 signatures in
lib/bindings/python/rust/llm/replay.rs (the __init__ signature at line 1637 and
the create_disagg signature).
lib/bindings/python/tests/replay/test_replay_policy_plumbing.py (1)

1-30: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add required pytest category markers to this new test module.

This file currently has no lifecycle/test-type/hardware markers, so marker enforcement can fail for this test.

✅ Suggested fix
+import pytest
+
 import dynamo.replay.api as replay_api
 
+pytestmark = [
+    pytest.mark.gpu_0,
+    pytest.mark.pre_merge,
+    pytest.mark.unit,
+]
+
 
 def test_replay_api_forwards_policy_model_name(monkeypatch):

As per coding guidelines, files under **/tests/**/*.py must follow pytest guidance, and this new test should carry required scheduling/marker metadata. Based on learnings, the required marker categories are Lifecycle (pre_merge), Test Type (unit), and Hardware (gpu_0).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/bindings/python/tests/replay/test_replay_policy_plumbing.py` around lines
1 - 30, The test module test_replay_api_forwards_policy_model_name lacks
required pytest category markers for lifecycle, test type, and hardware
configuration. Import pytest at the top of the file and add three decorator
markers to the test_replay_api_forwards_policy_model_name function:
`@pytest.mark.pre_merge` for lifecycle, `@pytest.mark.unit` for test type, and
`@pytest.mark.gpu_0` for hardware designation. Stack these decorators above the
function definition to ensure proper test categorization and scheduling
compliance.

Sources: Coding guidelines, Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/src/dynamo/common/tests/configuration/test_kv_router_args.py`:
- Around line 405-427: The test functions
test_kv_router_kwargs_preserves_policy_config_path and
test_policy_config_cli_overrides_environment use hardcoded temporary paths like
/tmp/router-policy.yaml, which violates hermeticity and platform independence.
Add the tmp_path pytest fixture as a parameter to both test functions, then
replace all hardcoded /tmp paths with paths derived from tmp_path (e.g., by
converting them to string paths based on tmp_path). This ensures tests use
isolated temporary directories and work correctly across different platforms and
test environments.

In `@lib/bindings/python/src/dynamo/llm/exceptions.py`:
- Around line 16-21: The try/except ImportError block around the
RouterQueueLimitExceeded import is too broad and violates Python guidelines.
Instead of catching all ImportErrors, scope the exception handling to only
suppress the ImportError when the specific symbol cannot be imported from
dynamo._core, and re-raise any unexpected ImportErrors that may indicate other
issues. Capture the exception, check if it is related to the missing
RouterQueueLimitExceeded symbol, define the fallback class only in that case,
and re-raise the exception if it represents a different import failure.

In `@lib/data-gen/src/mooncake.rs`:
- Around line 59-60: The new policy_class field has been added to the trace
schema but lacks focused serialize/deserialize round-trip test coverage. Add
wire-format round-trip assertions for the policy_class field on both affected
row structs: the first struct containing the policy_class field (around line
59-60 in mooncake.rs) and the second struct (around line 94-95 in mooncake.rs).
The tests should verify that the field can be serialized and deserialized
correctly, including edge cases like None values which leverage the
serde(default, skip_serializing_if = "Option::is_none") attributes.
Additionally, verify that existing producer/consumer tests still properly cover
the updated schema shape with this new field.

In `@lib/llm/src/kv_router/prefill_router/query.rs`:
- Around line 73-75: The `QueueRejected` match arm in the pattern matching for
`FindBestMatchOutcome` is converting the rejection to a generic error using
`.into()`, which loses the typed rejection details needed by downstream callers
to distinguish throttling/backpressure failures from other error types. Instead
of converting rejection to a generic error, return a structured error variant or
outcome that preserves the QueueRejected semantics so that callers can reliably
classify it as queue throttling rather than treating it as a generic failure.
This may require defining a mapped error type or outcome variant that retains
the rejection information while fitting the function's return type.

In `@lib/mocker/src/replay/offline/components/router.rs`:
- Around line 564-581: The all_workers_busy_with function currently returns
false when workers_with_configs is empty (because checked_any remains false),
which allows drain_pending to pop items and risk losing them if admission fails.
Modify the return statement to handle the empty workers case: instead of
returning checked_any && !any_worker_not_busy, return true (treat as busy) when
checked_any is false, and otherwise return !any_worker_not_busy as before. This
prevents queue items from being popped when there are no workers available to
accept them.

---

Outside diff comments:
In `@lib/bindings/python/rust/llm/entrypoint.rs`:
- Around line 277-282: The from_json method in KvRouterConfig parses the JSON
string into RsKvRouterConfig but returns it directly without applying the same
validation that occurs in the __init__ method, allowing invalid
router_policy_config to bypass validation. After parsing the JSON with
serde_json::from_str and before constructing the KvRouterConfig return value,
apply the same validation logic that __init__ uses to ensure the inner
RsKvRouterConfig is properly validated, including strict policy YAML validation.

In `@lib/bindings/python/src/dynamo/_core.pyi`:
- Around line 1711-1740: The Python stub file is missing the
`overlap_score_credit_decay` parameter that is exposed in the Rust binding's
KvRouterConfig. Add the `overlap_score_credit_decay` parameter to the __init__
method in KvRouterConfig at the current location, ensuring it is placed with
appropriate type hints and default value alongside the other keyword-only
parameters. Additionally, apply the same change to the property accessors and
with_overrides method at lines 1815-1821 to maintain consistency across all
exposed interfaces in the stub file, ensuring type checkers recognize valid
Python calls that match the Rust binding's actual API.
- Around line 2292-2316: The PlannerReplayBridge class has parameter order
issues in both __init__ and create_disagg methods where model_name is positioned
before the numeric parameters arrival_speedup_ratio and trace_block_size,
causing positional argument binding to fail. Move model_name to appear after
trace_block_size (or make it keyword-only with a leading asterisk) in both
method signatures to restore positional compatibility. Apply this fix to both
the Python stub file lib/bindings/python/src/dynamo/_core.pyi (for both __init__
at line 2299 and create_disagg at line 2313) and the corresponding Rust PyO3
signatures in lib/bindings/python/rust/llm/replay.rs (the __init__ signature at
line 1637 and the create_disagg signature).

In `@lib/bindings/python/tests/replay/test_replay_policy_plumbing.py`:
- Around line 1-30: The test module test_replay_api_forwards_policy_model_name
lacks required pytest category markers for lifecycle, test type, and hardware
configuration. Import pytest at the top of the file and add three decorator
markers to the test_replay_api_forwards_policy_model_name function:
`@pytest.mark.pre_merge` for lifecycle, `@pytest.mark.unit` for test type, and
`@pytest.mark.gpu_0` for hardware designation. Stack these decorators above the
function definition to ensure proper test categorization and scheduling
compliance.

In `@lib/kv-router/src/scheduling/types.rs`:
- Around line 48-78: The is_overload() method in the KvSchedulerError
implementation does not classify QueueRejected as an overload condition. Update
the matches! pattern within is_overload() to include Self::QueueRejected as one
of the conditions that should return true, alongside the existing checks for
Backpressure, AllEligibleWorkersOverloaded, and PinnedWorkerOverloaded variants.
This ensures that callers using is_overload() for classification will correctly
treat a full policy-class queue (represented by QueueRejected) as an overload
scenario.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: be725754-b699-483d-9e5b-d096f0da8dd7

📥 Commits

Reviewing files that changed from the base of the PR and between 7e28276 and 94fe053.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • lib/bindings/kvbm/Cargo.lock is excluded by !**/*.lock
  • lib/bindings/python/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (56)
  • components/src/dynamo/common/configuration/groups/kv_router_args.py
  • components/src/dynamo/common/tests/configuration/test_kv_router_args.py
  • components/src/dynamo/mocker/__init__.py
  • components/src/dynamo/replay/api.py
  • components/src/dynamo/replay/main.py
  • docs/components/frontend/configuration.md
  • docs/components/router/router-configuration.md
  • docs/dynosim/runs.md
  • docs/observability/metrics.md
  • examples/router/policy-class-queues.yaml
  • lib/bindings/c/src/lib.rs
  • lib/bindings/python/rust/errors.rs
  • lib/bindings/python/rust/llm/entrypoint.rs
  • lib/bindings/python/rust/llm/kv.rs
  • lib/bindings/python/rust/llm/replay.rs
  • lib/bindings/python/src/dynamo/_core.pyi
  • lib/bindings/python/src/dynamo/llm/__init__.py
  • lib/bindings/python/src/dynamo/llm/exceptions.py
  • lib/bindings/python/tests/replay/test_replay_cli.py
  • lib/bindings/python/tests/replay/test_replay_policy_plumbing.py
  • lib/data-gen/src/mooncake.rs
  • lib/kv-router/Cargo.toml
  • lib/kv-router/src/protocols.rs
  • lib/kv-router/src/scheduling/config.rs
  • lib/kv-router/src/scheduling/local.rs
  • lib/kv-router/src/scheduling/mod.rs
  • lib/kv-router/src/scheduling/policy.rs
  • lib/kv-router/src/scheduling/policy_config.rs
  • lib/kv-router/src/scheduling/policy_queue.rs
  • lib/kv-router/src/scheduling/queue.rs
  • lib/kv-router/src/scheduling/selector.rs
  • lib/kv-router/src/scheduling/types.rs
  • lib/kv-router/src/services/selection/core/mod.rs
  • lib/kv-router/src/services/selection/error.rs
  • lib/kv-router/src/services/selection/server.rs
  • lib/kv-router/src/services/selection/tests.rs
  • lib/llm/src/http/service/metadata.rs
  • lib/llm/src/http/service/openai.rs
  • lib/llm/src/kv_router.rs
  • lib/llm/src/kv_router/metrics.rs
  • lib/llm/src/kv_router/prefill_router/query.rs
  • lib/llm/src/kv_router/push_router.rs
  • lib/llm/src/kv_router/push_router/selection.rs
  • lib/llm/src/kv_router/scheduler.rs
  • lib/mocker/src/common/protocols.rs
  • lib/mocker/src/loadgen/driver.rs
  • lib/mocker/src/loadgen/tests.rs
  • lib/mocker/src/loadgen/trace.rs
  • lib/mocker/src/loadgen/types.rs
  • lib/mocker/src/replay/offline/components/router.rs
  • lib/mocker/src/replay/offline/state.rs
  • lib/mocker/src/replay/online/live_runtime.rs
  • lib/mocker/src/replay/online/router.rs
  • lib/mocker/src/replay/online/tests.rs
  • lib/mocker/src/replay/router_shared.rs
  • lib/runtime/src/config/environment_names.rs

Comment thread lib/data-gen/src/mooncake.rs Resolved
Signed-off-by: PeaBrane <yanrpei@gmail.com>
Signed-off-by: PeaBrane <yanrpei@gmail.com>
Signed-off-by: PeaBrane <yanrpei@gmail.com>
PeaBrane added 2 commits June 16, 2026 16:04
Signed-off-by: PeaBrane <yanrpei@gmail.com>
Signed-off-by: PeaBrane <yanrpei@gmail.com>
Signed-off-by: PeaBrane <yanrpei@gmail.com>
@datadog-official

This comment has been minimized.

Signed-off-by: PeaBrane <yanrpei@gmail.com>
@PeaBrane
PeaBrane enabled auto-merge (squash) June 23, 2026 21:55
Signed-off-by: PeaBrane <yanrpei@gmail.com>
@PeaBrane
PeaBrane merged commit 62f41e1 into main Jun 23, 2026
101 checks passed
@PeaBrane
PeaBrane deleted the codex/policy-class-queues branch June 23, 2026 23:37

This branch had an error being deployed

1 failed deployment
GITLAB — 2429b50c Deployed Jun 24, 2026 by copy-pr-bot[bot] via Trigger CI Pipeline #31800
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation feat frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` router Relates to routing, KV-aware routing, etc. size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants