AUR-436 — aurumcode review --modelo: choose which AI reviews, including a local one
Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.
aurumcode review --base <ref> --modelo <nome> lets the user choose which
model performs the review — including a local model — instead of the
selection being decided only by environment variables. When nothing is
configured to serve the chosen model, the command fails loudly with a
clear, actionable error on stderr and exit 1: which model, why it is
unavailable, and how to configure a provider that serves it. It never
degrades to an empty review with exit 0. Without --modelo, nothing
changes: provider selection, output and exit codes are exactly as
documented in docs/specs/AUR-430.md and docs/specs/AUR-431.md.
Command
aurumcode review --base <ref> [--fail-on <level>] [--modelo <nome>]
| Flag | Required | Meaning |
|---|---|---|
--base <ref> |
yes | Unchanged from AUR-430: the ref to diff against HEAD. |
--fail-on <level> |
no | Unchanged from AUR-431: the severity gate. Composes freely with --modelo. |
--modelo <nome> |
no | The model that reviews, e.g. local, llama3, gpt-4. The flag commands the selection: with it set, LLM_MODEL is ignored. |
How the chosen model is served
--modelo adds no vendor. It reuses the two provider mechanisms AUR-430
already published (cmd/aurumcode/main.go, selectProvider):
AURUMCODE_LLM_FIXTURE=<path>— the deterministic offline provider (internal/review.FakeProvider) answers for the chosen model. This is how the sealed, network-denied acceptance exercises--modelo local.LLM_API_KEY+LLM_BASE_URL— the chosen model rides the existing OpenAI-compatible provider (internal/llm/provider/litellm), with the flag's name sent as the wiremodel, overridingLLM_MODEL. A local model is chosen by pointingLLM_BASE_URLat a local endpoint: an ollama server's OpenAI-compatible API (http://localhost:11434/v1), a llama.cpp server, or a litellm proxy in front of any local model.tests/integration/AUR-436.goproves with a loopbackhttptestendpoint that the name typed after--modelois the name that reaches the wire.
Neither configured — or the configured endpoint unreachable / not serving the model — means the chosen model is unavailable (see below).
When --modelo is set, one deterministic note goes to stderr (never
stdout) naming the selection:
aurumcode review: reviewing with model "local" (offline fixture provider)
Exit codes
| Code | Meaning |
|---|---|
0 |
The review ran with the chosen model (findings or No issues found. — an available model reporting nothing is a normal result). |
1 |
The review failed, unchanged from AUR-430, now including: the chosen model is unavailable. The error names the model, the reason and the fix. |
2 |
Usage error, unchanged plus one case: an explicitly empty model name (--modelo=, or --modelo "$VAR" with VAR empty). The command never silently falls back to a model the user did not choose. |
3 |
Unchanged from AUR-431: the --fail-on gate closed. The chosen model's findings gate exactly like the default selection's. |
Unavailable model
The defect this card guards against (MUT-001): an unavailable model must
never produce an empty review with exit 0. Instead, stderr carries two
lines — which model, why, how to fix — and the command exits 1:
aurumcode review: model "local" is unavailable: no LLM provider is configured to serve it
aurumcode review: to serve model "local": set AURUMCODE_LLM_FIXTURE=<response-file> for a deterministic offline run, or set LLM_API_KEY and LLM_BASE_URL to an OpenAI-compatible endpoint that serves it -- a local endpoint works, e.g. LLM_BASE_URL=http://localhost:11434/v1 (ollama) or a litellm proxy in front of any local model -- then re-run with --modelo local
A configured-but-unreachable endpoint (local server not running, wrong URL, model not served there) reports the same shape with the transport error as the reason.
Example (no secrets)
Fully offline, deterministic, no network and no credentials:
$ cat /tmp/response.json
{
"issues": [
{
"file": "config/demo-tokens.txt",
"line": 4,
"severity": "warning",
"rule_id": "security/hardcoded-secret",
"message": "A credential-shaped value was committed in plain text (DEMO_API_TOKEN)."
}
],
"summary": "The change commits plaintext credential-shaped values."
}
$ cd tests/fixtures/repos/git-demo/repo.git
$ AURUMCODE_LLM_FIXTURE=/tmp/response.json aurumcode review --base HEAD~1 --modelo local
aurumcode review: reviewing with model "local" (offline fixture provider)
config/demo-tokens.txt:4: [warning] A credential-shaped value was committed in plain text (DEMO_API_TOKEN). (rule security/hardcoded-secret: Hardcoded Secrets)
$ echo $?
0
(The finding cites an embedded rule — rule_id — because the AUR-434
rule-citation gate discards any finding that cannot cite one; see
docs/specs/AUR-434.md.)
(The selection note is on stderr; stdout carries only the findings, byte
for byte what the same run prints without --modelo.)
Against a genuinely local model:
# ollama serving llama3 on its OpenAI-compatible API:
LLM_API_KEY=ollama LLM_BASE_URL=http://localhost:11434/v1 \
aurumcode review --base HEAD~1 --modelo llama3
Failure diagnosis
- Exit
1,model "..." is unavailable: no LLM provider is configured to serve it— neitherAURUMCODE_LLM_FIXTUREnorLLM_API_KEY+LLM_BASE_URLis set. Configure one of them as the message says. - Exit
1,model "..." is unavailable: LLM request failed: ...— the endpoint inLLM_BASE_URLrefused or failed the request. For a local model: check the local server is running at that URL and actually serves the model name you typed. - Exit
2,--modelo: model name must not be empty— the flag was given without a value (typically--modelo "$VAR"withVARunset in CI). Name a model or drop the flag. No issues found., exit0— the chosen model was available and reported nothing. This is a healthy result, distinguishable from unavailability by the exit code and the absence of the error lines.
MUT-001 note
The skeptical mutation makes the unavailable-model path hand the engine a
deterministic empty review instead of the error
(selectProviderForModel's final return nil, "", errors.New(...) →
returning a review.FakeProvider with {"issues":[],"summary":"ok"}):
the command then prints No issues found. and exits 0 for a model
nothing serves, and the acceptance fails. The mutation is applied only to
a scratch staged copy inside tests/acceptance/AUR-436.sh::mutation_case;
the committed source contains no mutation hook, and the unmutated binary
reproduces the exact GREEN in the same run.
Scope
This card changes only cmd/aurumcode (flag parsing, provider selection
for the chosen model, the unavailability error). The review pipeline —
analyzer, prompt, parser, reviewer, providers — is byte-untouched, and
every contract published by AUR-430 and AUR-431 (output format, exit
codes, no-flag provider selection) holds verbatim.