---
issueRef: "#101"
version: 7
updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"}
updatedAt: 1785011116365
---
# Carnet #101 — défaut d'isolation multi-projet (cause racine figée)

> Diagnostic Architect (2026-07-25). Source de vérité du fix. Mémoire durable :
> `ticket101-cross-talk-multi-project-rootcause`.

## Cause racine
Stores disque IdeA **correctement scoppés par projet** (mémoire, contexte, handoff, live-state lus
depuis `input.project.root` ; agents persistés dans `.ideai/agents.json` par root projet, **sans
re-mint des UUID à l'ouverture**). Mais plusieurs **registres mémoire runtime restent globaux,
indexés par `AgentId` seul** → deux projets ouverts (surtout si l'un est une copie) peuvent porter
les **mêmes `AgentId`** et le runtime les confond.

### 2 manifestations, même défaut
- **A — contamination du contexte d'inférence** : conversation/session d'un projet réutilisée pour
  l'autre → contexte injecté à l'agent contaminé (preuve : pseudo-branche `wear-os-watch-sync`
  créée par l'agent Git avec un nom de l'autre projet).
- **B — notification de tâche backend perdue / agent s'arrête** (sujet original) : complétion
  livrable/bloquée/réveillant la mauvaise session.

## Points précis (registres par `AgentId` seul à requalifier)
- ConversationRegistry global + `ConversationId` dérivé des UUID agents seuls :
  `crates/domain/src/conversation.rs:71`, `crates/infrastructure/src/conversation/mod.rs:41`,
  orchestrateur `crates/application/src/orchestrator/service.rs:2192` (et `:2293`, `:2368`).
- Sessions PTY/structured par `agent_id` seul :
  `crates/application/src/terminal/registry.rs:182,437`.
- Verrous ask / busy-state / liveness / délégations différées :
  `crates/application/src/orchestrator/service.rs:418`,
  `crates/infrastructure/src/input/mod.rs:47`.
- Inbox/mailbox par `AgentId` seul : `crates/domain/src/inbox.rs:68,156`,
  `crates/infrastructure/src/input/mod.rs:1052`, `crates/infrastructure/src/mailbox/mod.rs:44`.
- Wake par `AgentId` seul : `crates/application/src/orchestrator/wake.rs:87`,
  provider `crates/backend/src/lib.rs:687`.

### Pour B — distinction runtime vs modèle
La chaîne sink→`project_id`→wake est **correcte** jusqu'au bridge
(`crates/infrastructure/src/background_task/sink.rs:23,142` ; `crates/backend/src/lib.rs:2228`
recharge le projet par `project_id` puis `wake_agent`). Le défaut réapparaît juste après
(inbox/mailbox/busy/session par AgentId seul). **Runtime IdeA suspecté en premier.** GLM 5.2 n'est
l'hypothèse principale que si les logs prouvent enqueue+wake+`BackgroundTaskCompletionDelivered`
sur le bon projet sans reprise. Traces : `lib.rs:2238`, `wake.rs:93`.

## Décision utilisateur
**Lancer le fix structurel maintenant (lots 1-2).** La collision d'UUID et les logs B se
vérifieront en parallèle.

## Périmètre DevBackend (lots 1-2 de ce fix)
- **Lot 1** : introduire une clé runtime scellée `RuntimeAgentKey { project_id, agent_id }` ;
  interdire toute map app-wide indexée par `AgentId` seul.
- **Lot 2** : propager la clé dans `AgentInbox`, `InputMediator`, `AgentMailbox`,
  busy/liveness/deferred, wake, session lookup, ask-locks. **Correctif structurel commun à A et B.**

Lots suivants (3-6, hors premier passage) : qualifier ConversationId/registry par projet (lot 3) ;
requalifier `TerminalSessions`/`StructuredSessions` par `(project_id, agent_id)` +
`AppWakeSessionProvider` refuse l'autre projet (lot 4) ; audit `session_limit`/tables reprise (lot 5) ;
télémétrie `project_id` sur logs diag wake/routage (lot 6).

## Invariants
- Sources de contexte sur disque restent root-scopées (ne pas régresser).
- Templates/profils globaux restent globaux produit (pas de vecteur de session/conversation partagée).
- Un projet non-actif doit continuer à recevoir ses wakes et complétions.
- Pas de régression OpenCode/Codex/Claude (correctif transverse runtime, pas moteur-spécifique).
- Aucun nouveau DTO frontend pour la correction minimale.

## QA — critère de vérité
Test d'intégration **non-cross-talk** : 2 projets ouverts avec **volontairement les mêmes `AgentId`** :
- délégation projet A ne réutilise jamais session/conversation vivante de projet B ;
- complétion `(projet A, agent X)` n'entre ni dans l'inbox ni dans la session de `(projet B, agent X)` ;
- wake d'un projet non-actif fonctionne ;
- collision d'ids qui échouait avant → verte sur PTY, structured et background wake.

## Clôture 2026-07-25
- Correctif livré sur `feature/ticket101-multi-project-isolation` puis mergé localement dans `develop`.
- Commit feature : `6e98fd8 fix(runtime): isolate agent state by project (#101)`.
- Merge local : `merge: integrate ticket 101 multi-project isolation`.
- QA ciblée verte :
  - `cargo test -p application --test agent_wake --test orchestrator_service --test structured_registry_d1 --test structured_launch_d3 --test session_limit_service --test session_limit_t4 --test workstate --test workstate_actions`
  - `cargo test -p infrastructure --test agent_inbox --test mcp_server`
  - `cargo test -p app-tauri --test session_limit_wiring`
  - `cargo test -p application`
  - `cargo test -p app-tauri --tests`
- Réserve connue : `cargo test -p infrastructure` complet reste rouge dans le sandbox QA sur tests `openai_compat` à cause du bind local interdit (`Operation not permitted`), sans signal de régression #101.

## Hors périmètre
- #91 (popup de notification) : purement front, indépendant.
- Remint systématique des AgentId à l'ouverture : non retenu (la clé runtime rend la collision
  inoffensive même sans remint).

## Lié
- #91 (relatesTo). Mémoires : `background-tasks-first-class-design`, `b8-command-runner-pty-framing`,
  `mcp-bridge-and-delegation-runtime-notes` (règle rebuild AppImage).