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:
co-authored by
Claude Opus 5
parent
5f85dbb718
commit
006432c2dc
@@ -489,8 +489,10 @@ pub async fn world_live(
|
||||
let mut last: std::collections::HashMap<String, String> = std::collections::HashMap::new();
|
||||
// Per-run journal cursor so we stream only NEW run_events each poll.
|
||||
let mut cursors: std::collections::HashMap<String, i64> = std::collections::HashMap::new();
|
||||
// Last emitted signature per phase, so the plan is sent once and then
|
||||
// only when a phase actually moves.
|
||||
// Last emitted signature per mission / per phase, so the plan is sent
|
||||
// once and then only when something actually moves.
|
||||
let mut last_mission: std::collections::HashMap<String, String> =
|
||||
std::collections::HashMap::new();
|
||||
let mut last_phase: std::collections::HashMap<String, String> =
|
||||
std::collections::HashMap::new();
|
||||
// Audit-log cursor for edge-initiated inter-agent events (delegation,
|
||||
@@ -555,16 +557,24 @@ pub async fn world_live(
|
||||
let mut seen_missions: HashSet<String> = HashSet::new();
|
||||
for m in &missions {
|
||||
if seen_missions.insert(m.mission_id.clone()) {
|
||||
yield sse(
|
||||
"mission.update",
|
||||
json!({
|
||||
"missionId": m.mission_id,
|
||||
"title": m.title,
|
||||
"status": m.status,
|
||||
"templateKind": m.template_kind,
|
||||
"completedAt": m.completed_at,
|
||||
}),
|
||||
);
|
||||
// Delta-guarded like every other stateful event here. Without
|
||||
// this it re-sent the same mission on every poll — harmless
|
||||
// to a client that keys on missionId, and pure noise on the
|
||||
// wire that hides the events that DID change.
|
||||
let sig = format!("{}|{}", m.status, m.completed_at.as_deref().unwrap_or(""));
|
||||
if last_mission.get(&m.mission_id).map(|s| s != &sig).unwrap_or(true) {
|
||||
last_mission.insert(m.mission_id.clone(), sig);
|
||||
yield sse(
|
||||
"mission.update",
|
||||
json!({
|
||||
"missionId": m.mission_id,
|
||||
"title": m.title,
|
||||
"status": m.status,
|
||||
"templateKind": m.template_kind,
|
||||
"completedAt": m.completed_at,
|
||||
}),
|
||||
);
|
||||
}
|
||||
// A terminal mission is a map to read, not a scene to
|
||||
// animate: it still gets an orb, but no heat.
|
||||
let running = m.status == "running";
|
||||
|
||||
Reference in New Issue
Block a user