Skip to content

fix(cli): exit 1 when refactor target is not found - #275

Open
Akshay0047 wants to merge 3 commits into
Anandb71:mainfrom
Akshay0047:fix/195-refactor-missing-symbol-exit
Open

Akshay0047 wants to merge 3 commits into
Anandb71:mainfrom
Akshay0047:fix/195-refactor-missing-symbol-exit

Conversation

@Akshay0047

@Akshay0047 Akshay0047 commented Oct 13, 2026 •

Copy link
Copy Markdown

Fixes #195.

arbor refactor <missing-symbol> exited 0. refactor mapped
resolve_symbol_ranked's Err to None and fell through to
suggest_similar_symbols, which prints a hint and returns Ok(()), so
main.rs never reached its process::exit(1) path. Scripts and CI could
not distinguish "refactor target exists" from "no such symbol."

The fix binds the original Err(e) and returns it after still running
suggest_similar_symbols (its return is discarded with let _ =; the
suggestion output is deliberately preserved). inspect and callers
already propagate this error the same way, so the new exit code matches
existing convention.

Test

refactor_not_found_symbol in
crates/arbor-cli/tests/graph_commands_integration.rs, next to
callers_not_found_symbol. Spawns the built binary, asserts non-zero
exit, and asserts the suggestion hint is still on stdout.

Verified failing on pre-fix code:

assertion failed: !output.status.success()
test refactor_not_found_symbol ... FAILED

and passing after:

test refactor_not_found_symbol ... ok

cargo fmt --all -- --check and cargo clippy --workspace --all-targets --all-features are clean.

Scope

Note on behavior

The previous code path had two matches and returned
suggest_similar_symbols's own error on failure; the new path always
returns the resolve_symbol_ranked error. Both exit 1 and both write to
stderr, so user-visible behavior is unchanged, but flagging it in case a
reviewer wants the old precedence preserved.

Round 2 (review feedback)

  • Gated the suggest_similar_symbols hint on !json_output, so
    arbor refactor missing --json writes nothing to stdout.
  • Added a --json case to refactor_not_found_symbol that asserts
    non-zero exit, empty stdout, and not found on stderr.
  • Added a not found assertion to the non-json case, matching
    callers_not_found_symbol.
  • Added CHANGELOG entry under [Unreleased] (rebased on main).
  • Corrected the description: arbor refactor "" now exits 1 too, which
    is the intended behavior.

@Anandb71 Anandb71 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, @Akshay0047, and welcome to Arbor! The write-up was easy to review: the root-cause explanation, the before/after test output and the scope notes all helped.

What I verified

  • Built the PR head locally:
    • cargo fmt --all -- --check is clean.
    • cargo clippy -p arbor-graph-cli --all-targets --all-features -- -D warnings is clean.
    • cargo test -p arbor-graph-cli is all green.
  • refactor_not_found_symbol fails against the pre-fix commands.rs and passes with your change.
  • Ran the binary against a small fixture:
    • arbor refactor nonexistent_xyz . exits 1, keeps the hint on stdout and prints error: Symbol 'nonexistent_xyz' not found on stderr. That's the same stderr message and exit code as inspect and callers.
    • A symbol that exists behaves exactly as before: exit 0, and valid JSON with --json.
  • main.rs is the only caller of commands::refactor. The Claude Code hook only allow-lists arbor refactor *, and neither receipts nor MCP run it as a subprocess, so agent workflows aren't affected.
  • It merges cleanly with current main.
  • About your "note on behavior": suggest_similar_symbols never actually returns Err, so there's no old error precedence to keep. Returning the resolve error is the right call.

CI: Because this is your first PR from a fork, GitHub holds the Rust CI, PR Bot and Benchmarks runs until a maintainer approves them. That's why only GitGuardian shows up so far. We'll approve them.

Requested changes (both small)

  1. --json on a missing symbol (crates/arbor-cli/src/commands.rs:2640-2644). arbor refactor nonexistent_xyz . --json still prints the human-readable "Couldn't find … / Tips" block on stdout. A script doing arbor refactor "$SYM" --json | jq then gets a parse error instead of empty stdout. inspect --json and callers --json print nothing on stdout in the same case. This predates your PR (it used to be that same text with exit 0), but it's the exact line you're editing. Could you gate the hint on !json_output?

    Err(e) => {
        if !json_output {
            let _ = suggest_similar_symbols(&graph, target);
        }
        return Err(e);
    }

    Please also add a --json case to the test that asserts a non-zero exit and empty stdout.

  2. CHANGELOG. CONTRIBUTING asks for user-visible changes under ## [Unreleased], and a new exit code counts. Please rebase on main first: 3.0.5 added a section right below [Unreleased], so an entry on the current base would conflict there. Something like:

    ### Fixed
    - **`arbor refactor` exited 0 for a missing symbol (#195):** it now exits 1 and prints `error: Symbol '<name>' not found` to stderr after the "Did you mean" suggestions, matching `inspect` and `callers`.

Nits (optional)

  • In refactor_not_found_symbol, could you also assert stderr.contains("not found"), as callers_not_found_symbol does? Scripts depend on that line.
  • The description says arbor refactor "" is unchanged. With this PR it also exits 1 (error: Symbol '' not found), which I think is the right outcome. It's just worth updating the description to match.

One follow-up on our side, not something this PR needs to do: the VS Code extension only shows stderr when arbor exits non-zero. So "Analyze Impact" on a typo will now say "Is Arbor installed?" and lose the "Did you mean" hints. We'll fix that separately.

Thanks again! Once those two changes are in and CI is green, this is good to merge.

Review feedback on Anandb71#195. When --json is set and the symbol is missing,
arbor refactor still wrote the human-readable 'Couldn't find / Tips'
block to stdout, so scripts piping to jq got a parse error instead of
empty stdout. Gate the suggest_similar_symbols hint on !json_output.

Add a --json case to refactor_not_found_symbol that asserts non-zero
exit, empty stdout, and 'not found' on stderr. Also assert 'not found'
on stderr in the non-json case, matching callers_not_found_symbol.

CHANGELOG entry under [Unreleased].
@Akshay0047
Akshay0047 force-pushed the fix/195-refactor-missing-symbol-exit branch from 6dcada5 to 9883bc0 Compare October 14, 2026 19:17
@Akshay0047

Akshay0047 commented Oct 14, 2026 •

Copy link
Copy Markdown
Author

Done @Anandb71 — both requested changes are in, plus the two nits.

  • commands.rs: gated the hint on !json_output (exact snippet from the
    review).
  • graph_commands_integration.rs: added a --json case that asserts
    non-zero exit, empty stdout, and not found on stderr; added the
    not found assertion to the non-json case.
  • CHANGELOG.md: entry under [Unreleased], added after rebasing on
    main to avoid the 3.0.5 section conflict.
  • Updated the PR description re: arbor refactor "" now exiting 1.

Rebased on upstream/main (e10cb78, includes v3.0.5). Pushed with
--force-with-lease since the rebase rewrote history.

Thanks for the note about suggest_similar_symbols never returning Err —
kept the resolve error as the returned one, as you suggested. Ready for
another look when you have a moment.

@Akshay0047
Akshay0047 requested a review from Anandb71 October 15, 2026 09:16

@Anandb71 Anandb71 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick turnaround, @Akshay0047! The round-2 write-up was again very easy to follow.

Requested change 1 (--json on a missing symbol): done ✅

  • commands.rs now gates suggest_similar_symbols on !json_output and returns the resolve error, exactly as suggested.
  • I built 9883bc0 and ran it against a small indexed fixture:
    • arbor refactor nonexistent_xyz . --json exits 1. Stdout is completely empty and stderr is error: Symbol 'nonexistent_xyz' not found, so | jq no longer chokes.
    • Without --json, it still prints the "Couldn't find / Tips" hint on stdout and exits 1.
    • An existing symbol with --json exits 0 and prints valid JSON.
    • arbor refactor "" . exits 1 with error: Symbol '' not found, matching your updated description.
  • The new --json case and the not found stderr assertions in refactor_not_found_symbol look good, and the test passes.
  • Locally: cargo fmt --all -- --check is clean, cargo clippy -p arbor-graph-cli --all-targets --all-features -- -D warnings is clean, and cargo test -p arbor-graph-cli is all green.
  • It merges cleanly with main (e10cb78).

Requested change 2 (CHANGELOG): one small fix still needed
The entry landed at CHANGELOG.md:36, at the end of the ## [3.0.4] ### Fixed list. ## [Unreleased] (line 8) is still empty. That's probably just the rebase moving it. As it stands, the next release notes would miss the fix, and 3.0.4 would appear to have shipped it. Could you move it up like this?

## [Unreleased]

### Fixed
- **`arbor refactor` exited 0 for a missing symbol (#195):** it now exits 1 and prints `error: Symbol '<name>' not found` to stderr after the "Did you mean" suggestions, matching `inspect` and `callers`.

## [3.0.5] - 2026-10-09

If you'd rather, say so and we can move it while merging. "Allow edits by maintainers" is on.

CI

  • GitHub is still holding the Rust CI, PR Bot and Benchmarks runs for this fork until a maintainer approves them. That's why only GitGuardian shows so far.
  • That's on us: we'll approve them, and we'll merge once the CHANGELOG line is moved and those runs are green.

Thanks again, and welcome aboard!

The rebase on v3.0.5 changed which section was at the top of the file,
so the entry landed inside [3.0.4] ### Fixed. Moved to [Unreleased] per
review; the next release notes would have missed it otherwise.
@Akshay0047

Copy link
Copy Markdown
Author

Done @Anandb71 — moved the entry to ## [Unreleased] ### Fixed and removed it from
[3.0.4]. Rebase artifact: it was written when the current ### Fixed
section was at the top of the file, and rebasing on 3.0.5 changed which
section that was.

Pushed as a small chore(changelog): commit. The commands.rs gate and
test assertions are unchanged from 9883bc0.

Thanks for catching it. Ready when CI is approved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor exits 0 when the symbol does not exist

2 participants