Pular para conteúdo

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):

  1. 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.
  2. 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 wire model, overriding LLM_MODEL. A local model is chosen by pointing LLM_BASE_URL at 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.go proves with a loopback httptest endpoint that the name typed after --modelo is 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 — neither AURUMCODE_LLM_FIXTURE nor LLM_API_KEY+LLM_BASE_URL is set. Configure one of them as the message says.
  • Exit 1, model "..." is unavailable: LLM request failed: ... — the endpoint in LLM_BASE_URL refused 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" with VAR unset in CI). Name a model or drop the flag.
  • No issues found., exit 0 — 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.