fix(snd): propagate Spec.Peers from SND template to existing child SeiNodes#371
Conversation
…iNodes ensureSeiNode previously only deep-copied Spec.Peers on the create-path (via generateSeiNode). The update-path used an allow-list of fields to diff and re-apply — Labels, Annotations, Spec.Image, Spec.Sidecar, Spec.PodLabels, Spec.ExternalAddress — and Peers was silently missing. This contradicted the templateHash godoc in labels.go, which explicitly states peers "propagate in-place via ensureSeiNode" and so are excluded from the hash. Adding a peer source to a live SND (e.g. platform#759 adding a LabelPeerSource to existing Harbor syncers) appeared to work at the SND CR level but never reached the child SeiNodes — their spec.peers stayed frozen at child-creation time, the resolver kept re-emitting the stale list, and Status.ResolvedPeers never picked up new sources. Fix: add a Spec.Peers diff/update branch between PodLabels and ExternalAddress, using equality.Semantic.DeepEqual so etcd nil/empty round-trips don't churn the diff. Coral cross-review (kubernetes-specialist + platform-engineer) confirmed the fix doesn't open a deployment-trigger feedback loop: - detectDeploymentNeeded gates on templateHash, which excludes peers. - childPhaseChangedPredicate filters out status-only updates, so live Status.ResolvedPeers churn doesn't enqueue the SND. - The Update() only fires when SND.spec.peers actually differs from the child's spec.peers — a human/Flux edit, not a resolver fluctuation. Tests: - Unit (nodes_test.go): PropagatesPeersOnUpdate, PropagatesPeerRemoval, PeersNoOpWhenUnchanged. - Envtest (peers_propagation_test.go): AddSourceOnLiveSND, RemoveSourceOnLiveSND. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR SummaryMedium Risk Overview Coverage adds unit tests for grow, shrink, and no-op reconciles, envtest tests that patch a live SND, and Reviewed by Cursor Bugbot for commit d2cc75a. Bugbot is set up for automated code reviews on this repo. Configure here. |
Summary
ensureSeiNodeonly propagatedSpec.PeersfromSND.spec.template.specon the create-path (viagenerateSeiNode's deep copy). The update-path used an allow-list of fields to diff and re-apply —Labels,Annotations,Spec.Image,Spec.Sidecar,Spec.PodLabels,Spec.ExternalAddress— andSpec.Peerswas silently missing.This contradicted the existing
templateHashgodoc inlabels.go:85-97, which explicitly states peers "propagate in-place via ensureSeiNode" and so are excluded from the hash. Adding a peer source to a live SND (e.g. platform#759 adding aLabelPeerSourceto existing Harbor syncers) appeared to work at the SND CR but never reached the child SeiNodes — theirspec.peersstayed frozen at child-creation time, the resolver kept re-emitting the stale list, andStatus.ResolvedPeersnever picked up new sources.Fix
Add a
Spec.Peersdiff/update branch betweenPodLabelsandExternalAddressinensureSeiNode, usingequality.Semantic.DeepEqual(so etcd nil/empty round-trips don't churn the diff):Coral cross-review
Both kubernetes-specialist and platform-engineer voted GO independently. Validated load-bearing concern: does this fix open a deployment-trigger feedback loop via live resolver fluctuations?
detectDeploymentNeeded(nodes.go:108) gates ontemplateHash, which hashes only ChainID + Image + Sidecar.Image. Peers are excluded by design.childPhaseChangedPredicate(predicates.go:18-38) filters out status-only updates — pureStatus.ResolvedPeerschurn on a child does NOT enqueue the SND.Update()only fires whenSND.spec.peers != child.spec.peers— i.e., a human/Flux edit, not a resolver fluctuation.No loop. Fix completes the contract the
templateHashgodoc already promised.Test coverage
Unit (
nodes_test.go):TestEnsureSeiNode_PropagatesPeersOnUpdate— adds a LabelPeerSource to a live SND, asserts the child carries 2 entries.TestEnsureSeiNode_PropagatesPeerRemoval— shrinks the source list, asserts the child shrinks too.TestEnsureSeiNode_PeersNoOpWhenUnchanged— identical template across reconciles must not bumpresourceVersion.Envtest (
envtest/peers_propagation_test.go):TestPeersPropagation_AddSourceOnLiveSND— live patch against a real apiserver.TestPeersPropagation_RemoveSourceOnLiveSND— shrink case end-to-end.Fixture:
fixtures.WithPeers(...)added to envtest fixtures package.Genesis interaction (analyzed, not a concern)
task/genesis_peers.go:92writeschild.Spec.Peers = [{Static{cohort}}]during the genesis ceremony. After this fix, the post-ceremony SND reconcile would revert that to the SND template's peers value.Not a concern because:
ensureSeiNodeis gated by!ConditionPlanInProgress, so my new branch doesn't fire during the active genesis plan.The structural genesis pieces (the plan orchestration, S3 artifact distribution, per-validator genesis.json) are independent of
Spec.Peersand unaffected by this fix.Test plan
pacific-1/syncer-0-0spec.peersshows all three sources (2 ec2Tags + 1 label);Status.ResolvedPeerspopulates with composed entries.🤖 Generated with Claude Code