Skip to content

EXIT_USAGE is declared as 64, and a bad flag exits 2 #30

Description

@CameronBrooks11

EXIT_USAGE = 64 is declared at gerberdiff/cli.py:25 and used at four call sites, and a usage error still exits 2.

Reproduced

On main, 2026-09-11:

$ uv run gerberdiff --bogus-flag; echo $?
2

partspec, which does the remap, exits 64. netspec has the identical defect and is filed at heibench/netspec#37.

The mechanism

argparse calls sys.exit(2) internally on an unrecognised flag. Unless parse_args is wrapped, that propagates out before any of this repo's EXIT_USAGE returns are reached — those cover gerberdiff's own validation, not argparse's.

Why it matters here specifically

2 is not a spare number in this repo. 0685cde made it indeterminate — the third diff outcome, "part of the comparison could not be made", the whole point of adjudication A3. The AGENTS.md added in #29 documents it as such.

So today a mistyped flag and a board that could not be fully compared return the same code, and a caller cannot tell them apart. That is the distinction A3 existed to create, reachable by typo.

The shape of the fix

slicelab/cli.py:100-106 does it, citing this repo and netspec as the reason:

try:
    parser.parse_args(argv)
except SystemExit as exc:
    # --help and --version raise SystemExit(0); that is a successful run.
    code = exc.code
    if code in (0, None):
        return 0
    return EXIT_USAGE

The --help carve-out matters: SystemExit(0) is a successful run and must not become 64.

And the test should measure a real process rather than assert the constant — declaring 64 while returning 2 is exactly what happened here, and a test on the constant would have passed throughout.

Recorded but not decided

No silence-defect label. On §2's axis this looks like a misroute — a real failure attributed to the wrong cause — which the contract says qualifies, and 2 carrying a meaning the repo deliberately created makes it sharper here than in netspec. But the record is the org's public argument and adding a case is the author's call, so the reasoning is stated rather than the label applied.

Measurement originally from notes/evidence.md V14 in slicelab's frozen dossier, which recorded it and noted nobody had filed it.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions