feat(layer4): line-range channel + trigger firing

- Line precision: parse git diff --unified=0 into per-file changed line ranges
  (defaultWorkingSetFor), so two agents in the SAME file but DIFFERENT functions
  no longer false-collide. Overlap channel now uses the overlap coefficient
  (|A∩B|/min(|A|,|B|)) — high when one edit sits inside the other's region, low
  for disjoint ranges; whole-file edit = 1. Docstring + design doc updated.
- Trigger firing: buildProximityTriggers() turns advisories into the concrete
  messages — transmit-intent to both on a Traffic Advisory, steer-away to the
  yielding agent + a hold notice on a Resolution Advisory. buildProximitySnapshot
  now returns triggers; dispatchProximityTriggers(triggers, {sendMessage}) delivers
  them through an injectable sink (the ECC messages table), best-effort.
- 12 new tests (line-range disjoint vs overlapping, parseDiffRanges, triggers,
  dispatch). Full suite 2881/2881; lint green.
This commit is contained in:
Affaan Mustafa 2026-06-20 17:30:52 -04:00
parent e2b8a51cea
commit bd1be0c1ce
6 changed files with 251 additions and 43 deletions

View file

@ -46,10 +46,14 @@ test('treeDistance: siblings are closer than cousins', () => {
test('lineRangeOverlap: full overlap when whole-file (no ranges)', () => {
assert.strictEqual(lineRangeOverlap([], []), 1);
});
test('lineRangeOverlap: partial overlapping ranges', () => {
test('lineRangeOverlap: partial overlapping ranges (overlap coefficient)', () => {
const r = lineRangeOverlap([[1, 10]], [[5, 14]]);
// overlap lines 5..10 = 6, union 1..14 = 14 → 6/14
assert.ok(Math.abs(r - 6 / 14) < 1e-9, `got ${r}`);
// overlap lines 5..10 = 6; min size = 10 → 6/10
assert.ok(Math.abs(r - 6 / 10) < 1e-9, `got ${r}`);
});
test('lineRangeOverlap: smaller edit fully inside the larger ⇒ 1', () => {
// overlap coefficient catches "B's whole edit is inside A's region".
assert.strictEqual(lineRangeOverlap([[1, 200]], [[40, 60]]), 1);
});
test('lineRangeOverlap: disjoint ranges are 0', () => {
assert.strictEqual(lineRangeOverlap([[1, 5]], [[20, 25]]), 0);
@ -78,12 +82,18 @@ test('graphDistance: direct edge is 1, two hops is 2, unreachable is Infinity',
// ── collision risk channels ──
test('collisionRisk: two agents editing the SAME file ⇒ high risk', () => {
const a = { agentId: 'a', files: [{ path: 'src/api/users.js', lines: [[1, 50]] }] };
const b = { agentId: 'b', files: [{ path: 'src/api/users.js', lines: [[40, 90]] }] };
// Whole-file edits to the same file (no line info) ⇒ full overlap.
const a = { agentId: 'a', files: [{ path: 'src/api/users.js' }] };
const b = { agentId: 'b', files: [{ path: 'src/api/users.js' }] };
const { risk, channels } = collisionRisk(a, b, {});
assert.ok(risk > 0.5, `same-file risk ${risk} should be high`);
assert.ok(channels.overlap > 0);
});
test('collisionRisk: same file but heavily-overlapping lines ⇒ still high', () => {
const a = { agentId: 'a', files: [{ path: 'src/api/users.js', lines: [[1, 50]] }] };
const b = { agentId: 'b', files: [{ path: 'src/api/users.js', lines: [[5, 55]] }] };
assert.ok(collisionRisk(a, b, {}).risk > 0.5);
});
test('collisionRisk: unrelated far-apart files ⇒ low risk', () => {
const a = { agentId: 'a', files: [{ path: 'src/api/users.js' }] };
const b = { agentId: 'b', files: [{ path: 'docs/guide.md' }] };

View file

@ -5,7 +5,7 @@
const assert = require('assert');
const { buildProximitySnapshot, sessionsToAgents } = require('../../scripts/lib/control-pane/proximity');
const { buildProximitySnapshot, sessionsToAgents, parseDiffRanges, dispatchProximityTriggers } = require('../../scripts/lib/control-pane/proximity');
let passed = 0;
let failed = 0;
@ -87,5 +87,64 @@ test('buildProximitySnapshot: advisories carry human-readable labels', () => {
assert.ok(collision.aLabel && collision.bLabel, 'labels present');
});
test('parseDiffRanges: extracts new-side line ranges per file', () => {
const diff = ['diff --git a/src/x.js b/src/x.js', '--- a/src/x.js', '+++ b/src/x.js', '@@ -10,0 +11,3 @@', '+a', '+b', '+c', '@@ -40,2 +44,1 @@', '+z'].join('\n');
const ranges = parseDiffRanges(diff);
assert.deepStrictEqual(ranges.get('src/x.js'), [
[11, 13],
[44, 44]
]);
});
test('line-range channel: same file but disjoint ranges ⇒ no resolution', () => {
// Two agents in the same file, far-apart functions. workingSetFor provides ranges.
const workingSetFor = s =>
({
'lead-hermes': [{ path: 'src/api/users.js', lines: [[1, 20]] }],
'worker-kb': [{ path: 'src/api/users.js', lines: [[500, 540]] }]
})[s.id] || [];
const prox = buildProximitySnapshot([sessions[0], sessions[1]], { workingSetFor, graph: { adjacency: {} } });
const collision = prox.advisories.find(a => [a.a, a.b].includes('worker-kb'));
// Disjoint line ranges in the same file should NOT be a resolution-level collision.
assert.ok(!collision || collision.level !== 'resolution', `disjoint ranges should not force a steer (got ${collision && collision.level})`);
});
test('line-range channel: same file overlapping ranges ⇒ resolution', () => {
// worker's edit sits inside the lead's region — a definite conflict zone.
const workingSetFor = s =>
({
'lead-hermes': [{ path: 'src/api/users.js', lines: [[1, 120]] }],
'worker-kb': [{ path: 'src/api/users.js', lines: [[30, 70]] }]
})[s.id] || [];
const prox = buildProximitySnapshot([sessions[0], sessions[1]], { workingSetFor, graph: { adjacency: {} } });
const collision = prox.advisories.find(a => [a.a, a.b].includes('worker-kb'));
assert.ok(collision && collision.level === 'resolution', 'overlapping ranges should force a steer');
});
test('triggers: resolution produces a steer message to the yielding agent and a hold notice', () => {
const prox = buildProximitySnapshot(sessions, { changedFilesFor, graph: { adjacency: {} } });
const steer = prox.triggers.find(t => t.type === 'proximity_steer');
const hold = prox.triggers.find(t => t.type === 'proximity_hold');
assert.ok(steer && steer.to === 'worker-kb', 'steer message goes to the yielding worker');
assert.ok(hold && hold.to === 'lead-hermes', 'hold notice goes to the lead');
assert.ok(/steer away/i.test(steer.content));
});
test('dispatchProximityTriggers: delivers each trigger through the injected sink', () => {
const prox = buildProximitySnapshot(sessions, { changedFilesFor, graph: { adjacency: {} } });
const sent = [];
const result = dispatchProximityTriggers(prox.triggers, {
sendMessage: m => sent.push(m)
});
assert.strictEqual(result.dispatched, prox.triggers.length);
assert.ok(sent.every(m => m.fromSession && m.toSession && m.content && m.msgType));
});
test('dispatchProximityTriggers: no sink ⇒ nothing thrown, all skipped', () => {
const r = dispatchProximityTriggers([{ to: 'a', from: 'b', type: 'x', content: 'c' }], {});
assert.strictEqual(r.dispatched, 0);
assert.strictEqual(r.skipped, 1);
});
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
if (failed > 0) process.exit(1);