fix(node): import a newly selected node inbound instead of sweeping it

Saving the node form writes the grown selection and marks the node dirty
in one transaction. On the next tick ReconcileNode runs before the
snapshot merge, and its delete sweep treats a selected tag with no
central row as "deleted on the master" — so an inbound the operator just
ticked in the picker (or every unselected one, when switching the node
to "all") is deleted from the node before the import that would have
created its row ever runs.

Nothing on disk separates "pending import" from "deleted while the node
was unreachable", but the pre-adoption guard already expresses the
former: while inbounds_adopted_at is zero the sweep waits for a clean
sync to adopt. A save that grows the managed set now zeroes it again,
and the same clean sync re-stamps it, so the offline-delete sweep is
only deferred by one successful sync, not disabled.

The trade: an inbound deleted on the master while the node was
unreachable is re-imported instead of swept if the operator grows the
node's selection during that same outage. That is visible and
recoverable, where the previous behaviour destroyed a live inbound.

Closes #6329
This commit is contained in:
Sanaei
2026-09-13 22:44:50 +02:00
parent 5ad9df69b9
commit 22346eef78
4 changed files with 96 additions and 3 deletions
+1 -1
View File
@@ -172,7 +172,7 @@ func (s *InboundService) ReconcileNode(ctx context.Context, rt *runtime.Remote,
errs = append(errs, fmt.Errorf("reconcile inbound %q: %w", ib.Tag, err))
}
}
// Before the first clean sync adopts the node's inbounds, "absent locally"
// Before the next clean sync adopts the node's inbounds, "absent locally"
// means "not imported yet" — sweeping now would wipe the node at onboarding.
if n.InboundsAdoptedAt == 0 {
return errors.Join(errs...)