--- name: conversation-viewer-ls7-frontend description: Contrat figé du viewer de transcript paginé (frontend pur, lecture seule, surface humaine). metadata: type: reference --- # LS7 — Viewer fil-par-paire (front pur) Dernier lot fonctionnel du programme persistance. UI humaine qui rejoue le transcript par paire, consomme la commande LS6 `read_conversation_page`. Lecture seule, zéro impact backend/agent. ## Gateway / adapter / mock (patron WorkStateGateway) - Port `ConversationGateway.readPage(projectId, conversationId, {anchor?, direction?, limit?}) -> TurnPage`. Ajouter `conversation` à `Gateways`. - Types domaine : `TurnView{id, atMs, role: prompt|response|toolActivity, source: {kind:human}|{kind:agent,agentId}, text COMPLET, textLen}`, `TurnPage{turns, hasMore, nextAnchor}`. - Adapter `TauriConversationGateway` → invoke("read_conversation_page",{projectId,conversationId,cursor:{anchor,direction},limit}) + `conversationNormalization.ts` (mapper source Human/Agent calqué sur workStateNormalization). Mock avec pagination réelle + `_setTurns` pour tests offline. - Frontière : composant → useGateways().conversation → adapter → invoke. Jamais d'invoke direct. ## Modèle d'affichage - Clé = conversationId. Entrée = drill-down depuis le Work panel (`ConversationWorkSummary.conversationId` déjà énuméré ; rendre les lignes cliquables via prop `onOpenConversation`). Pas de nouvel appel « liste conversations ». - Rejeu chrono croissant ; distinction sobre User↔Agent vs Agent↔Agent (parties déduites des sources, noms résolus depuis l'inventaire agents) ; toolActivity atténué/replié. - Pagination : ouverture backward/None = dernière page (bas du fil) ; scroll-up = backward ancré sur le tour le plus ANCIEN du buffer (préfixe, dédup par id, hasMore gate) ; refresh queue = forward ancré sur le plus récent (manuel ou sur domain events delegationReady/orchestratorRequestProcessed). ## Intégration - État local `viewerConversationId` dans ProjectsView ; swap main-area (rend ConversationViewer à la place de LayoutGrid, PAS un nouveau kind backend) ; bouton retour ; reset au changement de projet. viewerConversationId=null ⇒ UI actuelle inchangée (non-régression terminal). ## Frontière / backend Lecture seule (read_conversation_page LS6, hors chemin chaud), jamais injecté dans un contexte agent. **Aucune part backend** : juste vérifier la signature de la commande exposée et aligner l'adapter si écart.