# CommitBrief 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.

Released July 25, 2026

Canonical URL: https://commitbrief.com/changelog/v1.14.0/

---

## Added

- **`review.sandbox_command` binds the sandbox-rerun executor (ADR-0033).**
  `--sandbox-rerun[=N]` / `review.sandbox_rerun` shipped in v1.12.0 as a
  documented no-op — the rerun orchestration existed, but no runner was bound.
  A new `review.sandbox_command` config key closes that gap: a **list of argv
  elements**, never a shell string, each rendered as a Go `text/template` over
  `{{.File}}` (repo-relative), `{{.Line}}`, and `{{.Test}}` (the enclosing test
  function name), then handed directly to `exec.CommandContext`. No shell is
  invoked, so there is no quoting or injection surface.

  ```yaml
  review:
    sandbox_rerun: 5
    sandbox_command: ["go", "test", "-count=1", "-run", "^{{.Test}}$", "./..."]
  ```

- Binding requires a **double opt-in** — a positive
  `--sandbox-rerun` / `review.sandbox_rerun` **and** a non-empty
  `review.sandbox_command`. Either alone stays inert, so the default path is
  byte-identical to v1.13.0's static detector.
- `config set review.sandbox_command` is **rejected** (hand-edit only, matching
  the existing treatment of `guard.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 mcp` and `commitbrief guard` **never** run the bound command,
  unconditionally and with no user-facing toggle. Both drive the review through
  the shared `runReviewForMCP` seam, 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.Executor` widens to a `Target` struct (ADR-0033 §9, internal).** The
  rerun seam took an opaque `testID string`; it now takes
  `Target{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.go` files with `go/parser` / `go/ast` and 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.