v1.14.0
Sandbox-rerun gets a runner. review.sandbox_command binds the executor seam that shipped inert in v1.12.0 — a list of argv elements, never a shell string, templated over the flagged test's file, line and name. Binding requires a double opt-in, and the MCP server and guard never run it.
Added
-
review.sandbox_commandbinds the sandbox-rerun executor (ADR-0033).--sandbox-rerun[=N]/review.sandbox_rerunshipped in v1.12.0 as a documented no-op — the rerun orchestration existed, but no runner was bound. A newreview.sandbox_commandconfig key closes that gap: a list of argv elements, never a shell string, each rendered as a Gotext/templateover{{.File}}(repo-relative),{{.Line}}, and{{.Test}}(the enclosing test function name), then handed directly toexec.CommandContext. No shell is invoked, so there is no quoting or injection surface.review: sandbox_rerun: 5 sandbox_command: ["go", "test", "-count=1", "-run", "^{{.Test}}$", "./..."] -
Binding requires a double opt-in — a positive
--sandbox-rerun/review.sandbox_rerunand a non-emptyreview.sandbox_command. Either alone stays inert, so the default path is byte-identical to v1.13.0’s static detector. -
config set review.sandbox_commandis rejected (hand-edit only, matching the existing treatment ofguard.secret_patterns): a config surface that can arm code execution deserves the same friction as one that can disable secret scanning. -
Each attempt runs under its own 2-minute timeout, so one hung test costs one attempt rather than the whole review. A stderr notice names the configured command template — the un-rendered argv — once per review, before any per-finding rendering happens. The review path has never before executed code, so it is never silent about it.
-
The command runs against the working tree, not the staged snapshot a review may be scoped to, because that is what the bound command actually executes against. Sandbox-rerun is not cached: the flaky pre-pass runs before the cache lookup, so a repeated review against the same diff still re-executes the command even when the review body itself is served from cache.
-
commitbrief mcpandcommitbrief guardnever run the bound command, unconditionally and with no user-facing toggle. Both drive the review through the sharedrunReviewForMCPseam, and an agent host must not execute repository code unattended — their flaky findings stay at the static-only confidence level even when a runner is configured.
Changed
flaky.Executorwidens to aTargetstruct (ADR-0033 §9, internal). The rerun seam took an opaquetestID string; it now takesTarget{File, Line, Test}so a bound command’s template can address the test by name instead of re-parsing a"file:line"string. The seam had no shipped consumer before this release, so the change is free.- Test-name resolution (
flaky.EnclosingTest) is Go-only: it parses*_test.gofiles withgo/parser/go/astand returns no name for every other language, after three fix rounds of a hand-rolled multi-language scanner kept producing confident wrong names — a worse outcome than not confirming at all. A finding whose test name can’t be resolved skips the rerun (with a stderr warning) and keeps its bare static finding. Python / JS / PHP / Java tests keep full static flaky detection; they just never get sandbox-rerun confirmation.