Skip to content

feat(planner): live retune from recorded traces through DGDR v1beta2 - #17483

Merged
tedzhouhk merged 126 commits into
mainfrom
hzhou/dgdr-trace-pvc
Nov 4, 2026
Merged

tedzhouhk merged 126 commits into
mainfrom
hzhou/dgdr-trace-pvc

Conversation

@tedzhouhk

@tedzhouhk tedzhouhk commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Note

This PR now carries the whole live retune stack. It started as the DGDR v1beta2 trace workload (the operator part below). The five PRs stacked on it were reviewed separately and merged into this branch on 2026-11-02:

PR Layer
this PR Operator: spec.workload.trace replays a recorded trace from a PVC in DGDR v1beta2 Runs
#17733 Replay: DGDR trace Runs replay with common random numbers
#17734 Planner: retune.executor: dgdr configuration and deployment premises; frontend parser builder
#17735 Planner: window cutter and reconciler on the trace claim
#17736 Planner: the DGDR sweep executor and Kubernetes client
#17562 Planner: supervisor, Lease state, router actuator, wiring, Helm RBAC and docs

Each layer's PR keeps its detailed description and its review follow-ups. This description summarizes the combined change, which lands on main as one squash commit.

Overview

Periodic retune (#17095, #17540) runs only inside offline planner replay today. This PR lets a live Planner on Kubernetes retune its KV router with retune.executor: dgdr:

  1. Frontends record their request traces to a shared ReadWriteMany claim.
  2. At the end of each window, the Planner cuts the window's segments into one trace file on that claim.
  3. It replays the file through DGDR v1beta2 Requests for a grid of router parameters. Each Request uses the new trace workload, and every trace Run replays with common random numbers, so Candidates of different Runs are comparable. It scores the Candidates on retune.objective.
  4. Unless it runs in advisory mode, it sets the winner on every frontend router with PATCH /router_policy.
# DGDR v1beta2 Request (the Planner creates these; users can too)
spec:
  workload:
    trace:
      format: Dynamo                    # optional; defaults to Dynamo, the only value
      source:
        persistentVolumeClaim:
          claimName: request-traces     # PVC in the Request namespace
          subPath: retune/w-1.jsonl.gz  # one file, relative to the claim root
      replay:
        arrivalSpeedupRatio: 2.0        # optional

Live retune is EXPERIMENTAL, for development clusters only. It searches the three router knobs a DGDR Request can express (overlap_score_credit, prefill_load_scale, temperature) with fixed replicas, so the Planner must run retune-only, with load and throughput scaling off. The default executor: local keeps today's behavior, and the Planner's Helm RBAC is gated by the new value dgdrV1Beta2.plannerLiveRetune (default false).

User guides: docs/fern/pages/kubernetes/auto-deployment/planner-live-retune.md (new) and the "Replay a recorded trace (v1beta2)" section of the DGDR reference.

Key Changes

99 files, +34.1k/−0.3k lines, including regenerated CRDs and API reference.

Operator: DGDR v1beta2 trace workload (deploy/operator)

  • API. New spec.workload.trace{format, source.persistentVolumeClaim{claimName, subPath}, replay.arrivalSpeedupRatio}, exclusive with static, following the trace workload in DEP DEP: Evolve DGDR for replay-backed multi-candidate search #13092. format is optional, with the enum value and CRD default Dynamo; lowering translates it to AISimulate's native dynamo. CEL and the shared schema check that claimName is a DNS-1123 subdomain, that subPath is relative with no empty, . or .. segment, no NUL and at most 1024 characters, and that the speedup is greater than 0. The Run snapshot rule from feat(operator): integrate DGDR v1beta2 candidate flow #17308 now accepts static or trace.
  • Markers and lint. Every serialized v1beta2 field is marked +optional or +required (no schema change for existing fields). kube-api-linter's optionalorrequired rule enforces it: make lint-api (part of make lint) and the operator Dockerfile's linter stage run it over api/v1beta2 with .golangci-kal.yml.
  • Validation. Structural validators in shared_v1beta2.go mirror the CRD rules for a v1beta1 carrier stored without admission. inputOverrides stay authoritative: they are applied last as a JSON Merge Patch and may restate, replace or delete any traffic the trace lowers; the operator restores nothing. The typed claim alone decides the Job's mount and the claim the Run depends on. The Request controller no longer validates the trace; a Run create the CRD rejects as Invalid reports InvalidSpec instead of retrying.
  • Lowering. traffic.source{type: trace, format: dynamo, paths: [<fixed mount path>]}, traffic.load.type: trace_timestamps, and traffic.load.speedup when set, as an underlay for the overrides.
  • Run Job. Only the trace file is mounted, read-only through subPath at /var/run/aisimulate/trace/trace.jsonl.gz (or trace.jsonl), into the sweeper alone. No fsGroup; a trace Job's pod gets group 65532 as a supplemental group.
  • Claim lifecycle. Before it creates a trace Job, the Run adds its finalizer nvidia.com/dgdr-run-<run-uid> to the claim with an optimistic-lock patch. Deleting the claim cancels the Run through the foreground stop path (stopAndCompleteRun); the Run fails with TraceSourceDeleted only once the Job is gone, then releases its finalizer. A missing claim keeps the Run Pending (TraceSourceMissing) until it appears; a block or lost claim fails it (TraceSourceUnavailable). A waiting sweeper or publisher container only sets the ContainerWaiting diagnostic. The new DynamoGraphDeploymentRunTraceClaimReconciler releases finalizers of deleted Runs once none of their Jobs is left.
  • RBAC and watches. PVCs, Run Job pods, Run and Job deletions; persistentvolumeclaims get;list;watch;patch, pods get;list;watch, jobs delete.
  • Golden. internal/aisimulate/testdata/trace_request_lowering.golden.json pins the Planner's shard Request and the Run input it lowers to. TestDGDRV1beta2TraceRequestLoweringGolden admits that Request through the webhooks and CRD schema and lowers its Run; a mismatch writes <golden>.new. The planner's executor tests read the same file.

Replay: common random numbers (components/src/dynamo/replay)

  • DynamoReplayRunner, which AISimulate's Sweeper loads and every DGDR trace Run executes, passes _deterministic=True (ordinal request ids, the canonical router seed) to both trace replay calls. This applies to every DGDR trace Run, not only the Planner's: a Run's scores no longer depend on the other candidates or the Run's parallelism. Synthetic workloads are unchanged.

Planner configuration and premises (planner/config, planner/retune, frontend and common configuration)

  • RetuneConfig.executor (local by default, or dgdr) and RetuneConfig.dgdr (DgdrExecutorConfig, DgdrRunConfig), required if and only if the executor is dgdr.
  • Configuration premises for dgdr: P1 (Kubernetes, decision latency, explicit timeout_seconds ≤ interval_seconds − 600), P2 (retune-only), P3 (only the three DGDR knobs, prefill_load_model: none), P5 (an all-scalar engine with one parallelism preset and no replicas), P13 (the grid fits run.max_shards shards of at most 100 points within the timeout), and safe claim paths. P13 and the executor share one shard planner (balanced_shard_parts, largest_shard_points, dgdr_rounds, dgdr_need_seconds).
  • retune/live/frontend_config.py parses the DGD's frontend command, args and env into the startup KvRouterConfig and evaluates the spec premises P4 and P6–P10 (evaluate_premises(dgd, *, planner_config)). retune.controller.startup_router_domain holds the router checks that depend on the frontend startup; the controller and P4 both call it.
  • To parse another process's frontend command, the frontend and common configuration modules gain ArgEnv and frontend_args.build_frontend_parser(env); the router, KV router and frontend argument groups take an optional env. Existing callers pass none and are unchanged.
  • Offline replay rejects executor: dgdr (replay/api.py); replay retune runs executor: local.

Window cut and reconciler (planner/retune/live)

  • window_cut.py merges each frontend pod's request_end jsonl.gz segments into <windows_dir>/<dgd>/<window_end_ms>.jsonl.gz, with the same rows as retune.window.read_trace_window. It runs in a niced, budgeted child process, validates each gzip member (CRC32, ISIZE), excuses a truncated tail at the end of any segment, fails a mostly corrupt window (trace_corrupt), bounds memory by max_window_rows, and publishes atomically with mode 0644 (the Run's sweeper reads as uid 1000 with group 65532). The output's gzip header comment holds the cut's counts, so a later leader reuses a published window without reading segments again.
  • reconciler.py garbage-collects finished Requests, window files no live pod reads, cut temp files and old segments, asking the caller before every delete or Kubernetes read so a round stops when leadership is lost. It is also the ref-counted SweepRegistry that protects in-flight windows.

DGDR sweep executor (planner/retune/live)

  • dgdr.py (run_dgdr_sweep) splits the router grid into balanced shards and creates one Request per shard with the trace workload, the pinned retune.dgdr.engine, the DGD's replica counts and their GPU total, and generator: direct. An off-grid baseline gets its own Request, and a common-random-numbers probe re-scores one grid point (relative error ≤ 1e-9, else crn_mismatch).
  • It adopts a previous leader's Requests, creates new ones with Strict field validation, checks each Run's status.aisimulate.input against the Request with a subset check (the operator golden is the oracle), waits on Runs, and scores Candidates with retune.objective. Open-Run reasons (ContainerWaiting, TraceSourceMissing, RunNameConflict, …) show up in the shard status and errors. It never raises and never deletes; on shutdown or lost leadership it returns at once and leaves the Requests to the next leader.
  • kube.py (KubernetesRetuneKube) implements the Kubernetes calls over the official client with request timeouts and status-carrying errors; Leases round-trip without model deserialization.

Live retune on the Planner (planner, Helm, docs)

  • supervisor.py (LiveRetuneSupervisor) runs each window: epoch-aligned windows that survive restarts, leadership, premise and time-budget checks, advisory and active modes, and a two-phase rollback to the startup parameters. Each decision is persisted before any router sees it, and each router's latched initial before the actuator moves that router. stop aborts the sweep and releases leadership before the engine shuts down.
  • state.py: the leadership Lease <dgd>-planner-retune and the state Lease <dgd>-planner-retune-state, with writes fenced by leader term and deploy sequence, resourceVersion preconditions on decommission deletes, and an unknown format version refusing initialization.
  • actuator.py reads and sets the eight /router_policy parameters on every frontend router with revision-checked PATCH and reset, reverts manual changes outside advisory mode, and treats a router as gone only once every pod instance it ran on is gone, finished or restarted. metrics.py and bootstrap.py add the Prometheus metrics and the wiring.
  • retune/controller.py gains optional hooks (external sweep_fn, launch and harvest gates, generation, a shared single-thread executor); the replay path passes none and is unchanged. engine_adapter.py, core/base.py and __main__.py wire the supervisor; a live Planner now rejects only executor: local. A Kubernetes Planner without retune checks in the background whether a removed live retune left its Leases and cleans up. SIGTERM cancels the run so the Lease is released before exit.
  • Helm planner.yaml: with dgdrV1Beta2.enabled and dgdrV1Beta2.plannerLiveRetune, the Planner Role and ClusterRole gain create/get/list/delete on DGDR Requests, get on Runs, list on Candidates and get/create/update/delete on Leases, with helm-unittest cases.
  • Docs: the live retune guide, retune.executor and retune.dgdr in planner-configuration.mdx, and executor notes in the planner guide (en and zh-CN), planner-design.md and aisimulate-planner-replay.mdx.

Behavior notes

  • Recipes whose workers advertise their own router configuration (--router-mode or DYN_ROUTER_MODE on a worker, such as minimax-m3 and solar-open2) fail P4 by design: the Run replays only the frontend's configuration.
  • /router_policy is the frontend's unauthenticated admin API; the guide explains how to deny it at L7.
  • The chart has one Planner role per install, so with plannerLiveRetune=true Planners without retune get the live retune rules too. The guide lists what that allows.

Validation

CI on this head (08c5eb9661) runs the whole stack together for the first time. Local checks from the last review follow-up:

Check Head Result
go build, go vet (no tags and clustertest) 03106cf4d3 Clean
go test ./api/... ./internal/aisimulate/... ./internal/webhook/... ./internal/controller/ (envtest, golden in compare mode) 03106cf4d3 Pass
make lint (golangci-lint and lint-api) 03106cf4d3 0 issues
Planner unit tests, integration/test_live_retune_e2e.py, frontend parser builder and common configuration tests 08c5eb9661 2490 passed, 4 skipped (engines not installed)
pre-commit over every layer's follow-ups 08c5eb9661 Clean
docs_lint.py 08c5eb9661 0 errors

The operator code did not change above 03106cf4d3. The Helm RBAC tests were checked against helm template output; helm-unittest was not run locally after the follow-ups. Each layer's PR has its per-layer runs.

Development cluster. Before the review follow-ups, the pre-split branch ran on an H200 development cluster (vcluster, operator with dgdrV1Beta2.enabled=true, Qwen/Qwen3-0.6B on vLLM, one KV-router frontend recording traces, interval_seconds: 1200, run.parallelism: 2, max_shards: 3):

Case What happened
1 worker, grid overlap_score_credit: {choices: [0.5, 1.0]}, objective GoodputPerGPU The cut wrote 3143 requests in 2.7 s; 3 Requests, all Runs succeeded, 2 of 2 candidates harvested. Decision kept (one worker makes the knobs irrelevant). A manual PATCH /router_policy was reverted within 10 s.
2 workers, frontend at DYN_ROUTER_TEMPERATURE=1.0, grid temperature: {choices: [0.0, 1.0]}, objective TTFT The cut wrote 3101 requests in 3.1 s; 3 Runs succeeded, sweep 28.7 s. Decision applied: simulated mean TTFT 4.493 ms at 1.0 and 3.778 ms at 0.0 (−15.9 %). The frontend applied temperature 0.0 at revision 1 two seconds later.

That run used the earlier trace fields (source.pvc.path, format: dynamo) and a chart without plannerLiveRetune; it has not been repeated since.

Not verified:

  • A cluster run of the stack after the review follow-ups.
  • Online TTFT after an applied decision, the advisory → promote_last_advisory path, and several frontends.
  • The default grid's run time (108 points, 3 shards of 36) against real replay time and memory.
  • Real foreground garbage collection of a Job and its pods on claim deletion, release across a live operator restart, and RBAC in a non-system:masters install.

Issues and Ongoing Work

Pull Request Checklist
  • I used Dynamo's /pr-checklist skill.

🤖 Generated with Claude Code

@tedzhouhk
tedzhouhk requested review from a team as code owners October 28, 2026 03:36
@github-actions github-actions Bot added feat documentation Improvements or additions to documentation deployment::k8s Relates to dynamo deployment in kubernetes labels Oct 28, 2026
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

@tedzhouhk
tedzhouhk requested a review from a team as a code owner October 28, 2026 04:51
@devin-ai-integration

devin-ai-integration Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

❌ Dynamo PR CI failed — run 41680495672 (attempt 1) on 143a8375bb

Gate checks: ✅ backend-status-check · ❌ deploy-status-check · ❌ dynamo-status-check

Framework Snapshot
vLLM ❌ 1
Other Jobs
dynamo-runtime ❌ 1 ✅ 6

Failure details

2 jobs failed: the vLLM Snapshot vCluster setup timed out in helm waiting for a DaemonSet (infrastructure), and the dynamo-runtime CPU test job had 5 planner/common tests fail after retries before the runner's custom container implementation died mid-run, so no tracebacks were printed.

❌ vLLM Snapshot Operator Setup: helm "context deadline exceeded" waiting for vcluster-hpm-hostpath-mapper DaemonSet (4/5 ready)

Job: vLLM Snapshot Operator Setup · Failed step: Setup vCluster and operator · Logs: gh run view --job 126086337590 -R ai-dynamo/dynamo --log-failed

ready.go:336: [debug] DaemonSet is not ready: gh-id-41680495672-checkpoint-vllm-dt/vcluster-hpm-hostpath-mapper. 4 out of 5 expected pods are ready
ready.go:336: [debug] DaemonSet is not ready: gh-id-41680495672-checkpoint-vllm-dt/vcluster-hpm-hostpath-mapper. 4 out of 5 expected pods are ready
wait.go:87: [debug] Error received when checking status of resource vcluster-hpm-hostpath-mapper. Error: 'client rate limiter Wait returned an error: context deadline exceeded'
Error: context deadline exceeded
helm.go:86: [debug] context deadline exceeded
##[error]Process completed with exit code 1.

The vCluster helm install waited ~10 minutes for the vcluster-hpm-hostpath-mapper DaemonSet, but one of its 5 pods never became ready, so helm hit its deadline. This happened during K8s cluster setup, before any PR code was deployed. It is an infrastructure (K8s scheduling/pod readiness) timeout, and rerunning the failed jobs is likely enough.

❌ dynamo-runtime / test / sequential cuda13.0, amd64: 5 tests FAILED, then "Executing the custom container implementation failed"

Job: dynamo-runtime / test / sequential cuda13.0, amd64 · Failed step: Run CPU-only tests (parallelized) · Logs: gh run view --job 126092066722 -R ai-dynamo/dynamo --log-failed

components/src/dynamo/common/tests/http/test_proxy_connections.py::test_one_time_budget_covers_every_redirect_hop FAILED [  9%]
components/src/dynamo/planner/tests/integration/test_fpm_event_delivery.py::test_endpoint_fpm_reaches_planner_and_drives_scale_up FAILED [ 29%]
components/src/dynamo/planner/tests/integration/test_live_retune_e2e.py::test_advisory_records_recommendations_and_never_writes FAILED [ 29%]
components/src/dynamo/planner/tests/integration/test_retune_sweep_workers.py::test_a_dead_worker_fails_only_its_candidate FAILED [ 29%]
components/src/dynamo/planner/tests/unit/test_system_control_api.py::test_planner_control_uses_the_actual_system_listener FAILED [ 64%]
...
components/src/dynamo/profiler/tests/integration/test_profile_sla_dgdr.py::TestAutoBackend::test_no_planner_no_load
##[error]Executing the custom container implementation failed. Please contact your self hosted runner administrator.
...
❌ pre_merge_cpu: step outcome 'failure'
##[error]A pytest stage did not record a passing result. See this step's log for the stage.

In the pre_merge_cpu stage, 5 tests failed on every attempt (3 auto-retries each). At 67%, during test_profile_sla_dgdr.py::TestAutoBackend::test_no_planner_no_load, the runner's container hook (/home/runner/k8s/index.js) stopped the test container. pytest never reached its summary, so the log has no tracebacks or assertion messages for the 5 failures. To get them, run the tests listed here locally, e.g. python3 -m pytest components/src/dynamo/planner/tests/integration/test_live_retune_e2e.py::test_advisory_records_recommendations_and_never_writes -v. The container dying looks like a runner infrastructure problem, but a rerun will not fix the 5 tests if they fail on their own.

For agents
{"pr": 17483, "run_id": 41680495672, "run_attempt": 1, "head_sha": "143a8375bbad500cd6aa659168051fabd51ad444",
 "failures": [
  {"job": "vLLM Snapshot Operator Setup", "job_id": 126086337590, "failed_step": "Setup vCluster and operator", "signature": "helm context deadline exceeded: DaemonSet vcluster-hpm-hostpath-mapper 4/5 pods ready (infra)", "tests": [], "log_cmd": "gh run view --job 126086337590 -R ai-dynamo/dynamo --log-failed"},
  {"job": "dynamo-runtime / test / sequential cuda13.0, amd64", "job_id": 126092066722, "failed_step": "Run CPU-only tests (parallelized)", "signature": "5 pytest FAILED (after retries); then 'Executing the custom container implementation failed' killed the run before the summary", "tests": [
    "components/src/dynamo/common/tests/http/test_proxy_connections.py::test_one_time_budget_covers_every_redirect_hop",
    "components/src/dynamo/planner/tests/integration/test_fpm_event_delivery.py::test_endpoint_fpm_reaches_planner_and_drives_scale_up",
    "components/src/dynamo/planner/tests/integration/test_live_retune_e2e.py::test_advisory_records_recommendations_and_never_writes",
    "components/src/dynamo/planner/tests/integration/test_retune_sweep_workers.py::test_a_dead_worker_fails_only_its_candidate",
    "components/src/dynamo/planner/tests/unit/test_system_control_api.py::test_planner_control_uses_the_actual_system_listener"], "log_cmd": "gh run view --job 126092066722 -R ai-dynamo/dynamo --log-failed"}
 ]}

Posted automatically by Devin for run 41680495672. Updated on every full-CI run of this PR.

@sttts
sttts force-pushed the sttts-dgdr-v1beta2-integration branch from d8d5ee2 to e2d17ad Compare October 28, 2026 13:16
@sttts
sttts requested review from a team as code owners October 28, 2026 13:16
@sttts
sttts force-pushed the sttts-dgdr-v1beta2-integration branch from e2d17ad to a3d4cf8 Compare October 28, 2026 14:21
Pranjulcr7 added a commit to Pranjulcr7/dynamo that referenced this pull request Oct 28, 2026
Port the standalone CI fix from ai-dynamo#17483 without its DGDR changes.
Original fix by hongkuanz in 934ceb3.

Ignore only the unset fixture-loop-scope notice so pytest 9.2 can configure
plugins under filterwarnings=error while preserving existing fixture scopes.

(cherry picked from commit 934ceb3)

Signed-off-by: Pranjul Gupta <pranjulgupta0203@gmail.com>
@sttts
sttts force-pushed the sttts-dgdr-v1beta2-integration branch from a3d4cf8 to 30884c7 Compare October 28, 2026 14:41
@tedzhouhk tedzhouhk changed the title feat(operator): replay recorded traces from a PVC in DGDR v1beta2 runs feat(planner): live retune from recorded traces through DGDR v1beta2 Nov 3, 2026
@tedzhouhk
tedzhouhk enabled auto-merge (squash) November 3, 2026 00:16
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
@sttts
sttts dismissed their stale review November 3, 2026 10:41

Rereviewing as contents has materially changed.

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

Six P2 findings from the combined live-retune review. The inline comments describe each trigger, production failure path, focused correction and regression coverage.

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

Approved for the operator and documentation changes at 143a837.

This approval is scoped to those areas. The Planner/tuning findings in my inline review remain open and must be addressed separately before merging.

tedzhouhk and others added 6 commits November 3, 2026 13:30
…adline

- lease_duration_seconds must be at least 37 s: the 15 s lease margin
  plus two 11 s renewal I/O budgets with the 5 s Kubernetes request
  timeout. One timing policy in planner_config (the live_retune_*_seconds
  helpers) backs SupervisorSettings and the DgdrExecutorConfig validator,
  and the schema states the minimum.
- While leading, the lease loop starts the next renewal at least one I/O
  budget before leader_until (LeaseLeadership.renewal_wait_s), so a
  renewal that uses its whole budget still lands inside the term. A
  failed renewal is retried one request timeout after it started.
- Initialization keeps renewing the lease: a keepalive shares the lease
  loop's schedule and step lock, and ends even when the initializing task
  is cancelled. A lapse during initialization (LeaseLeadership
  acquisitions / leads_since) aborts it, and the next round initializes
  the new term.
- LeaseLeadership no longer caps the margin at two thirds of the lease;
  it rejects a margin that is not below the lease duration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
Live retune fixes its scoring SLA when its controller and state
fingerprint are built, and a runtime configuration update does not
rebuild them. With retune.sla_ttft_ms or retune.sla_itl_ms unset, a
runtime update of ttft_ms or itl_ms was accepted and reported while live
retune kept scoring and creating Requests with the old SLA.

While live retune runs, runtime candidate validation rejects (HTTP 422)
an update that changes the effective scoring SLA and leaves the config
untouched. The message says to restart the planner with the new values,
or with the unset retune SLA overrides set to keep those fields
changeable at runtime. Planners without live retune are unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
… selection

Window files and Requests were keyed by the window end alone, so a sweep
with another window start or as_of could reuse a file or Request cut for
a different trace selection.

- Window files are named <windows_dir>/<dgd>/<end_ms>-<selection>.jsonl.gz,
  where the selection is the first 12 hex digits of a SHA-256 over the
  window start, end and as_of. build_request takes window_start_ms and
  as_of_ms, so the Request's subPath, spec hash and name follow the
  selection, and Requests of another selection are deleted, not adopted.
- The cut records the selection in the gzip header and reuses a
  published file only for the same selection.
- The reconciler recognizes the new names as well as the old ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
… args in P4

P4 reads worker commands the way the operator runs them and fails closed
when a value it cannot read could form a router option.

- A worker without a command runs /bin/sh -c (the operator's
  getCommonContainer default) unless the pod runs the native "runtime"
  sidecar, so its one-string script is split into shell words before the
  router parser runs.
- Env is readable, inert (POD_*, non-annotation fieldRef,
  resourceFieldRef) or dangerous (ConfigMap, Secret, annotation fieldRef,
  and names only an envFrom source may define). In exec form a dangerous
  reference passes only attached to its option (--opt=$(VAR)) or as the
  value of --speculative-config.
- Shell scripts are scanned after Kubernetes substitution: readable env
  is substituted, an unquoted dangerous $VAR fails, and a quoted one
  fails as a standalone argument of the worker module, eval or a nested
  sh -c. A script's own assignment does not clear explicit dangerous env.
  Shells behind launchers (env, tini, dumb-init) and shell options with
  operands (-o pipefail) are recognized.
- Command substitution and backticks are not evaluated; the live retune
  guide's Limitations table lists what P4 does not read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
The workers take envFrom from a Secret without a prefix, so live retune's
P4 cannot rule out that the Secret defines LD_LIBRARY_PATH or PATH, and an
unquoted reference in an export could split into more words in a shell
that does not treat export as a declaration. Quoting changes nothing for
bash and keeps the examples eligible for live retune.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
…annot run

The pinned AISimulate's ParallelismPresetConfig has no decode_context,
and its parallel mapping rejects prefill_context above 1 as
predict-only, so such a preset passed P5 and then failed the Run.

- P5 accepts prefill_context only when omitted or 1, and rejects
  decode_context with its own message.
- A comment lists what to widen together when the pin moves.
- The pytest marker report stubs aisimulate.config.engine.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
@tedzhouhk
tedzhouhk requested review from a team as code owners November 3, 2026 21:31
tedzhouhk and others added 5 commits November 3, 2026 14:58
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
…s them

P4 misjudged several worker shapes:

- Operator env (DYN_NAMESPACE, DYN_COMPONENT, a worker's DYN_SYSTEM_*,
  NIXL_TELEMETRY_* and DYN_FORWARDPASS_METRIC_PORT, a multinode
  component's DYNAMO_RANK and DYNAMO_LEADER_ADDRESS) counts as inert
  container env, never as an envFrom value.
- A worker whose launches are only in role pod templates is checked
  role by role, and P7 reads its model flags there too.
- A native-sidecar worker is skipped: its main runs the engine.
- An unreadable value right after --model, --model-path,
  --served-model-name or --model-name is that option's value; on the
  frontend, only --tool-call-parser, --reasoning-parser and
  --chat-template exempt a separate value.
- The script scan sees env, export, source, eval and shells by path and
  behind exec, nohup, command or builtin, and a redirection target
  other than a here-string is never an option.
- Messages name a script variable's source, give shell-form $(VAR) its
  own advice and say when an option's name is unreadable; the docs list
  the stdin, xargs and su -c forms P4 does not read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
A renewal thread still running when stop() released the Lease could
take it over again, so the successor waited a full lease duration.
LeaseLeadership.release() is now final: a step that reads the Lease
after it stands by and writes nothing.

- The cancelled-initialization test runs the late step in a real thread.
- New tests cover a lapse reported after initialization and the step
  lock between a rebuild and the lease loop.
- The live_retune_sla_errors docstring says when an inherited SLA change
  would reach the controller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
@tedzhouhk
tedzhouhk merged commit c3fb4fe into main Nov 4, 2026
131 checks passed
@tedzhouhk
tedzhouhk deleted the hzhou/dgdr-trace-pvc branch November 4, 2026 01:46
tanmayv25 pushed a commit that referenced this pull request Nov 4, 2026
#17483 added live-retune test cases that pass --router-mode power-of-two
to the frontend and a worker. #17899 removed that mode, and the two
merged 29 minutes apart, so main's planner unit tests fail on both
cases. Use least-loaded for the frontend case and drop the worker case,
which the random, least-loaded and --router-mode=kv cases already cover.

Refs DYN-5265

Signed-off-by: Karen Chung <karenc@nvidia.com>
Signed-off-by: tanmayv25 <tanmay2592@gmail.com>
jh-nv added a commit that referenced this pull request Nov 5, 2026
Check every row and note of the Metrics Catalog against the code, and fix
what differed:

- Add the 16 dynamo_planner_retune_* metrics, which #17483 added without
  catalog entries, as Experimental rows under Planner Metrics.
- Correct descriptions that did not match the code, among them drain
  time, the failover switch counters, KV event ID gaps, routing overhead
  under queueing, the approximate cache policies, planner plugin latency
  and overrides, and the System One, Model Metrics, and Global Frontend
  notes.
- Correct label and exposure claims: the model labels each backend adds,
  the router's component labels, the router queue labels, the mocker's
  engine labels, what --kserve-grpc-server exposes, and which processes
  emit dynamo_component_uptime_seconds.
- python -m dynamo.vllm forces disable_log_stats off, so the page no
  longer says that --disable-log-stats turns its metrics off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jie Hao <jihao@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deployment::k8s Relates to dynamo deployment in kubernetes documentation Improvements or additions to documentation feat frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` planner size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants