Skip to content

Error contract: exit-code taxonomy and JSON error envelope (Closes #31) - #47

Closed
0xLeif wants to merge 1 commit into
mainfrom
kimi/issue-31-error-contract
Closed

0xLeif wants to merge 1 commit into
mainfrom
kimi/issue-31-error-contract

Conversation

@0xLeif

@0xLeif 0xLeif commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Closes #31.

Summary

Implements the error contract from design decision 4:

  • Exit taxonomy (sysexits-aligned): 64 usage (bad key/flags/invalidValue), 65 corrupt persisted state (decodingFailed), 69 unavailable (keychainUnavailable), 70 internal (encodingFailed), 73 write did not persist (persistenceFailed); 66 reserved. All APSError values flow through one CLIOutput.fail path instead of being flattened into ValidationError (which made everything 64).
  • JSON error envelope: with --json/--jsonl, or APS_ERROR_JSON=1, stderr additionally gets {"error":{"code","message","hint"}} with stable snake_case codes. stdout stays empty on error in every mode.
  • Loud corrupt-state: new StateStore.ensureReadable distinguishes missing files (initial-value semantics, unchanged) from existing-but-undecodable note.json/profile.json (exit 65) before get/watch output. Disk readers now split missing (persistenceFailed) from corrupt (decodingFailed); set verification maps read-back failures to persistenceFailed as before.

Verification (all local, worktree)

  • swift build clean; 42 tests (6 new: taxonomy mapping, envelope shape, envelope modes, ensureReadable missing/corrupt/corrupt-profile), 0 failures
  • smoke.sh extended and green: exit 64/65/73 assertions, stdout purity, envelope greps, APS_ERROR_JSON=1
  • specsync check --force (100% LOC) and specsync change check (15 active valid) green; fledge lanes run verify green
  • Manual exercise of every contract path

SpecSync

  • CHG-0016 accepted (feature; deltas applied to both spec modules; requirement evidence for REQ-aps-cli-002 + REQ-state-store-011)
  • Evidence rebound for CHG-0003, 0004, 0007, 0011, 0012, 0013, 0014, 0015 via audited reopen (actor 0xLeif): this PR touches files those accepted changes own

Notes

  • The envelope encodes with .withoutEscapingSlashes so paths in hints stay readable.
  • ArgumentParser's own usage errors keep their native 64 (bad key token, flag shape), consistent with the taxonomy.

- sysexits-aligned exit codes: 64 usage, 65 corrupt state, 69 unavailable,
  70 internal, 73 write did not persist (66 reserved)
- single CLIOutput.fail path: human stderr line + optional
  {error:{code,message,hint}} envelope (--json/--jsonl or APS_ERROR_JSON=1)
- StateStore.ensureReadable: corrupt note.json/profile.json exits 65
  instead of silently returning the initial value
- disk readers split missing (persistenceFailed) from corrupt (decodingFailed)
- tests + smoke assertions for the whole contract; specs/README in lockstep
- SpecSync CHG-0016 accepted; evidence rebound for CHG-0003/0004/0007/0011/
  0012/0013/0014/0015 (audited reopens, actor 0xLeif)
@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@0xLeif

0xLeif commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #50 - #43 landed the corrupt-state slice with different naming, so this was rebuilt on fresh main rather than rebased.

@0xLeif 0xLeif closed this Jul 18, 2026
0xLeif added a commit that referenced this pull request Jul 19, 2026
- sysexits-aligned exit codes for every APSError: 64 usage, 65 data
  (corruptState + decodingFailed), 69 unavailable, 70 internal,
  73 write did not persist (66 reserved)
- single CLIOutput.fail path: human stderr line + optional
  {error:{code,message,hint}} envelope (--json/--jsonl or APS_ERROR_JSON=1);
  replaces the corruptState-only reportAPSError shim and ValidationError
  flattening; dump/reset covered for the first time
- keeps CHG-0016's requireDecodableDiskState as the loud corrupt-state
  mechanism (no duplicate)
- tests + smoke assertions for the whole contract; specs/README in lockstep
- SpecSync CHG-0018 accepted; evidence rebound for CHG-0003/0004/0007/0011/
  0012/0013/0014/0015/0016/0017 (audited reopens, actor 0xLeif)

Supersedes #47 (rebuilt on post-#43 main).
0xLeif added a commit that referenced this pull request Jul 19, 2026
- sysexits-aligned exit codes for every APSError: 64 usage, 65 data
  (corruptState + decodingFailed), 69 unavailable, 70 internal,
  73 write did not persist (66 reserved)
- single CLIOutput.fail path: human stderr line + optional
  {error:{code,message,hint}} envelope (--json/--jsonl or APS_ERROR_JSON=1);
  replaces the corruptState-only reportAPSError shim and ValidationError
  flattening; dump/reset covered for the first time
- keeps CHG-0016's requireDecodableDiskState as the loud corrupt-state
  mechanism (no duplicate)
- tests + smoke assertions for the whole contract; specs/README in lockstep
- SpecSync CHG-0018 accepted; evidence rebound for CHG-0003/0004/0007/0011/
  0012/0013/0014/0015/0016/0017 (audited reopens, actor 0xLeif)

Supersedes #47 (rebuilt on post-#43 main).
@0xLeif
0xLeif deleted the kimi/issue-31-error-contract branch July 19, 2026 23:45
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.

Error contract: exit-code taxonomy + JSON error envelope

1 participant