feat(viz): the mission becomes a map — centre, stations, and agents at theirs

The clump was structural, not cosmetic. Four causes, each fixed here.

`homes` (an agent's resting node) was written only by `seed()`, so every agent
homed to the mission centre and orbited the same dot regardless of which phase
it was on. `setHome` points each agent at its CURRENT phase, and the existing
physics does the rest for free: the pawn rests at its station, the pawn→home
line tethers it there, and a touch becomes a visible departure and return. No
new motion code.

The mission node was seeded as `level: "team"` (my own bug from the focus
work). `seed()` casts that straight to a Tier and `ensureNode` is
first-write-wins, so it was created as a small teal team dot that the later
`node.activity` could never upgrade. That dot at the centre of the scene was
one line.

`mission`/`phase` replace the retired `repo`/`loop` tiers rather than adding a
parallel set. The backend stopped emitting repo:/loop: ids, which left their
whole landmark treatment — bigger radius, distinct colour, always-labelled, 60s
fade instead of 22s — orphaned on prefixes nothing sends. Missions and phases
need exactly that treatment. The two separately-written prefix→tier ternaries
in onTouch and onNodeActivity are now one `tierFor`: they agreed only by luck,
and whichever path saw a node first fixed its tier forever.

Phase stations spring out at 190 rather than the shared 64, or they pack into a
rosette around the centre and the point — agents moving BETWEEN stations — is
invisible. Idle roam is off under a mission scope: wandering to a random node
keeps an idle workspace alive, but inside one mission it sends agents to files
nobody opened, which reads as work and isn't.

Palette is injected at construction and keyed on template_kind, so a benchmark
run and a security sweep no longer render identically to a research mission.
It also collapses two uncoordinated kind→colour maps that had drifted:
LEVEL_COLOR by tier, and the fireColor if-chain by id prefix.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-08-10 18:17:12 -07:00
co-authored by Claude Opus 5
parent 5f85dbb718
commit 006432c2dc
6 changed files with 377 additions and 69 deletions
+4
View File
@@ -1706,6 +1706,7 @@ pub async fn workforce(
"SELECT m.id::text AS mission_id,
m.title AS mission_title,
m.status AS mission_status,
m.template_kind AS template_kind,
m.created_at AS created_at,
a.id::text AS agent_id,
a.name AS agent_name,
@@ -1736,6 +1737,9 @@ pub async fn workforce(
"mission_id": mid,
"title": r.get::<String, _>("mission_title"),
"status": r.get::<String, _>("mission_status"),
// Drives the World's palette: what the mission is FOR
// should be visible before any label is read.
"templateKind": r.get::<String, _>("template_kind"),
"agents": Vec::<Value>::new(),
}));
seen_mission.insert(r.get::<String, _>("mission_id"), missions.len() - 1);