feat(workstate): snapshot des délégations en file par agent (Lot B backend)

Ajoute un port de lecture ségrégué `AgentQueueSnapshot` (ISP) distinct du
`AgentMailbox` mutant : il expose `queue_for(agent)` qui renvoie des
`QueuedTicketSnapshot` clonés, ordonnés FIFO, avec position recalculée
(0 = tête). Observer la file ne la mute jamais ; le one-shot reply sender
reste dans l'adaptateur.

- domain : value object `QueuedTicketSnapshot` + trait `AgentQueueSnapshot`
  (object-safe, partagé en `Arc<dyn …>`).
- infrastructure : `InMemoryMailbox` implémente la vue lecture en plus de la
  vue mutation ; positions recalculées à chaque appel.
- application : le read-model work-state liste les délégations en attente via
  ce port, troncature de l'aperçu de tâche en conservant la longueur d'origine.
- app-tauri : DTO `camelCase` des tickets en file câblé dans l'état.

Tests verts : domain mailbox (6), infrastructure mailbox (13),
application workstate (12), app-tauri dto_agents (20).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 18:52:16 +02:00
parent 7453181e6c
commit cc7d99a63e
9 changed files with 692 additions and 15 deletions

View File

@ -993,6 +993,10 @@ impl AppState {
// partagé pour `resolve`/`resolve_ticket`/`cancel_head` côté orchestrateur.
let inmemory_mailbox = Arc::new(InMemoryMailbox::new());
let mailbox = Arc::clone(&inmemory_mailbox) as Arc<dyn domain::mailbox::AgentMailbox>;
// Same concrete mailbox, second (read-only) port view for the work-state
// read model: lists pending tickets without touching the mutating surface.
let queue_snapshot =
Arc::clone(&inmemory_mailbox) as Arc<dyn domain::mailbox::AgentQueueSnapshot>;
let mediated_inbox = Arc::new(
MediatedInbox::with_pty(
Arc::clone(&inmemory_mailbox),
@ -1031,6 +1035,7 @@ impl AppState {
Arc::clone(&contexts_port),
Arc::clone(&live_sessions),
Arc::clone(&input_mediator),
queue_snapshot,
));
// --- Limites de session des agents (ARCHITECTURE §21, LS7) ---