L'erreur « La réponse du modèle n'a pas pu être finalisée. » indique désormais
l'adapter en cause (Session Codex / Claude / OpenCode / HTTP) pour lever
l'ambiguïté constatée sur GameTime entre session Codex et Claude.
event_supersedes_pending_final ne fait plus annuler le final en attente par
tout événement autre que Heartbeat/RateLimited/turn-progress: seuls un progress
non-turn Started/Delta, un ToolActivity ou un Error annulent. Le buffering
agent_message survive ainsi jusqu'au flush a turn.completed (regréssion
codex_agent_message_survives_late_completed_item_as_final).
assistantFailureText conserve le texte déjà streamé puis classe l'échec
(sans contenu, tronqué, fin non reçue, transitoire) avec conseil de reprise
adapté, au lieu d'écraser la bulle par « Échec — … finalisée. ».
append_text_fallback_final accumule les TextDelta et produit un Final uniqne
en fin de flux si aucun Final/Error/RateLimited n'a été émis et que le texte
est non vide. Un long message utilisateur sur un autre projet (GameTime) ne
conclut plus a tort « La réponse du modèle n'a pas pu être finalisée. ».
Le test qui pinnait l'absence de Final devient la régression #239.
ConversationViewer remplace « Aucun tour pour le moment » par un diagnostic
differentié (agent actif sans tour affichable, transcript non synchronisé,
activité sur un autre fil) avec action « Ouvrir le fil actif ». Le panneau
Work state affiche le résumé du fil du ticket actif et ProjectsView/WebWorkspace
câblent onOpenConversation.
ensure_structured_session reçoit désormais le conversation_id déjà résolu et le
transmet au plan de spawn au lieu de retomber sur le fallback User-B. WorkState
et la session lancée pointent ainsi sur le même fil. Test de régression
ask_cold_structured_agent_requester_launches_on_resolved_pair_thread.
QA verte périmètre ticket: fmt/check/websocket_chat/websocket single-thread.
cargo test -p web-server complet reste rouge sur bruit historique PTY/fd
(Too many open files puis 7 échecs PTY mono-thread), non attribué au ticket.
Les grants Landlock RO/RW empêchaient la custom CLI de démarrer côté web
téléphone avant d'atteindre le project root. Les providers structurés/headless
gèrent leur propre sandbox compatible CLI.