Skip to content

reconverge says exactly what went wrong, and we print the six lines that do not #19

Description

@vyncint

Where

crates/launchbound-prune/src/runner.rs:112-127. When cargo reconverge exits with anything other than 0 or 1, the failure is reported like this:

let stderr = String::from_utf8_lossy(&output.stderr);
let tail: String = stderr
    .lines()
    .rev()
    .take(6)          // <- the last six lines
    ...
AnalyzerOutcome::ToolError {
    detail: format!("cargo reconverge exited {exit_code}:\n{tail}"),
}

Why the last six lines are the wrong six

reconverge prints its diagnostic first and then its usage text. Measured on a real failure (cargo reconverge check --cc 80):

  • 45 lines of stderr
  • line 1 is the message: error: `80` is not a compute capability; expected e.g. `8.6`
  • lines 2–45 are the usage text, ending with the exit-code legend

So .rev().take(6) reliably captures the legend, and reliably discards the diagnosis:

TOOL ERROR (hard stop): cargo reconverge exited 2:
                        with their recorded reasons

Exit codes: 0 = no findings at deny/confirmed confidence, 1 = findings,
2 = tool error. Findings accepted by the baseline never gate the exit
code, and their count is always reported.

It even begins mid-sentence — with their recorded reasons is the tail of --show-suppressed's description — which is why the block reads as corruption rather than as a message.

This is not specific to --cc. Any reconverge failure that ends in usage text lands here, and reconverge prints usage on every argument error.

Fix

Prefer the lines that say what went wrong. reconverge marks them: they start with error:.

let lines: Vec<&str> = stderr.lines().collect();
let errors: Vec<&str> = lines.iter().copied().filter(|l| l.starts_with("error:")).collect();
let detail = if errors.is_empty() { first_n(&lines, 6) } else { errors.join("\n") };

Falling back to the head rather than the tail when nothing matches, since a tool that prints usage puts the reason first. Worth taking the sibling issue on reconverge's side too — it should not need 44 lines of usage to report a bad flag value — but launchbound should read it correctly either way, because it cannot control what its analyzer prints.

A second thing this exposes

The same detail is repeated once per configuration. Eleven identical blocks for one cause. A tool error is a property of the invocation, not of the candidate — worth collapsing identical tool errors into one report with a count, which is also what makes the output readable at corpus scale (101 candidates).

Done when

A reconverge failure reports the line reconverge wrote to explain it, and identical failures are not repeated once per candidate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions