Repository navigation
feat(planner): add the live retune configuration and deployment premises - #17734
Conversation
DynamoReplayRunner now replays every candidate of a trace sweep with _deterministic=True: ordinal request ids and the canonical router seed. Candidates of one trace then differ only by their configuration, so a candidate's score does not depend on the other candidates, the Run or the parallelism. Live planner retune compares candidates that different DGDR Runs of one window scored on that basis. The synthetic-workload path is unchanged. First layer of the live retune stack split from #17562. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
Add retune.executor ('local' | 'dgdr') and the retune.dgdr section
(DgdrExecutorConfig, DgdrRunConfig) to the planner config, with the
configuration premises of live retune: P1 (Kubernetes, decision latency,
explicit timeout), P2 (retune-only, router-only), P3 (DGDR router knobs),
P5 (a pinned, scalar AISimulate engine), safe claim paths and P13 (the
largest grid shard finishes within the sweep deadline).
Add the dependency-free live retune contracts (retune/live/contracts.py),
the frontend premise checks that parse the startup router config from the
DGD (retune/live/frontend_config.py), the live fields of SweepRequest and
SweepResult (router_domain, deadline_s, spec_replicas, replicas_verified,
generation; failure_reason, details), which replay leaves at their
defaults, and the shared test fakes.
Nothing runs a live retune yet: a live Planner still rejects any retune at
startup (NativePlannerBase), and the planner.retune description still says
replay-only; the last layer (#17562) wires the live Planner and updates that
description. Replay's _retune_inputs now rejects executor 'dgdr' (with a
test): replay runs local sweeps only, and before this check it accepted a
dgdr configuration and silently ran local sweeps instead.
Second layer of the live retune stack split from #17562.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
Stacks this PR on #17736. The library layers of live retune now come from #17733 (CRN replay), #17734 (configuration and premises), #17735 (window cut and reconciler) and #17736 (DGDR executor), so this PR's diff against #17736 is the supervisor, state, actuator, metrics, the Planner wiring, Helm RBAC, docs and the end-to-end tests. #17734 also adds a replay check that rejects executor 'dgdr'. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
✅ Dynamo PR CI passed — run 41524033037 (attempt 2) on
|
Fold the trace replay determinism check into test_trace_runner_preserves_current_replay_arguments with an agg and a disagg row, and drop the separate test file. Cut the runner comment to the invariant, and update replay/api.py: _deterministic now applies to every trace replay through the Sweeper's Dynamo runner, not only to retune sweeps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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>
…mises - Parse the frontend's and workers' router flags through a public parser builder: ArgEnv in dynamo.common.configuration.utils carries another process's env, the router, KV router and frontend argument groups take it, and frontend_args.build_frontend_parser(env) returns the parser and its env var -> dest map. Every env default comes from that env, notices are skipped and nothing reads the local filesystem, so frontend_config no longer copies functions with overridden globals or touches router_args' private action classes. - Keep one DGDR shard planner: balanced_shard_parts takes the Run parallelism and minimizes evaluation rounds first, dgdr_rounds is public, and P13 plans with the same call the executor will use. - evaluate_premises(dgd, planner_config=...) derives the startup and the parse error itself and reads the planner replicas from the DGD. - Drop the unused trace_incomplete_threshold, the v1alpha1 DGD layout and the graph spec.envs fallback, and envFrom from the parse cache key. - P6 treats only ImportError as "aisimulate absent"; any other failure is logged and reported as a P6 warning. - Move the function-body imports to the module top, remove references to the design document, and move live_retune_fakes.py to the DGDR sweep layer, which uses it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
jthomson04
left a comment
There was a problem hiding this comment.
Re-reviewed at ba2a372. All nine comments are addressed: one shard-math implementation shared with #17736, a public build_frontend_parser, no v1alpha1 branch, no trace_incomplete_threshold. Two should-fix items inline (a second copy of the controller's domain checks, and nothing guarding the parser's env isolation); the rest are trims, about 200 lines.
Separately, this PR uses only FrontendStartup and PremiseReport from contracts.py. The kube, policy, actuation, reconciler, window and metrics types (most of its 471 lines) and the live SweepRequest/SweepResult fields could land with the PRs that use them.
- P4 runs the controller constructor's own startup router checks: RetuneController._router_domain and live retune's _startup_errors both call the new module-level controller.startup_router_domain, replacing the copy in frontend_config. - Guard build_frontend_parser's env isolation: a test sets every env var the parser registers to sentinels in os.environ and expects the empty-env defaults. - Premise tests build validated PlannerConfigs; drop the tests and the branches only impossible configs reached (no router domain, a slash-wrapped segments_dir, an unexpandable or non-'none' load model). - Drop retune.dgdr.startup_router_config and its P4 check. - balanced_shard_parts requires parallelism; drop the points-only ranking and its tests. - One P10 table row per branch. - contracts.py keeps FrontendStartup and PremiseReport; the other types and the live SweepRequest/SweepResult fields move to the PRs that use them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
Note
Stacked PR, live retune (split from #17562). Merge order: #17483 → #17733 → #17734 (this PR) → #17735 → #17736 → #17562
This PR targets
hzhou/live-retune-1-crn, the branch of #17733 (the PR below it), so its diff shows only this layer. #17562 was split into these layers for review. At the split they carried #17562's original diff exactly, plus the 40-line replay check that this PR adds; the review follow-up of 2026-11-02 has since changed several layers.Overview
This is the second layer of live retune (#17562), which adds
retune.executor: dgdr. That executor runs periodic retune on a live Planner on Kubernetes through DGDR v1beta2 Requests. This layer adds the configuration surface, the checks that decide whether a deployment can run live retune, and the shared types that the later layers build on.Nothing runs a live retune in this layer:
retuneat startup.NativePlannerBase.__init__(core/base.py:134-135, unchanged) raisesplanner.retune is replay-only in this release. feat(planner): enable live retune through DGDR v1beta2 #17562 changes that check.PlannerConfignow acceptsexecutor: dgdr. A replay config passes the Kubernetes check (P1), becausekubernetesis the default environment. Without a check, offline replay then ran localrun_sweepsweeps and silently ignored the executor; a probe on this layer confirmed it, and feat(planner): enable live retune through DGDR v1beta2 #17562's own branch behaved the same way. So this layer makes replay reject any executor other thanlocal. The check stays after feat(planner): enable live retune through DGDR v1beta2 #17562:dgdrneeds a live Planner.planner.retunefield description keeps its current text ("Replay-only in this release"). feat(planner): enable live retune through DGDR v1beta2 #17562 updates it together with the runtime change.Key Changes
About 2.9k lines of implementation (0.2k of them in the frontend and common configuration modules) and 2.6k lines of tests.
planner/config/planner_config.py:RetuneConfig.executor(localby default, ordgdr) andRetuneConfig.dgdr, which is required if and only if the executor isdgdr:DgdrExecutorConfig: window phase, the ReadWriteMany claim and its segment and window directories, an optionalstartup_router_config, the model, the SKU, the pinned AISimulateengine, the cut budget, Job start-up time,keep_requests,max_window_rows,promote_last_advisory, the Lease duration and the actuator interval.DgdrRunConfig:parallelism,candidate_timeout_secondsandmax_shards(at most 16).dgdr, the configuration premises P1–P3, P5 and P13 are validated:kubernetes;decision_latency_seconds0, ormeasuredwith scale 1; an explicittimeout_secondsof at mostinterval_seconds − 600.retune.planner.overlap_score_credit,prefill_load_scale,temperature), withprefill_load_modelnone.run.max_shardsshards of at most 100 points, and the largest shard'sneed(n) ≤ timeout_seconds. P13 plans the shards with the same call the executor (feat(planner): run a live retune sweep through DGDR v1beta2 Requests #17736) makes for each window, so both see the same largest shard.balanced_shard_parts(sizes, max_shards, *, parallelism)minimizes the evaluation rounds of the largest shard first, then the shard count;largest_shard_points,dgdr_roundsanddgdr_need_secondsgive that shard's points, rounds and wall time.New package
components/src/dynamo/planner/retune/live/:contracts.py: the shared types, which import nothing else from the package. They include the eight/router_policyparameters, the DGDR knob name map, the Request labels, the DGDR group, version and plurals,NON_DECISION_FAILURES, theKube*errors, and the protocols the later layers implement or consume (RetuneKube,RouterPolicyClient,SweepRegistry,WindowCutter,RetuneMetricsSink).frontend_config.py: parses the DGD's frontend command, args and env into the startupKvRouterConfig. It reads the DGD as v1beta1 (spec.components), as the planner reads every DGD. It applies the operator's defaults, the graph and container env and$(VAR)expansion, and parses with the frontend's own parser frombuild_frontend_parser(env)(below), without reading or changing the Planner's own environment.evaluate_premises(dgd, *, planner_config)parses the frontend itself and evaluates the spec premises: P4 (every unsearched router field is at its default; this also fails when a worker advertises its own router configuration), P7–P10 (P9 reads the planner replicas from the DGD), and the P6 and P7 warnings. P6 treats only anImportErroras AISimulate being absent; any other failure is logged and reported as a P6 warning.envFromproduces only a warning. All functions are pure and make no Kubernetes calls. P14 belongs to the router actuator in feat(planner): enable live retune through DGDR v1beta2 #17562.__init__.py: the package docstring.Frontend and common configuration (
frontend/frontend_args.py,common/configuration/utils.py,common/configuration/groups/router_args.pyandkv_router_args.py):ArgEnvcarries another process's env.env_or_default,add_argument,add_negatable_bool_argument,RouterArgGroup,KvRouterArgGroup,FrontendArgGroupandadd_worker_router_argumentstake an optionalenv. With one, every env default comes from it, deprecation and removal notices are skipped, nothing reads the local filesystem (no--model-pathcheck, no AISimulate perf-model arguments), andArgEnv.env_destsrecords the env var → dest of every argument registered.frontend_args.build_frontend_parser(env)returns the frontend's parser for that env and the env var → dest map.env(every existing caller), parsing, notices and checks are unchanged.planner/retune/sweep.py:SweepRequestgains the live fieldsrouter_domain,deadline_s,spec_replicas,replicas_verifiedandgeneration.SweepResultgainsfailure_reasonanddetails. Replay leaves them at their defaults, andrun_sweepignores them. They are in this layer because #17736's executor uses them.Tests:
unit/test_live_retune_config.pyandunit/test_live_retune_frontend_config.py: every configuration and spec premise rule.frontend/tests/test_frontend_parser_builder.py:build_frontend_parserreads only the given env, leavesos.environunchanged, and maps env vars to dests.common/tests/configuration/test_utils.py:ArgEnvreplacesos.environ, skips deprecation notices and records the dests.tests/live_retune_fakes.py) moved to feat(planner): run a live retune sweep through DGDR v1beta2 Requests #17736, whose executor tests use them.Replay check (40 lines, new in the split; #17562 had no such check):
replay/api.py_retune_inputsraisesplanner.retune executor 'dgdr' is not supported in replay; replay retune runs executor 'local'._retune_inputsis the onlyretune_inputs_factory, so the guard coversrun_trace_replay, andaisimulate predict --stack dynamothrough it. A caller that builds retune inputs itself and passes them straight to the replay planner adapter is not covered; no non-test code does that.replay/tests/test_retune_replay.py::test_retune_rejects_the_dgdr_executor.Validation
Ran on this layer (
c99516cf5f, before the review follow-up) and compared with the same suites at the stack base6e8087d359(#17483's head):test_live_retune_config.py,test_live_retune_frontend_config.pyandtest_retune_rejects_the_dgdr_executorcomponents/src/dynamo/planner/tests,components/src/dynamo/replay/tests, no xdist)pre-commit run --fileson the 10 changed filesdynamo-pipeline.ymlcommand,MYPYPATH=components/src:lib/bindings/python/src mypy --explicit-package-bases) ondynamo/planneranddynamo/replayyaml/pandas/nvtxstubs and existingarg-typeerrors); none is newdgdrPlannerConfigvalidates. Constructing a live Planner with it fails inNativePlannerBase.__init__.run_trace_replaywith it fails at the guard.The 59 failures come from this host. Its prebuilt bindings lack
conversation_affinity(#16854) and theais-forward-passfeature, and it has noetcdbinary. CI builds the bindings from source.After the review follow-up, the tests ran at the top of the stack (#17562's head
92cee14c88), where this layer's files differ only by #17736'sSupportsIsSetincontracts.pyand #17562'splanner.retunedescription: the planner unit tests, the live retune e2e test, the frontend parser builder tests and the common configuration tests gave 2463 passed and 3 skipped (trtllm, sglang and vllm are not installed).pre-commitfrom8d098bed48to92cee14c88is clean. Per-layer runs, the replay suite and mypy were not part of that run.This layer adds library code that nothing reachable calls until #17562. The
retune.livemodules are imported only by tests.core/,__main__.py,retune/controller.pyandplugins/are unchanged. The frontend and common configuration changes add an optionalenvparameter that onlybuild_frontend_parserandfrontend_configpass.Issues and Ongoing Work
retune.executorfield already names its live use ("DGDR v1beta2 Requests (live; requires dgdr)"). It describes what the option is for, whileplanner.retunekeeps saying replay-only until feat(planner): enable live retune through DGDR v1beta2 #17562 enables it.Review follow-up (2026-11-02)
Frontend parsing:
frontend_configno longer copies the frontend's argument functions with overridden globals or touchesrouter_args' private action classes. The frontend and common configuration modules gained the publicArgEnvandbuild_frontend_parser(env), and the router, KV router and frontend argument groups take an optionalenv. This layer now changes those modules.Configuration and premises:
planner_config(balanced_shard_partswith the Run parallelism,largest_shard_points, the now publicdgdr_rounds, anddgdr_need_seconds).evaluate_premises(dgd, *, planner_config)derives the frontend startup, the parse error and the planner replicas from the DGD itself.trace_incomplete_threshold, the v1alpha1 DGD layout, the graphspec.envsfallback, andenvFromfrom the parse cache key.ImportErroras AISimulate being absent; other failures are logged and reported as a P6 warning.Clean-up:
live_retune_fakes.pyto feat(planner): run a live retune sweep through DGDR v1beta2 Requests #17736, the layer whose tests use it.Second review follow-up (2026-11-02)
retune.controller.startup_router_domainholds the router checks that depend on the frontend startup (zero credit, grid, load model, policy config); the controller and P4 both call it, so P4 cannot pass a domain the controller then rejects.os.environand checks thatbuild_frontend_parser({})still returns the empty-env defaults.startup_router_configand its P4 check;balanced_shard_partsrequiresparallelism.contracts.pykeeps onlyFrontendStartupandPremiseReport; the other types and the liveSweepRequest/SweepResultfields moved to the layers that first use them.Validation at
df3a979458: planner unit 1733 passed; frontend and common configuration tests 373 passed, 4 skipped (engines not installed).Pull Request Checklist
/pr-checklistskill.🤖 Generated with Claude Code