---
id: PRD-0015
title: "M11.1 — dynamic tool list and legible handle conflicts"
status: done
owner: "Aaron Roney"
created: 2026-07-03
updated: 2026-07-03

depends_on:
- PRD-0012

principles:
- "The offered toolset must track reality: when gating state changes, the client is told to re-list — never 'wait for it to propagate'."
- "A handle conflict should read as a diagnosis with a remedy, not an unbounded notice stream."
- "Live permission changes have exactly one story: the set_perm tool; the CLI edits the future."

acceptance_tests:
- id: uat-001
  name: "The bridge declares tools.listChanged and emits notifications/tools/list_changed when emit or admin gating changes (and not otherwise)"
  command: cargo make test
  uat_status: verified
- id: uat-002
  name: "Repeated instant link drops surface one handle-conflict diagnostic and suppress further link notices until the link stabilizes"
  command: cargo make test
  uat_status: verified

tasks:
- id: T-001
  title: "tools/list_changed: declare the capability, emit on toolset-gating changes"
  priority: 1
  status: done
  notes: "Signature = (any_emit_allowed, admin_servers empty); check around the two dispatch entry points (handle_mcp, handle_link_event) so every path — set_perm, join/leave, ServerInfo — is covered in one place. Found live: send_channel could never appear mid-session."
- id: T-002
  title: "Handle-conflict circuit breaker: diagnose rapid instant drops, suppress notice spew"
  priority: 1
  status: done
  notes: "Track per-server uptime in BridgeCore; 3 consecutive sub-30s links -> one diagnostic naming --as as the remedy, then no link notices until a link survives the stability window. Reuses client::STABLE_UPTIME."
- id: T-003
  title: "Perm-propagation story: CLI hint + skill docs (one bridge per session, --as default collision)"
  priority: 2
  status: done
  notes: "perm set prints that a running bridge needs its set_perm tool; skill mental model documents one-bridge-per-CC-session and the same-directory default-handle collision."
---

# Summary

Three fixes from the first live multi-session test. The bridge's tool list is now dynamic (the MCP
`listChanged` contract), a session-handle conflict diagnoses itself instead of streaming
disconnect notices, and the permission-propagation story is stated plainly in the CLI and skill.

# Problem

Live test findings (2026-07-03, after PRD-0012): (1) `send_channel` could never appear mid-session
— the bridge never emits `notifications/tools/list_changed`, so Claude Code's cached tool list
goes stale the moment `set_perm`/join/admin-arrival changes gating; (2) two Claude Code sessions
in the same directory collide on the default handle (dir name) and supersede each other — with
PRD-0012 the fight is slow, but it still streams notices without naming the cause; (3) `conclave
perm set` writes disk that a running bridge never re-reads, which reads as a propagation delay but
is actually a design boundary nobody stated.

# Technical Approach

- **T-001**: fingerprint the gating inputs before/after each dispatched event in `BridgeCore`;
  on change, send `notifications/tools/list_changed` (and declare `tools: { listChanged: true }`
  at initialize).
- **T-002**: `BridgeCore` records link-up instants; a drop under `STABLE_UPTIME` bumps a
  consecutive counter. At 3, emit one diagnostic ("another live session may hold this handle —
  pass a distinct `--as`") and stop emitting per-cycle link notices until a link survives the
  window (counter resets, notices resume).
- **T-003**: `perm set` output states the boundary; the skill's mental model documents
  one-bridge-per-session and the same-directory collision.

# Non-Goals (MVP)

- Auto-unique default handles (breaks stable whisper targets and supersede-take-over; no session
  ID is available in the MCP child environment — verified).
- Config-file watching in the bridge (the set_perm tool is the live path).

# History

- 2026-07-03: Drafted from the first live two-session test; executing immediately.
- 2026-07-03: All three tasks landed same-day; gate green (187 tests).
