AUR-459 — O formato que o prompt pede e o que o parser le
Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.
O defeito
internal/prompt/templates/review.md mostrava dois schemas de achado no
mesmo exemplo de saida: line_comments primeiro, issues depois. O parser
(internal/prompt/parser.go) lia so issues. O modelo escolhe o primeiro
que ve — medido contra o gateway real (resposta de 6042 chars,
finish_reason=stop): o JSON devolvido traz line_comments, iso_scores e
summary, nunca issues. Consequencia medida: um diff com tres segredos
plantados imprimia No issues found. com exit 0. O modelo achou e descreveu
os tres; a ferramenta jogou fora e afirmou o contrario com confianca.
O conserto
- Um schema so no prompt. O template mostra
issues,iso_scoresesummary. Os blocosline_comments,file_commentsecommit_commentsairam do exemplo. Nenhum deles era consumido:LineCommentsnunca era lido em lugar nenhum, eFileComments/CommitCommentso eram tocados pela redacao (internal/review/reviewer.go) antes de serem descartados. O texto de nivel de arquivo e de commit passa a ser pedido no camposummary. O template tambem passa a dizer querule_ide obrigatorio e por que: achado semrule_idresolvivel e descartado pelo portao do AUR-434 e nunca aparece.
Correcao apos review: a chave do merge era (file, line) e escondia achado
A primeira versao deste card casava comentario com achado so pela
localizacao e justificava assim: "o registro de issues vence, e o mais
rico". Executado, o argumento e falso — um nit de estilo em a.go:42
engolia um SECRET LEAK reportado na mesma linha via line_comments, e dois
comentarios distintos numa linha colapsavam num so, sem contador e sem
aviso. Varios achados dividem uma linha rotineiramente.
A chave passou a ser (file, line, mensagem normalizada) — caixa e espacos
dobrados, entao o mesmo achado restado na outra forma ainda colapsa, mas
achados diferentes na mesma linha sobrevivem todos. E os tres caminhos que
nao adotam um comentario (repeticao de achado ja reportado, path vazio,
body em branco) sao contados e nomeados em
Metadata["parse_discard_warning"], que cmd/aurumcode imprime no stderr
ao lado do aviso do AUR-448:
aurumcode review: 2 line comment(s) not converted: 1 already reported as an issue, 1 with no path.
Um card cuja resposta escolhida e "anuncie o descarte" nao pode descartar em
silencio no proprio merge.
- O parser aceita as duas formas.
adoptLineCommentsconverte cada entrada deline_commentsemtypes.ReviewIssue(path/file->File,line->Line,body/message->Message, maisrule_id,severityesuggestionquando vierem; severidade ausente virawarning, o mesmo default quedegradedExtractja usa). E merge, nao substituicao, com a chave(file, line, mensagem normalizada)descrita acima: so o mesmo achado restado na outra forma colapsa, e o colapso e anunciado. Entrada malformada nao vira falha dura: bloco que nao decodifica e ignorado, entrada sempathou sembodye pulada em vez de ir paravalidateReviewResult, que rejeitaria a resposta inteira por causa de um item lixo. - A divergencia futura quebra o build.
TestReviewTemplateMatchesParserextrai os campos de topo reais do template embarcado (le os bytes do proprio arquivo, nao uma copia) e exige exatamentecanonicalReviewFields.TestAcceptedReviewFieldsAreConsumedprova, campo a campo, que cada nome deacceptedReviewFieldsmuda o resultado do parse — uma lista escrita a mao e exatamente a classe de falha deste card, entao a lista sozinha nao valeria como prova.
A armadilha: nao trocar um falso negativo por outro
Um line_comment convertido normalmente nao traz rule_id, e o portao do
AUR-434 (internal/review.enforceRuleCitations) descarta achado sem
rule_id do catalogo embarcado. Converter sem mais nada devolveria
No issues found. — o mesmo silencio, por outra porta.
Escolha: anunciar o descarte (a segunda das duas saidas admitidas pelo
card). O aviso do AUR-448 ja faz isso: formatDiscardWarning conta quantos e
por que, e cmd/aurumcode imprime a linha literal no stderr —
aurumcode review: 1 finding(s) discarded: 1 with no rule_id. O usuario
recebe a contagem e a razao, nunca silencio.
A outra saida (exigir rule_id dentro de cada line_comment) foi
rejeitada por incoerencia: o template nao mostra mais line_comments, entao
documentar um campo obrigatorio dentro de uma forma que o prompt nunca pede
seria um contrato que ninguem e oferecido. O rule_id e exigido onde o
prompt de fato pede — dentro de issues — e line_comments fica como alias
tolerado para o modelo que viu um prompt antigo ou um
.aurumcode/prompts/review.md do usuario. Quando esse alias traz rule_id,
o achado sobrevive e aparece no stdout; quando nao traz, o descarte e
anunciado.
Comando, saida e exit codes
aurumcode review --base HEAD~1, sem mudanca de contrato:
0— a review rodou. Achados no stdout, um por linha,<file>:<line>: [<severity>] <message> (rule <id>: <title>), ouNo issues found.1— a review falhou (provider ausente ou indisponivel, parse impossivel).2— erro de uso.3—--fail-onfechou o portao.
Exemplo executavel sem segredo, com o provider offline deterministico:
cat > /tmp/resp.json <<'JSON'
{"line_comments":[{"path":"config/demo-tokens.txt","line":4,"severity":"error",
"rule_id":"security/hardcoded-secret","body":"credential-shaped value"}]}
JSON
AURUMCODE_LLM_FIXTURE=/tmp/resp.json aurumcode review --base HEAD~1
Diagnostico de falha: se o stdout disser No issues found. e o stderr
trouxer N finding(s) discarded, o modelo reportou algo que o portao de
regra recusou — o rule_id citado esta ausente ou nao existe no catalogo
embarcado. Se o stdout estiver vazio e o exit for 1, nenhum provider foi
configurado: a propria mensagem no stderr mostra a forma completa do
fixture.
Limites declarados
internal/review/cache.PromptVersioncontinua"v1". Esse arquivo esta fora dospathsdeste card, entao entradas de cache gravadas sob o prompt antigo continuam validas sob o prompt novo. Quem quiser reprocessar limpa o diretorio de cache (AURUMCODE_CACHE_DIR).- Os seletores do card sao
TestAUR459,IntegrationAUR459eE2EAUR459(o card trazia...AUR435por erro de gabarito, corrigido fora deste worktree:TestAUR435ja existe emtests/unit/AUR-435.go, no mesmo pacoteunit, e redefini-lo quebraria a compilacao). Os programas Go rodam pelo bridge_test.goque a convencao do repositorio usa (vejatests/acceptance/AUR-448.sh), porquetests/unit/*.goetests/integration/*.gonao sao_test.goego testsozinho reportaria "no test files" e passaria vazio; o contrato mais fino vive eminternal/prompt/schema_contract_test.go, no pacote do proprio codigo. - Cada seletor declarado roda o SEU programa:
TestAUR459->tests/unit/AUR-459.go(o parser sozinho),IntegrationAUR459->tests/integration/AUR-459.go(a costura parser + portao de regra viaGenerateReview, comFakeProvider),E2EAUR459->tests/e2e/AUR-459.sh(a decisao de CI:--fail-onfecha em achado convertido e NAO fecha em achado descartado). Seletor sem programa proprio sai 64: ausencia le-se como ausencia, nunca como um verde colhido das asserções do AC-001. - Nao existe segunda copia do prompt de review no repositorio:
.aurumcode/prompts/contem apenasdocumentation, entaointernal/prompt/templates/review.md— o arquivo embarcado portemplateFSe lido em runtime — e a unica lista de campos mantida a mao, e e ela queTestReviewTemplateMatchesParserguarda. O comentario debuilder.goque fala em "build-time copy de.aurumcode/prompts/ review.md" descreve a origem historica do texto, nao um arquivo presente.
Prova
- RED 1: reintroduzir o bloco
line_commentsno template →TestReviewTemplateMatchesParserfalha nomeando os dois schemas. - RED 2: remover a chamada a
adoptLineComments→TestAcceptedReviewFieldsAreConsumed/line_comments,TestLineCommentsDoNotDisplaceIssueseTestLineCommentsJunkIsSkippedNotFatalfalham. tests/acceptance/AUR-459.sh AC-001-MUT-001reconstroi o binario com o defeito de volta e exige que o achado suma; se sobrevivesse, o aceite reportariaAUR-459/AC-001/MUT-001.