Skip to content

feat(planner): run a live retune sweep through DGDR v1beta2 Requests - #17736

Merged
tedzhouhk merged 25 commits into
hzhou/dgdr-trace-pvcfrom
hzhou/live-retune-4-dgdr
Nov 2, 2026
Merged

tedzhouhk merged 25 commits into
hzhou/dgdr-trace-pvcfrom
hzhou/live-retune-4-dgdr

Conversation

@tedzhouhk

@tedzhouhk tedzhouhk commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

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 rejects executor: dgdr in 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_sweep is the sweep_fn that #17562's RetuneController hooks call. Nothing calls it in this layer. A live Planner still rejects retune at startup, and replay still rejects executor: dgdr through #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.py gains SupportsIsSet, and window_cut.py accepts it as cancel.

  • planner/retune/live/dgdr.py: builds and runs the DGDR Requests of one window, and scores the result.
    • It splits the router grid into at most run.max_shards balanced Cartesian shards of at most 100 points each, with planner_config's balanced_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 carries spec.workload.trace with source.persistentVolumeClaim{claimName, subPath} and no format (the CRD defaults it to Dynamo), the pinned retune.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.
    • One more single-point Request replays a grid point again as a common-random-numbers probe. The two scores must agree within a relative error of 1e-9 (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.
    • It adopts the Requests a previous leader created for the window, matched by DGD uid, window, shard and spec hash. A window whose shards were all adopted as Succeeded is harvested without being cut again.
    • It cuts the window file through feat(planner): cut live retune windows and reconcile the trace claim #17735's cutter and then creates the Requests with Strict field validation. It checks that the API server kept every submitted field. It then checks each Run's status.aisimulate.input against the Request with the same 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 an expected null (a deleted worker role, an unset SLA or replay speedup) must stay unset. inputOverrides win 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.
    • It waits on Runs, reads Candidates, maps their router parameters back to live names, requires identical non-router parameters across the window, and scores them with retune.objective. An open Run's Completed reason and message (ContainerWaiting, TraceSourceMissing, JobRunning) become the shard's status and appear in the timeout and run_pending errors.
    • It never raises and never deletes. Requests to remove go to the SweepRegistry queue. 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.
    • A failed baseline or probe shard fails the window. Any other failed shard only leaves its points unscored.
  • planner/retune/live/kube.py: KubernetesRetuneKube, which implements contracts.RetuneKube over the official kubernetes client.
    • It requires an api_client with a loaded configuration; from_kube_api reuses the planner connector's client.
    • Every call carries a request timeout and raises a Kube* error that carries the HTTP status.
    • The DGD (v1beta1) and the DGDR v1beta2 Requests, Runs and Candidates come back as the API server's JSON.
    • Leases are read without model deserialization, so they round-trip unchanged.
  • planner/tests/live_retune_fakes.py (moved here from feat(planner): add the live retune configuration and deployment premises #17734): FakeRetuneKube is an in-memory Kubernetes with resourceVersion compare-and-swap, Strict field validation, label selectors and injectable faults. FakeDgdrOperator drives Requests through the DGDR v1beta2 lifecycle the way feat(planner): live retune from recorded traces through DGDR v1beta2 #17483's operator does; its lower_request_input lowers the persistentVolumeClaim trace source like the operator.
  • Tests: unit/test_live_retune_dgdr.py covers 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_golden reads feat(planner): live retune from recorded traces through DGDR v1beta2 #17483's trace_request_lowering.golden.json: build_request must produce its request_spec, the read-back must accept its run_input and still report a restored prefill role or a different trace mount path, and lower_request_input must reproduce run_input. unit/test_live_retune_kube.py covers the client.

dgdr.py imports contracts, planner_config, reconciler.trace_pvc_source (#17735), core.types.RetuneParams (already on main) and retune.sweep (with #17734's fields). kube.py imports contracts and kubernetes. 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 base 6e8087d359 (#17483's head):

Check Result
test_live_retune_dgdr.py and test_live_retune_kube.py 104 passed
Planner and replay suites (components/src/dynamo/planner/tests, components/src/dynamo/replay/tests, no xdist) 59 failed, 2698 passed, 2 skipped. The failing tests are the same 59 as at the base (59 failed, 2131 passed).
pre-commit run --files on the 4 changed files All hooks pass, no files changed
CI mypy (the dynamo-pipeline.yml command, MYPYPATH=components/src:lib/bindings/python/src mypy --explicit-package-bases) on dynamo/planner and dynamo/replay The same 9 errors as at the base (missing yaml/pandas/nvtx stubs and existing arg-type errors); none is new, and none is in retune/live

The 59 failures come from this host. Its prebuilt bindings lack conversation_affinity (#16854) and the ais-forward-pass feature, and it has no etcd binary. 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-commit from 8d098bed48 to 92cee14c88 is 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_sweep or KubernetesRetuneKube. retune/controller.py, engine_adapter.py, core/base.py and __main__.py are 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:

Executor:

  • Shard planning and the launch gate call planner_config's shard planner instead of a second copy.
  • Removed the CRN runtime-version floor, which nothing set; the Run's runtime image and version are still recorded.
  • An open Run's Completed reason and message show up in the shard status and in the timeout and run_pending errors.
  • Cancel and abort end the wait between polls at once. A small stop flag replaces the polling Event subclass passed to the window cutter, whose cancel is now typed SupportsIsSet.
  • Typed SweepRequest fields are read directly.

Client and tests:

Second review follow-up (2026-11-02)

  • RunNameConflict, RunCreating and CancelingSupersededRun are recorded on the shard, so a deadline reports them instead of a bare timeout.
  • generator: direct stays, now with a comment: the planner reads only each Candidate's parameters and score, and direct keeps retune Runs independent of the AIC generator (AISimulate DGD generation rejects candidates without an explicit block size #17581).
  • The poll wait is cancel.wait() followed by an abort check, with no helper threads; plan_shards requires parallelism.
  • Lease and DGD access in kube.py and the fakes moved to feat(planner): enable live retune through DGDR v1beta2 #17562; update_pod and run_to_completion are 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
  • I used Dynamo's /pr-checklist skill.

🤖 Generated with Claude Code

tedzhouhk and others added 4 commits October 30, 2026 15:48
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>
@tedzhouhk
tedzhouhk requested a review from a team as a code owner October 30, 2026 23:42
@github-actions github-actions Bot added the feat label 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>
@devin-ai-integration

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

Copy link
Copy Markdown
Contributor

✅ Dynamo PR CI passed — run 41524037365 (attempt 1) on dfe7edf204

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

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

@jthomson04 jthomson04 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 at 2dce2a5. Three should-fix items inline, plus nits. Naming, adoption after restart, 409/404 handling and the status fields read all match the operator at #17483.

tedzhouhk and others added 12 commits November 2, 2026 08:26
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>

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

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 *_lease methods) and in kube.py is used only by #17562; moving it there takes about 300 lines out of this PR. update_pod and run_to_completion aren't used anywhere in the stack.
  • dgdr.py:434-484 repeats P5's config-load checks (_validate_dgdr_engine, _validate_dgdr_parallelism): the backend, workers being a mapping, the single preset entry, positive integers. Keep the spec_replicas role and replicas >= 1 checks, which depend on the live DGD, and drop the rest with their test rows.

tedzhouhk and others added 9 commits November 2, 2026 11:54
- 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>
@tedzhouhk
tedzhouhk changed the base branch from hzhou/live-retune-3-trace to hzhou/dgdr-trace-pvc November 2, 2026 23:57
@tedzhouhk
tedzhouhk requested review from a team as code owners November 2, 2026 23:57
@tedzhouhk
tedzhouhk merged commit 08c5eb9 into hzhou/dgdr-trace-pvc Nov 2, 2026
117 of 132 checks passed
@tedzhouhk
tedzhouhk deleted the hzhou/live-retune-4-dgdr branch November 2, 2026 23:57
@sttts sttts mentioned this pull request Nov 5, 2026
22 of 31 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants