Skip to content

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

Merged
cursor[bot] merged 3 commits into
mainfrom
kimi/issue-31-error-contract-v2
Jul 19, 2026
Merged

cursor[bot] merged 3 commits into
mainfrom
kimi/issue-31-error-contract-v2

Conversation

@0xLeif

@0xLeif 0xLeif commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Closes #31. Supersedes #47 (rebuilt onto post-#43 main; see notes).

Summary

Full error contract from design decision 4, built on top of #43's merged corruptState semantics instead of duplicating them:

  • Exit taxonomy (sysexits-aligned): every APSError now maps: 64 usage (invalidValue), 65 data (corruptState + decodingFailed), 69 unavailable (keychainUnavailable), 70 internal (encodingFailed), 73 write did not persist (persistenceFailed); 66 reserved.
  • One failure path (CLIOutput.fail): human line on stderr, optional {"error":{"code","message","hint"}} envelope (with --json/--jsonl or APS_ERROR_JSON=1), taxonomy exit code. Replaces both the old flatten-to-ValidationError bridge (everything was 64) and Add: loud torn FileState reads and multi-writer docs #43's corruptState-only reportAPSError shim. dump and reset are covered for the first time.
  • Loud corrupt-state stays with StateStore.requireDecodableDiskState (Add: loud torn FileState reads and multi-writer docs #43) — no duplicate mechanism here.
  • Stable codes: invalid_value, encoding_failed, decoding_failed, persistence_failed, keychain_unavailable, corrupt_state.

Verification (local, worktree)

  • swift build clean; 44 tests (4 new: taxonomy mapping, envelope shape, envelope modes, requireDecodableDiskState corrupt case), 0 failures
  • smoke.sh extended and green: exit 64/65/73 assertions, stdout purity, envelope greps, APS_ERROR_JSON=1
  • specsync check --force 100%, specsync change check 17 active valid, fledge lanes run verify green (4 steps incl. plugin validate)
  • Every contract path exercised manually (invalid/corrupt/unwritable/env opt-in)

SpecSync

  • CHG-0018 accepted (feature; full-section deltas for aps-cli; requirement evidence for REQ-aps-cli-002)
  • Evidence rebound for CHG-0003, 0004, 0007, 0011, 0012, 0013, 0014, 0015, 0016, 0017 via audited reopen (actor 0xLeif)

Notes on the rebuild

#47 was invalidated when #43 landed the corrupt-state slice with different naming (corruptState vs my decodingFailed) and its own exit mapping. Rather than fight a 3-way conflict, this branch re-applies only the remaining contract delta on fresh main: #43's case name, requireDecodableDiskState, and the jsonl corrupt-state watch event are kept as-is.

@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 added 2 commits July 18, 2026 18:06
- 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).
Main took CHG-0018 (Windows audit), CHG-0019 (PowerShell smoke), and
CHG-0020 (windows tests) while this branch was in flight; the error
contract change is recreated as CHG-0021 and all shared accepted changes
are rebound (audited reopens, actor 0xLeif).
@0xLeif
0xLeif force-pushed the kimi/issue-31-error-contract-v2 branch from e2a3b68 to 5e6433c Compare July 19, 2026 00:19
Sync @mainactor XCTest methods break Linux package test discovery;
async throws matches the rest of APSTests and unblocks linux-smoke.

Co-authored-by: Cursor <cursoragent@cursor.com>
@0xLeif

0xLeif commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Cursor babysit: linux-smoke failed because testRequireDecodableDiskStateCorruptThrows was @MainActor + sync throws, which Linux XCTest discovery rejects.

Pushed a one-line fix: async throws (same pattern as the other MainActor tests). SpecSync rebound.

@cursor

cursor Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review (agent:cursor) — tested locally

Verdict: Approve to merge first. Individually green; good foundation for the rest of the stack.

Tested

  • fledge lanes run verify on kimi/issue-31-error-contract-v2: pass (41 tests + smoke)
  • CI: build-test-smoke / linux-smoke / trust / windows-smoke all green
  • Manual: set counter nope --json → exit 64 + invalid_value envelope; torn note.json → exit 65 + corrupt_state; APS_ERROR_JSON=1 works without --json

Merge coordination (required)

Please merge this before #51 / #53 / #54 / #55.

Your SpecSync change is CHG-0021-error-contract-.... PRs #53, #54, and #55 also claim CHG-0021-* with different slugs. After this lands, those PRs must renumber to the next free IDs (0022+).

Stack note

After this merges, #51 will need a rebase (smoke/tests/specs + SpecSync evidence conflict). That is expected; not a defect in this PR.

@cursor
cursor Bot merged commit 246479b into main Jul 19, 2026
4 checks passed
@cursor
cursor Bot deleted the kimi/issue-31-error-contract-v2 branch July 19, 2026 12:27
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