Read an adopted or converged node's mode from its state on a re-run of genesis, and refuse a flag that disagrees (hq ADR 0103)

This commit is contained in:
2026-09-22 18:08:02 +02:00
parent 52e139d96f
commit 078e84c681
2 changed files with 74 additions and 0 deletions
+31
View File
@@ -6,6 +6,7 @@ import (
"net"
"strings"
"github.com/novox/mesh-host/internal/declaration"
"github.com/novox/mesh-host/internal/reachable"
"github.com/novox/mesh-host/internal/store"
)
@@ -76,6 +77,20 @@ func RefuseAMachineInUse(ctx context.Context, o Options, run Runner, say func(st
return err
}
if len(known.Resources) > 0 {
// **The machine says how it was raised** (novox/hq ADR 0103). A re-run must not change
// the node's mode by a flag forgotten or added: without --adopted the bundle would load
// the foundation's dropping filter over the found firewall, and with it on a converged
// machine the filter the node relies on would be removed as no longer carried.
switch adopted := RecordsAdoption(known); {
case adopted && !o.Adopted:
return fmt.Errorf("this machine was raised adopted, and genesis was run again without --adopted. " +
"Run it again the way it was raised: pass --adopted. Returning it to converged is the " +
"controller's act (converge), never genesis's; nothing was changed")
case !adopted && o.Adopted:
return fmt.Errorf("this machine was raised converged, and genesis was run again with --adopted, " +
"which would remove the foundation's filter it relies on. Run it again without --adopted; " +
"returning a node to adopted is the controller's act (adopt); nothing was changed")
}
// What genesis raised on an earlier run is the mesh's, and it is what the machine now
// serves; the question was answered the first time.
say(" in use not asked: this machine carries what an earlier genesis raised")
@@ -109,3 +124,19 @@ func RefuseAMachineInUse(ctx context.Context, o Options, run Runner, say func(st
"force and every module is taken on it one at a time. Nothing was changed",
strings.Join(named, "\n - "))
}
// RecordsAdoption is whether this machine's state says it is an adopted node: it holds something
// of the mesh's that only an adopted node has — the guard or an opening, under the adoption prefix
// — or something it found and holds. A node the controller converged has neither any more; the
// record of the firewall it found outlives the flip, so it is not read as the mode.
func RecordsAdoption(known store.State) bool {
if len(known.Held) > 0 {
return true
}
for _, r := range known.Resources {
if strings.HasPrefix(r.ID, declaration.AdoptionPrefix) {
return true
}
}
return false
}