Skip to content

fix: usage errors exit 3, disjoint from the honest lane - #20

Merged
chaoz23 merged 2 commits into
mainfrom
fix/usage-errors-exit-3
Aug 25, 2026
Merged

chaoz23 merged 2 commits into
mainfrom
fix/usage-errors-exit-3

Conversation

@chaoz23

@chaoz23 chaoz23 commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Closes #15.

The defect

FAMILY.md clause 1: exit 2 is the honest lane — a first-class cannot-adjudicate verdict a consuming agent routes to a human without retrying. A malformed invocation is the opposite: the caller should fix the call and retry.

dmcheck returned 2 for both. They were distinguishable only by whether stdout happened to carry JSON, so an agent following the docs escalated its own bad calls to a human as if they were rulings.

srdcheck's exit 3 is the family precedent, and clause 1 now says so explicitly.

The fix

argparse hardcodes exit 2 in parser.error(), so main() builds an ArgumentParser subclass that exits 3 instead. Nothing else moves:

invocation before after
clean session 0 0
findings 1 1
unreadable input (honest lane) 2 2
unknown flag 2 3
unknown command 2 3

The packaging-incomplete path and every unusable-input envelope stay on 2 — those are verdicts, not bad calls.

Docs and tests

SKILL.md and tool.json updated to match. A code change that leaves the contract prose stale is the exact defect this whole effort exists to catch.

New regression tests assert usage errors exit 3 and that a legitimate honest-lane refusal stays on 2 — the real risk here is over-applying the change, so both directions are locked. Suite: 157 tests, only the pre-existing test_packaging build-backend env error, verified identical on untouched main.

Release note

0.6.0 is unreleased (tool.json: "public 0.5.5 predates this contract"), so this contract change folds into it rather than breaking a shipped version.

Pin bump

Bundled, and required: chaoz23/srdcheck#88 removed this waiver, and the ratchet fails a waiver that no longer fires. Fix without pin bump → STALE BASELINE.

Remaining for dmcheck: #14 (--pipe), now its only waived finding.

🤖 Generated with Claude Code

chaoz23 and others added 2 commits August 25, 2026 13:31
FAMILY.md clause 1: exit 2 is the honest lane -- a first-class
cannot-adjudicate verdict a consuming agent routes to a human WITHOUT
retrying. A malformed invocation is the opposite: the caller should fix the
call and retry.

Sharing one code made the two indistinguishable, so an agent following the
docs escalated its own bad calls to a human as if they were rulings. Exit 3
is the family precedent, set by srdcheck.

Implemented by overriding ArgumentParser.error(), which hardcodes exit 2.
The packaging-incomplete path and every unusable-input envelope stay on 2 --
those are verdicts, not bad calls.

SKILL.md and tool.json updated to match -- a code change that leaves the
contract prose stale is the exact defect this whole effort exists to catch.
Regression tests assert usage errors exit 3 AND that legitimate refusals stay
on 2, because the risk here is over-applying the change.

Also bumps the family-conformance srdcheck pin to the first baseline that no
longer waives HONEST_LANE_OVERLOAD; both must land together or the ratchet
fails with STALE BASELINE.

Closes #15

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
scripts/assert_test_collection.py pins the collected-test count so pytest
cannot silently stop collecting part of the suite. Three tests added in this
branch, so 202 -> 205. Updated deliberately, which is the point of the ratchet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chaoz23
chaoz23 merged commit ec62ffd into main Aug 25, 2026
6 checks passed
@chaoz23
chaoz23 deleted the fix/usage-errors-exit-3 branch August 25, 2026 20:35
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.

[DMC-010] Exit 2 is overloaded between the honest lane and argparse usage errors

1 participant