Assign around what a machine already holds

The other half of ADR 0038, and what 04-ISSUES/028 was actually about.
A module can now avoid colliding with another module; until this it
could not avoid colliding with the mesh itself.

The substrate is not a module. A node raises it from the bundle it
carries before any mesh exists, so the control plane had never heard of
the store, the broker, or its own container — and handed a database
module 5432, which the store already had.

So the machine says. The host records what each resource binds,
distinguishing what it carried from what the mesh sent — a distinction
that already existed so the two never remove each other — and reports
the carried ones. The node states and this context writes, which is the
shape of every message between them.

What the declaration binds, not what is open. A machine's open ports are
a moving target, and assigning around them would mean a port that was
free when it was asked for and taken when it was used.

Replaced whole each time rather than merged: a machine that gave a port
back must be believed about that too, and a set that only grows keeps a
port reserved for something no longer there.

Tested against a real database, and the tests bite — removing the check
hands the module 20000, which the machine had said it holds.
This commit is contained in:
2026-09-01 18:32:38 +02:00
parent 1f5b70a995
commit 41f7c51032
5 changed files with 131 additions and 0 deletions
+41
View File
@@ -76,6 +76,35 @@ func (i *Inventory) PortFor(
return i.assignPort(ctx, record.ID, node, module, wanted, fixed)
}
// RecordCarried keeps what a machine says it already holds, replacing whatever it said before.
//
// **Replaced whole, not merged.** A machine that gave a port back must be believed about that too,
// and a set the mesh only ever adds to would keep a port reserved for something that is no longer
// there.
func (i *Inventory) RecordCarried(ctx context.Context, node string, ports []int) error {
record, err := i.NodeByName(ctx, node)
if err != nil {
return err
}
if ports == nil {
ports = []int{}
}
_, err = i.store.Pool().Exec(ctx,
`update node set carried_ports = $2 where id = $1`, record.ID, ports)
return err
}
// carriedOn is what a machine said it already holds.
func (i *Inventory) carriedOn(ctx context.Context, nodeID any) ([]int, error) {
var ports []int
err := i.store.Pool().QueryRow(ctx,
`select carried_ports from node where id = $1`, nodeID).Scan(&ports)
if err != nil {
return nil, err
}
return ports, nil
}
func (i *Inventory) freePort(ctx context.Context, node any, module string, wanted int) error {
_, err := i.store.Pool().Exec(ctx,
`delete from port_assignment where node = $1 and module = $2 and wanted = $3`,
@@ -90,6 +119,18 @@ func (i *Inventory) assignPort(
if err != nil {
return Assigned{}, err
}
// And what the machine itself says it already holds — the substrate it raised before there
// was a mesh to ask (novox/hq ADR 0038). Not assignments: nothing here chose them, and
// nothing here can move them.
carried, err := i.carriedOn(ctx, nodeID)
if err != nil {
return Assigned{}, err
}
for _, port := range carried {
if _, mine := taken[port]; !mine {
taken[port] = "something this machine already runs"
}
}
machine := wanted
if !fixed {