diff --git a/docs/00-plano-de-projeto.md b/docs/00-plano-de-projeto.md index 7760f78..a670ac8 100644 --- a/docs/00-plano-de-projeto.md +++ b/docs/00-plano-de-projeto.md @@ -149,6 +149,9 @@ código (`# RN-012`) precisa de um endereço estável. partida e da postura. - **[`02-regras-de-negocio.md`](02-regras-de-negocio.md)** — RN-001 a RN-042, cada uma com o ponto onde é imposta e o que prova que ela vale. +- **[`08-achados.md`](08-achados.md)** — log de descobertas: o que surpreendeu, o + que quebrou de um jeito que ensinou algo. Alimenta artigo e evita reaprender o + mesmo tropeço. Regra nova entra em `02`, nunca aqui. Este plano pode citar número, nunca transcrever texto de regra. diff --git a/docs/08-achados.md b/docs/08-achados.md new file mode 100644 index 0000000..114ab0b --- /dev/null +++ b/docs/08-achados.md @@ -0,0 +1,215 @@ +# Achados + +> Log de descobertas, não de tarefas. Entra aqui o que surpreendeu, o que +> quebrou de um jeito que ensinou algo, e o que só se aprende fazendo. +> O roadmap está no [plano](00-plano-de-projeto.md); as decisões, em [`adr/`](adr/). + +**Por que existe:** os detalhes bons evaporam. Daqui a três meses ninguém lembra +por que o fato-prova apontava para a pessoa errada, e é justamente esse tipo de +coisa que sustenta um artigo honesto — ou impede de reaprender o mesmo tropeço. + +**Formato:** data, o que aconteceu, por que importa, link. Uma entrada por +descoberta. Se não surpreendeu ninguém, não é achado — é changelog. + +--- + +## Domínio e geração + +### 2026-08-29 — O validador se pagou no primeiro dia + +Duas invariantes quebradas pelo próprio gerador, ambas passariam em revisão de +código, ambas pegas por checagem automática ([#11](https://github.com/Madeuss/firenze/pull/11)): + +1. Dois inocentes podiam sortear o mesmo par (cômodo, intervalo) para o segredo. + Esvaziar o cômodo para um deles arrastava o outro para longe do próprio + segredo, e o fato passava a contradizer a linha do tempo. +2. O fato-prova marcava **quem achou** o objeto como a pessoa que ele localizava + — colocando um inocente na cena do crime, na hora do crime. + +**Por que importa:** é o argumento inteiro para validar o artefato pronto em vez +de confiar na intenção de quem gerou. Nenhum dos dois é erro de digitação; são +erros de modelagem, e modelagem errada lê como código certo. + +### 2026-08-29 — Metade dos mistérios sorteados é insolúvel, e eles parecem bons + +Não dá para gerar caso e confiar. O solver reprova, o caso é descartado e outro +nasce de semente derivada (RN-002). Sem esse portão, o jogador descobre o +problema depois de uma hora perdida. + +**Por que importa:** é a diferença entre "gerei conteúdo com IA" e "gerei +conteúdo verificável". O verificador é mais interessante que o gerador. + +### 2026-08-31 — Semente sozinha não identifica um caso + +`seed` só identifica junto com versão do gerador **e cenário**. Enquanto existe +um cenário só, nada é ambíguo — que é exatamente por que o campo custou cinco +minutos agora e seria migração depois ([#17](https://github.com/Madeuss/firenze/pull/17)). + +**Por que importa:** reprodutibilidade é a base do eval. Um eixo esquecido na +identidade do caso faz baseline comparar coisas diferentes e reportar como +regressão do modelo. + +--- + +## Modelos e IA + +### 2026-08-29 — Quem escreve sabendo o culpado entrega o culpado + +O verniz recebe `Case`, nunca `CaseWithSolution` — mesma disciplina do solver, +motivo diferente. Ninguém escreveria de propósito, mas o culpado ganharia a +descrição mais afiada ([#15](https://github.com/Madeuss/firenze/pull/15)). + +O teste que vale é o forte: **cada suspeito aparece exatamente uma vez no +prompt**, na lista de elenco. Modelo que não consegue distingui-los não consegue +escrever um deles como mais culpado. + +### 2026-08-29 — Canary na saída do verniz acusa a gente, não o modelo + +O verniz só recebe fatos públicos. Como ele nunca vê um fato restrito, não pode +vazar um — então canary ali significa que a montagem de contexto quebrou +**antes** do modelo. + +**Por que importa:** inverte o sentido da checagem. O mesmo filtro, no mesmo +lugar, testa coisas diferentes dependendo do que entrou no contexto. + +### 2026-08-31 — Escrever a desvantagem numa ADR não é o mesmo que agir sobre ela + +A ADR-0007 listou, em consequências negativas, *"dois adaptadores, um dos quais +nada em produção vai usar"* — e o adaptador ficou lá mesmo assim, até o usuário +perguntar por que ele existia ([#18](https://github.com/Madeuss/firenze/pull/18)). + +**Por que importa:** documentar um custo dá a sensação de tê-lo endereçado. O +registro serve para decidir, não para absolver. + +### 2026-08-31 — Um falso que satisfaz schema não satisfaz domínio + +O `FakeModel` preenche qualquer schema, e a validação do verniz o rejeita — +porque o elenco que ele inventa não pertence a mistério nenhum. Correto, e é a +fronteira entre *"esse pipeline roda offline"* e *"isso dá para mostrar a um +jogador"*. + +### 2026-08-31 — Quase todo um turno funciona sem modelo + +Montar dossiê, validar schema, validar transição de postura, filtrar canary e +escopo, debitar turno: nada disso precisa de API. Só a fala soar em personagem +precisa. + +**Por que importa:** derruba a premissa de que trabalho com LLM depende de chave +para começar. Depende para *terminar*. + +### 2026-08-31 — Cobrança por token e por hora não se comparam direto + +GPU cobra por hora ligada, usando ou não; API cobra por token. Com uso +intermitente de desenvolvimento, a economia inverte: o prompt do verniz mede +~400 tokens de entrada e ~400 de saída, ordem de US$ 0,0025 por caso em modelo +barato — contra uma VM que consome créditos dormindo. + +--- + +## Idioma + +### 2026-08-29 — Gramática portuguesa vazou para dentro do modelo de domínio + +Um mapa `PREPOSICAO = {"adega": "na", "porão": "no"}` dentro do gerador. Inglês +não contrai preposição; alemão pediria três artigos +([#12](https://github.com/Madeuss/firenze/pull/12)). + +**Por que importa:** frase pronta guardada como dado é uma decisão de idioma +tomada em silêncio. O sintoma aparece como conveniência. + +### 2026-08-29 — Estrutura em vez de prosa se pagou duas vezes + +Solver, validador e pontuação já raciocinavam sobre campos estruturados. Como +nada no caminho da dedução lê texto, tudo virou independente de idioma **sem uma +linha a mais**. + +**Por que importa:** a decisão foi tomada por reprodutibilidade de eval e rendeu +i18n de graça. Decisão boa costuma pagar num eixo que não era o motivo dela. + +### 2026-08-29 — Resistência a injeção varia por idioma + +Jailbreak que falha em português passa em inglês, e vice-versa — modelos são +treinados de forma desigual entre línguas ([ADR-0005](adr/0005-locale-is-a-property-of-the-match.md)). + +**Por que importa:** golden set adversarial precisa de casos **por idioma**, não +de tradução automática do conjunto português. Cada locale multiplica o custo de +eval, e português com pesos abertos é provavelmente a combinação mais difícil +que este projeto poderia escolher ([ADR-0008](adr/0008-magalu-prosa-as-the-model-provider.md)). + +--- + +## Processo, CI e GitHub + +### 2026-08-29 — Check obrigatório com filtro `paths:` trava o merge para sempre + +Se o job não roda, ele nunca reporta, e o PR fica *pending* eternamente. Por isso +nenhum job obrigatório tem filtro de caminho. + +### 2026-08-29 — `working-directory` global quebra job que não faz checkout + +O `pr-title` não clona nada e falhava tentando entrar em `apps/api`. Default +global parece economia e é armadilha. + +### 2026-08-29 — Ruleset não vale em repositório privado no plano Free + +O ruleset estava configurado e **inerte**. Um merge commit passou apesar de +"require linear history" estar marcado na tela. A proteção só passou a valer com +o repositório público. + +**Por que importa:** configurar não é o mesmo que estar protegido. Vale testar a +regra tentando violá-la. + +### 2026-08-29 — Renomear branch pela API fecha o PR aberto + +O endpoint de rename reaponta PR cujo *base* é a branch, mas **fecha** o PR cujo +*head* foi renomeado. Dois PRs morreram assim e precisaram ser recriados. + +### 2026-08-29 — `Closes E1 (#5)` não fecha nada + +O GitHub só reconhece a palavra-chave colada na referência: `Closes #5`. Com +qualquer coisa no meio, nenhum link é criado e a issue fica aberta. E para PR já +mergeado a janela fechou — não dá para corrigir depois. + +### 2026-08-31 — A caixa de merge congela a mensagem quando a página abre + +Editar o corpo do PR depois disso não chega ao commit. O `Closes #5` estava no +PR e não estava no merge — a issue não fechou. + +### 2026-08-29 — PR empilhado diverge quando o de baixo entra squashed + +O de cima carrega os commits originais, a main carrega a versão achatada, e todo +arquivo em comum conflita falsamente. Saída: rebase logo após o merge, ou merge +`-s ours` quando a árvore de cima já contém tudo que a main tem. + +--- + +## Infra + +### 2026-08-29 — `wsl.exe` do System32 é só um lançador + +Habilitar os recursos por DISM não bastou: faltava `C:\Program Files\WSL`, e o +erro que o Docker mostrava era do lançador não achando o destino. +`winget install Microsoft.WSL` resolveu. + +### 2026-08-29 — pgvector local e gerenciado divergem de versão + +Imagem em 0.8.6, DBaaS da Magalu em 0.8.2. Recurso novo de índice precisa ser +conferido contra produção antes de ser usado +([ADR-0002](adr/0002-postgres-pgvector-instead-of-a-vector-database.md)). + +### 2026-08-31 — Nenhum tipo de máquina com GPU na conta + +50 tipos disponíveis, `gpu: 0` em todos, todos em `br-ne1`. O experimento com +modelo local da fase 8 não é só "depois" — precisa de pedido de quota antes. + +--- + +## Ideias que nasceram do caminho + +- **Detetive automático como eval.** Um agente que joga a partida só com o que o + jogador vê prova que o caso é solucionável *na prática*; o solver prova que ele + é dedutível *estruturalmente*. São garantias diferentes, e a segunda é mais + convincente. Seria o primeiro lugar onde MCP faria trabalho de verdade neste + projeto. +- **Comparar modelos abertos servidos pela Prosa contra a suíte adversarial, em + português.** Ninguém publicou esse número.