AUR-539 — Os aceites do AUR-467 e AUR-477 voltam a passar com o prompt atual
Problema
Os aceites selados de dois cards em done falhavam em main, sem nenhuma
mudança de comportamento: AUR-467 (oci-run, seletor padrão AC-001)
saía 79 — "assembly failed: prompt instructions and fixed content need 3789
tokens and the reply reserves 40, which leaves no room for a single code
change in the 1700-token budget" — e AUR-477 (oci-run, seletor padrão
all, que inclui E2EAUR477) saía 1 pelo mesmo motivo a 4000 tokens. A
falha já existia no commit base 1d26968.
Medição
O conteúdo fixo de um prompt de review (PromptBuilder.BuildPrompt, schema
"review": instruções do template, catálogo de regras, métricas, idioma,
escopo da mudança, mais o cabeçalho fixo do conteúdo do usuário) foi medido
com um diff vazio, chamando o novo PromptBuilder.FixedOverheadTokens
(internal/prompt/builder.go):
| O que | Tokens (heurística ~4 chars/token) |
|---|---|
FixedOverheadTokens (schema "review", diff vazio) |
3800 |
FixedOverheadTokens (schema "summary", diff vazio) |
61 |
System (instruções + catálogo) isolado, schema "review" |
3749 |
Catálogo de regras (RenderRuleCatalog(DefaultRuleCatalog)) |
262 (1049 chars) |
Os orçamentos que os aceites fixavam (1700, 2200 em AUR-467; 800–4000 em
AUR-477) ficam abaixo dos ~3800 tokens que o schema "review" sozinho
já consome — não há mais margem nenhuma para um único hunk de código, daí a
recusa (que é o comportamento correto do AC-003 do AUR-467/477: a montagem
recusa alto e bom som em vez de mandar um prompt sem diff).
O schema "summary" (usado pelos seletores unit/integration do AUR-477)
tem overhead fixo de 61 tokens — não é afetado pelo crescimento do catálogo
de regras/instruções do schema "review", por isso os orçamentos literais
desses dois arquivos (tests/unit/AUR-477.go, tests/integration/AUR-477.go)
continuam passando sem alteração; só o E2E do AUR-477 (que usa o schema
"review" via internal/review.Reviewer) e as fixturas do AUR-467 (que
também usam "review") precisavam de orçamento derivado.
Decisão: derivar os orçamentos, não encolher o prompt
Encolher o prompt (instruções, catálogo de regras, schema de resposta)
precisaria provar que nenhum comportamento se perde — o catálogo é a lista
fechada de rule_id que o gate do AUR-434 aceita, e o schema ensina o
formato de resposta exigido pelo parser. Não há medição de inchaço: o
conteúdo está onde o AUR-430/AUR-461/AUR-519 o deixaram, crescendo porque
mais regras e seções foram adicionadas, não porque algo ficou redundante.
A decisão foi derivar o orçamento dos testes do conteúdo fixo medido,
nunca de um número que envelhece.
Implementação
internal/prompt/builder.go: extraídofixedOverhead(privado, usado porBuildPrompt) e expostoPromptBuilder.FixedOverheadTokens(diff, metrics, opts) (int, error)— mesma computação, uma única fonte de verdade, sem duplicar a lógica entre produto e teste.internal/prompt/overhead_test.go(novo):TestAUR539FixedOverheadRefusalBoundaryprova AC-002 (a recusa continua existindo:MaxTokens == FixedOverheadTokensnão deixa espaço algum eBuildPromptrecusa, com a mensagem exata) e AC-003 (o mesmo piso medido, com margem, admite o diff).tests/unit/AUR-467.go: as três fixturas que fixavam 1700/40 e 1510/20 agora buscam, a partir deFixedOverheadTokens, o menor orçamento onde a forma exigida pelo teste (algum arquivo revisado e algum omitido; ou hunk0 presente e hunk1 ausente) realmente ocorre — nunca um literal.tests/integration/AUR-467.go:ArithmeticConsistencytroca os literais{1700, 2200, 8000}por{fixedOverhead+200, fixedOverhead+700, fixedOverhead+6000}.tests/acceptance/AUR-467.sh: o modo"tight"do programa gerado (cmd/aur467dump) busca o orçamento mínimo viaFixedOverheadTokensem vez do literal1700, 40.tests/e2e/AUR-477.sh: o programa gerado medeFixedOverheadTokenspara o diff de 200 arquivos e usafixedOverhead + 1000em vez do literalMaxTokens: 4000. A margem de 1000 tokens continua muito menor que o pior caso anterior ao AUR-477 (uma bala por arquivo omitido, ~200 arquivos), então o teste ainda prova a reserva limitada (maxOmittedBullets), não apenas "deu mais orçamento".tests/acceptance/AUR-539.sh(novo): seletoresall,AC-001(os programas de teste do AUR-467 e AUR-477 passam),AC-002(a recusa continua testada),AC-003(os literais antigos não reapareceram eFixedOverheadTokensé usado nos arquivos reescritos) eAC-001-MUT-001(restaurar o orçamento fixo antigo em uma das fixturas do AUR-467 reproduz a recusa 1700 < ~3800 e vira RED).
Critérios de aceite
- AC-001:
oci-run --card AUR-467(seletor padrãoAC-001) eoci-run --card AUR-477(seletor padrãoall, incluiE2EAUR477) saem 0 emmaincom estes commits. - AC-002: a recusa de montar um prompt sem espaço para o diff continua
valendo e testada (
TestAUR539FixedOverheadRefusalBoundary,testAUR467PartialCoverageDeclared, AC-003 do AUR-477). - AC-003: o orçamento usado nos aceites é derivado de
FixedOverheadTokens, não de um literal.
Mutação
- MUT-001: restaurar, em uma cópia staged de
tests/unit/AUR-467.go, o orçamento fixo antigo (MaxTokens: 1700) na fixtura de AC-003 em vez do orçamento derivado — a função ainda compila, masBuildPromptrecusa (3800 > 1700) e o teste cai (RED). Vertests/acceptance/AUR-539.shseletorAC-001-MUT-001.
Lacunas conhecidas (fora do escopo deste card)
tests/e2e/AUR-467.sh(seletorE2EAUR467) falha emmain, sem qualquer mudança deste card, por um motivo não relacionado a orçamento de token (um check de "no-regression-gate" sobreNOTES.txt/config/demo-tokens.txt). Esse arquivo não está nospathsdo card, o seletor padrãoAC-001que ooci-rundo AUR-467 executa nunca o invoca, e o Non-goal deste card proíbe mexer no que o AUR-467/477 prometem além do orçamento. Fica registrado para um card futuro.- Os orçamentos "com espaço de sobra" (8000/1000) que permanecem literais
em
tests/unit/AUR-467.go(AC-001, AC-002, blocker de medição) etests/integration/AUR-467.go(três testes de controle) não foram convertidos paraFixedOverheadTokens— hoje 8000 ainda está bem acima de ~3800 e essas fixturas não fazem parte da falha que motivou o card. Continuam sendo um literal que pode, no futuro, sofrer o mesmo envelhecimento; registrado como dívida, não corrigido sob o prazo deste card.