AUR-526: review lê arquivos e busca no repo em qualquer linguagem
Medido antes (leitura, base a2d71756)
- A deliberação (AUR-580) já existia:
internal/deliberation.Sessioncommax_rounds,max_cost_tokens,per_tool_timeout_seconds, validação de argumentos e transcrição;internal/review/toolsofereciascanner_<engine>,codebase_context(só arquivos do diff) eskill_section. Nenhuma ferramenta lia outro arquivo, buscava texto ou símbolo. - O card lista
internal/reviewtools; esse pacote não existe: as ferramentas vivem eminternal/review/tools(coberto porinternal/reviewempaths). analyzer.Reposó exportaTrackedFiles(árvore do commit com id de blob e modo); a leitura de blob é privada.internal/grammar.Providerdevolve os símbolos definidos por arquivo (sem posição), detecção de linguagem eIsComment.config.contextInjectingProvider(internal/config/wrap.go) eprofileProvider(cmd/aurumcode/profiles.go) alteram o pedido e não sãollm.Unwrapper: com o contexto do repositório ligado,llm.AsToolCallerficava falso e a deliberação nunca era oferecida.- Uma chamada de ferramenta sem
idvinda do provedor passava; uma chamada de assistente semidera enviada de volta (AC-008).
Decisão
- Ferramentas novas em
internal/review/tools, um arquivo por responsabilidade:read_file(linhas numeradas, até 200 por chamada),search_text(texto literal, até 50 ocorrências),find_symbol(arquivos cuja gramática declara o nome + ocorrências de palavra inteira fora de linha de comentário, decidida pela gramática; arquivo sem gramática entra como texto e diz isso) echanged_file_diff(diff revisado de outro arquivo alterado). Nenhuma lista de linguagem: tudo vem degrammar.Provider. Revision(revision.go) é a única porta de leitura. Um arquivo só é lido se: o caminho é limpo, relativo e chave deTrackedFiles(HEAD)(o commit revisado:--baserevisa base..HEAD;--prusa o checkout já verificado como head da PR); o modo não é120000;os.Lstatmostra arquivo regular (nunca segue link); o diretório resolvido fica dentro da raiz; o tamanho cabe; e o sha1 de blob git dos bytes é igual ao id do commit. Bytes que diferem (edição na árvore de trabalho, outro commit) são recusados: é a prova de "nunca a árvore de trabalho nem outro commit" sem ler blobs.- Arquivo de segredo: catálogo embutido
internal/config/secret_paths.yml(dado, não código) +deliberation.secret_paths; arquivo deignorepela mesma sintaxe de glob (Config.IgnoresPath). Sem catálogo, tudo é segredo (falha fechada). Todo resultado passa pela redação AUR-009 (na ferramenta e de novo na sessão). - Teto de bytes
deliberation.max_read_bytes(padrão 256 KiB), dividido pelas ferramentas do repositório (ByteBudget). O resultado que passaria do teto não é devolvido;review.Deliberation.Partial(preenchido portools.PartialLimit) converte o teto atingido emdeliberation.LimitError{max_read_bytes}depois da conversa: a resposta é descartada e o caminho existentemodelDeliberationLimittorna a revisão inconclusiva conformegate.inconclusive.internal/deliberationnão foi alterado. - AC-007:
contextInjectingToolProvidereprofileToolProvidersó existem quando o provedor embrulhado éllm.ToolCaller; injetam o mesmo bloco (no primeiro user) ou prefixo (na primeira mensagem). Um provedor sem ferramentas continua sem (AC-006 intacto). Perfis continuam sem deliberação (toolsCapable), sem mudança de comportamento. - AC-008:
llm.ValidateToolCall(id, nome e argumentos objeto) noOrchestrator.CompleteWithTools(qualquer provedor), no parse do LiteLLM e emtoWireMessagepara chamadas de assistente enviadas. --prcom checkout não verificado (scanBlocked) ou raiz sem.git: as ferramentas do repositório não são oferecidas, com aviso no stderr.
Como cada AC/MUT é provado (tests/acceptance/AUR-526.sh)
- AC-001:
TestAUR526SymbolFindsTheJavaCallerOutsideTheDiff(fixture Javainternal/review/tools/testdata/aur526: definição pela gramática, chamadorCaller.java:6, linha de comentário fora),TestAUR526JavaCallerReadThroughToolsFindingAnchoredInDiff(o modelo pedefind_symbol, recebe o chamador e o achado final fica emContract.java:5),TestAUR526ReadFileReachesTheModelThroughTheCommand. - AC-002:
TestAUR526ReadsTheReviewedRevisionNeverTheWorkingTree(edição depois do commit e arquivo não rastreado recusados; busca não os vê). - AC-003:
TestAUR526RefusesEscapesIgnoredAndSecretFiles,TestAUR526SecretAndIgnoredPaths; redação verificada no conteúdo. - AC-004:
TestAUR526ByteCeilingMakesTheReviewPartial,TestAUR526ByteCeilingIsADeliberationLimit,TestAUR526ReadCeilingIsInconclusive(exit != 0, gate inconclusive,limit=max_read_bytes, nada publicado) e o teto de rodadas do AUR-580. - AC-005: o achado do loop passa por
applyGatescomo qualquer outro (o do chamador fora do diff nunca chega aIssues). - AC-006: caracterização (
TestAUR580DeferredScannerRunsWhenToolsCannotBeOffered,TestAUR525ToolSupportDetectableBeforeCall). - AC-007:
TestAUR526ContextWrapperForwardsToolCalling,TestAUR526ProfileDecoratorForwardsToolCalling. - AC-008:
TestAUR526ValidateToolCall,TestAUR526OrchestratorRefusesIDLessCall,TestAUR526IncomingCallWithoutIDIsRefused,TestAUR526OutgoingInvalidCallIsNeverSent. - MUT-001: troca
os.Lstatporos.StatemRevision.Read; o fixture é um arquivo rastreado substituído no disco por link para fora com os mesmos bytes (o id de blob bate e o diretório é a raiz), então só a guarda de link o recusa eTestAUR526MUT001SymlinkWithMatchingBytesIsRefusedfica vermelho.
Portão de recall (pendente de medição)
O Outcome exige recall maior no corpus do AUR-523 sem queda de precisão acima do limite. Limite registrado: queda de precisão de no máximo 2 pontos percentuais. A medição não foi executada neste stream (regra: escrever sem executar); fica para o fluxo único de testes. Sem ganho medido, o card volta ao backlog.
Documentação stale corrigida
docs/configuration.md(Deliberação): lista de ferramentas não citava leitura de arquivo/busca; limites semmax_read_bytes; chaves novasmax_read_bytesesecret_pathsno bloco yml.docs/architecture.md: ferramentas oferecidas e limites; decoradores que agora repassamllm.ToolCaller.docs/tutorials/deliberacao.md: objetivo, limites e "O que validar". As saídas gravadas emdemo/tutoriais/deliberacao/out/passam a listar as ferramentas do repositório em "oferecidas"; a regravação fica para o fluxo final (regra do stream).
Correção da revisão estática
- Cache de arquivos com teto de memória
deliberation.max_cache_bytes(padrão 64 MiB): passar dele recusa a leitura e esgota o orçamento com o limitemax_cache_bytes, a mesma revisão parcial demax_read_bytes(TestAUR526CacheCeilingMakesTheReviewPartial). - Catálogo de segredo comparado sem diferenciar maiúsculas (
.ENV,Credentials) e ampliado comkubeconfig,.kube/config,.docker/config.jsone*service-account*.json(TestAUR526SecretPathsIgnoreCaseAndCoverCloudCredentials).