# Agent-space distance metric & collision avoidance (Layer 4)

> Status: v0 implemented in `scripts/lib/agent-proximity/`. This is the moat
> layer of ECC 2.0 — *spatial deconfliction for multiple agents (and humans)
> working the same codebase*, modeled on aircraft collision avoidance (TCAS).

## The analogy

Two aircraft sharing airspace don't wait until they touch — TCAS continuously
measures their separation and closure rate, issues a **Traffic Advisory** ("there
is traffic near you") and then a coordinated **Resolution Advisory** ("you climb,
the other descends"). We want the same for agents: a continuous notion of *how
close two agents are in code-space*, so that as they approach we fire a trigger
that makes them **transmit what they're doing** to each other and, if needed,
makes one **steer away** — before they collide at the git/merge layer.

## 1. Agent state

At time *t*, agent *a* has a **working set**

```
W_a = { (f, R_f, w_f) }                                              (1)
```

where *f* is a touched file, *R_f* the set of edited line ranges in *f*, and
*w_f ∈ (0,1]* a recency weight (older edits decay toward a floor). An agent may
also declare an **intent set** *I_a* of files it is about to touch (look-ahead).

## 2. Collision is multi-channel (noisy-OR)

Two agents can collide through several independent channels. Each channel *i*
yields a collision probability *r_i ∈ [0,1]*; we combine them as the probability
of colliding through **at least one** channel:

```
R(a,b) = 1 − Π_i ( 1 − ω_i · r_i )                                   (2)
```

with channel weights *ω_i ∈ [0,1]*. The reported **distance** is the dual
*D(a,b) = 1 − R(a,b)*.

### Channel 1 — edit overlap *r_overlap*

For shared files *S = files(W_a) ∩ files(W_b)*:

```
lineOverlap(f) = |R_f^a ∩ R_f^b| / min(|R_f^a|, |R_f^b|)   (overlap coefficient)
r_overlap = max_{f∈S} w_f^a·w_f^b · lineOverlap(f)                        (3)
```

The overlap coefficient (not Jaccard) is the right measure: it stays high when one
agent's small edit sits inside the other's large region (Jaccard would dilute it by
union size). A whole-file edit (no line info) ⇒ `lineOverlap = 1`. Same file,
overlapping lines ⇒ imminent collision; same file, *disjoint* line ranges (different
functions) ⇒ low `r_overlap`. Different files ⇒ no shared `f` ⇒ `r_overlap = 0`.

### Channel 2 — dependency coupling *r_dep*

Build a dependency graph *G=(V,E)*, edge *f→g* iff *f* imports *g*. Even when two
files sit in distant subtrees, if one agent edits a file the other imports, the
edit breaks the importer. Coupling decays with (direction-agnostic) graph
distance *d_G*:

```
coupling(f,g) = γ^{ d_G(f,g) − 1 }     γ ∈ (0,1), 0 if unreachable   (4)
r_dep = max_{f∈W_a, g∈W_b}  w_f · w_g · coupling(f,g)                (5)
```

A direct import (*d_G = 1*) ⇒ *coupling = 1*. This is the **"collision even when
far away"** term the metric must capture — a cross-file parameter/return
dependency that fails at a distance.

### Channel 3 — tree proximity *r_tree* (soft prior)

For two paths with lowest-common-ancestor depth *L*:

```
treeDistance(f,g) = ((depth_f − L) + (depth_g − L)) / (depth_f + depth_g)  (6)
r_tree = 1 − min_{f∈W_a, g∈W_b} treeDistance(f,g)
```

(0 = same file, 1 = disjoint roots.) Tree proximity alone rarely causes a
collision, so *ω_tree* is small — it nudges the metric, never dominates it.

### Future channels (same shape)

Call-graph distance (two functions near in the call stack), symbol-level
read/write hazard (a writes a symbol b reads), and test-coverage overlap all slot
in as additional *r_i* with their own weights — the noisy-OR (2) absorbs them
without changing the framework.

## 3. The TCAS protocol

Two thresholds carve a protected zone around *R*:

| Risk band | Advisory | Action |
|---|---|---|
| `R < τ_TA` | **Clear** | nothing |
| `τ_TA ≤ R < τ_RA` | **Traffic Advisory** | both agents **transmit intent** to each other (the scout handshake — "here is what I'm doing / did") |
| `R ≥ τ_RA` | **Resolution Advisory** | the **lower-priority** agent steers away; the other holds course |

The resolution is **coordinated and deterministic** (like one plane climbing while
the other descends) so the two agents never pick the same maneuver. Right-of-way
priority:

```
priority(a) = ( committed-work(a),  age(a) )      lexicographic
```

More committed work wins; ties break on earlier start; the final tiebreak is a
stable agent id. The lower-priority agent receives the steer.

**Closure rate.** TCAS escalates on *closing speed*, not just separation. From two
risk samples Δt apart, `closureRate = (R_t − R_{t−Δt}) / Δt`; a positive closure
rate near *τ_TA* can pre-emptively escalate before the protected zone is entered.

## 4. Vector-space view (the visualization)

Each file gets a coordinate via a **space-filling embedding of its path** (files
sharing a long directory prefix share most of their coordinate), then pulled
toward its dependency neighbours by one averaging step. An agent sits at the
recency-weighted centroid of its files' coordinates. The result: `‖v_a − v_b‖`
tracks the collision risk *R*, so a **3D "where are the agents" view** renders
agents as moving points in a file-cloud — you literally watch them crawl toward
each other, see the advisory line light up, and watch one steer away.

`scanAirspace(agents, graph)` returns, in one pass: the non-clear `advisories`
(what the trigger layer acts on), the 3D `positions` and `fileCoordinates` (what
the renderer draws), and pairwise `links` with risk (the edges to color).

## 5. How it wires into ECC

- **Inputs** come from the session/work state: each running session's worktree
  diff gives its working set *W_a*; the dependency graph is built from the repo
  (`buildDependencyGraph`).
- **Triggers**: the control-pane tick calls `scanAirspace`; a Traffic Advisory
  injects a "transmit intent" message between the two agents' sessions; a
  Resolution Advisory tells the lower-priority agent to steer (re-target to a
  different file/subtree) — the first concrete realization of *just-in-time
  multi-agent (and multi-human) deconfliction*.
- **Board**: advisories surface on the kanban as proximity warnings, extending
  the agent/human JIT assignment layer already in the control pane.

## Roadmap

- v0 (done): tree + overlap + dependency channels, noisy-OR risk, TCAS advisories,
  priority/steer, 3D embedding, full test coverage.
- v1: call-graph & symbol read/write channels; intent look-ahead; closure-rate
  escalation wired to live session diffs.
- v2: cross-machine airspace over Tailscale (teammate agents enter the same
  space); the recorded "N agents, M humans, zero merge conflicts" demo.
