feat(persistence): P8a — cohérence de clé conversation (id de paire stable)
Corrige l'incohérence P6/P7 : la cellule et la persistance partagent désormais le MÊME id de paire IdeA, déterministe et stable au redémarrage — la clé sous laquelle P6b sauve log/handoff == celle sous laquelle P7 les charge. - domaine : ConversationId::for_pair(a,b) pur/déterministe (User↔Agent = uuid agent ; Agent↔Agent = XOR commutatif) ; LeafCell gagne engine_session_id (cache resumable moteur, additif serde default) - infrastructure : InMemoryConversationRegistry::resolve utilise for_pair au lieu de new_random() → id recalculable sans état, identique après restart - application : launch_structured persiste l'id de paire sur la cellule (et l'id moteur sur engine_session_id) ; cellule neuve ⇒ dérive for_pair(User,agent) ; resolve_conversation repli factorisé sur for_pair ; withers layout clone-and- mutate (préservent les champs additifs) - app-tauri : engine_session_id propagé dans les DTO Suites domain/infra/application/app-tauri vertes (assertion structured_launch_d3 recodée sur le contrat). Test déterminisme/restart dédié à ajouter au retour de quota agent (binôme Test interrompu par limite de session). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -528,6 +528,7 @@ fn agent_leaf(
|
||||
session: None,
|
||||
agent,
|
||||
conversation_id: conversation_id.map(str::to_owned),
|
||||
engine_session_id: None,
|
||||
agent_was_running,
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,6 +198,7 @@ fn single_leaf(node_id: NodeId) -> LayoutTree {
|
||||
session: None,
|
||||
agent: None,
|
||||
conversation_id: None,
|
||||
engine_session_id: None,
|
||||
agent_was_running: false,
|
||||
})
|
||||
}
|
||||
|
||||
@ -328,6 +328,7 @@ fn agent_leaf(
|
||||
session: None,
|
||||
agent,
|
||||
conversation_id: conversation_id.map(str::to_owned),
|
||||
engine_session_id: None,
|
||||
agent_was_running,
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,6 +161,7 @@ fn agent_leaf(node: NodeId, agent: Option<AgentId>, conv: Option<&str>, running:
|
||||
session: None,
|
||||
agent,
|
||||
conversation_id: conv.map(str::to_string),
|
||||
engine_session_id: None,
|
||||
agent_was_running: running,
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,6 +181,7 @@ fn agent_leaf(node: NodeId, agent: Option<AgentId>) -> LeafCell {
|
||||
session: None,
|
||||
agent,
|
||||
conversation_id: None,
|
||||
engine_session_id: None,
|
||||
agent_was_running: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -741,8 +741,20 @@ async fn structured_launch_starts_session_registers_no_pty_spawn() {
|
||||
out.session.kind,
|
||||
SessionKind::Agent { agent_id } if agent_id == f.agent.id
|
||||
));
|
||||
// L'id de conversation moteur est exposé pour persistance sur la cellule.
|
||||
assert_eq!(out.assigned_conversation_id.as_deref(), Some("engine-conv"));
|
||||
// P8a (ARCHITECTURE §19.7) : la CELLULE porte l'**id de paire IdeA**, pas l'id
|
||||
// moteur. Cellule neuve, lancement direct (aucun requester) ⇒ `pair(User, agent)`
|
||||
// dérivé via `ConversationId::for_pair` = l'UUID de l'agent (`aid(1)`).
|
||||
assert_eq!(
|
||||
out.assigned_conversation_id.as_deref(),
|
||||
Some("00000000-0000-0000-0000-000000000001"),
|
||||
"cell carries the IdeA pair id (pivot logique), not the engine resumable"
|
||||
);
|
||||
// L'id de session MOTEUR (resumable provider) part dans le cache séparé.
|
||||
assert_eq!(
|
||||
out.engine_session_id.as_deref(),
|
||||
Some("engine-conv"),
|
||||
"engine resumable id is cached separately from the pair key"
|
||||
);
|
||||
}
|
||||
|
||||
/// Profil **non structuré** (même câblage structuré présent) ⇒ chemin PTY inchangé :
|
||||
|
||||
@ -62,6 +62,7 @@ fn tab(n: u128) -> Tab {
|
||||
session: None,
|
||||
agent: None,
|
||||
conversation_id: None,
|
||||
engine_session_id: None,
|
||||
agent_was_running: false,
|
||||
})),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user