# Chat Transcript Leakage + Thinking-Only Fix Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Eliminar o vazamento de transcript/prompt (`# System: ...`), impedir que respostas corrompidas voltem ao contexto e garantir que o chat exiba a resposta útil além do thinking. **Architecture:** A correção será feita em três camadas complementares: (1) parser/sanitização no frontend para detectar transcript leakage em formatos markdown e role-prefix tradicionais; (2) contenção na persistência e reidratação do histórico para impedir reinfecção do contexto; (3) endurecimento do backend para detectar stops por sufixo acumulado, em vez de comparação token-a-token. O rollout deve ser guiado por testes primeiro, com mudanças pequenas e verificadas por camada. **Tech Stack:** React + TypeScript + Vitest no frontend; Rust no backend (`inference-server`, `inference-core`); SSE streaming; SQLite/local DB. --- ## Estratégia de implementação ### Abordagem A — Parser defensivo no frontend Usar uma função única de sanitização que reconheça: - `System:` / `User:` / `Assistant:` / `Developer:` - `# System:` / `## System:` etc. - blocos fenced que comecem com transcript vazado - prefixos de prompt conhecido (`You are a precise coding assistant running locally...`) Essa abordagem protege a UI mesmo quando o backend ainda falhar. ### Abordagem B — Quarentena do histórico persistido Antes de salvar ou reenviar mensagens do assistente: - limpar transcript leakage - marcar como corrompida quando só restar prompt echo / transcript - não reenviar mensagens contaminadas para o modelo Essa abordagem interrompe o ciclo de reinjeção. ### Abordagem C — Stop detection real no backend Trocar a verificação de stop sequence baseada em token isolado por verificação baseada em buffer/sufixo acumulado da saída gerada. Essa abordagem reduz a chance do vazamento nascer. ### Ordem recomendada 1. Frontend parser + testes 2. Histórico/persistência + testes 3. Backend stop detection + testes 4. Validação integrada streaming/non-streaming --- ## Critérios de aceitação - Respostas contendo `# System:` não aparecem mais como conteúdo visível ao usuário. - Respostas contendo apenas `...` seguido de transcript leakage não são persistidas como resposta válida. - Mensagens contaminadas previamente salvas não são reenviadas ao modelo em `buildApiMessages()`. - O streaming continua mostrando thinking em tempo real, mas a resposta final visível aparece corretamente quando existir. - O backend corta transcript leakage por stop sequence mesmo quando ele chega fragmentado em múltiplos tokens. - Testes frontend e backend cobrem os formatos reais do bug. --- ### Task 1: Criar matriz de casos reais do vazamento **Files:** - Modify: `tauri-app/src/lib/chat.test.ts` - Modify: `tauri-app/src/prompts/response-rules.ts` **Step 1: Escrever testes falhos para transcript leakage em formatos reais** Adicionar casos para: - `# System: You are a precise coding assistant...` - ````md ```markdown # System: ... ``` ```` - `...` seguido de `# System:` - transcript tradicional `Assistant:` / `User:` - resposta normal com markdown legítimo que **não** deve ser cortada **Step 2: Rodar os testes para confirmar falha** Run: `cd tauri-app && npm test -- src/lib/chat.test.ts` Expected: FAIL nos novos casos de `# System:` / fenced leakage. **Step 3: Commit** ```bash git add tauri-app/src/lib/chat.test.ts tauri-app/src/prompts/response-rules.ts git commit -m "test: cover transcript leakage variants" ``` --- ### Task 2: Centralizar a detecção de transcript leakage no frontend **Files:** - Modify: `tauri-app/src/prompts/response-rules.ts` - Modify: `tauri-app/src/lib/chat.ts` - Test: `tauri-app/src/lib/chat.test.ts` **Step 1: Expandir os padrões de transcript leakage** Em `tauri-app/src/prompts/response-rules.ts`: - substituir `TRANSCRIPT_LEAKAGE_PATTERN` por versão que aceite prefixos markdown opcionais: - `(?:^|\n)\s*(?:#{1,6}\s*)?(?:System|User|Assistant|Human|Developer)\s*:` - adicionar padrão explícito para prompt echo atual: - `/you are a precise coding assistant running locally/i` **Step 2: Criar sanitização mais forte em `chat.ts`** Em `tauri-app/src/lib/chat.ts`: - extrair helper como `stripPromptEchoAndTranscriptLeakage(text: string): string` - cortar conteúdo ao encontrar: - role-prefix simples - role-prefix markdown (`# System:`) - prompt echo conhecido no início da seção visível - garantir que markdown legítimo com `# Heading` continue funcionando se não for um role marker. **Step 3: Ajustar `isLoopedOrCorruptedResponse()`** Adicionar o novo padrão de corrupção (`precise coding assistant running locally`). **Step 4: Rodar os testes** Run: `cd tauri-app && npm test -- src/lib/chat.test.ts` Expected: PASS **Step 5: Commit** ```bash git add tauri-app/src/prompts/response-rules.ts tauri-app/src/lib/chat.ts tauri-app/src/lib/chat.test.ts git commit -m "fix: sanitize transcript leakage in assistant responses" ``` --- ### Task 3: Impedir reinfecção do histórico em `buildApiMessages()` **Files:** - Modify: `tauri-app/src/components/ChatView.tsx` - Create: `tauri-app/src/components/chat-history-sanitizer.test.ts` (ou incluir no teste existente mais próximo) **Step 1: Escrever teste falho para reidratação contaminada** Cobrir cenário: - mensagem do assistant salva com `# System: ...` - `buildApiMessages()` não deve reenviar essa parte - se a mensagem toda for corrupção, ela deve ser descartada do contexto **Step 2: Extrair helper reutilizável de sanitização do histórico** Em `ChatView.tsx`: - substituir regex inline em `buildApiMessages()` por uso do helper central de `chat.ts` - regra recomendada: - assistant com conteúdo limpo vazio => descartar do contexto - assistant com conteúdo útil + vazamento => manter só parte útil **Step 3: Garantir simetria com persistência** Não usar regex diferente no histórico. Tudo deve passar pelo mesmo parser/sanitizer. **Step 4: Rodar testes** Run: `cd tauri-app && npm test -- src/components/chat-history-sanitizer.test.ts src/components/ChatView.test.tsx` Expected: PASS **Step 5: Commit** ```bash git add tauri-app/src/components/ChatView.tsx tauri-app/src/components/chat-history-sanitizer.test.ts tauri-app/src/components/ChatView.test.tsx git commit -m "fix: prevent transcript leakage from reentering chat context" ``` --- ### Task 4: Corrigir persistência da resposta final vs thinking-only **Files:** - Modify: `tauri-app/src/components/ChatView.tsx` - Modify: `tauri-app/src/components/ChatView.test.tsx` - Possibly Modify: `tauri-app/src/components/StreamingBubble.tsx` **Step 1: Escrever testes falhos para dois casos críticos** Caso A: - stream = `analiseResposta útil` - deve salvar `content = "Resposta útil"` e `reasoning_content = "analise"` Caso B: - stream = `analise# System: ...` - não deve salvar resposta visível corrompida - opcionalmente deve mostrar placeholder/erro controlado **Step 2: Ajustar regra de persistência** Em `ChatView.tsx`, no trecho final de `send()`: - calcular `sanitizedVisibleContent` - se `sanitizedVisibleContent` for vazio **e** reasoning existir, tratar como resposta sem conteúdo útil - não salvar transcript leak como `content` - salvar `reasoning_content` apenas quando existir conteúdo útil ou quando a UX desejada permitir thinking-only explícito **Step 3: Definir comportamento de UX para thinking-only corrompido** Abordagem recomendada: - se só sobrar reasoning e o conteúdo visível estiver corrompido/vazio, salvar mensagem de erro controlado: - `⚠️ O modelo gerou apenas raciocínio interno e nenhuma resposta utilizável.` - não persistir o prompt echo bruto **Step 4: Rodar testes** Run: `cd tauri-app && npm test -- src/components/ChatView.test.tsx` Expected: PASS **Step 5: Commit** ```bash git add tauri-app/src/components/ChatView.tsx tauri-app/src/components/ChatView.test.tsx tauri-app/src/components/StreamingBubble.tsx git commit -m "fix: handle thinking-only and corrupted final responses" ``` --- ### Task 5: Corrigir stop detection no backend **Files:** - Modify: `crates/inference-core/src/session.rs` - Add test in: `crates/inference-core/src/session.rs` or dedicated module test file **Step 1: Escrever teste falho para stop fragmentado** Criar teste para simular emissão fragmentada de: - `\n` - `System` - `:` O detector deve reconhecer que o sufixo acumulado forma `\nSystem:` mesmo quebrado em múltiplos tokens. **Step 2: Implementar buffer de sufixo acumulado** Em `session.rs`: - adicionar campo para acumular os últimos N caracteres emitidos (`recent_output_suffix`) - a cada token detokenizado: - concatenar ao buffer - truncar buffer para tamanho máximo do maior stop + margem pequena - verificar `ends_with(stop)` no buffer acumulado **Step 3: Manter comportamento atual de streaming** Não parar por igualdade de token isolado; parar por sufixo acumulado. **Step 4: Rodar testes do crate** Run: `cargo test -p inference-core session -- --nocapture` Expected: PASS **Step 5: Commit** ```bash git add crates/inference-core/src/session.rs git commit -m "fix: detect stop sequences across fragmented tokens" ``` --- ### Task 6: Endurecer stops do template genérico e alinhar com parser **Files:** - Modify: `crates/inference-server/src/compat.rs` - Test: `crates/inference-server/src/compat.rs` **Step 1: Adicionar variantes markdown aos `extra_stop_sequences`** Em `prepare_prompt()` para `ChatTemplate::Generic`, incluir: - `\n# System:` - `\n# User:` - `\n# Assistant:` - `\n## System:` (opcional) **Step 2: Adicionar teste de contrato** Garantir que o template genérico injeta essas variantes. **Step 3: Rodar testes** Run: `cargo test -p inference-server compat -- --nocapture` Expected: PASS nos testes do módulo `compat` relevantes. **Step 4: Commit** ```bash git add crates/inference-server/src/compat.rs git commit -m "fix: add markdown transcript stops for generic prompt template" ``` --- ### Task 7: Validação integrada frontend + backend **Files:** - No code required initially - Possibly add/update integration tests after manual verification **Step 1: Rodar suíte frontend completa** Run: `cd tauri-app && npm test` Expected: PASS **Step 2: Rodar build frontend** Run: `cd tauri-app && npm run build` Expected: PASS **Step 3: Rodar testes backend focados** Run: ```bash cargo test -p inference-core -- --nocapture cargo test -p inference-server compat -- --nocapture ``` Expected: PASS nos testes tocados pela mudança. **Step 4: Verificação manual** Cenários manuais: 1. resposta normal sem `` 2. resposta com `` e resposta útil 3. resposta com `` + `# System:` 4. mensagem previamente contaminada no DB não deve ser reenviada ao contexto **Step 5: Commit final** ```bash git add . git commit -m "fix: stop transcript leakage from corrupting chat responses" ``` --- ## Observações de implementação - Não criar regex diferentes em cada arquivo. A sanitização precisa ter **uma fonte de verdade**. - O parser do frontend e a limpeza do histórico devem compartilhar helpers. - O backend deve reduzir a chance do bug, mas o frontend ainda precisa ser resiliente porque modelos locais podem ignorar formato. - Não confiar apenas em `isLoopedOrCorruptedResponse()`; usar também sanitização determinística do conteúdo. ## Resultado esperado final Depois dessas tarefas: - o usuário não verá mais blocos `# System: ...` nas mensagens; - o thinking continuará disponível, mas não substituirá a resposta útil; - respostas corrompidas não contaminarão o histórico; - o backend interromperá transcript leakage com mais robustez.