nodetask: read RestartPod podUID from spec, drop status snapshot#388
Conversation
The synthesis path special-cased RestartPod to copy spec.restartPod.podUID into status.task.restartedPodUID, which restartPodParams then read back to build the task. That snapshot loop was a vestige of the original fetch-at-synthesis design (the live-fetched UID had to be persisted). With the UID now a caller-supplied spec field, the value is already stable on the object — restartPodParams already reads spec.restartPod.podUID for its non-empty guard. - restartPodParams reads spec.restartPod.podUID directly into the task params; the status read and the nil-status early-validation dance are gone. - spec.restartPod.podUID is now immutable (CEL transition rule, mirroring the existing spec.kind immutability) — preserves the frozen-at-synthesis guarantee the snapshot gave. - status.task.restartedPodUID is removed — it was fully determined by the immutable spec field. - The synthesis SeiNodeTaskExecution literal is now kind-agnostic; Reconcile no longer branches on spec.kind. Forward-safe across upgrade: the removed status field is pruned by the structural schema and is read by nothing post-refactor; in-flight RestartPod tasks rebuild params from spec every reconcile, so content-addressed completion is unaffected. Apply the CRD and controller together. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR SummaryMedium Risk Overview To keep the restart target fixed after create, admission adds a CEL immutability rule on Tests and envtest cover spec-sourced params (with and without Reviewed by Cursor Bugbot for commit b5d7d74. Bugbot is set up for automated code reviews on this repo. Configure here. |
What
Removes the RestartPod-specific branch from the SeiNodeTask synthesis path.
Reconcilenow seedsstatus.taskidentically for every kind.Why
RestartPod's pod UID was snapshotted from
spec.restartPod.podUID→status.task.restartedPodUIDat synthesis, then read back byrestartPodParamsto build the task. That loop is a vestige of the original fetch-at-synthesis design (a live-fetched UID had to be persisted to survive reconciles). Now that the UID is a caller-supplied spec field, the value is already stable on the object —restartPodParamswas already readingspec.restartPod.podUIDtwo lines up for its non-empty guard, then turning around to read the redundant copy off status.Change
restartPodParamsreadsspec.restartPod.podUIDdirectly into the task params; thestatus.taskread and the nil-status early-validation dance are gone.spec.restartPod.podUIDis now immutable (CEL transition rule, mirroring the existingspec.kindimmutability) — preserves the frozen-at-synthesis guarantee the snapshot provided.status.task.restartedPodUIDis removed — fully determined by the immutable spec field (implicit over explicit).SeiNodeTaskExecutionliteral is now kind-agnostic ({ID, Status, ExecutionStartedAt});Reconcileno longer branches onspec.kind.Net: −code, and the only kind-specific concern leaves the generic reconcile surface.
Upgrade safety
Apply the CRD and controller together. Forward-safe:
status.task.restartedPodUIDis pruned by the structural schema and is read by nothing post-refactor.driveTask→taskParamsForKind), and the task ID is keyed oncr.UID/kind/index (not the removed field) — so content-addressed completion is unaffected and identity is stable across the controller swap.Test
restartPodParamsyieldsRestartedPodUID == spec.restartPod.podUIDon both thestatus.task == nil(early-validation) and populated paths.podUIDimmutability (create → patch podUID → rejected); existing required/union/kind-immutability cases stay green.make manifests generate,make test,make test-integration,golangci-lint --new-from-rev=origin/main→ 0.🤖 Generated with Claude Code