Repository navigation
feat(planner): run a live retune sweep through DGDR v1beta2 Requests - #17736
Merged
Merged
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>
Add the two trace-claim pieces of live retune: - retune/live/window_cut.py cuts one retune window from the frontends' gzip request-trace segments on the shared RWX claim into the window file a DGDR Run replays, with the selection, censoring and de-duplication of retune.window.read_trace_window, bounded memory (window_too_large), corrupt-member handling (trace_corrupt) and an atomic output, in a spawn child killed at the deadline or on cancel. - retune/live/reconciler.py garbage-collects what live retune leaves on the claim and in the namespace (old frontend segments, window and temp files, and DGDR Requests beyond retune.dgdr.keep_requests), and is the SweepRegistry a sweep uses to protect its window and Requests. Both are libraries that only the live retune supervisor calls; nothing in this layer wires them into a Planner, which still rejects retune at startup. Third 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 the live sweep executor and its Kubernetes client: - retune/live/dgdr.py: run_dgdr_sweep, the live sweep_fn of RetuneController. It shards the router grid into balanced Cartesian Requests of at most 100 points plus an off-grid baseline shard and a common-random-numbers probe, adopts the Requests a previous leader created for the window, cuts the window file, creates one Request per remaining shard, verifies each Run's input, maps and scores the Candidates on retune.objective, and checks the CRN probe. It never raises and never deletes: removals go to the SweepRegistry queue, and shutdown or lost leadership return at once with every Request kept for the next leader. - retune/live/kube.py: contracts.RetuneKube over the kubernetes client, with request timeouts, Kube* errors that carry the HTTP status, and Leases read without model deserialization so they round-trip unchanged. The executor is not wired into a Planner yet: a live Planner still rejects retune at startup, and replay still rejects executor 'dgdr'. Fourth 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>
This was referenced Oct 30, 2026
tedzhouhk
added a commit
that referenced
this pull request
Oct 30, 2026
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>
1 task
Contributor
✅ Dynamo PR CI passed — run 41524037365 (attempt 1) on
|
jthomson04
reviewed
Oct 31, 2026
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>
…iler
Window cut:
- Check for a published window before reading any segment. The window
file's gzip header comment now holds the counts of the cut that wrote
it, so a later leader adopting the window gets those counts back and
can no longer fail it on segments that changed or broke since; a link
race reports the winner's counts.
- Skip segments last modified more than 300 s before the window starts:
rows are appended when requests complete, after they arrive.
- Read only .jsonl.gz segments and drop the plain JSONL reader; the live
sink writes gzip and the reconciler collects only those segments.
- Compress and write synchronously; drop the writer thread and the
switch-interval tweak, keep the child's lower CPU priority.
Reconciler:
- Ask should_continue before listing Requests and before each uncached
Run-state read, not only before deletes.
- Log a missing trace directory or Request label when it starts rather
than every round; the gauge tracks the condition.
- Read the Request trace source from
spec.workload.trace.source.persistentVolumeClaim.{claimName,subPath}
through one helper, trace_pvc_source.
- State the protected-window and sink-layout rules inline instead of
citing the design document.
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>
- Requests name the trace as workload.trace.source.persistentVolumeClaim
{claimName, subPath} and leave format to its CRD default (Dynamo); the
input read-back finds the trace file with reconciler.trace_pvc_source.
- The Run input read-back is the create path's subset check: the input
may carry new operator defaults under engine, router, optimizer or the
trace source, but must hold every value the Request asks for, and a
null (a deleted worker role, an unset SLA or replay speedup) must stay
unset. inputOverrides win over the typed trace source; nothing
restores it.
- Shard planning and the launch gate call planner_config's
balanced_shard_parts, largest_shard_points and dgdr_need_seconds instead
of a second copy.
- Drop the CRN runtime version floor, which nothing set; the Run's runtime
image and version are still recorded in the details.
- An open Run's Completed reason and message (ContainerWaiting,
TraceSourceMissing, JobRunning) become the shard's message and are part
of the timeout and run_pending errors.
- The wait between polls blocks on the cancel and abort events, so either
ends it at once; a small stop flag with is_set() replaces the polling
Event subclass handed to the window cutter, whose cancel parameter is
typed as any object with is_set() (contracts.SupportsIsSet).
- Read typed SweepRequest fields directly; KubernetesRetuneKube requires
its api_client; drop the tests of the fakes.
- Re-add tests/live_retune_fakes.py (moved here from the configuration
PR), lowering the new trace source like the operator.
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>
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>
…olden The operator's TestDGDRV1beta2TraceRequestLoweringGolden writes deploy/operator/internal/aisimulate/testdata/trace_request_lowering.golden.json: the Request spec of one aggregated grid shard and the Run input that dgdrRunInput lowers it to. The new test checks that build_request returns request_spec, that input_mismatches accepts run_input, and that a restored prefill role or a different trace mount path is still reported. It also checks live_retune_fakes.lower_request_input against run_input, whose docstrings now name the golden as the oracle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
tedzhouhk
added a commit
that referenced
this pull request
Nov 2, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
1 task
jthomson04
reviewed
Nov 2, 2026
jthomson04
left a comment
Contributor
There was a problem hiding this comment.
Re-reviewed at 444ab6d. All nine comments are addressed. input_mismatches is a subset check now and is tested against the Go golden file; the Python rebuild of the lowering stays (here and in live_retune_fakes.lower_request_input), but the golden pins it. One should-fix inline (the same bare-timeout gap as before, on the Request side), a question and a nit.
Trims:
- The Lease and DGD support in
live_retune_fakes.py(get_dgd, the*_leasemethods) and inkube.pyis used only by #17562; moving it there takes about 300 lines out of this PR.update_podandrun_to_completionaren't used anywhere in the stack. dgdr.py:434-484repeats P5's config-load checks (_validate_dgdr_engine,_validate_dgdr_parallelism): the backend,workersbeing a mapping, the single preset entry, positive integers. Keep thespec_replicasrole andreplicas >= 1checks, which depend on the live DGD, and drop the rest with their test rows.
- 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>
- Publish the window file with mode 0644: the Run's sweeper reads it as uid 1000 with supplemental group 65532 and no fsGroup, so 0600 fails every Run of a Planner that runs as another uid. - Excuse a truncated tail at the end of any segment, not only the newest: after an in-place container restart the sink continues in a new segment, so the crashed writer's last flush ends an older one. Drop the newest-segment plumbing and segment_index. - Remove the test-only temp_file_window_end, window_file_name and window_relpath. The reconciler imports TEMP_PREFIX, SEGMENT_SUFFIX and the temp-name regex from window_cut instead of redefining them, and its margins and Kubernetes timeout are module constants. - Re-add the contracts.py types this layer uses first (labels, Kubernetes access, SweepRegistry, the window cutter and the metrics sink). - Trim the module docstrings, the segment-walk errno table and the timing-dependent registry stress test. 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>
- Record why a Request without a Run waits (RunNameConflict, RunCreating, CancelingSupersededRun) in the shard status, as for a waiting Run, so a deadline that passes there reports the reason instead of a bare timeout. - Wait between polls on cancel alone and check abort when the wait ends; every mutation already checks is_leader(). The window cutter keeps one is_set() flag for both events. No helper threads. - Explain why every Request pins the direct generator: the planner reads only Candidate parameters and scores, and the AIC generator can reject a Candidate (#17581) and fail the Run and the window. - Drop the engine checks that P5 already enforces at config load (backend, workers mapping, single preset entry, positive integers); keep the spec_replicas role and replica checks, which depend on the live DGD. - plan_shards requires the Run parallelism, as balanced_shard_parts does. - Move the DGD and Lease access (RetuneKube methods, KubernetesRetuneKube, the fake and their tests) to the layer that uses it, and delete the unused FakeRetuneKube.update_pod and FakeDgdrOperator.run_to_completion. - Re-add the contracts.py types and SweepRequest/SweepResult fields this layer uses first. 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>
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>
tedzhouhk
added a commit
that referenced
this pull request
Nov 2, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
tedzhouhk
added a commit
that referenced
this pull request
Nov 2, 2026
#17736 The #17736 review fixes moved the Lease and DGD support to the layer that uses it, and the merge applied those removals without a conflict. Restore this layer's contracts.py, kube.py and their test, and re-add the fake's DGD and Lease stores. FakeRetuneKube.update_pod and FakeDgdrOperator.run_to_completion stay deleted: nothing calls them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: hongkuanz <hongkuanz@nvidia.com>
sachalmalick
approved these changes
Nov 2, 2026
jthomson04
approved these changes
Nov 2, 2026
tedzhouhk
changed the base branch from
hzhou/live-retune-3-trace
to
hzhou/dgdr-trace-pvc
November 2, 2026 23:57
22 of 31 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
Stacked PR, live retune (split from #17562). Merge order: #17483 → #17733 → #17734 → #17735 → #17736 (this PR) → #17562
This PR targets
hzhou/live-retune-3-trace, the branch of #17735 (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 a 40-line replay check in #17734 that rejectsexecutor: dgdrin offline replay; the review follow-up of 2026-11-02 has since changed several layers.Overview
This is the fourth layer of live retune (#17562). It adds the live sweep executor, which runs one retune window through DGDR v1beta2 Requests, and the Kubernetes client the live modules use.
run_dgdr_sweepis thesweep_fnthat #17562'sRetuneControllerhooks call. Nothing calls it in this layer. A live Planner still rejectsretuneat startup, and replay still rejectsexecutor: dgdrthrough #17734's replay check.Key Changes
About 2.3k lines of implementation and 3.5k lines of tests (1.1k of them the shared fakes). All files are new except two typing changes:
contracts.pygainsSupportsIsSet, andwindow_cut.pyaccepts it ascancel.planner/retune/live/dgdr.py: builds and runs the DGDR Requests of one window, and scores the result.run.max_shardsbalanced Cartesian shards of at most 100 points each, withplanner_config'sbalanced_shard_parts, the same call P13 (feat(planner): add the live retune configuration and deployment premises #17734) makes, and creates one Request per shard. Each Request carriesspec.workload.tracewithsource.persistentVolumeClaim{claimName, subPath}and noformat(the CRD defaults it toDynamo), the pinnedretune.dgdr.engine, the DGD's replica counts and their GPU total as the budget. An off-grid baseline or startup point gets its own single-point Request.crn_mismatch). There is no runtime-version floor, so the probe alone decides; the Run's runtime image and version are still recorded in the details.status.aisimulate.inputagainst the Request with the same subset check: the input may carry new operator defaults (underengine,router,optimizeror the trace source), but must hold every value the Request asks for, and an expectednull(a deleted worker role, an unset SLA or replay speedup) must stay unset.inputOverrideswin over the typed trace source, as in the operator, and nothing restores it. The operator's lowering golden from feat(planner): live retune from recorded traces through DGDR v1beta2 #17483 is the oracle for this check.retune.objective. An open Run'sCompletedreason and message (ContainerWaiting,TraceSourceMissing,JobRunning) become the shard's status and appear in thetimeoutandrun_pendingerrors.SweepRegistryqueue. On shutdown or lost leadership it returns at once and keeps every Request for the next leader: the wait between polls blocks on the cancel and abort events, so either ends it immediately.planner/retune/live/kube.py:KubernetesRetuneKube, which implementscontracts.RetuneKubeover the officialkubernetesclient.api_clientwith a loaded configuration;from_kube_apireuses the planner connector's client.Kube*error that carries the HTTP status.planner/tests/live_retune_fakes.py(moved here from feat(planner): add the live retune configuration and deployment premises #17734):FakeRetuneKubeis an in-memory Kubernetes withresourceVersioncompare-and-swap, Strict field validation, label selectors and injectable faults.FakeDgdrOperatordrives Requests through the DGDR v1beta2 lifecycle the way feat(planner): live retune from recorded traces through DGDR v1beta2 #17483's operator does; itslower_request_inputlowers thepersistentVolumeClaimtrace source like the operator.unit/test_live_retune_dgdr.pycovers shard planning and the time budget, the RFC 7386 shape of the Requests, adoption and replacement of attempts, API and webhook errors, Run timeouts, the CRN probe and scoring, the Run input read-back, plus one sweep with the real window cutter.test_request_and_run_input_match_the_operator_goldenreads feat(planner): live retune from recorded traces through DGDR v1beta2 #17483'strace_request_lowering.golden.json:build_requestmust produce itsrequest_spec, the read-back must accept itsrun_inputand still report a restored prefill role or a different trace mount path, andlower_request_inputmust reproducerun_input.unit/test_live_retune_kube.pycovers the client.dgdr.pyimportscontracts,planner_config,reconciler.trace_pvc_source(#17735),core.types.RetuneParams(already on main) andretune.sweep(with #17734's fields).kube.pyimportscontractsandkubernetes. Neither imports a later layer.Validation
Ran on this layer (
d0aedfc17f, before the review follow-up) and compared with the same suites at the stack base6e8087d359(#17483's head):test_live_retune_dgdr.pyandtest_live_retune_kube.pycomponents/src/dynamo/planner/tests,components/src/dynamo/replay/tests, no xdist)pre-commit run --fileson the 4 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 new, and none is inretune/liveThe 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 are unchanged: the planner unit tests (this layer's, the golden test included), 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. No production code outside this layer references
live.dgdr,live.kube,run_dgdr_sweeporKubernetesRetuneKube.retune/controller.py,engine_adapter.py,core/base.pyand__main__.pyare unchanged. The executor's real-cluster behavior was exercised only in #17562's development-cluster run, on the pre-split branch and before the review follow-up.Issues and Ongoing Work
Review follow-up (2026-11-02)
Requests and read-back:
source.persistentVolumeClaim{claimName, subPath}and omitformat, which the CRD defaults toDynamo. The read-back finds the trace file through feat(planner): cut live retune windows and reconcile the trace claim #17735'strace_pvc_source.null. It follows feat(planner): live retune from recorded traces through DGDR v1beta2 #17483's rule thatinputOverrideswin over the typed trace source.test_request_and_run_input_match_the_operator_golden, which checks the Request, the read-back and the fake operator against feat(planner): live retune from recorded traces through DGDR v1beta2 #17483's lowering golden.Executor:
planner_config's shard planner instead of a second copy.Completedreason and message show up in the shard status and in thetimeoutandrun_pendingerrors.Eventsubclass passed to the window cutter, whosecancelis now typedSupportsIsSet.SweepRequestfields are read directly.Client and tests:
KubernetesRetuneKuberequires itsapi_client.live_retune_fakes.pyhere (moved from feat(planner): add the live retune configuration and deployment premises #17734) and dropped the tests of the fakes themselves.Second review follow-up (2026-11-02)
RunNameConflict,RunCreatingandCancelingSupersededRunare recorded on the shard, so a deadline reports them instead of a baretimeout.generator: directstays, now with a comment: the planner reads only each Candidate's parameters and score, anddirectkeeps retune Runs independent of the AIC generator (AISimulate DGD generation rejects candidates without an explicit block size #17581).cancel.wait()followed by an abort check, with no helper threads;plan_shardsrequiresparallelism.kube.pyand the fakes moved to feat(planner): enable live retune through DGDR v1beta2 #17562;update_podandrun_to_completionare gone; the config-load checks P5 already enforces are no longer repeated.Validation at
dfe7edf204: planner unit 1968 passed, including the golden test.Pull Request Checklist
/pr-checklistskill.🤖 Generated with Claude Code