[autoresearch] baseline: system prompt quality tests (5/5 passing)
This commit is contained in:
1 parent
05cc036f6d
commit
60b0101717
142 files changed
+18589
-9947
No files matched your search
+1906
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,347 @@
|
||||
# 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 `<think>...</think>` 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: ...
|
||||
```
|
||||
````
|
||||
- `<think>...</think>` 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 = `<think>analise</think>Resposta útil`
|
||||
- deve salvar `content = "Resposta útil"` e `reasoning_content = "analise"`
|
||||
|
||||
Caso B:
|
||||
- stream = `<think>analise</think># 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 `<think>`
|
||||
2. resposta com `<think>` e resposta útil
|
||||
3. resposta com `<think>` + `# 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.
|
||||
@@ -0,0 +1,548 @@
|
||||
# Memory Architecture: Chat + User Consolidation Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Introduzir uma arquitetura de memória segura e incremental que extraia memórias estruturadas com o modelo local `models/embedding/gemma-3-270m-it-Q8_0.gguf`, separe memória de chat e memória de usuário, consolide memórias entre chats sem duplicação e prepare o terreno para uso dinâmico em prompts futuros.
|
||||
|
||||
**Architecture:** A implementação será dividida em duas pipelines desacopladas: (1) extração de memória de chat a partir de mensagens concluídas em um chat específico; (2) consolidação de memória de usuário a partir das memórias de chat já processadas. Para evitar quebrar o fluxo atual, a extração será feita em background, com schema novo e compatibilidade retroativa com `user_memories`. A primeira fase não altera o prompt principal do chat; apenas cria, valida, deduplica e persiste a memória corretamente.
|
||||
|
||||
**Tech Stack:** React/TypeScript, Tauri frontend, SQLite local (`db.ts`), API compatível OpenAI do runtime local, modelo GGUF local `gemma-3-270m-it-Q8_0.gguf`, Vitest.
|
||||
|
||||
---
|
||||
|
||||
## Princípios de segurança desta implementação
|
||||
|
||||
1. **Não quebrar o chat atual**: memória nova roda em background e falha silenciosamente.
|
||||
2. **Não misturar memória bruta com prompt principal ainda**: primeiro persistimos corretamente, depois conectamos ao prompt.
|
||||
3. **Não usar mensagens inteiras como memória final**: só fatos estruturados, classificados e deduplicados.
|
||||
4. **Separação explícita**:
|
||||
- `chat memories` = fatos extraídos de um chat específico
|
||||
- `user memories` = fatos consolidados a partir de vários chats
|
||||
5. **Idempotência**: nunca reprocessar o mesmo insumo sem necessidade.
|
||||
6. **Deduplicação conservadora**: primeiro por chave/categoria/valor normalizado; sem embeddings sofisticados nesta fase.
|
||||
7. **Modelo único para extração/classificação**: usar `gemma-3-270m-it-Q8_0.gguf` como extractor/classifier local.
|
||||
|
||||
---
|
||||
|
||||
## Resultado esperado desta fase
|
||||
|
||||
Ao final desta implementação:
|
||||
- cada chat poderá gerar memórias estruturadas próprias;
|
||||
- memórias de usuário serão derivadas das memórias de chat já consolidadas;
|
||||
- duplicatas não serão reinseridas;
|
||||
- memórias terão tipo/classificação/confiança/origem;
|
||||
- o sistema estará pronto para usar essas memórias em prompts dinâmicos futuros, sem ainda acoplar tudo ao chat principal.
|
||||
|
||||
---
|
||||
|
||||
## Modelo de dados recomendado
|
||||
|
||||
### Tabela 1: `chat_memories`
|
||||
Representa fatos persistidos derivados de um chat.
|
||||
|
||||
Campos sugeridos:
|
||||
- `id INTEGER PRIMARY KEY`
|
||||
- `chat_id INTEGER NOT NULL`
|
||||
- `source_message_id INTEGER NULL`
|
||||
- `memory_key TEXT NOT NULL`
|
||||
- `memory_value TEXT NOT NULL`
|
||||
- `memory_category TEXT NOT NULL`
|
||||
- `memory_scope TEXT NOT NULL DEFAULT 'chat'`
|
||||
- `confidence REAL NOT NULL`
|
||||
- `evidence TEXT NULL`
|
||||
- `first_seen_at INTEGER NOT NULL`
|
||||
- `last_seen_at INTEGER NOT NULL`
|
||||
- `normalized_value TEXT NOT NULL`
|
||||
- `superseded_by INTEGER NULL`
|
||||
- `created_at INTEGER NOT NULL`
|
||||
- `updated_at INTEGER NOT NULL`
|
||||
|
||||
Categorias permitidas inicialmente:
|
||||
- `identity`
|
||||
- `profile`
|
||||
- `preference`
|
||||
- `interest`
|
||||
- `habit`
|
||||
- `project`
|
||||
- `constraint`
|
||||
- `goal`
|
||||
- `topic_pattern`
|
||||
- `skill`
|
||||
|
||||
### Tabela 2: `user_memories_v2`
|
||||
Representa fatos consolidados a partir de `chat_memories`.
|
||||
|
||||
Campos sugeridos:
|
||||
- `id INTEGER PRIMARY KEY`
|
||||
- `memory_key TEXT NOT NULL`
|
||||
- `memory_value TEXT NOT NULL`
|
||||
- `memory_category TEXT NOT NULL`
|
||||
- `confidence REAL NOT NULL`
|
||||
- `normalized_value TEXT NOT NULL`
|
||||
- `supporting_chat_memory_ids TEXT NOT NULL` (JSON array)
|
||||
- `evidence_summary TEXT NULL`
|
||||
- `first_seen_at INTEGER NOT NULL`
|
||||
- `last_seen_at INTEGER NOT NULL`
|
||||
- `created_at INTEGER NOT NULL`
|
||||
- `updated_at INTEGER NOT NULL`
|
||||
|
||||
### Tabela 3: `memory_jobs`
|
||||
Fila/log de processamento para idempotência.
|
||||
|
||||
Campos sugeridos:
|
||||
- `id INTEGER PRIMARY KEY`
|
||||
- `job_type TEXT NOT NULL` (`chat_extract` | `user_consolidate`)
|
||||
- `target_id INTEGER NOT NULL`
|
||||
- `status TEXT NOT NULL` (`pending` | `running` | `done` | `failed`)
|
||||
- `attempts INTEGER NOT NULL DEFAULT 0`
|
||||
- `last_error TEXT NULL`
|
||||
- `created_at INTEGER NOT NULL`
|
||||
- `updated_at INTEGER NOT NULL`
|
||||
|
||||
---
|
||||
|
||||
## Prompt recomendado para extração de memória de chat
|
||||
|
||||
Arquivo novo sugerido: `tauri-app/src/prompts/memory-extraction.ts`
|
||||
|
||||
### Prompt base
|
||||
```text
|
||||
You are a local memory extraction and classification engine.
|
||||
|
||||
Your task is to read a conversation fragment and extract ONLY durable, reusable memory items.
|
||||
|
||||
Return ONLY valid JSON as an array.
|
||||
|
||||
Each item must follow this schema:
|
||||
{
|
||||
"memory_key": "snake_case_key",
|
||||
"memory_value": "concise factual value",
|
||||
"memory_category": "identity|profile|preference|interest|habit|project|constraint|goal|topic_pattern|skill",
|
||||
"confidence": 0.0,
|
||||
"evidence": "short quote or short rationale",
|
||||
"is_user_memory_candidate": true
|
||||
}
|
||||
|
||||
Extraction policy:
|
||||
- Extract durable facts, not temporary requests.
|
||||
- Extract user preferences, likes/dislikes, recurring interests, profession, age, location, constraints, active projects, goals, skills, and patterns in what the user usually searches or asks about.
|
||||
- Prefer atomic facts.
|
||||
- Do not repeat equivalent items.
|
||||
- If a fact is uncertain, lower confidence.
|
||||
- If nothing durable exists, return [].
|
||||
- Never output markdown.
|
||||
```
|
||||
|
||||
### Prompt adicional para consolidação de memória de usuário
|
||||
```text
|
||||
You are a user memory consolidator.
|
||||
|
||||
Input: existing user memories + candidate chat memories.
|
||||
Goal: produce ONLY new or improved user-level memories.
|
||||
|
||||
Rules:
|
||||
- Do not repeat existing memories.
|
||||
- Merge semantically equivalent facts.
|
||||
- Prefer the most stable formulation.
|
||||
- Keep only durable cross-chat knowledge.
|
||||
- If a fact appears in multiple chats, increase confidence.
|
||||
- Return ONLY valid JSON array with the same schema.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fases de implementação
|
||||
|
||||
### Task 1: Congelar o comportamento atual com testes de regressão
|
||||
|
||||
**Files:**
|
||||
- Create: `tauri-app/src/hooks/useMemoryExtractor.test.ts`
|
||||
- Test: `tauri-app/src/components/ChatView.test.tsx`
|
||||
|
||||
**Step 1: Escrever teste de regressão do fluxo atual**
|
||||
Validar que, se o extractor falhar, o chat principal continua funcionando.
|
||||
|
||||
**Step 2: Rodar teste para confirmar baseline**
|
||||
Run: `cd tauri-app && npm test -- src/hooks/useMemoryExtractor.test.ts`
|
||||
Expected: FAIL inicialmente (arquivo novo).
|
||||
|
||||
**Step 3: Criar teste mínimo de não-regressão**
|
||||
Cobrir:
|
||||
- extractor não bloqueia envio de mensagem
|
||||
- erro de memória não quebra render/chat
|
||||
|
||||
**Step 4: Rodar testes**
|
||||
Run: `cd tauri-app && npm test -- src/hooks/useMemoryExtractor.test.ts src/components/ChatView.test.tsx`
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/hooks/useMemoryExtractor.test.ts tauri-app/src/components/ChatView.test.tsx
|
||||
git commit -m "test: add memory extraction regression coverage"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Introduzir schema novo sem remover o antigo
|
||||
|
||||
**Files:**
|
||||
- Modify: `tauri-app/src/lib/db.ts`
|
||||
- Modify: `tauri-app/src/lib/types.ts`
|
||||
- Create: `tauri-app/src/lib/memory-types.ts`
|
||||
- Test: `tauri-app/src/lib/db.test.ts`
|
||||
|
||||
**Step 1: Escrever testes falhos para novas tabelas**
|
||||
Cobrir criação idempotente de:
|
||||
- `chat_memories`
|
||||
- `user_memories_v2`
|
||||
- `memory_jobs`
|
||||
|
||||
**Step 2: Adicionar migração aditiva**
|
||||
Em `db.ts`, usar `ensureTable`/`ensureColumn` (ou equivalente local) sem remover `user_memories` atual.
|
||||
|
||||
**Step 3: Declarar tipos explícitos**
|
||||
Criar interfaces para:
|
||||
- `ChatMemory`
|
||||
- `UserMemoryV2`
|
||||
- `MemoryJob`
|
||||
- `MemoryCandidate`
|
||||
|
||||
**Step 4: Rodar testes**
|
||||
Run: `cd tauri-app && npm test -- src/lib/db.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/lib/db.ts tauri-app/src/lib/types.ts tauri-app/src/lib/memory-types.ts tauri-app/src/lib/db.test.ts
|
||||
git commit -m "feat: add chat and user memory schema"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Configurar o modelo local de memória sem tocar no modelo principal
|
||||
|
||||
**Files:**
|
||||
- Create: `tauri-app/src/config/memory.ts`
|
||||
- Modify: `tauri-app/src/config/ai.ts` or `tauri-app/src/config/ai/index.ts`
|
||||
- Test: `tauri-app/src/features/runtime/runtime-utils.test.ts`
|
||||
|
||||
**Step 1: Escrever teste falho de resolução da configuração**
|
||||
Configurar constante para:
|
||||
- `MEMORY_MODEL_PATH = "models/embedding/gemma-3-270m-it-Q8_0.gguf"`
|
||||
- `MEMORY_MODEL_ID = "gemma-3-270m-it-Q8_0"`
|
||||
|
||||
**Step 2: Implementar configuração dedicada**
|
||||
A memória deve usar modelo separado do chat principal.
|
||||
|
||||
**Step 3: Adicionar fallback seguro**
|
||||
Se o arquivo não existir, a memória desabilita-se sem derrubar o app.
|
||||
|
||||
**Step 4: Rodar testes**
|
||||
Run: `cd tauri-app && npm test -- src/features/runtime/runtime-utils.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/config/memory.ts tauri-app/src/config/ai.ts tauri-app/src/config/ai/index.ts tauri-app/src/features/runtime/runtime-utils.test.ts
|
||||
git commit -m "feat: configure dedicated local memory model"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Implementar prompt e parser de extração estruturada
|
||||
|
||||
**Files:**
|
||||
- Create: `tauri-app/src/prompts/memory-extraction.ts`
|
||||
- Create: `tauri-app/src/lib/memory-parser.ts`
|
||||
- Create: `tauri-app/src/lib/memory-parser.test.ts`
|
||||
|
||||
**Step 1: Escrever testes falhos para parsing de JSON robusto**
|
||||
Cobrir:
|
||||
- array JSON puro
|
||||
- JSON com ruído ao redor
|
||||
- array vazio
|
||||
- item inválido descartado
|
||||
- normalização de `memory_key`
|
||||
- clamp de confiança
|
||||
|
||||
**Step 2: Implementar parser minimalista**
|
||||
Funções sugeridas:
|
||||
- `parseMemoryCandidates(raw: string): MemoryCandidate[]`
|
||||
- `normalizeMemoryCandidate(candidate): MemoryCandidate | null`
|
||||
|
||||
**Step 3: Rodar testes**
|
||||
Run: `cd tauri-app && npm test -- src/lib/memory-parser.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
**Step 4: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/prompts/memory-extraction.ts tauri-app/src/lib/memory-parser.ts tauri-app/src/lib/memory-parser.test.ts
|
||||
git commit -m "feat: add structured memory extraction prompt and parser"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Extrair memórias de chat em background
|
||||
|
||||
**Files:**
|
||||
- Modify: `tauri-app/src/hooks/useMemoryExtractor.ts`
|
||||
- Create: `tauri-app/src/lib/chat-memory-repository.ts`
|
||||
- Test: `tauri-app/src/hooks/useMemoryExtractor.test.ts`
|
||||
|
||||
**Step 1: Escrever testes falhos para pipeline de chat memory**
|
||||
Cobrir:
|
||||
- usa modelo de memória dedicado
|
||||
- envia prompt de extração correto
|
||||
- salva em `chat_memories`
|
||||
- marca job/mensagem como processado
|
||||
- não salva duplicata exata
|
||||
|
||||
**Step 2: Refatorar o hook atual**
|
||||
O hook atual não deve mais gravar direto em `user_memories`.
|
||||
Agora deve:
|
||||
- ler mensagens recentes
|
||||
- chamar o modelo de memória
|
||||
- parsear candidatos
|
||||
- persistir em `chat_memories`
|
||||
- registrar job concluído
|
||||
|
||||
**Step 3: Implementar deduplicação conservadora**
|
||||
Deduplicar por:
|
||||
- `chat_id`
|
||||
- `memory_key`
|
||||
- `normalized_value`
|
||||
|
||||
**Step 4: Rodar testes**
|
||||
Run: `cd tauri-app && npm test -- src/hooks/useMemoryExtractor.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/hooks/useMemoryExtractor.ts tauri-app/src/lib/chat-memory-repository.ts tauri-app/src/hooks/useMemoryExtractor.test.ts
|
||||
git commit -m "feat: extract chat-scoped memories with local model"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Consolidar memórias de usuário a partir das memórias de chat
|
||||
|
||||
**Files:**
|
||||
- Create: `tauri-app/src/lib/user-memory-consolidator.ts`
|
||||
- Create: `tauri-app/src/lib/user-memory-repository.ts`
|
||||
- Create: `tauri-app/src/lib/user-memory-consolidator.test.ts`
|
||||
|
||||
**Step 1: Escrever testes falhos da consolidação**
|
||||
Cobrir:
|
||||
- lê `chat_memories` já processadas
|
||||
- compara com `user_memories_v2`
|
||||
- cria apenas memórias novas
|
||||
- melhora memória existente quando confiança aumenta
|
||||
- não duplica fatos equivalentes
|
||||
|
||||
**Step 2: Implementar consolidador em duas etapas**
|
||||
Etapa A:
|
||||
- selecionar candidatas recentes de `chat_memories`
|
||||
Etapa B:
|
||||
- chamar o modelo com:
|
||||
- memórias de usuário já existentes
|
||||
- novas memórias de chat
|
||||
- receber apenas novos fatos consolidados
|
||||
|
||||
**Step 3: Persistir com rastreabilidade**
|
||||
Salvar também `supporting_chat_memory_ids`.
|
||||
|
||||
**Step 4: Rodar testes**
|
||||
Run: `cd tauri-app && npm test -- src/lib/user-memory-consolidator.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/lib/user-memory-consolidator.ts tauri-app/src/lib/user-memory-repository.ts tauri-app/src/lib/user-memory-consolidator.test.ts
|
||||
git commit -m "feat: consolidate user memories from chat memories"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Definir política de classificação e uso futuro em prompts
|
||||
|
||||
**Files:**
|
||||
- Create: `tauri-app/src/lib/memory-prompt-context.ts`
|
||||
- Create: `tauri-app/src/lib/memory-prompt-context.test.ts`
|
||||
- Modify: `tauri-app/src/hooks/useMemoryExtractor.ts`
|
||||
|
||||
**Step 1: Escrever teste falho para construção de contexto dinâmico**
|
||||
Sem injetar ainda no chat principal, criar builder que monte:
|
||||
- `chat memory context`
|
||||
- `user memory context`
|
||||
separados e filtrados por confiança/categoria.
|
||||
|
||||
**Step 2: Implementar builder de contexto**
|
||||
Regras iniciais:
|
||||
- `identity/profile/preferences/constraints/goals` com prioridade alta
|
||||
- `topic_pattern/interests` limitados por recência e confiança
|
||||
- sem repetir fatos equivalentes
|
||||
|
||||
**Step 3: Rodar testes**
|
||||
Run: `cd tauri-app && npm test -- src/lib/memory-prompt-context.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
**Step 4: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/lib/memory-prompt-context.ts tauri-app/src/lib/memory-prompt-context.test.ts tauri-app/src/hooks/useMemoryExtractor.ts
|
||||
git commit -m "feat: prepare structured memory prompt context builder"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: Adicionar comando de consolidação segura e agendada
|
||||
|
||||
**Files:**
|
||||
- Create: `tauri-app/src/lib/memory-orchestrator.ts`
|
||||
- Modify: `tauri-app/src/components/ChatView.tsx`
|
||||
- Test: `tauri-app/src/components/ChatView.test.tsx`
|
||||
|
||||
**Step 1: Escrever teste falho do orquestrador**
|
||||
Cobrir:
|
||||
- após resposta concluída, roda extração de chat
|
||||
- consolidação de usuário roda desacoplada/debounced
|
||||
- falha em qualquer etapa não afeta o chat
|
||||
|
||||
**Step 2: Implementar orquestrador leve**
|
||||
Fluxo:
|
||||
- `assistant turn complete` → enqueue `chat_extract`
|
||||
- depois → enqueue `user_consolidate` com debounce maior
|
||||
|
||||
**Step 3: Rodar testes**
|
||||
Run: `cd tauri-app && npm test -- src/components/ChatView.test.tsx`
|
||||
Expected: PASS
|
||||
|
||||
**Step 4: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/lib/memory-orchestrator.ts tauri-app/src/components/ChatView.tsx tauri-app/src/components/ChatView.test.tsx
|
||||
git commit -m "feat: orchestrate chat and user memory processing safely"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 9: Estratégia de migração sem quebra
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/memory-migration-notes.md`
|
||||
- Modify: `tauri-app/src/hooks/useMemoryExtractor.ts`
|
||||
- Test: `tauri-app/src/lib/db.test.ts`
|
||||
|
||||
**Step 1: Definir política de coexistência**
|
||||
- `user_memories` antiga fica preservada
|
||||
- nova pipeline escreve em `chat_memories` e `user_memories_v2`
|
||||
- nenhuma leitura crítica do app depende imediatamente da nova tabela
|
||||
|
||||
**Step 2: Opcional: migração parcial de legado**
|
||||
Se necessário, criar utilitário futuro de backfill de `user_memories` → `user_memories_v2`, mas **não nesta fase**.
|
||||
|
||||
**Step 3: Documentar explicitamente**
|
||||
Descrever:
|
||||
- rollback fácil
|
||||
- como desligar a feature
|
||||
- como validar DB localmente
|
||||
|
||||
**Step 4: Commit**
|
||||
```bash
|
||||
git add docs/memory-migration-notes.md tauri-app/src/hooks/useMemoryExtractor.ts tauri-app/src/lib/db.test.ts
|
||||
git commit -m "docs: add safe migration notes for new memory architecture"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 10: Validação final e critérios de aceite
|
||||
|
||||
**Files:**
|
||||
- No new files required
|
||||
|
||||
**Step 1: Rodar suíte de memória**
|
||||
Run:
|
||||
```bash
|
||||
cd tauri-app && npm test -- src/hooks/useMemoryExtractor.test.ts src/lib/memory-parser.test.ts src/lib/user-memory-consolidator.test.ts src/lib/memory-prompt-context.test.ts
|
||||
```
|
||||
Expected: PASS
|
||||
|
||||
**Step 2: Rodar suíte principal**
|
||||
Run:
|
||||
```bash
|
||||
cd tauri-app && npm test
|
||||
cd tauri-app && npm run build
|
||||
```
|
||||
Expected: PASS
|
||||
|
||||
**Step 3: Validação manual**
|
||||
Verificar:
|
||||
- mensagem normal continua funcionando
|
||||
- memórias de chat são criadas
|
||||
- memórias de usuário aparecem só quando novas/mais fortes
|
||||
- duplicatas não são inseridas
|
||||
- se modelo de memória falhar, chat continua estável
|
||||
|
||||
**Step 4: Commit final**
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: add safe chat and user memory architecture"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Riscos e mitigação
|
||||
|
||||
### Risco 1: O modelo `gemma-3-270m-it-Q8_0.gguf` não ser bom para extração factual
|
||||
**Mitigação:**
|
||||
- manter parser robusto
|
||||
- limitar escopo a fatos atômicos
|
||||
- usar confiança + deduplicação conservadora
|
||||
- tratar esse modelo como extractor heurístico, não como verdade absoluta
|
||||
|
||||
### Risco 2: Duplicação excessiva
|
||||
**Mitigação:**
|
||||
- chave normalizada
|
||||
- valor normalizado
|
||||
- consolidação só com fatos novos ou confiança melhor
|
||||
|
||||
### Risco 3: Impacto de performance
|
||||
**Mitigação:**
|
||||
- debounce
|
||||
- background only
|
||||
- janelas pequenas de contexto
|
||||
- consolidação de usuário menos frequente que extração de chat
|
||||
|
||||
### Risco 4: Quebra do fluxo atual
|
||||
**Mitigação:**
|
||||
- schema aditivo
|
||||
- falhas silenciosas
|
||||
- nenhuma injeção automática no prompt principal nesta fase
|
||||
|
||||
---
|
||||
|
||||
## Critérios de aceitação
|
||||
|
||||
1. O chat principal continua funcionando sem regressão.
|
||||
2. O sistema usa o modelo `models/embedding/gemma-3-270m-it-Q8_0.gguf` exclusivamente para a pipeline de memória.
|
||||
3. Memórias de chat são estruturadas, classificadas e persistidas separadamente.
|
||||
4. Memórias de usuário são geradas a partir das memórias de chat já processadas.
|
||||
5. O sistema não duplica memórias equivalentes.
|
||||
6. Existe builder separado para uso futuro dessas memórias em prompts.
|
||||
7. Falhas na pipeline de memória não quebram chat, build ou testes.
|
||||
|
||||
---
|
||||
|
||||
## Recomendação de rollout
|
||||
|
||||
### Release 1
|
||||
- schema novo
|
||||
- extractor de chat
|
||||
- consolidator de usuário
|
||||
- sem injeção no prompt principal
|
||||
|
||||
### Release 2
|
||||
- leitura controlada de `user_memories_v2` + `chat_memories` em prompt dinâmico
|
||||
- observabilidade de qualidade
|
||||
|
||||
### Release 3
|
||||
- integração com pesquisa web + contexto híbrido
|
||||
- memória + pesquisa + multiagente no orquestrador final
|
||||
@@ -0,0 +1,639 @@
|
||||
# Tauri Physical SQLite Migration Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Migrar o armazenamento atual baseado em `sql.js + localStorage` para um SQLite físico real no Tauri, com melhor performance, durabilidade e estrutura de recuperação de contexto adequada para workloads de IA e memória.
|
||||
|
||||
**Architecture:** A migração será feita de forma incremental, introduzindo primeiro uma camada de acesso a dados em Rust/Tauri com SQLite físico como source of truth, enquanto mantemos um caminho de compatibilidade temporária para importação do banco legado do `localStorage`. O frontend não consultará banco diretamente em nenhuma hipótese: toda leitura e escrita passará pelo backend via comandos/APIs Tauri orientados a domínio (`chat`, `message`, `memory`, `migration`, `search`, `summary`), reduzindo acoplamento, melhorando performance e preparando a base para estratégias de compressão/recall que economizam tokens.
|
||||
|
||||
**Tech Stack:** Tauri + Rust, SQLite físico local, comandos Tauri (`invoke`), React/TypeScript frontend, migração do legado `sql.js`, Vitest + testes Rust.
|
||||
|
||||
---
|
||||
|
||||
## Recomendação explícita: caminho ideal
|
||||
|
||||
### Escolha recomendada
|
||||
**Implementar SQLite físico via backend Rust/Tauri como source of truth, com DAO/repositórios tipados e API de domínio para o frontend.**
|
||||
|
||||
### Motivo
|
||||
Esse é o melhor caminho para o seu produto porque oferece:
|
||||
- **mais performance real** que `sql.js + localStorage`
|
||||
- **durabilidade de verdade** (arquivo físico)
|
||||
- **concorrência/controlabilidade melhores**
|
||||
- **ferramentas reais de inspeção e manutenção** (`sqlite3`, DB Browser for SQLite, LiteCLI, Datasette, SQLx/rusqlite)
|
||||
- **base ideal para memória, recall, sumarização e deduplicação**, que são as partes que mais ajudam a reduzir tokens em apps de IA
|
||||
|
||||
### Escolha técnica recomendada de biblioteca Rust
|
||||
**Recomendação principal: `rusqlite`**
|
||||
|
||||
Motivo:
|
||||
- simples
|
||||
- rápido
|
||||
- excelente para SQLite local embedded
|
||||
- controle fino sobre pragmas, índices, transações, FTS5
|
||||
- ideal para Tauri desktop local-first
|
||||
|
||||
### Escolha de schema para IA/memória
|
||||
**Recomendação principal: SQLite relacional + FTS5 + tabelas de memória estruturadas**
|
||||
|
||||
Motivo:
|
||||
- reduz tokens ao permitir:
|
||||
- recall seletivo por chat
|
||||
- busca lexical rápida com FTS5
|
||||
- consolidação e deduplicação de memória
|
||||
- recuperação por categoria/confiança/recência
|
||||
- evita mandar histórico bruto inteiro ao modelo
|
||||
|
||||
---
|
||||
|
||||
## O que muda conceitualmente
|
||||
|
||||
### Hoje
|
||||
- banco em memória (`sql.js`)
|
||||
- persistência em `localStorage`
|
||||
- frontend executa SQL diretamente
|
||||
- schema simples, pouca rastreabilidade para memória
|
||||
|
||||
### Depois
|
||||
- banco físico em arquivo SQLite real
|
||||
- backend Rust controla schema, migração e consultas
|
||||
- frontend usa API de domínio, não SQL cru
|
||||
- schema otimizado para:
|
||||
- chats
|
||||
n - mensagens
|
||||
- memória de chat
|
||||
- memória de usuário
|
||||
- FTS para recuperação
|
||||
- jobs de processamento
|
||||
- metadados de compressão/contexto
|
||||
|
||||
---
|
||||
|
||||
## Benefícios esperados para IA e economia de tokens
|
||||
|
||||
### 1. Recuperação seletiva
|
||||
Em vez de reenviar 20+ mensagens sempre, o app poderá consultar:
|
||||
- últimas mensagens do chat
|
||||
- memórias de chat com alta confiança
|
||||
- memórias de usuário relevantes
|
||||
- snippets recuperados por FTS5
|
||||
|
||||
### 2. Context packing mais barato
|
||||
Você poderá montar prompts com:
|
||||
- fatos duráveis
|
||||
- resumo do chat
|
||||
- poucos trechos relevantes
|
||||
- não o histórico bruto completo
|
||||
|
||||
### 3. Estrutura para compressão e summaries
|
||||
SQLite físico facilita adicionar depois:
|
||||
- tabela de `chat_summaries`
|
||||
- snapshots de contexto
|
||||
- fragments de recall
|
||||
- ranking por recência/relevância/confiança
|
||||
|
||||
### 4. Ferramentas melhores
|
||||
Você ganha ferramentas de inspeção e tuning reais:
|
||||
- `sqlite3`
|
||||
- DB Browser for SQLite
|
||||
- `EXPLAIN QUERY PLAN`
|
||||
- FTS5
|
||||
- índices compostos
|
||||
- WAL mode
|
||||
|
||||
---
|
||||
|
||||
## Arquitetura alvo recomendada
|
||||
|
||||
## Camada 1 — Storage engine
|
||||
Arquivo físico SQLite, por exemplo em:
|
||||
- diretório de app data do Tauri
|
||||
- ex.: `ForgeLM/forgelm.sqlite3`
|
||||
|
||||
### Pragmas recomendados
|
||||
- `journal_mode = WAL`
|
||||
- `synchronous = NORMAL`
|
||||
- `foreign_keys = ON`
|
||||
- `temp_store = MEMORY`
|
||||
- `cache_size` ajustado
|
||||
|
||||
Esses pragmas equilibram performance e segurança para desktop local.
|
||||
|
||||
## Camada 2 — Backend service layer (source of truth)
|
||||
Criar módulos Rust como:
|
||||
- `chat_service.rs`
|
||||
- `message_service.rs`
|
||||
- `memory_service.rs`
|
||||
- `migration_service.rs`
|
||||
- `search_service.rs`
|
||||
- `summary_service.rs`
|
||||
|
||||
Esses serviços usam repositórios SQLite internamente, mas expõem contratos estáveis para a camada de API.
|
||||
|
||||
## Camada 3 — Backend API / Tauri commands
|
||||
O backend deve servir tudo que o frontend precisar. O frontend não acessa banco, SQL, arquivo SQLite, `sql.js` ou `localStorage` como fonte operacional.
|
||||
|
||||
Exemplos de endpoints/commands:
|
||||
- `chat_list`
|
||||
- `chat_get`
|
||||
- `chat_create`
|
||||
- `chat_rename`
|
||||
- `chat_delete`
|
||||
- `message_list_by_chat`
|
||||
- `message_create_user`
|
||||
- `message_create_assistant`
|
||||
- `message_update`
|
||||
- `message_delete`
|
||||
- `memory_chat_list`
|
||||
- `memory_user_list`
|
||||
- `memory_reprocess_chat`
|
||||
- `memory_consolidate_user`
|
||||
- `context_search`
|
||||
- `summary_get_by_chat`
|
||||
- `legacy_import`
|
||||
- `db_health`
|
||||
|
||||
## Camada 4 — Frontend API client
|
||||
No frontend, criar uma camada única de acesso:
|
||||
- `tauri-app/src/lib/backend-client.ts`
|
||||
|
||||
Ela substitui qualquer acesso direto a banco e fala apenas com o backend via `invoke()`.
|
||||
|
||||
---
|
||||
|
||||
## Schema recomendado
|
||||
|
||||
### Tabela `chats`
|
||||
Manter, com pequenos aprimoramentos.
|
||||
Campos:
|
||||
- `id`
|
||||
- `title`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
- `archived_at NULL`
|
||||
- `summary_updated_at NULL`
|
||||
|
||||
### Tabela `messages`
|
||||
Campos:
|
||||
- `id`
|
||||
- `chat_id`
|
||||
- `role`
|
||||
- `content`
|
||||
- `reasoning_content`
|
||||
- `display_mode`
|
||||
- `forgeagent_state`
|
||||
- `prompt_tokens`
|
||||
- `completion_tokens`
|
||||
- `total_tokens`
|
||||
- `tokens_per_second`
|
||||
- `memory_processed`
|
||||
- `content_hash`
|
||||
- `created_at`
|
||||
|
||||
### Tabela `chat_memories`
|
||||
Para memórias derivadas de um chat.
|
||||
|
||||
### Tabela `user_memories`
|
||||
Versão nova consolidada.
|
||||
|
||||
### Tabela `memory_jobs`
|
||||
Controle de processamento.
|
||||
|
||||
### Tabela `chat_summaries`
|
||||
**Recomendação importante:** já criar a tabela, mesmo que não seja usada imediatamente.
|
||||
Campos sugeridos:
|
||||
- `id`
|
||||
- `chat_id`
|
||||
- `summary_type` (`rolling`, `milestone`, `session`)
|
||||
- `summary_text`
|
||||
- `source_message_start_id`
|
||||
- `source_message_end_id`
|
||||
- `created_at`
|
||||
|
||||
### Tabela virtual FTS5
|
||||
Recomendação forte:
|
||||
- `message_search` via FTS5 sobre `messages.content`
|
||||
- possivelmente FTS também sobre memórias/summaries depois
|
||||
|
||||
Isso será um dos maiores ganhos para reduzir tokens no futuro.
|
||||
|
||||
---
|
||||
|
||||
## Estratégia de migração segura
|
||||
|
||||
### Fase 0 — Compatibilidade
|
||||
Não remover o `sql.js` imediatamente.
|
||||
|
||||
### Fase 1 — Criar banco físico e schema novo
|
||||
- app continua funcionando
|
||||
- banco físico nasce vazio
|
||||
|
||||
### Fase 2 — Implementar importador do legado
|
||||
- ler `forgelm_db_v2` do `localStorage`
|
||||
- converter para o schema novo
|
||||
- importar uma única vez com flag de migração
|
||||
|
||||
### Fase 3 — Trocar frontend para `db-client`
|
||||
- componentes deixam de falar SQL direto
|
||||
- passam a chamar Tauri commands
|
||||
|
||||
### Fase 4 — Desligar `sql.js`
|
||||
- só depois de validar import, escrita, leitura, edição e build
|
||||
|
||||
---
|
||||
|
||||
## Plano por fases
|
||||
|
||||
### Task 1: Congelar comportamento atual com testes de regressão
|
||||
|
||||
**Files:**
|
||||
- Modify: `tauri-app/src/lib/db.test.ts`
|
||||
- Modify: `tauri-app/src/App.test.tsx`
|
||||
- Modify: `tauri-app/src/components/ChatView.test.tsx`
|
||||
|
||||
**Step 1: Escrever testes de comportamento atual**
|
||||
Cobrir:
|
||||
- criar chat
|
||||
- carregar histórico
|
||||
- inserir mensagem user/assistant
|
||||
- editar/deletar
|
||||
- persistir métricas
|
||||
|
||||
**Step 2: Rodar testes**
|
||||
Run:
|
||||
```bash
|
||||
cd tauri-app && npm test -- src/lib/db.test.ts src/App.test.tsx src/components/ChatView.test.tsx
|
||||
```
|
||||
Expected: PASS
|
||||
|
||||
**Step 3: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/lib/db.test.ts tauri-app/src/App.test.tsx tauri-app/src/components/ChatView.test.tsx
|
||||
git commit -m "test: freeze current chat db behavior before sqlite migration"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Introduzir backend SQLite físico no Rust/Tauri
|
||||
|
||||
**Files:**
|
||||
- Create: `src-tauri/src/db/mod.rs`
|
||||
- Create: `src-tauri/src/db/schema.rs`
|
||||
- Create: `src-tauri/src/db/connection.rs`
|
||||
- Modify: `src-tauri/src/main.rs`
|
||||
- Test: Rust unit tests in `src-tauri/src/db/*`
|
||||
|
||||
**Step 1: Escrever testes falhos de inicialização**
|
||||
Cobrir:
|
||||
- cria arquivo físico
|
||||
- aplica schema
|
||||
- ativa pragmas corretos
|
||||
|
||||
**Step 2: Implementar conexão SQLite com `rusqlite`**
|
||||
- path em diretório de app data do Tauri
|
||||
- abrir conexão singleton ou pool simples controlado
|
||||
|
||||
**Step 3: Aplicar schema inicial**
|
||||
Criar tabelas `chats`, `messages`, `user_memories`, `chat_memories`, `memory_jobs`, `chat_summaries`, FTS5.
|
||||
|
||||
**Step 4: Rodar testes Rust**
|
||||
Run:
|
||||
```bash
|
||||
cargo test db -- --nocapture
|
||||
```
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add src-tauri/src/db src-tauri/src/main.rs
|
||||
git commit -m "feat: add physical sqlite backend for tauri"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Implementar repositórios Rust e service layer orientados a domínio
|
||||
|
||||
**Files:**
|
||||
- Create: `src-tauri/src/db/chat_repository.rs`
|
||||
- Create: `src-tauri/src/db/message_repository.rs`
|
||||
- Create: `src-tauri/src/db/memory_repository.rs`
|
||||
- Create: `src-tauri/src/services/chat_service.rs`
|
||||
- Create: `src-tauri/src/services/message_service.rs`
|
||||
- Create: `src-tauri/src/services/memory_service.rs`
|
||||
- Test: Rust tests per repository/service
|
||||
|
||||
**Step 1: Escrever testes falhos por repositório e service**
|
||||
Cobrir:
|
||||
- CRUD de chats
|
||||
- insert/list de mensagens
|
||||
- leitura por chat
|
||||
- atualização de timestamps
|
||||
- contratos de service retornando DTOs estáveis
|
||||
|
||||
**Step 2: Implementar repositórios mínimos**
|
||||
Acesso bruto ao SQLite.
|
||||
|
||||
**Step 3: Implementar services**
|
||||
Toda regra de negócio deve ficar aqui. Commands não devem montar SQL.
|
||||
|
||||
**Step 4: Rodar testes**
|
||||
Run:
|
||||
```bash
|
||||
cargo test repository -- --nocapture
|
||||
cargo test service -- --nocapture
|
||||
```
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add src-tauri/src/db/chat_repository.rs src-tauri/src/db/message_repository.rs src-tauri/src/db/memory_repository.rs src-tauri/src/services/chat_service.rs src-tauri/src/services/message_service.rs src-tauri/src/services/memory_service.rs
|
||||
git commit -m "feat: add sqlite repositories and backend service layer"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Expor API/backend commands completos para o frontend
|
||||
|
||||
**Files:**
|
||||
- Modify: `src-tauri/src/main.rs`
|
||||
- Create: `src-tauri/src/commands/chat_commands.rs`
|
||||
- Create: `src-tauri/src/commands/message_commands.rs`
|
||||
- Create: `src-tauri/src/commands/memory_commands.rs`
|
||||
- Create: `src-tauri/src/commands/system_commands.rs`
|
||||
- Create: `tauri-app/src/lib/backend-client.ts`
|
||||
- Test: `tauri-app/src/lib/backend-client.test.ts`
|
||||
|
||||
**Step 1: Escrever testes falhos do client**
|
||||
Cobrir contratos como:
|
||||
- `listChats()`
|
||||
- `getChat(chatId)`
|
||||
- `getMessages(chatId)`
|
||||
- `createChat()`
|
||||
- `createUserMessage()`
|
||||
- `createAssistantMessage()`
|
||||
- `listChatMemories()`
|
||||
- `listUserMemories()`
|
||||
- `healthCheck()`
|
||||
|
||||
**Step 2: Implementar commands Tauri**
|
||||
Usar services Rust por trás. O frontend não deve conhecer SQL, schema ou detalhes de armazenamento.
|
||||
|
||||
**Step 3: Implementar client TS**
|
||||
Centralizar chamadas `invoke()` em `backend-client.ts`.
|
||||
|
||||
**Step 4: Rodar testes**
|
||||
Run:
|
||||
```bash
|
||||
cd tauri-app && npm test -- src/lib/backend-client.test.ts
|
||||
```
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add src-tauri/src/commands/chat_commands.rs src-tauri/src/commands/message_commands.rs src-tauri/src/commands/memory_commands.rs src-tauri/src/commands/system_commands.rs src-tauri/src/main.rs tauri-app/src/lib/backend-client.ts tauri-app/src/lib/backend-client.test.ts
|
||||
git commit -m "feat: expose backend api for chats messages memory and system"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Adaptar frontend para falar apenas com o backend
|
||||
|
||||
**Files:**
|
||||
- Modify: `tauri-app/src/lib/db.ts`
|
||||
- Modify: `tauri-app/src/App.tsx`
|
||||
- Modify: `tauri-app/src/components/ChatView.tsx`
|
||||
- Modify: arquivos que usam `DB` diretamente
|
||||
|
||||
**Step 1: Escrever testes falhos de integração**
|
||||
Cobrir o fluxo principal usando `backend-client`.
|
||||
|
||||
**Step 2: Implementar camada de compatibilidade**
|
||||
Recomendação: não apagar `db.ts` de imediato.
|
||||
Transformá-lo em façade legada ou adaptador temporário até toda a UI migrar.
|
||||
|
||||
**Step 3: Migrar `ChatView`, `App` e demais módulos**
|
||||
Substituir qualquer leitura/escrita local por chamadas ao backend.
|
||||
|
||||
**Step 4: Rodar testes frontend**
|
||||
Run:
|
||||
```bash
|
||||
cd tauri-app && npm test
|
||||
```
|
||||
Expected: PASS
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/lib/db.ts tauri-app/src/App.tsx tauri-app/src/components/ChatView.tsx
|
||||
git commit -m "refactor: make frontend consume backend api only"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Implementar importador do banco legado do localStorage
|
||||
|
||||
**Files:**
|
||||
- Create: `src-tauri/src/db/import_legacy.rs`
|
||||
- Create: `src-tauri/src/commands/migration_commands.rs`
|
||||
- Create: `tauri-app/src/lib/legacy-db-export.ts`
|
||||
- Test: Rust + TS tests
|
||||
|
||||
**Step 1: Escrever testes falhos para importação**
|
||||
Cobrir:
|
||||
- chats importados
|
||||
- messages importadas
|
||||
- user_memories importadas
|
||||
- import idempotente
|
||||
|
||||
**Step 2: Implementar exportador legado no frontend**
|
||||
Transformar `forgelm_db_v2` em JSON transferível.
|
||||
|
||||
**Step 3: Implementar importador no Rust**
|
||||
Receber JSON e inserir no SQLite físico dentro de transação.
|
||||
|
||||
**Step 4: Criar flag de migração concluída**
|
||||
Pode ser tabela `app_meta` ou arquivo de config.
|
||||
|
||||
**Step 5: Rodar testes**
|
||||
Run:
|
||||
```bash
|
||||
cargo test import_legacy -- --nocapture
|
||||
cd tauri-app && npm test -- src/lib/legacy-db-export.ts
|
||||
```
|
||||
Expected: PASS
|
||||
|
||||
**Step 6: Commit**
|
||||
```bash
|
||||
git add src-tauri/src/db/import_legacy.rs src-tauri/src/commands/migration_commands.rs tauri-app/src/lib/legacy-db-export.ts
|
||||
git commit -m "feat: import legacy localStorage database into physical sqlite"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Otimizar SQLite para workloads de IA e economia de tokens
|
||||
|
||||
**Files:**
|
||||
- Modify: `src-tauri/src/db/connection.rs`
|
||||
- Modify: `src-tauri/src/db/schema.rs`
|
||||
- Create: `docs/sqlite-context-strategy.md`
|
||||
- Test: Rust tests/query-plan checks if viable
|
||||
|
||||
**Step 1: Ativar FTS5**
|
||||
Criar tabela virtual para busca textual eficiente em mensagens.
|
||||
|
||||
**Step 2: Criar índices úteis**
|
||||
Sugestões:
|
||||
- `messages(chat_id, created_at)`
|
||||
- `messages(role, created_at)`
|
||||
- `chat_memories(chat_id, memory_category, confidence)`
|
||||
- `user_memories(memory_category, confidence, updated_at)`
|
||||
|
||||
**Step 3: Preparar schema para summaries e recall**
|
||||
Criar `chat_summaries` e metadados de contexto.
|
||||
|
||||
**Step 4: Documentar estratégia anti-token-bloat**
|
||||
Ex.: usar FTS5 + summary + memory retrieval.
|
||||
|
||||
**Step 5: Commit**
|
||||
```bash
|
||||
git add src-tauri/src/db/connection.rs src-tauri/src/db/schema.rs docs/sqlite-context-strategy.md
|
||||
git commit -m "feat: optimize sqlite schema for ai context retrieval"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: Desligar persistência em localStorage e manter fallback controlado
|
||||
|
||||
**Files:**
|
||||
- Modify: `tauri-app/src/lib/db.ts`
|
||||
- Modify: `tauri-app/src/App.tsx`
|
||||
- Modify: `tauri-app/src/lib/legacy-db-export.ts`
|
||||
|
||||
**Step 1: Escrever testes falhos de pós-migração**
|
||||
Cobrir:
|
||||
- app lê do SQLite físico
|
||||
- localStorage não é mais source of truth
|
||||
|
||||
**Step 2: Remover `persist()` como mecanismo principal**
|
||||
Pode manter apenas como utilitário legado temporário, não mais ativo.
|
||||
|
||||
**Step 3: Rodar testes**
|
||||
Run:
|
||||
```bash
|
||||
cd tauri-app && npm test
|
||||
cd tauri-app && npm run build
|
||||
```
|
||||
Expected: PASS
|
||||
|
||||
**Step 4: Commit**
|
||||
```bash
|
||||
git add tauri-app/src/lib/db.ts tauri-app/src/App.tsx tauri-app/src/lib/legacy-db-export.ts
|
||||
git commit -m "refactor: disable localStorage db persistence after sqlite migration"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 9: Validação final ponta a ponta
|
||||
|
||||
**Files:**
|
||||
- No new files required initially
|
||||
|
||||
**Step 1: Rodar testes Rust**
|
||||
```bash
|
||||
cargo test -- --nocapture
|
||||
```
|
||||
|
||||
**Step 2: Rodar testes frontend**
|
||||
```bash
|
||||
cd tauri-app && npm test
|
||||
cd tauri-app && npm run build
|
||||
```
|
||||
|
||||
**Step 3: Verificação manual**
|
||||
Validar:
|
||||
- criar chat
|
||||
- enviar mensagens
|
||||
- reiniciar app e confirmar persistência real
|
||||
- importar banco legado
|
||||
- editar/deletar mensagens
|
||||
- inspecionar arquivo SQLite físico com ferramenta externa
|
||||
|
||||
**Step 4: Commit final**
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: migrate app storage to physical sqlite in tauri"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ferramentas recomendadas após a migração
|
||||
|
||||
Para desenvolvimento e debugging:
|
||||
- **DB Browser for SQLite** — melhor opção visual simples
|
||||
- **sqlite3 CLI** — excelente para scripts e inspeção rápida
|
||||
- **LiteCLI** — autocomplete SQL
|
||||
- **Datasette** (opcional) — excelente para explorar dados localmente
|
||||
|
||||
Para economia de tokens no futuro:
|
||||
- **FTS5** para recall lexical barato
|
||||
- **chat_summaries** para compaction
|
||||
- **chat_memories / user_memories** para fatos duráveis
|
||||
- **ranking por confiança + recência** para montar prompt enxuto
|
||||
|
||||
---
|
||||
|
||||
## Riscos e mitigação
|
||||
|
||||
### Risco 1: quebrar o frontend ao remover `db.ts`
|
||||
**Mitigação:** manter adaptador temporário e migrar por etapas.
|
||||
|
||||
### Risco 2: migração incompleta do legado
|
||||
**Mitigação:** importador idempotente + flag de migração + logs claros.
|
||||
|
||||
### Risco 3: latência do `invoke()` no Tauri
|
||||
**Mitigação:** commands orientados a domínio, não excessivamente granulares.
|
||||
|
||||
### Risco 4: schema ainda inadequado para IA no futuro
|
||||
**Mitigação:** já criar FTS5 + summaries + memória estruturada nesta migração.
|
||||
|
||||
---
|
||||
|
||||
## Critérios de aceitação
|
||||
|
||||
1. O app usa SQLite físico real como source of truth.
|
||||
2. O banco persiste entre reinícios do app sem depender de localStorage.
|
||||
3. Chats, mensagens e memórias são mantidos corretamente.
|
||||
4. Existe caminho de importação do banco legado.
|
||||
5. O frontend não depende mais de SQL direto via `sql.js` para operação normal.
|
||||
6. O schema já suporta estratégias futuras de redução de tokens.
|
||||
7. Build e testes seguem verdes.
|
||||
|
||||
---
|
||||
|
||||
## Resumo executivo
|
||||
|
||||
### O que eu recomendo implementar
|
||||
- **SQLite físico real em Rust/Tauri com `rusqlite`**
|
||||
- **API de domínio para o frontend**
|
||||
- **FTS5 + schema preparado para memória e summaries**
|
||||
- **migração incremental do legado `localStorage`**
|
||||
|
||||
### Por que isso é o melhor para IA
|
||||
Porque essa base permite fazer direito, depois:
|
||||
- memória estruturada
|
||||
- busca local eficiente
|
||||
- resumos incrementais
|
||||
- recall seletivo
|
||||
- menos contexto bruto enviado ao modelo
|
||||
- menor consumo de tokens
|
||||
|
||||
---
|
||||
|
||||
## Aprovação para execução
|
||||
|
||||
Se você aprovar, eu recomendo começar por esta ordem:
|
||||
1. **Task 1** — congelar comportamento atual
|
||||
2. **Task 2** — subir o SQLite físico no Tauri
|
||||
3. **Task 4** — expor commands ao frontend
|
||||
4. **Task 6** — importação do legado
|
||||
|
||||
Essa é a sequência com menor risco.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Bug + Dead Code Audit — 2026-04-03
|
||||
|
||||
## Scope
|
||||
Static audit focused on the changed `tauri-app` surface plus verification via:
|
||||
- `cd tauri-app && npm test`
|
||||
- `cd tauri-app && npm run build`
|
||||
- `cd tauri-app/src-tauri && cargo check`
|
||||
- targeted reference searches with `rg`
|
||||
|
||||
## Files reviewed
|
||||
- `tauri-app/src/App.tsx`
|
||||
- `tauri-app/src/App.test.tsx`
|
||||
- `tauri-app/src/components/ChatView.tsx`
|
||||
- `tauri-app/src/components/Sidebar.tsx`
|
||||
- `tauri-app/src/components/Sidebar.test.tsx`
|
||||
- `tauri-app/src/components/MessageBubble.tsx`
|
||||
- `tauri-app/src/components/StreamingBubble.tsx`
|
||||
- `tauri-app/src/lib/devLogger.ts`
|
||||
- `tauri-app/src/types/forgeagent.ts`
|
||||
- `tauri-app/src/components/chat/index.ts`
|
||||
- `tauri-app/src/components/chat/MessageBubble.tsx`
|
||||
- `tauri-app/src/components/chat/ThinkingCard.tsx`
|
||||
- `tauri-app/src/components/chat/TaskList.tsx`
|
||||
- `tauri-app/src/components/chat/ArtifactViewer.tsx`
|
||||
|
||||
## Findings
|
||||
|
||||
### 1. `tauri-app/src/components/ChatView.tsx:21-33`
|
||||
**Severity:** High
|
||||
**Problem:** Stream decoders are module-level singletons with `stream: true` and are never flushed/reset.
|
||||
**Evidence:** `WINDOWS_1252_DECODER` and `UTF8_DECODER` live across requests. If a request aborts or ends mid-multibyte sequence, decoder internal state can bleed into the next response and create phantom mojibake.
|
||||
**Fix:** Create fresh decoders per request inside `handleSend`, and flush on stream completion with `decoder.decode()`.
|
||||
|
||||
### 2. `tauri-app/src/App.tsx:22-25`
|
||||
**Severity:** Medium
|
||||
**Problem:** `window.localStorage.getItem(...)` is called without checking that `localStorage` is a functional Storage object.
|
||||
**Evidence:** Full suite fails with `TypeError: window.localStorage.getItem is not a function` from this exact line.
|
||||
**Fix:** Guard with `typeof window.localStorage?.getItem === 'function'` and wrap storage access in a safe helper.
|
||||
|
||||
### 3. `tauri-app/src/components/Sidebar.tsx:196-198`
|
||||
**Severity:** Medium
|
||||
**Problem:** Settings control has only `title="Settings"` and no explicit accessible name.
|
||||
**Evidence:** Sidebar tests cannot reliably locate the footer settings action after the UI rewrite; button markup lacks `aria-label`.
|
||||
**Fix:** Add `aria-label="Open settings"`.
|
||||
|
||||
### 4. `tauri-app/src/components/ChatView.tsx:467-491`
|
||||
**Severity:** Medium
|
||||
**Problem:** Assistant message persistence depends on a DB refresh path after generation; one regression test shows the final reply is not visible after completion.
|
||||
**Evidence:** `npm test` fails at `src/components/ChatView.test.tsx:514` even though DB insert succeeds (`The answer is 42` logged and inserted).
|
||||
**Fix:** Add a direct optimistic append to local `messages` state after successful insert, then re-sync from DB.
|
||||
|
||||
### 5. `tauri-app/src/components/chat/index.ts:1-4` + `tauri-app/src/components/chat/*`
|
||||
**Severity:** Medium
|
||||
**Problem:** Obsolete component subtree appears dead.
|
||||
**Evidence:** Reference search shows no runtime imports of `components/chat/index.ts`, `ThinkingCard`, `TaskList`, `ArtifactViewer`, or `components/chat/MessageBubble.tsx`.
|
||||
**Fix:** Remove the unused subtree or wire it back intentionally. Keeping both old and new message-bubble systems increases maintenance risk.
|
||||
|
||||
### 6. `tauri-app/src/types/forgeagent.ts:109-112`
|
||||
**Severity:** Low
|
||||
**Problem:** `ArtifactViewerProps` is duplicated/unused.
|
||||
**Evidence:** The real component defines its own local props in `src/components/chat/ArtifactViewer.tsx`; no imports reference the exported type.
|
||||
**Fix:** Delete the unused interface or centralize the prop type.
|
||||
|
||||
## Test / verification summary
|
||||
- `build`: PASS
|
||||
- `cargo check`: PASS
|
||||
- `npm test`: FAIL
|
||||
- `src/App.test.tsx` (4 failures)
|
||||
- `src/Sidebar.test.tsx` (4 failures)
|
||||
- `src/components/ChatView.test.tsx` (1 failure)
|
||||
|
||||
## Checklist summary
|
||||
- Injection/XSS/auth/CSRF/crypto: no concrete new exploit found in reviewed files
|
||||
- Bugs/regressions: confirmed
|
||||
- Dead code/obsolete paths: confirmed
|
||||
- Not fully verified: Rust inference crates outside `tauri-app` changed set were not fully line-audited in this pass
|
||||
Reference in new issue
Block a user