| index 8c85f7358..6b957e762 100644 |
| --- a/internal/registry/registry.go |
| +++ b/internal/registry/registry.go |
| @@ -646,12 +646,20 @@ func (r *Registry) Delete(host string) error { |
| // |
| // `addrs` and `health` (multi-upstream routing, issue #152) are, by |
| // contrast, PLAIN overwrites — see their ON CONFLICT clause below — same as |
| -// `addr`, `status` and the rest of the un-preserved majority. That makes |
| -// SetUpstreams (registry.go, next to SetUnit) unsafe to rely on until |
| -// provision.routeFor is taught to carry Record.Addrs/Health onto the Route |
| -// it mints: until then, every reconcile tick's Upsert on that host blanks |
| -// whatever SetUpstreams last wrote, the same way a plain excluded.environment |
| -// once silently unbound a route. |
| +// `addr`, `status` and the rest of the un-preserved majority. That is safe |
| +// against the provision reconcile pass specifically: provision.routeFor |
| +// (reconcile.go, func routeFor) now carries Record.Addrs/Health onto every |
| +// route it mints, and the mint branch (reconcile.go, routeFor → reg.Upsert) |
| +// is the only reconcile branch that calls Upsert at all — the owned-route |
| +// branch (reconcile.go, the `existing.Provisioned && ...` case) converges |
| +// through narrow setters (convergeOwned, SetHibernate, SetSeed), never a |
| +// full-row Upsert, so a reconcile tick on an already-owned host cannot blank |
| +// what SetUpstreams wrote. The one remaining plain-overwrite blanker is |
| +// `carlos add` re-run over an existing host (cli.go:194-198): its Upsert |
| +// builds a Route literal with no Addrs/Health fields, so re-adding a host |
| +// with an established multi-upstream set still blanks it, the same way a |
| +// plain excluded.environment once silently unbound a route. That gap is |
| +// this CLI verb's, not routeFor's, and is the next task's job to close. |
| func (r *Registry) Upsert(t Route) error { |
| if t.CreatedAt == 0 { |
| t.CreatedAt = time.Now().Unix() |
| @@ -904,19 +912,23 @@ func (r *Registry) SetUnit(host, unit string) error { |
| // SetUpstreams repoints a route's multi-upstream set as a narrow UPDATE — |
| // same rationale as SetChannel/SetUnit: a read-modify-write Upsert racing a |
| // deploy's SetVersions or the activator's SetNextDue would clobber those |
| -// columns, and this is meant to be how the provision reconcile pass converges |
| -// them independently of everything else a full-row Upsert would touch. But |
| -// unlike environment/caps/tunnel/provisioned/seed/unit/fleet_box, addrs and |
| -// health are PLAIN overwrites in Upsert (registry.go:684), not |
| -// preserve-when-empty — so today, until provision.routeFor is taught to carry |
| -// Addrs/Health onto the Route it builds, every reconcile tick's Upsert blanks |
| -// whatever a SetUpstreams call just wrote. SetUpstreams is not yet safe to |
| -// rely on in the presence of Upsert traffic on the same host; that wiring is |
| -// the next task's job. addrs is the caller's already comma-joined list ("" = |
| -// none); health is the probe-config JSON verbatim ("" = unprobed). Neither |
| -// argument is validated here — the rails live at the provision pass's own |
| -// door (ValidateShape), which runs before a record ever reaches this column, |
| -// exactly as SetCaps's callers validate before calling it. |
| +// columns, and this is how the provision reconcile pass converges them |
| +// independently of everything else a full-row Upsert would touch. Unlike |
| +// environment/caps/tunnel/provisioned/seed/unit/fleet_box, addrs and health |
| +// are PLAIN overwrites in Upsert (registry.go:684), not preserve-when-empty |
| +// — but provision.routeFor now carries Record.Addrs/Health onto every route |
| +// it mints, and the reconcile pass's owned-route branch never calls Upsert |
| +// (it converges through narrow setters, this one included), so a reconcile |
| +// tick cannot blank what a prior SetUpstreams call wrote. The surviving |
| +// plain-overwrite hazard is `carlos add` re-run over an existing host |
| +// (cli.go:194-198): its Upsert carries no Addrs/Health, so re-adding a host |
| +// still blanks an established multi-upstream set — a CLI-side gap, not a |
| +// SetUpstreams or reconcile one, and the next task's job to close. addrs is |
| +// the caller's already comma-joined list ("" = none); health is the |
| +// probe-config JSON verbatim ("" = unprobed). Neither argument is validated |
| +// here — the rails live at the provision pass's own door (ValidateShape), |
| +// which runs before a record ever reaches this column, exactly as SetCaps's |
| +// callers validate before calling it. |
| // |
| // Errors on an unmatched host, the SetChannel/SetUnit contract: a silent |
| // no-op on a host that does not exist would hide a reconcile pass writing to |