Skip to content

refactor(operator): implement composition-first DGD reconciliation - #12283

Merged
julienmancuso merged 19 commits into
mainfrom
jsm/12035-6
Aug 3, 2026
Merged

refactor(operator): implement composition-first DGD reconciliation#12283
julienmancuso merged 19 commits into
mainfrom
jsm/12035-6

Conversation

@julienmancuso

@julienmancuso julienmancuso commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Complete the composition-first refactor of DynamoGraphDeployment reconciliation while preserving the existing workload pathways and Kubernetes behavior.

This pull request consolidates the full series into one reviewable change. Component/DCD and Grove remain separate, complete workload programs, but both now compose focused reconcilers with explicit dependencies instead of delegating back to the all-capable DynamoGraphDeploymentReconciler.

The outer DGD reconciler is reduced to lifecycle ownership: load and finalize the DGD, select one workload program, invoke it once, persist its authoritative status, and emit queued status-transition events after persistence succeeds.

What changed

Establish a small program contract

  • Introduce a workload-program request containing only the mutable DGD.
  • Return ctrl.Result, complete desired status, and queued status-transition events in the program result.
  • Preserve intentional non-status mutations on the request DGD while accumulating status separately.
  • Keep the outer reconciler as the only DGD status-subresource writer.
  • Preserve meaningful partial status when a later reconciliation step fails.
  • Emit status-transition events only after status persistence succeeds and direct resource-mutation events only after the corresponding semantic mutation succeeds.

Compose complete, separate workload programs

  • Keep Component/DCD and Grove as separate programs that own their own order and timing.
  • Keep the existing one-method program-selection boundary.
  • Avoid a shared provider lifecycle, renderer lifecycle, rollout abstraction, or mutable facts/request bag.
  • Pass concrete domain inputs and typed observations directly between collaborators.

The Component program owns DCD generation and synchronization, managed worker rollout, restart progress, checkpoint startup policy, readiness aggregation, and component-path cleanup.

The Grove program owns PodCliqueSet rendering and synchronization, Grove scaling, stable services and ingress resources, restart progress, coherent readiness observation, topology-condition projection, and Grove child watches.

Decompose shared DGD reconciliation

Replace the former monolithic program-input flow with focused reconcilers for:

  • RBAC;
  • PVCs;
  • discovery resources;
  • GMS ResourceClaimTemplates;
  • checkpoints;
  • EPP resources;
  • the wait-for-leader ConfigMap;
  • MPI SSH keys;
  • scaling adapters.

The shared-resources reconciler preserves the existing execution order and returns focused, typed checkpoint observations for later workload steps.

Narrow rendering and provider boundaries

  • Make DCD and Grove workload rendering read-only through client.Reader dependencies.
  • Move checkpoint-storage writes out of rendering and into dedicated reconciliation.
  • Replace Grove-wide render-facts, workload-model, and render-request bags with direct inputs and local temporary values.
  • Isolate Grove rendering, scaling, stable-resource reconciliation, readiness interpretation, topology projection, and watch setup behind focused collaborators.
  • Preserve Grove ordering, topology migration, restart annotations, and scale-subresource-owned replica values.
  • Preserve scaling-adapter-owned replicas after adapter creation while allowing the DGD replica count to seed new adapters.

Make source and test ownership explicit

  • Keep program code focused on construction, sequencing, and result projection.
  • Place focused tests alongside the reconcilers they exercise while retaining end-to-end controller coverage.
  • Add scoped agent guidance documenting the composition, status, event, capability, and ownership boundaries future changes must preserve.

Status and event ownership

The selected program returns the complete desired status for the reconciliation attempt, including:

  • state and component status;
  • checkpoint status;
  • restart and rolling-update status;
  • the final Ready condition;
  • ObservedGeneration;
  • provider-specific conditions such as Grove topology availability.

The outer reconciler persists that status once. Status-transition events are queued by the program and emitted only after persistence succeeds. Events for child-resource mutations are emitted only when the corresponding create, update, patch, or delete succeeds and produces a semantic change.

Behavior and compatibility

This is an internal architecture refactor. It does not intentionally change:

  • DGD APIs, CRDs, or RBAC permissions;
  • workload-path selection or feature-gate behavior;
  • DCD, LWS, or Grove workload semantics;
  • rendered names, labels, annotations, selectors, or ownership;
  • managed rolling-update eligibility or phase behavior;
  • restart and checkpoint startup policies;
  • service, ingress, and virtual-service generation;
  • Grove readiness, topology, scaling, cleanup, or significant-watch behavior;
  • the single event-driven reconciliation model.

Component and Grove remain separate complete workload programs. No cross-provider lifecycle or capability-driven rollout algorithm is introduced.

Review guidance

A useful review order is:

  1. the workload-program request/result boundary and outer status/event ownership;
  2. Component and Grove program construction and sequencing;
  3. shared-resource reconciliation and its focused child reconcilers;
  4. Component workload, restart, and rollout collaborators;
  5. Grove workload, scaling, readiness, topology, and watch collaborators;
  6. focused tests and the scoped architectural agent guidance.

Review history

This pull request contains the cumulative work previously presented through:

GitHub marked #12502 merged after its head became fully contained by this pull request.

Validation

Combined head 6773306ee9 passed:

GOCACHE=/tmp/dynamo-go-cache go test ./internal/controller -count=1

docker buildx build --platform linux/arm64 --target linter --progress=plain --build-context snapshot=../snapshot .

docker buildx build --platform linux/arm64 --target tester --progress=plain --build-context snapshot=../snapshot --build-context operator-chart=../helm/charts/platform/components/operator .

The ARM64 tester runs the complete operator make test target, including formatting, vetting, generated-resource checks, envtest-backed tests, and coverage. Controller-package coverage is 73.9%.


Open in Devin Review

Summary by CodeRabbit

  • New Features

    • Added automatic checkpoint storage provisioning when checkpointing is enabled.
    • Improved checkpoint restoration, including PVC-backed restores and GPU-related configuration.
    • Added enhanced Grove workload scaling, readiness tracking, topology status, and resource preservation.
    • Added support for more consistent workload rendering across component and Grove deployments.
  • Bug Fixes

    • Improved reconciliation behavior for missing or temporarily unavailable workload resources.
    • Preserved existing replica counts, ordering, restart settings, and legacy deployment compatibility during updates.
  • Tests

    • Expanded coverage for checkpoint restoration, scaling, readiness, upgrades, rollouts, and status reporting.

@julienmancuso
julienmancuso requested review from a team as code owners July 28, 2026 21:05
@github-actions github-actions Bot added refactor deployment::k8s Relates to dynamo deployment in kubernetes labels Jul 28, 2026

@devin-ai-integration devin-ai-integration Bot 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.

Devin Review found 1 potential issue.

Open in Devin Review

Comment thread deploy/operator/internal/controller/dynamographdeployment_grove_status.go Outdated

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

Disclosure: This review was written by Codex as its interpretation of a discussion with Stefan; it is not Stefan’s text.

This is an update to the architectural review on #12263 at fc2e40a, after reading the incremental b09d873 commit in this PR.

What this PR improves

This is a meaningful step in the proposed direction:

  • groveProgram now owns concrete renderer, scaler, and status collaborators.
  • Grove watch setup is separated from the common controller.
  • Read-only paths use client.Reader instead of client.Client.
  • Readiness is observed once from a coherent post-scaling snapshot.
  • Grove topology status is accumulated in the returned program status; the outer reconciler remains the status writer.
  • Kubernetes-backed retrieval and PodCliqueSet construction are now mechanically separated.

The new groveScaler, groveStatusResolver, and groveWatchSetup demonstrate the useful part of the approach: concrete responsibilities with narrower capabilities.

1. Keep the retrieval/rendering boundary, but avoid facts and request bags

The capability boundary is good. The resulting data abstraction is not.

GrovePodCliqueSetRenderFactsRequest, GrovePodCliqueSetRenderFacts, GrovePodCliqueSetRenderRequest, and groveRenderInputs divide one concrete operation into several structureless carrier types. They make the call graph more abstract without giving the values a stronger domain invariant.

checkpoint.ResolvedPodSpecRestore is different: it represents one cohesive, validated domain result and prevents callers from depending on checkpoint-storage internals. That is a useful resolved type. A generic collection of unrelated “facts” is not.

I would keep groveWorkloadRenderer as the concrete boundary, inject client.Reader, retrieve the required objects directly, keep temporary collections local, and pass concrete values to pure leaf functions:

type groveWorkloadRenderer struct {
    reader                client.Reader
    config                *configv1alpha1.OperatorConfiguration
    runtimeConfig         *commoncontroller.RuntimeConfig
    dockerSecretRetriever dockerSecretRetriever
}

func (r *groveWorkloadRenderer) Render(
    ctx context.Context,
    dgd *nvidiacomv1beta1.DynamoGraphDeployment,
    restart *dynamo.RestartState,
    checkpoints map[string]*checkpoint.CheckpointInfo,
) (*grovev1alpha1.PodCliqueSet, error) {
    existing := &grovev1alpha1.PodCliqueSet{}
    key := types.NamespacedName{
        Name:      dynamo.PCSNameForDGD(dgd.Name, dgd.Spec.Components),
        Namespace: dgd.Namespace,
    }
    if err := r.reader.Get(ctx, key, existing); err != nil {
        if !apierrors.IsNotFound(err) {
            return nil, fmt.Errorf("get PodCliqueSet %s: %w", key, err)
        }
        existing = nil
    }

    renderDGD := dgd.DeepCopy()
    applyGroveCompatibility(renderDGD, existing)

    // Resolve queue, topology, and checkpoint inputs here. Keep collections
    // local unless an individual value has a cohesive domain contract.
    // Then call pure rendering helpers with the actual inputs.
    // ...
}

The goal is a hard read/write capability boundary, not purity at the price of argument-bag abstractions. There is also no need for a custom one-method reader interface or a helper that merely renames reader.Get.

2. Continue replacing method-name composition with struct composition

The Grove-specific extractions are good examples, but the program still retains the complete DynamoGraphDeploymentReconciler and still composes large responsibilities through it:

p.reconciler.reconcileProgramInputs(...)
p.reconciler.resolveProgramRestartState(...)
p.reconciler.reconcileProgramResult(...)
p.reconcileStableResources(...)

I would continue until the struct graph itself explains the composition:

type groveProgram struct {
    rollout         *dgdUnsupportedRolloutReconciler
    sharedResources *dgdSharedResourcesReconciler
    restart         *dgdRestartReconciler
    workloads       *groveWorkloadReconciler
    stableResources *dgdStableResourcesReconciler
    topology        *dgdGroveTopologyConditionReconciler
}

Each should be independently constructible and testable with only its own fixtures. Use short standardized method names such as Reconcile, Resolve, and Render; let the concrete type identify the purpose. Separate files should use a consistent DGD prefix, for example dgd_checkpoints_reconciler.go and dgd_restart_reconciler.go.

In particular, reconcileProgramInputs still effectfully reconciles RBAC, PVCs, discovery, GMS claims, checkpoints, EPP resources, the wait-for-leader ConfigMap, and MPI SSH keys. These are the next concrete reconcilers to extract. The criterion is cohesive resource ownership and an independent fixture contract, not mechanical fragmentation.

3. Finish the Request/Result and status-ownership boundary

The empty resolvedFacts and unused Request.Facts still exist. Remove them until a real common input appears.

workloadProgramResult also still splits Status from ReadyReason and ReadyMessage, while the outer reconciler computes and overrides Ready based on rollout state. That leaves condition ownership shared.

The contract should remain:

type Request struct {
    // Mutable primary object. Programs may persist non-status mutations.
    DGD *nvidiacomv1beta1.DynamoGraphDeployment
}

type Result struct {
    ctrl.Result
    Status nvidiacomv1beta1.DynamoGraphDeploymentStatus
    Events []Event
}

The selected program should return the complete desired status, including the final Ready condition, rollout/restart state, and ObservedGeneration. The outer reconciler should persist that status unchanged.

This PR moves topology projection in that direction. The same ownership rule should now be applied to Ready instead of returning a reason/message that another layer later interprets and overrides.

4. Return status-transition events with the status

groveStatusResolver now writes into the returned status, but it also owns an EventRecorder and emits the topology warning before the outer Status().Update succeeds.

That event describes a DGD status transition. It should therefore be queued in Result.Events and emitted only after the corresponding status update succeeds and actually changes persisted status. Otherwise an update failure can produce an event for an edge that was not persisted, and retries can emit it again.

Direct event creation remains fine after a locally detected semantic resource mutation successfully completes. The distinction is where the edge becomes real:

  • resource mutation edge: emit after the successful Create, Update, Patch, or Delete, and only when something actually changed;
  • DGD status edge: return it with the status, persist the status, then emit it.

Direction

This PR materially improves Grove isolation and read-side dependency boundaries. It does not yet complete the program abstraction described in the earlier review.

The main remaining work is:

  • remove the empty common facts container;
  • avoid Grove-wide facts/request bags;
  • make the returned status authoritative, including Ready;
  • queue status-transition events and emit them after persistence;
  • replace the remaining all-powerful reconciler calls with concrete nested reconcilers;
  • decompose reconcileProgramInputs into cohesive DGD reconcilers.

DCD and Grove should remain separate workload programs by design. No renderer or provider lifecycle composition between them is being proposed. The shared abstraction is the small program Request/Result contract; each program continues to own its own order and timing.

Comment thread deploy/operator/internal/controller/dynamographdeployment_grove_watches.go Outdated
Comment thread deploy/operator/internal/controller/dynamographdeployment_grove_watches.go Outdated
Comment thread deploy/operator/internal/controller/dynamographdeployment_grove_status.go Outdated
Comment thread deploy/operator/internal/controller/dynamographdeployment_grove_program.go Outdated
Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
…gram

Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
…oller

Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
…aborators

Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
@datadog-official

This comment has been minimized.

@julienmancuso
julienmancuso changed the base branch from jsm/12035-5 to main July 31, 2026 17:20
@julienmancuso julienmancuso changed the title refactor(operator): isolate Grove reconciliation behind provider collaborators refactor(operator): compose DGD reconciliation as workload programs Jul 31, 2026
Signed-off-by: Julien Mancuso <jmancuso@nvidia.com>
@julienmancuso

Copy link
Copy Markdown
Contributor Author

/ok to test 6bf4030

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Checkpointed workload reconciliation

Layer / File(s) Summary
Checkpoint resolution and storage preparation
deploy/operator/internal/checkpoint/*, deploy/operator/internal/controller/dcd_checkpoint_storage_reconciler*, deploy/operator/internal/dynamo/graph*
Checkpoint restoration now resolves state before PodSpec injection. PVC storage reconciliation runs when checkpoint storage is configured.
DCD workload rendering and controller wiring
deploy/operator/internal/controller/dynamocomponentdeployment_*
A reusable renderer now generates DCD PodSpecs, Services, labels, and component types. The controller uses the renderer and reconciles checkpoint storage first.
Workload programs and status ownership
deploy/operator/internal/controller/dynamographdeployment_controller*, dynamographdeployment_program*, dynamographdeployment_rollingupdate*
Reconciliation now selects workload programs. Program results own status updates and events. Rolling-update methods receive explicit status and progress resolvers.
Grove rendering, scaling, status, and watches
deploy/operator/internal/controller/dynamographdeployment_grove_*
Grove reconciliation now uses dedicated rendering, scaling, readiness, status, and watch components.
Grove readiness and read-only APIs
deploy/operator/internal/dynamo/grove.go, deploy/operator/internal/controller/upgrade_test.go
Grove readiness uses a shared snapshot. Read-only Kubernetes interfaces and centralized Grove resource naming are used across readiness and rendering paths.

Estimated code review effort: 5 (Critical) | ~120 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description explains the architecture, behavior, review order, and validation, but it omits the required Related Issues section. Add the required Related Issues section and either link the relevant issue numbers or confirm that no related issue exists.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: a composition-first refactor of DynamoGraphDeployment reconciliation.

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (19)
deploy/operator/internal/controller/dynamocomponentdeployment_controller.go (1)

184-191: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a one-line story comment above the checkpoint-storage step.

The block creates the checkpoint storage reconciler and converges storage before workload rendering. The guidelines require a one-line story comment above such a block.

♻️ Proposed comment
+	// Converge checkpoint storage first so workload rendering stays read-only.
 	checkpointStorageReconciler := newDCDCheckpointStorageReconciler(

As per coding guidelines: "In Go code, put a one-line story comment above every multi-line block of logically connected code."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamocomponentdeployment_controller.go`
around lines 184 - 191, Add a concise one-line story comment immediately above
the checkpointStorageReconciler creation and Reconcile block, describing that
checkpoint storage is converged before workload rendering. Do not alter the
reconciliation logic or error handling.

Source: Coding guidelines

deploy/operator/internal/dynamo/graph_test.go (1)

1245-1320: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add t.Log headings for each test step.

The guidelines require t.Log headings that explain the test story, with one heading before each block that implements a test step. This test has three steps: build the PVC-backed fixtures, generate the PodCliqueSet, and assert the injected checkpoint volume.

As per coding guidelines: "In Go tests, use t.Log to explain the test's story, with one heading before each block implementing a test step."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/dynamo/graph_test.go` around lines 1245 - 1320, Add
t.Log headings in TestGenerateGrovePodCliqueSet_InjectsReadyCheckpointRestore
before each test step: building the PVC-backed fixtures, generating the
PodCliqueSet, and asserting the injected checkpoint volume. Keep the existing
setup, generation, and assertions unchanged.

Source: Coding guidelines

deploy/operator/internal/controller/dynamocomponentdeployment_renderer.go (2)

395-438: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Guard runtimeConfig like reader.

Line 400 checks r == nil and r.reader == nil, but Line 413 dereferences r.runtimeConfig.Gate without a check. A renderer built with a nil runtimeConfig panics here instead of returning an error. Either drop the defensive nil checks at Line 400 or extend them to r.runtimeConfig.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamocomponentdeployment_renderer.go`
around lines 395 - 438, The nil guard in hasExistingLegacyWorkerSelector is
incomplete because the method dereferences runtimeConfig when evaluating the LWS
feature gate. Extend the initial guard to include r.runtimeConfig, preserving
the existing false, nil return for an unavailable renderer dependency.

81-105: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Resolve the workload component type once per render.

getDCDWorkloadPodLabels calls getDCDWorkloadComponentType, and generatePodTemplateSpec calls it again for each role. getDCDWorkloadComponentType can call hasExistingLegacyWorkerSelector, which issues up to three Get calls (Deployment, LeaderWorkerSet, Service). For a multinode render this repeats the same resolution three times, so up to nine reads occur per reconcile. Resolve the component type once in renderMultinodePodTemplateSpecs and pass it into the per-role helpers. This also removes the risk that the pod labels and the pod spec disagree if a legacy object appears between calls.

Also applies to: 149-159

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamocomponentdeployment_renderer.go`
around lines 81 - 105, Update renderMultinodePodTemplateSpecs to resolve the
workload component type once, then pass that resolved value through
getDCDWorkloadPodLabels and the leader/worker pod-template generation helpers.
Adjust generatePodTemplateSpec and related helper signatures to reuse the
supplied type instead of calling getDCDWorkloadComponentType per role. Preserve
existing label and pod-spec behavior while eliminating repeated legacy-object
lookups and ensuring both paths use the same resolution.
deploy/operator/internal/dynamo/graph.go (1)

2457-2472: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Centralize the "needs resolved restore" predicate and add a story comment.

The resolve condition here and the shouldUseAdmissionRestore condition in buildCliqueForRole (Lines 2158-2164) encode the same policy with inverted logic. The two sites must stay in agreement, otherwise buildCliqueForRole fails with resolved checkpoint restore is required for role ... or silently skips restore. Extract one helper, for example needsResolvedRestore(gate, checkpointInfo), and call it from both sites.

Also add a one-line story comment above this block, as the guidelines require for multi-line blocks of logically connected Go code.

As per coding guidelines: "In Go code, put a one-line story comment above every multi-line block of logically connected code."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/dynamo/graph.go` around lines 2457 - 2472, Extract
the shared checkpoint policy into a helper such as needsResolvedRestore, and use
it both in buildCliqueForRole’s shouldUseAdmissionRestore logic and this
checkpoint.ResolvePodSpecRestore block so the conditions remain consistent. Add
a one-line story comment immediately above this multi-line restore-resolution
block describing its purpose.

Source: Coding guidelines

deploy/operator/internal/checkpoint/podspec.go (1)

256-308: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant Ready checks in the read-free phase.

ResolvePodSpecRestore returns nil unless the checkpoint is enabled and ready. Therefore restore.info.Ready is always true inside InjectResolvedCheckpointIntoPodSpec. The parameter at Line 277 and the condition at Line 296 always evaluate to true. Consider dropping these checks, or document that ResolvedPodSpecRestore is only constructed for ready checkpoints, so a future caller does not assume the unready case is still handled here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/checkpoint/podspec.go` around lines 256 - 308,
Remove the redundant restore.info.Ready argument passed to PrepareRestorePodSpec
and the restore.info.Ready condition guarding GPUMemoryService handling in
InjectResolvedCheckpointIntoPodSpec, since ResolvedPodSpecRestore is only
produced for ready checkpoints. Preserve the existing storage, seccompProfile,
GPU mode, and error behavior.
deploy/operator/internal/controller/dcd_checkpoint_storage_reconciler_test.go (1)

74-101: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add per-step t.Log headings and a disabled-checkpoint case.

Two points:

  1. The repository guidelines require one t.Log heading before each block that implements a test step. The subtest has three steps: build the fixtures, reconcile, and assert the PVC state. Only one heading exists.
  2. Add a table case where the component declares Checkpoint: &ComponentCheckpointConfig{Enabled: false}. That case pins the behavior for a declared-but-disabled checkpoint, which the current cases do not cover.

As per coding guidelines: "Use one t.Log heading before each block that implements a test step so test output tells the scenario's story."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@deploy/operator/internal/controller/dcd_checkpoint_storage_reconciler_test.go`
around lines 74 - 101, Add separate t.Log headings before each test-step block
in the subtest: fixture construction, reconciler execution, and PVC-state
assertion. Extend the table-driven cases with a scenario where
Experimental.Checkpoint is declared but Enabled is false, and assert the
expected PVC behavior for that case alongside the existing enabled and absent
configurations.

Source: Coding guidelines

deploy/operator/internal/controller/dcd_checkpoint_storage_reconciler.go (1)

54-72: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a one-line story comment above the validation block.

The repository guidelines require a one-line story comment above every multi-line block of logically connected code in Go. Lines 58-69 form one validation and short-circuit block without such a comment.

♻️ Proposed comment
 ) error {
+	// Skip storage convergence unless this DCD actually requests checkpointing.
 	if dcd == nil {
 		return fmt.Errorf("dynamo component deployment is required")
 	}

As per coding guidelines: "In Go code, put a one-line story comment above every multi-line block of logically connected code."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dcd_checkpoint_storage_reconciler.go`
around lines 54 - 72, Add a single one-line story comment immediately above the
validation and early-return block in Reconcile, covering the nil deployment, nil
feature gate, disabled Checkpoint gate, and missing checkpoint configuration
checks. Leave the validation logic and EnsureStoragePVC call unchanged.

Source: Coding guidelines

deploy/operator/internal/controller/dynamographdeployment_controller.go (3)

141-149: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a Reason constant for the finalizer failure.

Line 143 passes the raw string "failed_to_handle_the_finalizer". All other failure paths use the Reason constants declared near line 72. Declare a constant and use it so the reason set stays discoverable in one place.

♻️ Proposed change
-			programResult.Fail(dynamoDeployment.Generation, "failed_to_handle_the_finalizer", err)
+			programResult.Fail(dynamoDeployment.Generation, reasonFailedToHandleFinalizer, err)

Add the constant next to the other reasons:

reasonFailedToHandleFinalizer Reason = "failed_to_handle_the_finalizer"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamographdeployment_controller.go`
around lines 141 - 149, Declare a reasonFailedToHandleFinalizer Reason constant
alongside the existing Reason constants, then update the
newWorkloadProgramResult failure call in the finalizer error path to use it
instead of the raw string.

172-187: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Skip the status write when the projected status is unchanged.

persistWorkloadProgramResult calls Status().Update on every reconcile, including reconciles that produce an identical status. This adds one API write per reconcile for steady-state deployments. Compare the projected status with the stored status and write only on a difference. Keep the event flush after a successful write.

♻️ Proposed change
 ) error {
+	if equality.Semantic.DeepEqual(dgd.Status, result.Status) {
+		return nil
+	}
 	dgd.Status = result.Status
 	if err := r.Status().Update(ctx, dgd); err != nil {
 		return fmt.Errorf("update DynamoGraphDeployment status: %w", err)
 	}

Note that queued events must still flush when the status is already current, so move the event loop before the early return if that ordering is required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamographdeployment_controller.go`
around lines 172 - 187, Update persistWorkloadProgramResult to compare the
projected result.Status with dgd.Status before calling r.Status().Update,
skipping the status write when unchanged. Ensure result.Events are still flushed
through r.Recorder.Event in both unchanged and successfully updated cases, while
preserving error propagation for failed status updates.

154-169: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add story comments above the new reconcile blocks.

Lines 154-157 select and run the workload program. Lines 158-166 persist the result and propagate errors. The coding guidelines require a one-line story comment above every multi-line block of logically connected Go code. Add one comment per block.

As per coding guidelines: "In Go code, put a one-line story comment above every multi-line block of logically connected code."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamographdeployment_controller.go`
around lines 154 - 169, Add one-line story comments immediately above the
workload program selection/reconciliation block and above the result
persistence/error-propagation block in the reconciliation flow surrounding
selectWorkloadProgram, program.Reconcile, and persistWorkloadProgramResult. Keep
each comment concise and describing the block’s purpose.

Source: Coding guidelines

deploy/operator/internal/controller/dynamographdeployment_controller_test.go (1)

455-529: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add t.Log headings to the new tests.

TestReconcileScalingAdaptersEmitsDeleteEventOnlyAfterSuccessfulDelete has no t.Log heading before its setup and verification steps. TestGroveWatchSetup_MapPodCliqueToRequests (lines 4994-5025) and TestGroveChildEventPredicates (lines 5387-5399) have the same gap. Add one heading per test step so the test output tells the scenario story, as the neighboring TestDynamoGraphDeploymentReconciler_isGrovePathway already does.

♻️ Proposed change for the adapter delete test
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			t.Log("Seed a DGD with one orphaned scaling adapter")
 			dgd := &v1beta1.DynamoGraphDeployment{
+			t.Log("Verify the delete event is emitted only after a successful delete")
 			require.NoError(t, reconciler.reconcileScalingAdapters(context.Background(), dgd))

As per coding guidelines: "In Go tests, use t.Log to explain the test's story, with one heading before each block implementing a test step".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamographdeployment_controller_test.go`
around lines 455 - 529, Add t.Log headings for each setup and verification step
in TestReconcileScalingAdaptersEmitsDeleteEventOnlyAfterSuccessfulDelete,
TestGroveWatchSetup_MapPodCliqueToRequests, and TestGroveChildEventPredicates.
Follow the existing heading style used by
TestDynamoGraphDeploymentReconciler_isGrovePathway and ensure every test-step
block has one descriptive log heading.

Source: Coding guidelines

deploy/operator/internal/controller/dynamographdeployment_grove_scaling.go (1)

57-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the checkpoint startup-gate predicate.

Lines 58-61 inline the rule "checkpoint enabled, policy WaitForCheckpoint, not ready". componentProgram.applyCheckpointStartupPolicy applies the same rule in dynamographdeployment_program.go at lines 573-576. If the policy set changes, the two sites can diverge and Grove and component pathways would gate replicas differently. Extract one helper in the checkpoint package or in the controller package and call it from both sites.

♻️ Proposed helper
// checkpointGatesStartup reports whether a component must stay at zero
// replicas until its checkpoint is ready.
func checkpointGatesStartup(info *checkpoint.CheckpointInfo) bool {
	return info != nil &&
		info.Enabled &&
		info.StartupPolicy == nvidiacomv1alpha1.CheckpointStartupPolicyWaitForCheckpoint &&
		!info.Ready
}
-		gated := info != nil &&
-			info.Enabled &&
-			info.StartupPolicy == nvidiacomv1alpha1.CheckpointStartupPolicyWaitForCheckpoint &&
-			!info.Ready
+		gated := checkpointGatesStartup(info)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamographdeployment_grove_scaling.go`
around lines 57 - 71, Extract the shared checkpoint startup-gating predicate
currently in the Grove scaling logic into a reusable helper, such as
checkpointGatesStartup, in an accessible checkpoint or controller package.
Replace the inline condition in the Grove replica calculation and the equivalent
condition in componentProgram.applyCheckpointStartupPolicy with this helper,
preserving the existing zero-replica behavior.
deploy/operator/internal/controller/dynamographdeployment_program_test.go (1)

466-511: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add t.Log headings to both rollout subtests.

Both subtests execute three steps: fixture construction, reconcileWorkerRollout invocation, and verification. Neither subtest states its story in the test output. Add one heading before each step, as the other tests in this file do.

♻️ Proposed headings for the single-node subtest
 	t.Run("single-node component workload starts a managed rollout", func(t *testing.T) {
+		t.Log("Build a single-node worker change against a stale hash annotation")
 		dgd := createTestDGD("test-dgd", map[string]*nvidiacomv1alpha1.DynamoComponentDeploymentSharedSpec{
@@
 		status := dgd.DeepCopy().Status
 
+		t.Log("Reconcile the worker rollout against the isolated status accumulator")
 		require.NoError(t, program.reconcileWorkerRollout(context.Background(), dgd, &status))
 
+		t.Log("Verify the managed rollout starts without mutating request status or the hash")
 		require.NotNil(t, status.RollingUpdate)

As per coding guidelines: "In Go tests, use t.Log to explain the test's story, with one heading before each block implementing a test step".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamographdeployment_program_test.go`
around lines 466 - 511, Add three t.Log headings to each rollout subtest—before
fixture construction, before the reconcileWorkerRollout invocation, and before
verification—using the existing test-output heading style from this file. Keep
the test logic and assertions unchanged.

Source: Coding guidelines

deploy/operator/internal/controller/dynamographdeployment_grove_program.go (1)

205-364: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Split the stable-resource loop and add story comments.

reconcileStableResources spans about 180 lines and mixes three concerns: component Service synchronization, frontend Ingress synchronization, and frontend VirtualService synchronization. Two improvements apply here:

  1. Extract one helper per resource kind, for example reconcileComponentService, reconcileFrontendIngress, and reconcileFrontendVirtualService. Each helper returns ([]Resource, error).
  2. Add a one-line story comment above the annotation-reconciliation block at Lines 244-273 and above the frontend blocks at Lines 287 and 327. The Service block at Lines 210-216 already has one.

isK8sDiscoveryEnabled at Lines 212-215 is loop-invariant. Compute it once before the loop.

As per coding guidelines: "In Go code, put a one-line story comment above every multi-line block of logically connected code."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamographdeployment_grove_program.go`
around lines 205 - 364, Refactor reconcileStableResources by computing
isK8sDiscoveryEnabled once before the component loop and extracting component
Service, frontend Ingress, and frontend VirtualService synchronization into
separate helpers returning ([]Resource, error). Preserve existing behavior and
error handling while composing each helper’s resources in the loop. Add one-line
story comments above the Service annotation-reconciliation block and the
frontend Ingress and VirtualService blocks.

Source: Coding guidelines

deploy/operator/internal/controller/dynamographdeployment_grove_program_test.go (2)

75-89: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move the ordering assertion out of the interceptor closure.

The Get interceptor closure asserts that a scale update already happened. This hides bespoke verification logic inside a setup closure. Record the observation order in the closure, then assert it in the test body.

For example, capture scaleUpdatesAtFirstRead := len(scaleClient.updates) on the first PodClique read, and assert assert.Equal(t, 1, scaleUpdatesAtFirstRead) after reconcileWorkloads returns.

As per path instructions: "Keep bespoke test execution in the test body rather than hiding it in closures".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@deploy/operator/internal/controller/dynamographdeployment_grove_program_test.go`
around lines 75 - 89, Move the readiness ordering assertion out of the Get
interceptor in the test setup. In the PodClique branch, record the
scaleClient.updates length only on the first read using a variable such as
scaleUpdatesAtFirstRead; after reconcileWorkloads returns, assert that recorded
value equals 1 in the test body, while keeping the interceptor focused on
observation and delegation.

Source: Path instructions


40-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing t.Log story headings in the new controller tests. The repository requires one t.Log heading before each block that implements a test step. Three new tests omit them, so the test output does not describe the scenario being verified.

  • deploy/operator/internal/controller/dynamographdeployment_grove_program_test.go#L40-L111: add headings for fixture construction, fake-client and interceptor setup, reconcileWorkloads invocation, and verification.
  • deploy/operator/internal/controller/dynamographdeployment_grove_scaling_test.go#L102-L159: add headings for fixture construction, scaling reconciliation, and verification, and record why graph-0-defaulted is absent from the expected updates.
  • deploy/operator/internal/controller/dynamographdeployment_program_test.go#L466-L511: add headings inside both t.Run subtests for fixture construction, reconcileWorkerRollout invocation, and verification.

As per path instructions: "Use one t.Log heading before each block that implements a test step so test output tells the scenario's story."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@deploy/operator/internal/controller/dynamographdeployment_grove_program_test.go`
around lines 40 - 111, Add descriptive t.Log headings before each test-step
block in
deploy/operator/internal/controller/dynamographdeployment_grove_program_test.go:40-111
for fixture construction, fake-client/interceptor setup, reconcileWorkloads
invocation, and verification. In
deploy/operator/internal/controller/dynamographdeployment_grove_scaling_test.go:102-159,
add headings for fixture construction, scaling reconciliation, and verification,
documenting why graph-0-defaulted is absent from expected updates. In both t.Run
subtests in
deploy/operator/internal/controller/dynamographdeployment_program_test.go:466-511,
add headings for fixture construction, reconcileWorkerRollout invocation, and
verification.

Sources: Coding guidelines, Path instructions

deploy/operator/internal/controller/dynamographdeployment_grove_renderer.go (1)

255-273: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make checkpointInfoByComponent a required parameter.

The production caller passes one map. Only the generic test omits it; update that call to pass nil or an empty map.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamographdeployment_grove_renderer.go`
around lines 255 - 273, Update preserveGrovePodCliqueSetReplicas to accept
checkpointInfoByComponent as a required map parameter rather than a variadic
argument, and adjust its callers accordingly. In the generic test caller that
currently omits the map, pass nil or an empty map while preserving the existing
production caller’s behavior.
deploy/operator/internal/controller/dynamographdeployment_grove_watches.go (1)

168-176: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Check the PodCliqueSet owner API version before enqueuing a DGD request. Compare pcsOwnerRef.APIVersion with nvidiacomv1beta1.GroupVersion.String() in addition to checking Kind. Otherwise, a same-kind owner from another API group can produce an incorrect request.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/operator/internal/controller/dynamographdeployment_grove_watches.go`
around lines 168 - 176, Update the owner-reference validation in the
PodCliqueSet watch handler to require pcsOwnerRef.APIVersion to equal
nvidiacomv1beta1.GroupVersion.String(), alongside the existing controller and
Kind checks, before enqueuing a DynamoGraphDeployment request.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deploy/operator/internal/controller/dynamographdeployment_grove_renderer.go`:
- Around line 328-358: Update orderLikeExisting to verify that the reordered
result preserves every item in desired. After constructing ordered, return
desired unchanged if ordered has fewer items than desired; otherwise retain the
existing ordering behavior.

---

Nitpick comments:
In `@deploy/operator/internal/checkpoint/podspec.go`:
- Around line 256-308: Remove the redundant restore.info.Ready argument passed
to PrepareRestorePodSpec and the restore.info.Ready condition guarding
GPUMemoryService handling in InjectResolvedCheckpointIntoPodSpec, since
ResolvedPodSpecRestore is only produced for ready checkpoints. Preserve the
existing storage, seccompProfile, GPU mode, and error behavior.

In
`@deploy/operator/internal/controller/dcd_checkpoint_storage_reconciler_test.go`:
- Around line 74-101: Add separate t.Log headings before each test-step block in
the subtest: fixture construction, reconciler execution, and PVC-state
assertion. Extend the table-driven cases with a scenario where
Experimental.Checkpoint is declared but Enabled is false, and assert the
expected PVC behavior for that case alongside the existing enabled and absent
configurations.

In `@deploy/operator/internal/controller/dcd_checkpoint_storage_reconciler.go`:
- Around line 54-72: Add a single one-line story comment immediately above the
validation and early-return block in Reconcile, covering the nil deployment, nil
feature gate, disabled Checkpoint gate, and missing checkpoint configuration
checks. Leave the validation logic and EnsureStoragePVC call unchanged.

In `@deploy/operator/internal/controller/dynamocomponentdeployment_controller.go`:
- Around line 184-191: Add a concise one-line story comment immediately above
the checkpointStorageReconciler creation and Reconcile block, describing that
checkpoint storage is converged before workload rendering. Do not alter the
reconciliation logic or error handling.

In `@deploy/operator/internal/controller/dynamocomponentdeployment_renderer.go`:
- Around line 395-438: The nil guard in hasExistingLegacyWorkerSelector is
incomplete because the method dereferences runtimeConfig when evaluating the LWS
feature gate. Extend the initial guard to include r.runtimeConfig, preserving
the existing false, nil return for an unavailable renderer dependency.
- Around line 81-105: Update renderMultinodePodTemplateSpecs to resolve the
workload component type once, then pass that resolved value through
getDCDWorkloadPodLabels and the leader/worker pod-template generation helpers.
Adjust generatePodTemplateSpec and related helper signatures to reuse the
supplied type instead of calling getDCDWorkloadComponentType per role. Preserve
existing label and pod-spec behavior while eliminating repeated legacy-object
lookups and ensuring both paths use the same resolution.

In
`@deploy/operator/internal/controller/dynamographdeployment_controller_test.go`:
- Around line 455-529: Add t.Log headings for each setup and verification step
in TestReconcileScalingAdaptersEmitsDeleteEventOnlyAfterSuccessfulDelete,
TestGroveWatchSetup_MapPodCliqueToRequests, and TestGroveChildEventPredicates.
Follow the existing heading style used by
TestDynamoGraphDeploymentReconciler_isGrovePathway and ensure every test-step
block has one descriptive log heading.

In `@deploy/operator/internal/controller/dynamographdeployment_controller.go`:
- Around line 141-149: Declare a reasonFailedToHandleFinalizer Reason constant
alongside the existing Reason constants, then update the
newWorkloadProgramResult failure call in the finalizer error path to use it
instead of the raw string.
- Around line 172-187: Update persistWorkloadProgramResult to compare the
projected result.Status with dgd.Status before calling r.Status().Update,
skipping the status write when unchanged. Ensure result.Events are still flushed
through r.Recorder.Event in both unchanged and successfully updated cases, while
preserving error propagation for failed status updates.
- Around line 154-169: Add one-line story comments immediately above the
workload program selection/reconciliation block and above the result
persistence/error-propagation block in the reconciliation flow surrounding
selectWorkloadProgram, program.Reconcile, and persistWorkloadProgramResult. Keep
each comment concise and describing the block’s purpose.

In
`@deploy/operator/internal/controller/dynamographdeployment_grove_program_test.go`:
- Around line 75-89: Move the readiness ordering assertion out of the Get
interceptor in the test setup. In the PodClique branch, record the
scaleClient.updates length only on the first read using a variable such as
scaleUpdatesAtFirstRead; after reconcileWorkloads returns, assert that recorded
value equals 1 in the test body, while keeping the interceptor focused on
observation and delegation.
- Around line 40-111: Add descriptive t.Log headings before each test-step block
in
deploy/operator/internal/controller/dynamographdeployment_grove_program_test.go:40-111
for fixture construction, fake-client/interceptor setup, reconcileWorkloads
invocation, and verification. In
deploy/operator/internal/controller/dynamographdeployment_grove_scaling_test.go:102-159,
add headings for fixture construction, scaling reconciliation, and verification,
documenting why graph-0-defaulted is absent from expected updates. In both t.Run
subtests in
deploy/operator/internal/controller/dynamographdeployment_program_test.go:466-511,
add headings for fixture construction, reconcileWorkerRollout invocation, and
verification.

In `@deploy/operator/internal/controller/dynamographdeployment_grove_program.go`:
- Around line 205-364: Refactor reconcileStableResources by computing
isK8sDiscoveryEnabled once before the component loop and extracting component
Service, frontend Ingress, and frontend VirtualService synchronization into
separate helpers returning ([]Resource, error). Preserve existing behavior and
error handling while composing each helper’s resources in the loop. Add one-line
story comments above the Service annotation-reconciliation block and the
frontend Ingress and VirtualService blocks.

In `@deploy/operator/internal/controller/dynamographdeployment_grove_renderer.go`:
- Around line 255-273: Update preserveGrovePodCliqueSetReplicas to accept
checkpointInfoByComponent as a required map parameter rather than a variadic
argument, and adjust its callers accordingly. In the generic test caller that
currently omits the map, pass nil or an empty map while preserving the existing
production caller’s behavior.

In `@deploy/operator/internal/controller/dynamographdeployment_grove_scaling.go`:
- Around line 57-71: Extract the shared checkpoint startup-gating predicate
currently in the Grove scaling logic into a reusable helper, such as
checkpointGatesStartup, in an accessible checkpoint or controller package.
Replace the inline condition in the Grove replica calculation and the equivalent
condition in componentProgram.applyCheckpointStartupPolicy with this helper,
preserving the existing zero-replica behavior.

In `@deploy/operator/internal/controller/dynamographdeployment_grove_watches.go`:
- Around line 168-176: Update the owner-reference validation in the PodCliqueSet
watch handler to require pcsOwnerRef.APIVersion to equal
nvidiacomv1beta1.GroupVersion.String(), alongside the existing controller and
Kind checks, before enqueuing a DynamoGraphDeployment request.

In `@deploy/operator/internal/controller/dynamographdeployment_program_test.go`:
- Around line 466-511: Add three t.Log headings to each rollout subtest—before
fixture construction, before the reconcileWorkerRollout invocation, and before
verification—using the existing test-output heading style from this file. Keep
the test logic and assertions unchanged.

In `@deploy/operator/internal/dynamo/graph_test.go`:
- Around line 1245-1320: Add t.Log headings in
TestGenerateGrovePodCliqueSet_InjectsReadyCheckpointRestore before each test
step: building the PVC-backed fixtures, generating the PodCliqueSet, and
asserting the injected checkpoint volume. Keep the existing setup, generation,
and assertions unchanged.

In `@deploy/operator/internal/dynamo/graph.go`:
- Around line 2457-2472: Extract the shared checkpoint policy into a helper such
as needsResolvedRestore, and use it both in buildCliqueForRole’s
shouldUseAdmissionRestore logic and this checkpoint.ResolvePodSpecRestore block
so the conditions remain consistent. Add a one-line story comment immediately
above this multi-line restore-resolution block describing its purpose.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c5d24667-7ef0-45ac-bca1-debc83c00d5c

📥 Commits

Reviewing files that changed from the base of the PR and between 7054447 and 6bf4030.

📒 Files selected for processing (26)
  • deploy/operator/internal/checkpoint/checkpoint_test.go
  • deploy/operator/internal/checkpoint/podspec.go
  • deploy/operator/internal/checkpoint/resolve.go
  • deploy/operator/internal/checkpoint/resource.go
  • deploy/operator/internal/controller/dcd_checkpoint_storage_reconciler.go
  • deploy/operator/internal/controller/dcd_checkpoint_storage_reconciler_test.go
  • deploy/operator/internal/controller/dynamocomponentdeployment_controller.go
  • deploy/operator/internal/controller/dynamocomponentdeployment_controller_test.go
  • deploy/operator/internal/controller/dynamocomponentdeployment_renderer.go
  • deploy/operator/internal/controller/dynamographdeployment_controller.go
  • deploy/operator/internal/controller/dynamographdeployment_controller_test.go
  • deploy/operator/internal/controller/dynamographdeployment_grove_program.go
  • deploy/operator/internal/controller/dynamographdeployment_grove_program_test.go
  • deploy/operator/internal/controller/dynamographdeployment_grove_renderer.go
  • deploy/operator/internal/controller/dynamographdeployment_grove_scaling.go
  • deploy/operator/internal/controller/dynamographdeployment_grove_scaling_test.go
  • deploy/operator/internal/controller/dynamographdeployment_grove_status.go
  • deploy/operator/internal/controller/dynamographdeployment_grove_watches.go
  • deploy/operator/internal/controller/dynamographdeployment_program.go
  • deploy/operator/internal/controller/dynamographdeployment_program_test.go
  • deploy/operator/internal/controller/dynamographdeployment_rollingupdate.go
  • deploy/operator/internal/controller/dynamographdeployment_rollingupdate_test.go
  • deploy/operator/internal/controller/upgrade_test.go
  • deploy/operator/internal/dynamo/graph.go
  • deploy/operator/internal/dynamo/graph_test.go
  • deploy/operator/internal/dynamo/grove.go

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 3, 2026
@julienmancuso

Copy link
Copy Markdown
Contributor Author

/ok to test 6773306

@julienmancuso julienmancuso changed the title refactor(operator): compose DGD reconciliation as workload programs refactor(operator): implement composition-first DGD reconciliation Aug 3, 2026
@julienmancuso
julienmancuso merged commit 39c9e49 into main Aug 3, 2026
100 of 101 checks passed
@julienmancuso
julienmancuso deleted the jsm/12035-6 branch August 3, 2026 21:46
hhzhang16 added a commit that referenced this pull request Aug 4, 2026
dyn-3691-extract-shared-target-pid-cuda-customstorage-operation-layer

* 'main' of https://github.com/ai-dynamo/dynamo: (50 commits)
  docs(cli): correct removed vLLM prefill-worker flag reference (#12581)
  docs(operator): reserve webhook Ignore for emergencies (#12563)
  ci(docs): make previews and checks match what actually publishes (#12339)
  refactor(vllm): organize custom encoder modules (#12416)
  feat(llm): Select reasoning output field via env var (#11464)
  feat(runtime): add TLS support to TCP request plane (#10921)
  fix: convert conditional disagg sglang warning to httperror 400 (#12578)
  feat(operator): add runtime feature gates (#12421)
  refactor(runtime): extract PushRouter transport seam behind StreamingDispatch trait (#12447)
  feat(replay): add deterministic canonical offline reports (#12363)
  build: bump ModelExpress to 0.5.0(OPS-7978) (#12455)
  fix(mocker): use logical KV tokens for decode timing (#12583)
  fix(examples): update Triton example for CUDA 13 + fix libdcgm copy (DYN-3697) (#12577)
  refactor(operator): implement composition-first DGD reconciliation (#12283)
  feat(frontend): add basetenkenizer backend (#12376)
  fix(profiler): configure rapid mocker without planner (#12573)
  docs(vllm): correct worker-role flags and document --kv-transfer-config (#12568)
  ci: add Kubernetes deploy test to nightly (#12090)
  fix(container): reuse pinned protoc in runtime image (#12535)
  feat(self-host): flip DYN_SELF_HOST_METADATA default to ON (gh-8749) (#11417)
  ...

Signed-off-by: Hannah Zhang <hannahz@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 refactor size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants