vet: veredito sobre código gerado por IA
O codafort vet dá um veredito sobre o que mudou desde HEAD ou desde a base do PR: o que bloqueia, o que é consultivo e o que não rodou.
Ele avalia só o delta, em cinco eixos. O que está provado vai para blocking e reprova; o resto vai para advisory. O veredito diz quais eixos não rodaram, e eixo pulado nunca conta como limpo.
Uso
codafort vet # o delta vs HEAD (mudanças não-commitadas)
codafort vet --all # o projeto inteiro
codafort vet --json # o veredito completo, coda-vet/1 (agentes/CI)
codafort vet --base origin/main # num PR: o delta é vs a BASE, não vs HEAD
codafort vet --ingest tsc.out # correlaciona o que o CI já rodou (tsc/junit-xml/lcov)
codafort vet --evidence-out vet.json # grava coda-evidence/1 (modality: vet) para a declaração contra-assinada
Exit codes: 0 passa · 1 veredito bloqueante · 2 erro de execução. Com o 2, uma falha de execução nunca é lida como bloqueio.
Os eixos
| Eixo | Pergunta | Bloqueia? |
|---|---|---|
V0-security-delta | Há finding de segurança novo na mudança? (a mesma análise do scan, só no diff) | confirmado sim; suspeito é consultivo |
V1-ingested-diagnostics | O tsc/junit/lcov que o CI já rodou tem error em linha nova? | error sim; warning aconselha |
V2-vacuous-tests | Teste que passa sem testar (assert True, sem asserção, mock que devolve o esperado)? | consultivo |
V3-public-contract | Símbolo público removido/renomeado (contract_breaks)? | sim |
V4-blast-radius | Escopo: arquivos, linhas, arquivos críticos tocados, wide? | consultivo; alimenta prioridade |
health | Complexidade ciclomática/cognitiva das funções tocadas | nunca |
V1 só roda com --ingest; V3/V4 precisam de um delta. Quando não rodam, aparecem em axes.skipped, e não em ran.
A codafort não executa tsc, pytest nem outra ferramenta: ela lê o artefato que o CI já produziu e o cruza com o diff.
A forma do veredito (coda-vet/1)
{
"schema": "coda-vet/1",
"blocked": true,
"axes": { "ran": ["V0-security-delta", "V2-vacuous-tests", "V3-public-contract", "V4-blast-radius"],
"skipped": ["V1-ingested-diagnostics"] },
"blocking": [ { "id": "SF-1", "severity": "Critical", "tier": "confirmed", "rule": "TAINT-COMMAND-INJECTION",
"cwe": [78], "file": "./app.py", "line": 7, "is_new": true,
"taint": { "source": "os.environ", "sink": "os.system" } } ],
"advisory": [],
"ingested": [],
"contract_breaks": [ { "file": "./app.py", "symbol": "antiga_api", "kind": "function" } ],
"scope": { "files_changed": 1, "lines_added": 4, "critical_files": [], "wide": false },
"diff_only": true
}
Contrato publicado em /schemas; um veredito real capturado em /schemas/fixtures/coda-vet.json.
No CI (GitHub Action)
- uses: actions/checkout@v4
with: { fetch-depth: 0 } # a BASE precisa existir localmente
- uses: codafort/gate-action@v1
with:
source: '.'
vet: 'true' # default
vet-base: 'origin/main' # vazio = base do PR (github.base_ref)
vet-ingest: 'tsc.out' # opcional: artefato já produzido pelo CI
vet-enforce: 'true' # um veredito BLOQUEANTE reprova o job
Num checkout raso, o step tenta git fetch da base. Se ela não resolver, o vet é pulado com ::warning (report-only) ou reprova (vet-enforce: true); ele nunca passa em silêncio sem ter rodado. Detalhes em CI e gate.
Do veredito à declaração contra-assinada
--evidence-out vet.json grava a contribuição coda-evidence/1 com modality: "vet": blocking, advisory, scope, axes_ran, axes_skipped, verdict_digest. Anexada com codafort attest create --evidence vet.json, ela entra no ledger que a codafort contra-assina. Ver A cadeia de evidência e Declaração contra-assinada (o artefato coda-attestation/1).