feat(fusion): assert engine node positions at startup (bf-1tsm)
Some checks are pending
CI Benchmark - Fusion Loop Timing / Fusion Loop Timing Benchmark (push) Waiting to run

bf-6s3d added TestEngine_SeedNodePositions, the host/unit-test half of
the node-position invariant (it replays main.go's seeding loop against
the engine and asserts NodeCount()/NodePositions() hold distinct,
non-(0,0,1) positions). This bead adds the complementary half the
NodePositions() docstring (fusion.go:140-159) already advertises:
"a logged startup assertion" exercised in the live path.

Right after the main.go seeding loop (which calls
fusionEngine.SetNodePosition(node.MAC, node.PosX, node.PosY, node.PosZ)
per fleet node), the engine now inspects NodePositions() and logs:

- n == 0          → INFO  "no nodes positioned yet" (valid; IO-1 reaches
                              ready with no nodes attached)
- atDefault == n  → WARN  "all N seeded nodes collapsed to (0,0,1)"
                             (fleet never positioned → degenerate fusion)
- otherwise       → INFO  "N nodes seeded, D distinct, A at (0,0,1)"

The (0,0,1) collapse is the failure mode: when no node has been
positioned, every node retains the nodes-table schema default
(pos_x=0, pos_y=0, pos_z=1) and Fuse emits only degenerate peaks. The
assertion surfaces this without blocking startup (the hard gate stays
the bf-6s3d unit test).

Also gofmt's the file (drive-by): bf-3f6q's "fusion" import sat after
"ingestion" instead of alphabetically after "floorplan".

go build ./... / go vet ./... / go test ./... all pass; gofmt clean.

Co-Authored-By: Claude <noreply@anthropic.com>
Bead-Id: bf-1tsm
This commit is contained in:
jedarden 2026-07-03 16:54:15 -04:00
parent ce86575df4
commit 3785619967

View file

@ -43,11 +43,11 @@ import (
"github.com/spaxel/mothership/internal/falldetect"
"github.com/spaxel/mothership/internal/fleet"
"github.com/spaxel/mothership/internal/floorplan"
"github.com/spaxel/mothership/internal/fusion"
guidedtroubleshoot "github.com/spaxel/mothership/internal/guidedtroubleshoot"
"github.com/spaxel/mothership/internal/health"
featurehelp "github.com/spaxel/mothership/internal/help"
"github.com/spaxel/mothership/internal/ingestion"
"github.com/spaxel/mothership/internal/fusion"
"github.com/spaxel/mothership/internal/learning"
"github.com/spaxel/mothership/internal/loadshed"
"github.com/spaxel/mothership/internal/localization"
@ -1061,6 +1061,39 @@ func main() {
}
}
// bf-1tsm: Startup assertion over fusionEngine.NodePositions() (the
// fusion.go:140-159 docstring notes this startup-assertion use). After the
// seeding loop above, the engine must hold populated, distinct positions —
// NOT every node collapsed to the nodes-table schema default (pos_x=0,
// pos_y=0, pos_z=1 → NodePosition{X:0,Y:0,Z:1}). A fleet where every seeded
// node still sits at that default was never positioned: all nodes are
// co-located, so Fuse emits only degenerate peaks and cannot localize.
// This logs the assertion result but does NOT block startup, because an
// empty or freshly-onboarded fleet is a valid state (IO-1: the server
// reaches ready with no nodes positioned). The hard regression gate for
// the invariant is TestEngine_SeedNodePositions (bf-6s3d).
{
type posKey struct{ x, y, z float64 }
positions := fusionEngine.NodePositions()
atDefault := 0
seen := make(map[posKey]struct{}, len(positions))
for _, p := range positions {
if p.X == 0 && p.Y == 0 && p.Z == 1 {
atDefault++
}
seen[posKey{p.X, p.Y, p.Z}] = struct{}{}
}
switch n := len(positions); {
case n == 0:
log.Printf("[INFO] 3D fusion engine node-position assertion: no nodes positioned yet")
case atDefault == n:
log.Printf("[WARN] 3D fusion engine node-position assertion FAILED: all %d seeded nodes collapsed to (0,0,1) — position nodes in the dashboard before fusion can localize", n)
default:
log.Printf("[INFO] 3D fusion engine node-position assertion OK: %d nodes seeded, %d distinct positions, %d at (0,0,1) default",
n, len(seen), atDefault)
}
}
// Start the self-improving localization system
selfImprovingLocalizer.Start()
log.Printf("[INFO] Self-improving localization started (room: %.1fx%.1fm, interval: %v)",