feat(viz): the coding station fractures into the files it worked on

The engine already turned `file:src/lib/a.ts` into a real dir chain, but
both copies of that loop rooted it at the origin — so a mission's files
floated beside the map instead of belonging to the work that produced
them. One `fileParent` helper now serves both call sites; splitting them
was how half the files could end up nesting correctly and half not,
decided by whichever code path saw the file first.

Files hang under the coding station when there is exactly one, else the
single running phase, else the origin. `world.touch` carries no phase id,
so with two coding phases any attribution is invented — the fallback is
the honest answer.

Two ordering hazards, both silent:
- the server emitted files BEFORE phases, so on the first pass a file
  arrived with no station to hang under and first-write-wins pinned its
  tree at the origin. Loops reordered, with a source-walk guard.
- `setFileHome` re-parents trees rooted before the plan landed, for the
  reconnect case the ordering alone cannot cover.

`mission.file` with `source: "tool"` is treated as motion (burst, pawn
beams); `"diff"` is end-of-phase truth and only marks the file present
and warm — bursting every file of a captured diff would set the whole
map alight at once on reconnect.

Directories taper in radius and opacity by path depth, so `src` and
`src/lib/live` no longer render as identical dots.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-08-11 08:29:55 -07:00
co-authored by Claude Opus 5
parent cb8184e784
commit c2fa8067e1
4 changed files with 249 additions and 50 deletions
+14
View File
@@ -94,6 +94,19 @@ export interface TaxonomyEvents {
completedAt?: string | null;
agentIds: string[];
};
/** World → a file this phase touched, so the coding station fractures into
* the sections actually worked on. `source: "diff"` is end-of-phase truth
* from the captured diff; `"tool"` is a live per-tool touch. Ephemeral: the
* engine keeps the node alive itself, and replaying these would re-burst
* every orb on reconnect. */
"mission.file": {
missionId: string;
phaseId: string;
agentId?: string;
path: string;
status?: string;
source?: "diff" | "tool";
};
/** World → re-layout (add/remove org units, agents, projects). */
"topology.update": {
formation: "hierarchy" | "flat" | "live";
@@ -138,6 +151,7 @@ export const TAXONOMY_TYPES: TaxonomyType[] = [
"node.activity",
"mission.update",
"mission.phase",
"mission.file",
"topology.update",
"telemetry",
"routine.update",