Skip to content

bug(cli): wrong exit code on too many args for review submit and preview #2418

Description

@DS123-ally

I'd like to work on this — planning a small CLI-only fix.

Scope: backend/internal/cli/ only — wrap arg-count validators for ao review submit and ao preview (including ao preview clear) so misuse returns usageError and exits 2, matching AGENTS.md and the rest of the CLI.

Approach:

  • Add/reuse an atMostOneArg helper (same pattern as noArgs in root.go)
  • Wire it into review submit and preview
  • Use noArgs for preview clear instead of bare cobra.NoArgs
  • Add table tests asserting exit code 2 for too-many-args cases

No daemon/API/OpenAPI changes. I'll open a PR once tests pass locally.


---

## Issue description (full body)

### Summary

`AGENTS.md` documents a CLI convention: **usage errors exit 2; runtime/daemon failures exit 1**. Two commands break that convention for **argument-count misuse** — they exit **1** instead of **2** when too many positional args are passed.

Affected commands:

- `ao review submit`
- `ao preview`
- `ao preview clear`

### Expected behavior

When a user passes the wrong number of positional arguments, the process should exit **2** (usage error), consistent with other commands like `ao session get`, `ao completion`, and `ao project add`.

### Actual behavior

Passing too many args exits **1** (generic failure), which misleads scripts and wrappers that distinguish usage misuse from daemon/runtime errors.

### Reproduction

```bash
$ ao review submit mer-1 mer-2
Error: accepts at most 1 arg(s), received 2
$ echo $?
1   # expected 2

$ ao preview http://localhost:5173 extra
Error: accepts at most 1 arg(s), received 2
$ echo $?
1   # expected 2

$ ao preview clear extra
Error: unknown command "extra" for "ao preview clear"
# (or similar arg-count error — should exit 2, not 1)
$ echo $?
1   # expected 2

Root cause

In backend/internal/cli/:

File Current validator
review.go Args: cobra.MaximumNArgs(1) on review submit
preview.go Args: cobra.MaximumNArgs(1) on preview
preview.go Args: cobra.NoArgs on preview clear

Cobra's built-in arg validators return plain errors.New(...). The root command's SetFlagErrorFunc only wraps flag parse errors as usageError, not Args validation errors. So arg-count failures are not recognized as usage errors and ExitCode() returns 1.

Other commands already follow the correct pattern — they wrap Cobra validators so misuse becomes usageError:

  • noArgs in root.go (used by ao start, ao stop, etc.)
  • oneSessionIDArg, sessionRenameArgs in session.go
  • Inline wrappers in project.go, completion.go

Existing tests for these commands already assert exit 2 for other usage errors (e.g. TestReviewSubmitMissingVerdictIsUsageError, TestPreview_MissingSessionIDIsUsageError), but no test covers arg-count misuse for review/preview.

Proposed fix (CLI-only)

  1. Add a shared helper in root.go:

    func atMostOneArg(cmd *cobra.Command, args []string) error {
        if err := cobra.MaximumNArgs(1)(cmd, args); err != nil {
            return usageError{err}
        }
        return nil
    }
  2. Use atMostOneArg for review submit and preview.

  3. Use existing noArgs for preview clear instead of cobra.NoArgs.

  4. Add tests:

    • TestReviewSubmitTooManyArgsIsUsageError
    • TestPreview_TooManyArgsIsUsageError
    • TestPreviewClear_TooManyArgsIsUsageError

Out of scope

  • No daemon, HTTP, SQLite, or OpenAPI changes
  • No new CLI commands or flags
  • No changes to flag-validation paths (those already work)

Test plan

cd backend
go test ./internal/cli/ -run 'TestReviewSubmit|TestPreview' -count=1
go test ./internal/cli/ -count=1

Manual smoke:

ao review submit a b; echo $?    # should print 2
ao preview a b; echo $?          # should print 2
ao preview clear x; echo $?      # should print 2

References

  • Contributor convention: AGENTS.md"Return usage errors as usageError so CLI misuse exits 2"
  • Exit code mapping: backend/internal/cli/root.gousageError + ExitCode()
  • Prior art: noArgs, oneSessionIDArg, completion.go arg wrapper

Files to change

File Change
backend/internal/cli/root.go Add atMostOneArg helper
backend/internal/cli/review.go Args: atMostOneArg on review submit
backend/internal/cli/preview.go Args: atMostOneArg on preview; Args: noArgs on preview clear
backend/internal/cli/review_test.go TestReviewSubmitTooManyArgsIsUsageError
backend/internal/cli/preview_test.go TestPreview_TooManyArgsIsUsageError, TestPreviewClear_TooManyArgsIsUsageError

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions