# bugfix mut-diag-double-code — doubled `[code]` prefix in mut-local human diagnostics **Date:** 2026-05-15 **Status:** DONE **Trigger:** fieldtest finding F2 (`docs/specs/2026-05-15-fieldtest-mut-local.md`). **Started from:** 1faee67 ## Symptom Non-JSON `ail check` stderr rendered the kebab diagnostic code twice for the four mut-local `CheckError` variants, e.g. ``` error: [mut-var-captured-by-lambda] main: [mut-var-captured-by-lambda] mut-var `x` cannot be captured... ``` ## Cause `MutAssignOutOfScope`, `AssignTypeMismatch`, `UnsupportedMutVarType`, `MutVarCapturedByLambda` were authored in iters mut.2 / mut.4-tidy with their `#[error("[] ...")]` `thiserror` Display bodies embedding the bracketed code. The non-JSON `Cmd::Check` formatter in `crates/ail/src/main.rs` independently prepends `[{d.code}]` from `CheckError::code()`. Embedded + prepended = doubled. The non-mut `CheckError` variants never embedded the bracket, so only these four doubled — they were the inconsistent ones, brought in line here. ## Fix RED-first via the `debug` skill (`ailang-debugger` wrote the failing test; the GREEN side was a trivial four-string mechanical edit applied inline by the Boss per the CLAUDE.md trivial-mechanical-edit carve-out — no review-and-commit discipline shed). - RED test: `crates/ail/tests/ct1_check_cli.rs` — `check_human_mode_renders_mut_diagnostic_code_exactly_once`. Pins the *observable* property: the code appears exactly once in the rendered human diagnostic, exercising the same formatter path the CLI uses (not a brittle assertion on the raw `#[error]` body). - GREEN: dropped the leading `[] ` literal from the four `#[error(...)]` Display strings in `crates/ailang-check/src/lib.rs`. The mut-typecheck pin tests (`mut_typecheck_pin.rs`) and the in-source unit assertions match on the struct variants / `code()`, not the Display string, so the prefix removal did not touch them. ## Tests 598 → 599 green (the new RED-now-GREEN human-formatter test). Full workspace clean, zero failures. ## Not in scope (stays queued) F1/F4 (accumulator-over-iteration: the milestone motivation is unmet without a loop construct) and F3 (zero-arg `(app f)` rejected at parse) from the same fieldtest are NOT addressed here — they are design/roadmap items, not this bug.