Skip to content

Commands report failure on stderr but exit 0: Environment.ExitCode is discarded by System.CommandLine #484

Open

Description

@IanFrelinger

Several commands report a failure on stderr and then exit 0, so a caller checking $? cannot distinguish "it worked" from "it refused".

Cause. These handlers set Environment.ExitCode inside a void handler bound via SetHandler. Main returns await root.InvokeAsync(args) (Program.cs:87), so the process exit code is ctx.ExitCode — never set — and Environment.ExitCode is discarded.

The codebase already knows this. MeshCommand.cs:69-71 states the rule verbatim: "setting ctx.ExitCode is the only exit code System.CommandLine honours. Environment.ExitCode is overwritten back to 0 after the handler returns." It was applied to mesh health in round 3 and not to the rest.

Confirmed blockers

  1. ashlar mesh --set-trust-tier ghost-peer:trusted → stderr Peer 'ghost-peer' not found in instances.json., exit 0. Same for a malformed tier value. By contrast mesh admit / mesh revoke correctly exit 1 for the identical missing-peer condition. A trust-tier change that did not happen looks like success. (MeshCommand.cs:226, :234)
  2. ashlar rollback no-such-adaptation-id → stderr No snapshot found for adaptation …, exit 0. A script doing ashlar rollback "$id" || alert treats a restore that never happened as a success. (RollbackCommand.cs:96; :69 has the same defect for the usage error)

Same pattern, found by grep

AdaptCommand.cs:79, AnalyzeBricksCommand.cs:65, ComposeCommand.cs:57,78,91,98, ImproveCommand.cs:444,451,510, IngestFailuresCommand.cs:60, ObserveCommand.cs:108, DockerCommand.cs:238,300,313,369,441,477,517,604,669,731.

DockerCommand.cs:441 is Environment.ExitCode = result.ExitCode, which means ashlar docker run cannot propagate a container's exit code at all.

Fix: route every one through ctx.ExitCode. Worth a test that asserts a non-zero exit for each refusal path, since the failure mode is invisible to any test that only checks stderr text.

Found by the round-3 CLI hunt lane bb-cli-contract (78 probes).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions