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.
EXIT_USAGE = 64is declared atgerberdiff/cli.py:25and used at four call sites, and a usage error still exits 2.Reproduced
On
main, 2026-09-11: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. Unlessparse_argsis wrapped, that propagates out before any of this repo'sEXIT_USAGEreturns are reached — those cover gerberdiff's own validation, not argparse's.Why it matters here specifically
2is not a spare number in this repo.0685cdemade itindeterminate— the third diff outcome, "part of the comparison could not be made", the whole point of adjudication A3. TheAGENTS.mdadded 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-106does it, citing this repo and netspec as the reason:The
--helpcarve-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-defectlabel. On §2's axis this looks like a misroute — a real failure attributed to the wrong cause — which the contract says qualifies, and2carrying 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.mdV14 in slicelab's frozen dossier, which recorded it and noted nobody had filed it.