v0.17 — contract hardening (exit 64 + piped JSON errors)#17
Merged
Conversation
- client: the OAuth refresh was gated on attempts===1, so a 429 backoff consumed the slot and a token that expired during the storm never refreshed (unrecoverable 401 mid-batch). Gate on a dedicated `refreshed` flag and make the refresh round free (attempts--), so it neither double-refreshes nor eats the retry budget. - input: findField read d.field_name.toLowerCase() unguarded; add ?. to match lookup.js / upsert.js so a def with no field_name degrades instead of throwing.
Two breaking changes to the machine-facing contract, landed before the 1.0
freeze:
- oclif parse/usage errors (unknown flag, missing arg, bad enum) exited 70
(EX_SOFTWARE, an internal bug) — they now exit 64 (EX_USAGE) per spec §9.
Detected by oclif.exit===2 with no exitCode of ours; genuine internal throws
still exit 70.
- Error output now mirrors success output: explicit --output, else profile
default, else JSON when piped / human in a TTY. Previously errors stayed
human-text unless JSON was explicitly requested, so a piped consumer got JSON
on success and unparseable text on failure. Now stderr carries the
{error, message, exitCode, ...} envelope whenever success would be JSON.
BREAKING CHANGE: piped invocations now emit JSON error payloads on stderr (was
human text); oclif usage errors exit 64 instead of 70.
Tests now model an interactive TTY by default (test/setup.js); piped/machine
behavior is opted into per-test. This keeps the existing rejects.toThrow(msg)
error assertions valid under the new piped-JSON behavior.
- base-command: storedDefaultOutput() now swallows a throwing config read (returns undefined). handleError consults it while reporting another failure, so a corrupt/unreadable config must never crash error reporting itself. - errors: clarify that any non-table format (json/yaml/csv or piped) emits the JSON error envelope — there is no yaml/csv error serializer; only an interactive table context stays human. Added tests for yaml/csv defaults. - client: lock the retry=false + OAuth 401 path — a refresh still happens once and retries with the fresh token even under --no-retry (the refresh round is free; it is re-auth, not a load retry). - test setup: restore process.stdout.isTTY after each test to prevent leakage. Dismissed the suggested attempts=maxAttempts change: it would reintroduce the pre-v0.17 bug where retry=false + 401 refreshed but never retried (threw 69).
CHANGELOG 0.17.0 with the two BREAKING notes (usage errors exit 64; piped errors emit JSON) + the OAuth/null-guard/error-reporting fixes. agents page: corrected exit-code table (usage/bad-flags = 64, not 70) and the error-JSON note now covers piped + yaml/csv defaults, not just --output json. Version bump to 0.17.0; regenerated command reference + cli-stats.
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v0.17 — contract hardening
The last changes to the machine-facing surface (exit codes + error output) before the 1.0 stability freeze.
Changed (BREAKING)
EX_SOFTWARE); they now exit 64 (EX_USAGE). 70 is reserved for genuine internal failures.{error, message, exitCode, …}envelope on stderr for any machine format (--output json|yaml|csv, a non-tabledefault, or piped). A non-interactive consumer always gets a parseable failure.--output tableforces human.Fixed
--no-retry.--field/CSV: a field def missingfield_nameno longer throws when matched by hash code.default_outputthrows (corrupt config) while formatting another error.Quality
--bogusflag→ JSON errorexitCode: 64; piped 404 → full JSON envelope; success output intact.retry=false+OAuth-refresh lock, and the config-read guard. Dismissed a proposedattempts=maxAttemptschange that would have reintroduced the pre-0.17 "refresh-but-never-retry" bug.test/setup.js); piped behavior is opted into per-test.100% coverage;
npm run lintclean.