Skip to content

feat(pylon): handle Dynamo request-priority headers in Pylon - #673

Draft
along-2017 wants to merge 14 commits into
mainfrom
feat/pylon/dynamo-priority-header
Draft

feat(pylon): handle Dynamo request-priority headers in Pylon#673
along-2017 wants to merge 14 commits into
mainfrom
feat/pylon/dynamo-priority-header

Conversation

@along-2017

@along-2017 along-2017 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Pylon now translates the platform's x-priority header into Dynamo's x-dynamo-request-priority when forwarding to the upstream inference server, and strips any client-supplied x-dynamo-request-* header so spoofed values never reach the engine.

Additional Details

Dynamo schedules on x-dynamo-request-priority (i32, higher wins) and silently ignores values that do not parse as i32. The platform resolves a caller priority and carries it as x-priority (u32, lower is more urgent, absent means unconfigured). Without translation the engine never sees the platform priority; without the strip a client could set engine priority directly.

Pylon is the single contract point with the engine, so both pieces live only here; the gateway and Stargate stay Dynamo-agnostic.

  • Mapping: i32::MAX - min(x, i32::MAX). Inverts polarity and always produces a valid i32, so Dynamo never drops it.
  • The header is emitted only when x-priority is present on the request. Absent stays absent, so unconfigured traffic is never promoted to maximum engine priority. Health requests are excluded.
  • Derivation has a default-on kill switch: --pylon-derive-dynamo-priority (env PYLON_DERIVE_DYNAMO_PRIORITY). The strip is not gated, so disabling the feature cannot re-open header spoofing.
  • The emitted value is logged at info with the request id and recorded on the upstream request span.
  • mock-dynamo records the priority headers seen on the latest request per endpoint and model in GET /test-control.
  • The pylon and mock-dynamo crates had no Bazel test targets, so their in-crate tests never ran in CI. Both gain a rust_test target here.

For the Reviewer

The behavior change is concentrated in send_upstream_request and should_forward_header in crates/pylon-lib/src/quic_http_tunnel/core.rs. Everything else is plumbing (CLI flag to forwarding config), the mock-dynamo fixture, and tests.

Two known follow-ups, deliberately not in this PR: the per-request info log may be demoted to debug once QA validation is done.

For QA

  • bazel test //src/libraries/rust/stargate/... passes (14 targets, includes the two new ones).
  • New QUIC tunnel tests pin the contract end to end: the derived value reaches the backend, spoofed x-dynamo-request-* headers do not, absent x-priority emits nothing, and disabling the flag stops emission but not the strip.
  • Unit tests pin the mapping boundaries (0, i32::MAX, u32::MAX) and the presence rule.
  • On a live cluster, grep Pylon logs for derived dynamo request priority or query mock-dynamo's /test-control.

Issues

Closes #620

Checklist

  • I am familiar with the Contributing Guidelines.
  • I have signed off my commits for Developer Certificate of Origin (DCO) compliance.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

Summary by CodeRabbit

  • New Features

    • Added configurable upstream backend selection, including Dynamo and passthrough modes.
    • Added configurable priority ceilings for upstream request handling.
    • Validated request priorities are now derived and forwarded using backend-specific priority headers.
    • Engine-owned headers are removed before forwarding to prevent conflicting values.
    • Added command-line and environment configuration for backend and priority settings.
  • Bug Fixes

    • Requests without an explicit priority now remain distinct from rank-zero requests.
  • Documentation

    • Updated API gateway documentation with priority header behavior and backend handling.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 201f6517-b232-4935-987d-c7efcfbffe04

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Pylon now supports configurable Dynamo and passthrough upstream backends. It preserves optional x-priority, derives bounded Dynamo priority headers, strips inbound engine headers, propagates CLI settings, and validates the behavior with unit and integration tests.

Changes

Dynamo priority handling

Layer / File(s) Summary
Backend dialect and forwarding contract
src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel/backend.rs, src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel/core.rs, src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel.rs, src/libraries/rust/stargate/crates/pylon-lib/src/lib.rs
Adds UpstreamBackend, DEFAULT_PRIORITY_CEILING, Dynamo header constants, bounded priority conversion, and forwarding configuration fields.
Optional priority and queue normalization
src/libraries/rust/stargate/crates/pylon-lib/src/request_observer/..., src/libraries/rust/stargate/crates/pylon-lib/src/queue_admission.rs, src/libraries/rust/stargate/crates/pylon-lib/src/bringup/upstream.rs, src/libraries/rust/stargate/crates/pylon-lib/src/stats/collector.rs
Preserves absent priority as None and converts it to zero only for queue accounting and request tracking.
CLI configuration and startup propagation
src/libraries/rust/stargate/crates/pylon/src/main.rs, src/libraries/rust/stargate/crates/pylon/src/startup.rs, src/libraries/rust/stargate/crates/pylon/BUILD.bazel, src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel/raw_quic.rs
Adds backend and ceiling CLI options, startup propagation and logging, default fixtures, and a Bazel test target.
Priority forwarding and validation
src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel/core.rs, src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel/tests.rs, src/libraries/rust/stargate/docs/api-gateway-contract.md
Applies backend-specific headers for non-health requests, strips spoofed headers, records tracing fields, and documents the header contract.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Pylon
  participant UpstreamInferenceServer
  Client->>Pylon: Send x-priority and inbound Dynamo headers
  Pylon->>Pylon: Validate priority and select upstream backend
  Pylon->>UpstreamInferenceServer: Strip inbound headers and add derived Dynamo headers
  UpstreamInferenceServer-->>Pylon: Return response
Loading

Suggested reviewers: max-nv

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title uses the required feat(scope): subject format and accurately describes the primary Dynamo priority-header feature.
Linked Issues check ✅ Passed The changes satisfy issue [#620] through backend-specific derivation, sanitization, presence handling, logging, configuration, documentation, and test coverage.
Out of Scope Changes check ✅ Passed The configuration, tests, documentation, Bazel target, and priority plumbing directly support the linked issue objectives.
Docstring Coverage ✅ Passed Docstring coverage is 80.56% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pylon/dynamo-priority-header

Comment @coderabbitai help to get the list of available commands.

@along-2017 along-2017 self-assigned this Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

🛡️ CodeQL Analysis

🚨 Found 2 issue(s)

Severity Breakdown:

  • 🔴 Errors: 0
  • 🟡 Warnings: 0
  • 🔵 Notes: 0
📋 Top Issues

🔗 View full details in Security tab

🕐 Last updated: 2026-08-04 22:29:46 UTC | Commit: 1c43f89

Pylon owns the engine-facing Dynamo header contract. On every tunneled
inference request it now strips inbound x-dynamo-request-* headers so
client-supplied values never reach the engine, and derives
x-dynamo-request-priority from x-priority when that header is present
(i32::MAX - min(x, i32::MAX); absent stays absent). Derivation sits
behind the default-on --pylon-derive-dynamo-priority flag as a kill
switch; the strip is unconditional. The emitted value is logged with
the request id and recorded on the upstream request span.

mock-dynamo records the priority headers seen on the latest request
per endpoint and model in its /test-control snapshot so cluster QA can
assert what actually reached the engine. The pylon and mock-dynamo
crates gain rust_test Bazel targets; their in-crate tests previously
did not run in CI.

Refs: #620
Signed-off-by: along <along@nvidia.com>
Dynamo parses x-dynamo-request-strict-priority as a u32 queue tier, so
the spoofed test value should look like the real contract. The strip
assertion is name-based and unaffected.

Signed-off-by: along <along@nvidia.com>
@along-2017
along-2017 force-pushed the feat/pylon/dynamo-priority-header branch from fcbc062 to 39efe42 Compare August 5, 2026 21:23
@along-2017
along-2017 marked this pull request as ready for review August 5, 2026 21:23
@along-2017
along-2017 requested a review from a team as a code owner August 5, 2026 21:23
@along-2017
along-2017 requested review from FamousDirector, Max-NV, barrygreengus and harshm98 and removed request for harshm98 August 5, 2026 21:23

@FamousDirector FamousDirector 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.

Reviewed against Dynamo's actual source (lib/llm/src/protocols/common/extensions.rs, lib/kv-router/src/scheduling/policy.rs, lib/llm/src/preprocessor.rs) and the priority-scheduling doc.

What matches. Polarity is correct: requestctx.go documents x-priority as "Lower value is higher priority, 0 is highest" and Dynamo is higher-wins i32, so the inversion runs the right direction. The gateway already rejects client-supplied X-Priority with 400, so the input to the mapping is trusted. HeaderValue::from(i32) is infallible, the strip runs before the insert so no duplicate header is possible, and the mapping never emits a negative, so Dynamo's negative-clamp path is never hit.

Three blocking issues, detailed inline:

  1. The claim that spoofed values never reach the engine does not hold. Dynamo resolves priority from the header and the request body, and strict_priority (which Pylon never emits) sorts ahead of everything else in the router queue.
  2. x-dynamo-request- is the wrong prefix. The routing headers worth stripping (x-dynamo-worker-instance-id, x-dynamo-dp-rank, x-tenant-id, plus unprefixed aliases) all fall outside it.
  3. Anchoring at i32::MAX is a policy decision that is not stated anywhere: Dynamo treats the value as seconds of arrival-time bump, so every request carrying x-priority outranks every request without one, permanently.

One question outside the diff. rejectClientSuppliedPriority is registered on the LLM route group, "not globally". Any other route reaching stargate and then pylon would let a caller set x-priority directly, which now maps straight to engine priority. Worth confirming no such route exists before this merges.

Comment on lines +1102 to +1105
/// Client-supplied Dynamo request headers never reach the engine; Pylon is
/// the only writer of x-dynamo-request-* values.
pub(super) fn is_dynamo_request_header(name: &HeaderName) -> bool {
name.as_str().starts_with(DYNAMO_REQUEST_HEADER_PREFIX)

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.

Blocking: the body path is unguarded, so "spoofed values never reach the engine" is not true.

Dynamo resolves priority from the header and the body. From resolve_request_priority in lib/llm/src/protocols/common/extensions.rs:

let priority = priority_header.and_then(|h| h.trim().parse::<i32>().ok())
    .or_else(|| hints.and_then(|h| h.priority));
let strict_priority = strict_priority_header.and_then(|h| h.trim().parse::<u32>().ok())
    .or_else(|| hints.and_then(|h| h.strict_priority));

Three ways a client still controls engine scheduling:

  1. strict_priority is never emitted by Pylon and is the strongest lever. The router queue key is (strict_priority, policy_score) with the strict tier compared first (lib/kv-router/src/scheduling/policy.rs). A client sending {"nvext":{"agent_hints":{"strict_priority":4294967295}}} in the JSON body jumps ahead of every platform-prioritized request regardless of what x-priority resolved to. Stripping the header does nothing against it.
  2. Absent x-priority means no header at all, so body priority wins outright for any caller without a priority config.
  3. latency_sensitivity (deprecated, body-only, f64) feeds priority_jump whenever no priority exists. Same bypass.

The body reaches Dynamo verbatim: stargate does opaque body forwarding, and the gateway's proxyRequest passes request.Body through unmodified for the responses and embeddings paths. nvext and agent_hints appear nowhere in this repo, so nothing sanitizes them anywhere.

Three ways to close it, in rough order of preference:

  • Sanitize nvext.agent_hints out of the body at the trust boundary (gateway or here).
  • Emit both x-dynamo-request-priority and x-dynamo-request-strict-priority unconditionally, including when x-priority is absent, since a well-formed header beats the body per Dynamo's precedence rule.
  • Keep the current scope but drop the security claim from the PR description and the doc comment here, and file the body path as a known gap.

/// Engine-facing priority header in the Dynamo contract; Pylon owns this
/// contract, so the constant stays out of the shared tunnel contract.
pub(super) const HEADER_DYNAMO_REQUEST_PRIORITY: &str = "x-dynamo-request-priority";
const DYNAMO_REQUEST_HEADER_PREFIX: &str = "x-dynamo-request-";

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.

Blocking: x-dynamo-request- is the wrong boundary. The headers worth stripping are outside this prefix.

apply_header_routing_overrides in Dynamo honors all of these, and none of them match x-dynamo-request-:

header aliases also honored effect
x-dynamo-worker-instance-id x-worker-instance-id sets backend_instance_id and decode_worker_id
x-dynamo-prefill-instance-id x-prefill-instance-id pins the prefill worker
x-dynamo-dp-rank x-dp-rank, x-data-parallel-rank pins the DP rank
x-dynamo-prefill-dp-rank x-prefill-dp-rank pins the prefill DP rank
x-tenant-id none sets cache_salt

A client can pin itself to a chosen worker and DP rank, which bypasses the load balancer entirely and makes targeted worker overload trivial. x-tenant-id sets the KV cache namespace, which is a cross-tenant cache probing vector. Both are larger than the priority hole this PR closes, and the prefix match makes the strip look more complete than it is.

Suggest an explicit deny-list of the header names above plus their aliases, sourced from Dynamo's constants, rather than a prefix. A prefix match will keep silently missing whatever Dynamo adds next outside it.

Comment on lines +1108 to +1109
/// Dynamo schedules on an i32 where higher wins and silently drops values
/// that do not parse as i32, while x-priority is a u32 where lower wins, so

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.

The stated failure mode is not what Dynamo does. An unparseable header does not leave the request with no priority; it falls back to the client-controlled body value. Dynamo's own test asserts it:

let r = resolve_request_priority(Some(&hints), Some("abc"), None);
assert_eq!(r.priority, Some(5)); // the body value

Not live today because this function always produces a well-formed value, but the comment is the thing a future author will reason from when they change the emitted format. Worth correcting to "a malformed header falls back to the client body value".

Comment on lines +1111 to +1113
pub(super) fn dynamo_request_priority(priority: u32) -> i32 {
i32::MAX - i32::try_from(priority).unwrap_or(i32::MAX)
}

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.

Blocking: anchoring at i32::MAX is an unstated policy decision, and the unit is seconds.

Dynamo's FCFS queue key is:

OrderedFloat(ctx.request().priority_jump.max(0.0) - arrival_offset.as_secs_f64())

with priority_jump = priority as f64. The priority is seconds of arrival-time bump. So x-priority: 0 becomes a bump of 2147483647 seconds, roughly 68 years.

Two consequences:

  • Any request carrying x-priority, even the least urgent one, outranks every request without one, permanently. The PR reasons carefully about "absent must not be promoted to maximum", but the mirror case is unaddressed: in a mixed fleet where some functions have priority config and some do not, unconfigured tenants sit behind all configured traffic forever. WSPT has the same shape, weight = 1.0 + priority_jump, so the 1.0 baseline vanishes and unconfigured traffic is always last there too.
  • Within configured traffic, one platform priority step equals one second of queue jump. That scale is a side effect of the anchor, not a chosen value.

The justification in the doc comment only argues for staying inside i32 range, which does not require the maximum. A bounded ceiling gives identical ordering, stays a valid i32, and leaves unconfigured traffic somewhere sane:

/// Platform priorities occupy [0, CEILING]; the derived value stays small so
/// requests without x-priority keep a meaningful position relative to them.
const PLATFORM_PRIORITY_CEILING: u32 = 1_000;

pub(super) fn dynamo_request_priority(priority: u32) -> i32 {
    (PLATFORM_PRIORITY_CEILING.saturating_sub(priority.min(PLATFORM_PRIORITY_CEILING))) as i32
}

If i32::MAX is deliberate policy ("platform traffic always beats non-platform traffic"), that is a defensible choice, but it needs to be stated here and in the PR description rather than falling out of the clamp argument.

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.

This kinda becomes an extension of the stargate/gateway contract, and then assumes that the api gateway understands the priority api of the underlying engines. And what happens if stargate is connected to a mix of engines supporting the same model (I assume this is theoretically possible), say a mix of dynamo and raw sglang instances. Each may have a different priority (or other) APIs

I think Pylon/Stargate HAS to present a single unified contract to the api gateway, and will have to internally consolidate the api differences between different backends.

The easiest way I can think of to normalize priority behavior is to have pylon set priority to the lowest-priority value if no priority is supplied. And this will be the behavior for all backends

Comment on lines +1115 to +1120
/// Absent stays absent: a request without x-priority must not be promoted to
/// maximum engine priority, so this reads the raw header instead of the
/// parsed default of 0. Malformed values were already rejected upstream.
pub(super) fn x_priority_header_value(headers: &HeaderMap) -> Option<u32> {
headers
.get(HEADER_PRIORITY)?

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.

This is a second, independent parser for a header that validate_required_tunnel_headers in request_observer/headers.rs has already parsed on this exact path (non-health requests validate before reaching send_upstream_request, which is what makes the "rejected upstream" claim true).

The two agree today, both trim and both parse u32, but nothing enforces that they keep agreeing. The root cause is that RequiredTunnelHeaders.priority is a u32 built with unwrap_or_default(), which collapses absent into 0, exactly the distinction this PR needs.

Cleaner: make that field Option<u32> and thread the validated value into send_upstream_request. One parser, and the absent-versus-zero distinction lives in the type instead of in a comment.

/// Derive x-dynamo-request-priority for the upstream engine from x-priority
#[arg(
long,
action = clap::ArgAction::Set,

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.

With ArgAction::Set and default_value_t = true, a bare --pylon-derive-dynamo-priority is an error; only --pylon-derive-dynamo-priority=false works.

The PR description calls the kill switch --pylon-derive-dynamo-priority, which will send whoever is turning this off mid-incident down a wrong path. Worth spelling the =false form in the PR body and wherever this gets written down operationally. (Matches the surrounding flags, so no objection to the style itself.)

long,
action = clap::ArgAction::Set,
default_value_t = true,
env = "PYLON_DERIVE_DYNAMO_PRIORITY"

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.

The checklist marks documentation as up to date, but the diff contains no doc changes, and two existing docs specifically encode this class of rule:

  • src/libraries/rust/stargate/docs/api-gateway-contract.md already documents the analogous strip under "Internal header": "x-stargate-expected-queue-ms: Stargate-to-pylon only. Stargate strips caller values; pylon strips it before upstream forwarding." The new x-dynamo-request-* strip belongs alongside it, and the header table there should gain the derived header.
  • docs/user/llm-request-router-load-balancing.md carries the ingress RequestHeaderModifier remove-list plus the warning that the stock HTTPRoute does not strip router-facing headers. Neither the x-dynamo-* family nor this flag and env var appear in it.

The flag and PYLON_DERIVE_DYNAMO_PRIORITY also need to land somewhere an operator will find them under pressure.

rust_test(
name = "pylon_test",
crate = ":pylon",
deps = _WORKSPACE_DEPS + all_crate_deps(normal_dev = True),

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.

Nit: this re-lists _WORKSPACE_DEPS while mock-dynamo's new rust_test lists only all_crate_deps(normal_dev = True). With crate = ":target" rules_rust inherits the crate's deps, so if mock-dynamo builds then the re-listing here is redundant. Worth picking one style so the next person adding a test target does not have to guess which one is load-bearing.

Good catch on these two crates having had no test target at all, by the way. That is the most valuable part of the PR independent of the feature.

&HeaderName::from_bytes(b"X-Request-Id")?,
&retry
));
for name in [b"X-Request-Id".as_slice(), b"X-Priority", b"X-Dynamo-Nvext"] {

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.

This assertion is the clearest statement of the gap raised on DYNAMO_REQUEST_HEADER_PREFIX: any x-dynamo-* header that is not x-dynamo-request-* is forwarded to the engine. x-dynamo-nvext is harmless, but x-dynamo-worker-instance-id, x-dynamo-dp-rank and x-tenant-id are real Dynamo routing headers that pass this filter today.

Once the strip becomes a deny-list, this loop is the right place to pin which x-dynamo-* names are intentionally still forwarded.

Comment on lines +511 to +512
fn pylon_x_priority_header_value_distinguishes_absent_from_zero() {
let mut headers = HeaderMap::new();

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.

Minor: both the " 7 " and "not-a-priority" cases are unreachable in production. validate_required_tunnel_headers trims and returns 400 for an unparseable x-priority before send_upstream_request runs on any non-health path, and health requests never reach the derivation.

Fine as a unit-level contract for the function, but it is worth a line in the test saying so, otherwise it reads as coverage of a live path and hides the duplicate-parser issue raised on x_priority_header_value.

@barrygreengus

Copy link
Copy Markdown
Contributor

run this deslop prompt

Review this PR (diff against merge-base) specifically for over-engineering and unnecessary complexity.

Apply these principles:

- YAGNI: flag code supporting hypothetical requirements without a current caller or concrete need.
- KISS: prefer fewer concepts, states, branches, layers, and moving parts.
- Rule of Three: question abstractions introduced before a stable repeated pattern exists.
- Prefer small duplication over premature or incorrect abstraction.
- Prefer direct code over interfaces, factories, registries, callbacks, DTOs, wrappers, and helpers that have only one implementation or caller.
- Derive values instead of storing redundant state.
- Keep one source of truth and localize ownership, validation, and lifecycle logic.
- Avoid configurability, extension points, genericity, and fallback behavior without a demonstrated requirement.
- Avoid speculative performance optimizations without measurements.
- Require every new type, layer, dependency, and abstraction to justify its maintenance cost.
- Look for code that can be deleted, inlined, collapsed, or replaced with an existing mechanism.

The goal of the review is to
- reduce diff against merge base and cognitive complexity
- improve readability, maintainability, and clarity.

For each finding:
1. Identify the unnecessary complexity.
2. Explain the concrete maintenance or correctness cost.
3. State whether the complexity is required by a current requirement.
4. Propose the smallest simpler implementation.
5. Include a concrete diff or pseudodiff where practical.

Do not recommend simplification that weakens an important invariant, removes required error handling at a trust boundary, or makes the code materially harder to test. Please list the important invariants at the top, just so I am aware of them.

Please write outputs of this review into /tmp/yagni-<project>-<current commit short sha>.md

request_quality_monitor: RequestQualityMonitorConfig::default(),
retry: PylonRetryConfig::default(),
queue_mismatch_retry: PylonQueueMismatchRetryConfig::default(),
derive_dynamo_priority: true,

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.

pylon has to be backend agnostic. We shouldn't have multiple flags for each type of backend. imagine having derive_dynamo_priority, derive_sglang_priority, and derive_vllm_priority flags. Instead we need a backend_type, that contains the config block for that backend.

This can be a future PR

The recording had no automated consumer in this PR: the tunnel tests
assert receiver-side via an in-process echo backend, and live
verification uses the per-request pylon log. The fixture change will
land together with the e2e test that reads it.

Signed-off-by: along <along@nvidia.com>
… config

Rework the engine priority contract from review feedback on the initial
derivation:

- Always emit x-dynamo-request-priority and x-dynamo-request-strict-priority
  on inference requests in dynamo mode. Dynamo resolves each field from the
  header when present, falling back to client-controlled request-body hints
  otherwise, so emitting only on configured requests left the body as an
  open priority channel. Unconfigured requests now carry the lowest value 0
  and the strict tier is always 0.
- Replace the i32::MAX anchor with max(0, ceiling - x). Dynamo reads the
  value as seconds of arrival-time head start, so the old anchor made every
  configured request outrank unconfigured traffic permanently. The ceiling
  is configurable (--pylon-priority-ceiling, default 3600) and named
  backend-neutrally because the platform priority band is platform policy.
- Replace the derive_dynamo_priority bool with --pylon-upstream-backend
  <passthrough|dynamo> and move all Dynamo names and the mapping into a
  backend module, so per-backend flags cannot accumulate and core.rs keeps
  no engine-specific names. The strip stays active in every mode.
- Make RequiredTunnelHeaders.priority an Option<u32> and thread the
  validated value through, deleting the second x-priority parser the derive
  block previously needed.
- Drop the dedicated per-derivation info log. The existing per-request
  observation log already carries the priority; the request span gains the
  inbound priority next to the derived value, startup logs the resolved
  backend and ceiling, and stripped engine header names log at debug.

Signed-off-by: along <along@nvidia.com>
Add the x-dynamo-request-* strip/derive rules to the gateway contract's
internal headers section and the upstream backend and priority ceiling
flags to the request-router operator doc.

Signed-off-by: along <along@nvidia.com>
- Revert the user-doc addition; the feature is not QA validated yet, so the
  flag and header documentation stays in the stargate contract doc.
- Centralize the unconfigured-counts-as-0 rule in
  RequiredTunnelHeaders::queue_priority() instead of scattered
  unwrap_or_default() calls.
- Rename is_engine_priority_header to is_engine_request_header: the strip
  covers the whole pylon-owned request-header prefix, not only priority.
- Rename the send-path context to ValidatedRequestContext/validated so the
  health-request distinction reads off the signature.
- Trim comments to stay component-focused and concise.

Signed-off-by: along <along@nvidia.com>
…d path

Replace the single-field ValidatedRequestContext with two plain
parameters, matching the reviewer's suggestion to key the derive on
health_request directly.

Signed-off-by: along <along@nvidia.com>
…y denylist

Replace the x-dynamo-request- prefix match with a denylist of exactly the
two priority headers pylon derives. Other engine headers pass through
unchanged for now; widening the denylist is tracked separately. The filter
test pins both the stripped names and the pass-through behavior.

Signed-off-by: along <along@nvidia.com>
The debug log duplicated the strip predicate in the forwarding loop with
no consumer; spoof-attempt visibility can come back as a counter metric
if someone needs it. as_str had Display as its only caller.

Signed-off-by: along <along@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@src/libraries/rust/stargate/docs/api-gateway-contract.md`:
- Around line 151-160: Update the optional-header table’s x-priority default to
remove the conflicting default of 0. Document that an absent x-priority remains
absent, while explicitly setting x-priority: 0 retains its distinct Pylon/Dynamo
priority behavior described in the x-dynamo-request-priority section.
🪄 Autofix

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: 2d58ebc6-9d43-430c-8005-a2fd5ebc0a5b

📥 Commits

Reviewing files that changed from the base of the PR and between 39efe42 and 3ece2c2.

📒 Files selected for processing (14)
  • src/libraries/rust/stargate/crates/pylon-lib/src/bringup/upstream.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/lib.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/queue_admission.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel/backend.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel/core.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel/raw_quic.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/quic_http_tunnel/tests.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/request_observer.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/request_observer/headers.rs
  • src/libraries/rust/stargate/crates/pylon-lib/src/stats/collector.rs
  • src/libraries/rust/stargate/crates/pylon/src/main.rs
  • src/libraries/rust/stargate/crates/pylon/src/startup.rs
  • src/libraries/rust/stargate/docs/api-gateway-contract.md

Comment on lines +151 to +160
- `x-dynamo-request-priority` and `x-dynamo-request-strict-priority`:
pylon-to-engine only. Pylon strips inbound values in every backend mode, so
pylon is the only writer of these two headers. When pylon runs with
`--pylon-upstream-backend dynamo` (the default), it emits both headers on
every inference request: the priority is derived from `x-priority` as
`max(0, ceiling - x)` with a configurable ceiling
(`--pylon-priority-ceiling`, default 3600), requests without `x-priority`
carry the lowest value `0`, and the strict tier is always `0`. Always
emitting means the engine reads priority only from pylon, never from
client-supplied values. Other engine headers pass through unchanged; the

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Remove the conflicting x-priority default.

The optional-header table states that x-priority defaults to 0. This conflicts with this section. An absent header emits Dynamo priority 0, but explicit x-priority: 0 emits the configured ceiling.

State that absence must remain absent, or document separate gateway and Pylon semantics. Otherwise, a gateway can synthesize x-priority: 0 and assign the highest Dynamo priority to unconfigured requests.

🤖 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 `@src/libraries/rust/stargate/docs/api-gateway-contract.md` around lines 151 -
160, Update the optional-header table’s x-priority default to remove the
conflicting default of 0. Document that an absent x-priority remains absent,
while explicitly setting x-priority: 0 retains its distinct Pylon/Dynamo
priority behavior described in the x-dynamo-request-priority section.

The optional-header table said x-priority defaults to 0, which invites a
gateway to synthesize 0 for unconfigured requests. Absence maps to the
lowest engine priority while rank 0 maps to the highest, so the gateway
must omit the header when no priority resolves.

Signed-off-by: along <along@nvidia.com>
@along-2017
along-2017 marked this pull request as draft August 11, 2026 06:13
…l headers section

Keep the optional-header table row short and put the explanation where the
derivation is documented: absence and rank 0 are opposite ends of the
range, so the gateway must not synthesize 0 for unconfigured requests.

Signed-off-by: along <along@nvidia.com>
SECONDS is the Dynamo interpretation of the derived value; the flag itself
is a platform rank band, so name the placeholder RANK and note the Dynamo
unit in the help text.

Signed-off-by: along <along@nvidia.com>
Health requests must carry no derived engine headers, and a ceiling of 0
collapses every rank to the lowest value. Also tighten two doc comments.

Signed-off-by: along <along@nvidia.com>
The strip-in-every-mode rule lives on the denylist and the Passthrough
variant; the ceiling semantics live on the mapping function. Config
fields, flag help, and a test comment now reference instead of restate.

Signed-off-by: along <along@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Handle Dynamo request-priority headers in Pylon

3 participants