What checking a fix revealed
September's prod-code fixes exposed a per-file exception that skipped its own case, a refusal that said too much, and an estimated cost replaced by a reported measurement. What those records teach about checking a fix.
On this page · 4 sections
The previous post described work on prod-code using prod-code itself. Six issues were filed during that work on September 22–23; a seventh, about the coverage script, followed while checking a fix. The interesting part of the repair record is how the proposed fixes changed when applied to the cases that prompted them.
This account uses the linked issue reports, pull requests and their source changes. The terminal excerpts and durations are author-reported historical observations, not measurements reproduced for this post. The PRs record passing tests, but do not establish that every test passed on its first run or preserve the complete order of all development checks. The source changes let us inspect what was implemented; they do not independently prove that a reported execution happened.
A rule that skipped its own file
Issue #97 reported that extract_function
introduced std::prelude::v1::Result<McpToolCallResult, anyhow::Error> while splitting the
MCP dispatcher. PR #105 reports that 32
signatures needed a subsequent structural replacement. Its fix shortened prelude paths
introduced by an assist, then used analyzer diagnostics to decide whether to retain the
shorter spelling.
The first version skipped any file already containing the prefix. The PR records why that
failed on tools.rs: the implementation’s own constant and documentation contained
std::prelude::v1::. The exception excluded the file used for the check.
The reported extraction initially retained the qualified path:
+async fn fun_name(remote: SocketAddr) -> std::prelude::v1::Result<McpToolCallResult, anyhow::Error> {
The revised implementation compares complete lines against the original file. Lines already present keep their spelling; other lines containing the prefix become candidates for shortening. This is a textual line comparison, not a proof of semantic equivalence. The proposal is kept only if the analyzer check accepts it.
The PR quotes this result:
1 `std::prelude::v1::` path(s) the assist wrote are spelled as the name already in scope; the analyzer accepts the shorter spelling
[3.45s]
+async fn fun_name(remote: SocketAddr) -> Result<McpToolCallResult, anyhow::Error> {
It reports 3.45 seconds with the extra validation and 0.18 seconds without it, for this
extraction. Those two observations are not a general overhead estimate. The same PR notes
that extracting only a connect statement already produced a short Result path, so that
case would not exercise the new shortening step.
Messages need boundaries too
Issue #99 reported an unhelpful refusal
inside tokio::select!: the requested extraction was unavailable, and the message only
listed inline_macro. The first proposed explanation generalized this to no refactoring
inside macro input.
PR #104 records a counterexample from its test with macro detection deliberately disabled:
assist `extract_function` is not offered here; available: extract_variable, extract_constant, extract_static, inline_macro
The implemented refusal names the enclosing macro and the particular unavailable assist. That describes the selection under examination; it does not establish that the same assist is unavailable in every macro or analyzer version.
Issue #94 concerns a different boundary: an analyzer panic is not a successful check. PR #103 turns a panic during a file’s diagnostics query into one error at that file’s top. The message says nothing in it was checked and points to compilation as a remaining check. The baseline logic explicitly preserves that diagnostic even when the original file also panicked.
The source also trims trailing full stops from the panic payload before inserting its own sentence separator. Its test checks the complete phrase with one full stop. This supports the formatting behavior, without reconstructing an undocumented first-run history.
A number that was not measured
Issue #98 reported a rename that wrote
duplicate definitions. PR #101 added a
check of the planned file texts in an analyzer overlay before writing. It refuses when
error diagnostics remain after baseline handling, unless the caller supplies force.
File moves are explicitly reported as outside that pre-write check.
The PR’s edit history preserves the change in its cost claim: the version at 2026-09-23 00:41:48 UTC said “0.2–0.5 s on a warm engine”; at 00:42:37 UTC, the description instead reported a 9.8-second rename refusal on a Linux build node with a development client. The available record does not provide repeated runs or a complete environment specification.
That report says the analyzer returned ten errors at renamed call sites, including:
the trait bound Vec<String>: Future is not satisfied
expected 1 argument, found 3
It did not report the duplicate definition itself in that case. The report attributes the
refusal to checking the renamed files, including callers, rather than only the declaration.
Its historical output says “the result does not compile”, but this path used analyzer
diagnostics, not a rustc invocation. An empty diagnostic result would not prove compilation
success. The useful observation is narrower: this rename was reported refused, and an
unsupported latency estimate was replaced by an observation with a stated workload.
Keep the observation with the fix
Two surrounding-tool issues show why the record matters. Issue #95 reports a query-log flood and journald suppressing messages, including useful gateway output. Issue #102 reports the coverage gate rejecting a file containing only re-exports, then discarding a temporary report after a seven-minute instrumented run. These are reported operational failures, not evidence that every query or coverage run behaves that way.
The sixth original issue, #93, tracked CLI gaps. Its closing PR #106 also added multi-file validation. The PR shows a new constant and its re-export failing when proposed separately, then quotes a combined check:
prod-code validate crates/prod-code-protocol/src/lib.rs --from lib_demo.rs --with crates/prod-code-protocol/src/messages.rs=messages_demo.rs
The recorded output reports zero diagnostics in both files and 1.57 seconds. It demonstrates what that PR reported for the example; it is neither a new timing measurement nor a promise that the CLI covers every MCP capability.
For the next fix, keep the failing case, the proposed change and the observed output together. State which check ran, what it could detect and what remained unchecked. A passing fixture is useful evidence about that fixture. The actual caller, file contents and diagnostic message can ask a different question.
Cite this article
Alexander Panasenko (2026-10-12). What checking a fix revealed. https://prod.codes/blog/the-bug-in-every-fix/