GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||
GeezerVison is showing github.com — Decide: one shape for the `--json` top-level `error` (scan and get emit both a string and a {code, message} object) · Issue #704 · SocketDev/socket-patch Closed Labels agent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)Filed by a scheduled architecture audit routine (see the architecture review discussion)priority:p3refactorStructural change: duplicated code or logic, missing abstraction, layering, dead codeStructural change: duplicated code or logic, missing abstraction, layering, dead code Description[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: discussion #560 register. Kind: decision. Source: review 2.8 and R4; register C14. Question
Options:
Whichever option is chosen, one emitter per command should own the shape, so a new failure path can't pick its own. Problem (main @
|
Invocation (--json) |
stdout | stderr |
|---|---|---|
scan --global --mode vendored (L1634-L1637) |
empty | Error: … |
scan --mode hosted --apply (same site) |
empty | Error: … |
remove --preserve-state --skip-rollback (L321-L327) |
empty | Error: … |
rollback with a bad glob (L1010-L1015) |
empty (by reading) | Error: … |
get --global --mode vendored lodash (L2559-L2562, via report_error) |
{"status":"error","error":"<string>"}, no code |
nothing |
vendor --global (L728-L740) |
full Envelope, error.code: global_scope_unsupported |
nothing |
repair --offline --download-only (L49-L57) |
full Envelope with a code |
nothing |
vex --json with no -O (L298-L309) |
full Envelope, json_requires_output |
nothing |
Clap's own parse errors print nothing on stdout. scan's comment calls that the intended rule ("Cross-mode combinations are usage errors (exit 2), which print no JSON envelope even under --json, like clap's own"). But get, vendor, repair and vex don't follow it. CLI_CONTRACT.md documents each case on its own (the vendor envelope at L129, "stderr only" for scan PATHs at L157), not as one rule. A script that runs --json and parses stdout gets a parse failure from scan, remove and rollback, and a document from the others.
Suggested addition to the options above: whichever shape wins, also decide one rule for exit-2 usage errors. Either:
vendor, repair, vex and get change), orscan, remove and rollback change; clap's errors stay stdout-free).Then route them through one usage_error(cmd, json, code, msg) -> i32 helper, so a new conflict can't choose its own channel. Of the ~17 return 2 sites in commands/, 4 write JSON today.
Generated by Claude Code
audit-core: C35 decision #966, C53 into #704, Part 2 refresh
Option 1 is clearly the correct choice. Implement proposed solution.
[agent] Decision recorded: option 1. On every --json failure, the top-level error is a {code, message} object on every command, the same shape as EnvelopeError. This is a breaking change (MAJOR) that ships in v5.0, before the stable release. A PR will follow.
What changes (main @ db83f014)
One emitter per command, no bare strings.
A shared helper in json_envelope.rs sets status: "error", sets error: {code, message} and removes any top-level errorCode.
get: report_error (13 call sites), report_lock_failure and the hand-built objects at get.rs:2491, :2544, :3462, :3830 and :3931 all go through it. The nested-apply run error (get.rs:2443) moves from errorCode + string into error. selection_required (get.rs:1078) keeps its status, and its error becomes {code: "selection_required", message}.
scan: these go through it:
emit_json_error/emit_json_error_with_code (scan/hosted.rs:66-90)emit_discovery_error_json (scan/mod.rs:761)print_zero_error_envelope (:1478):2279, api_batch_failed)policy_error_json (scan/policy.rs:468)Scan's error results keep their counts and redirect keys.
rollback: emit_rollback_error takes a code, and the inline objects at rollback.rs:1127, :1266 and :1986 go through it.
Codes. Existing codes are reused where they fit:
patch_fetch_failed, manifest_not_found, manifest_invalid, manifest_unreadable, manifest_write_failedlock_held and lock_ioapi_batch_failed, socket_yml_invalid, socket_yml_ambiguous, global_scope_unsupported, invalid_args, rollback_failedNew codes are added only where nothing fits, for example a blob write failure, a patch with no applicable files, an offline refusal, an invalid identifier and a path glob that doesn't parse. Each new code goes into the contract's top-level code table.
Exit-2 usage errors (C53). The issue offered two rules. This takes rule (b), which follows from option 1: under option 1, get's report_error usage path already prints a coded object, and vendor, repair and vex already print coded envelopes. A new usage_error(cmd, json, code, msg) -> i32 replaces the stderr-only sites in scan (scan/mod.rs:1554-1702), remove (remove.rs:326) and rollback (rollback.rs:1014). It also replaces the bespoke ones in get, vendor, repair and vex. --global --mode vendored will give error.code: "global_scope_unsupported" on scan, get and vendor. Clap's parse errors still print nothing on stdout. Human stderr text is unchanged. If you'd rather have rule (a), where usage errors write no stdout at all, say so before the PR lands.
Guard test. No return 2; under commands/ outside usage_error. The only exceptions are list.rs's source rank and the hidden hosted-bundle harness.
Tests
scan, get and rollback, asserting error is an object with a non-empty code and no top-level errorCode.--json..error as a string or read the top-level errorCode are updated: the covgap_commands_{get,rollback,scan_hosted,scan_mod} suites, e2e_socket_yml_policy, cli/output_modes_e2e and the in-crate tests in get.rs, scan/hosted.rs and scan/vendor_flow.rs.Docs
CLI_CONTRACT.md:
scan, get and rollback now share the error shape.errorCode.2 row states the stdout rule.docs/migrating-to-v5.md gets a "JSON output" entry: read .error.message / .error.code instead of .error / .errorCode, and scan, remove and rollback usage errors now print JSON.CHANGELOG.md is not touched.Not in scope: moving these commands onto Envelope (option 3, which overlaps C11) and the typed code registry (C13, #930). The new codes will feed C13.
Generated by Claude Code