Repository navigation
Tracking: emit every --json error code from one typed ErrorCode registry checked against the contract tables #930
Description
[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: register comment.
Kind: tracking. Source: review 2.8, 3.7 #8, 8.5 F; register row C13.
Problem
Every --json error code is a free string. PatchEvent::with_reason/with_error and EnvelopeError::new take impl Into<String>, and the CLI has 113 such call sites. Core adds its own code() methods (policy, update, cargo_manifest, hosted::memory) and reason: "…".into() fields. Nothing ties a code to the contract's tables (errorCode tags, top-level codes), so on 9c43dfc the codes drift in two ways:
- Undocumented codes. A scan of production code for snake_case literals in code-emitting positions finds 186 candidates. 60 of them appear nowhere in
CLI_CONTRACT.mdin backticks; 43 remain after removing 16 telemetry event names and one PEP 440 token. I read the code for these and confirmed they reach--json:rollback_not_installed(remove),vendor_service_unsupported_ecosystem,hosted_restore_failed,vendor_orphan_removed,invalid_manifest,already_original(rollback),vendor_sha256_mismatch, and theredirect_composer_*,redirect_pnpm_*andredirect_requirements_*families. - One condition, many codes. An unparseable manifest is reported under five codes, depending on the command (child 1 below).
Target design
- One
ErrorCodeenum, in core so that core'scode()methods can return it.as_str()gives today's wire strings unchanged. The envelope builders takeErrorCodeinstead ofimpl Into<String>, so a new code can't be emitted without adding a variant. - A freshness test that parses the contract's two code tables. It fails when a variant is missing from them, or when a documented code has no variant (a phantom code).
- The mechanical steps change nothing on the wire. A rename that changes a code is its own small bug or decision issue.
Checklist (in order)
- Child 1: An unparseable .socket/manifest.json is reported under five different --json error codes depending on the command #931, one manifest-load error mapping for every command.
- Child 2: introduce
ErrorCodein the CLI envelope and convert the 113 CLI call sites mechanically, with no wire change. Not filed yet. - Child 3: move core's
code()/reasonstrings ontoErrorCode: policy, update, cargo_manifest, hosted::memory, vendor verify and the redirect families. Not filed yet. - Child 4: document the undocumented codes (or delete the dead ones), and add the freshness test. Not filed yet.
- Child 5: move the bare-string
errorofrollback,scanandgetontoErrorCode, after the shape decision in Decide: one shape for the--jsontop-levelerror(scan and get emit both a string and a {code, message} object) #704. Not filed yet.
Size and scope
Five PRs. Child 2 is the largest: about 113 mechanical call-site changes. Out of scope: the envelope shape (#704), the generated contract reference (register C33) and exit codes.
Acceptance criteria
- Every code in
--jsonoutput comes fromErrorCode. - The freshness test is green, and it fails on an undocumented or phantom code.
- The existing
errorCodeassertions in the test suite stay green, apart from deliberate renames made in their own issues.
Dependencies
Child 5 is blocked by #704. This coordinates with C33 (the generated contract reference), which can later generate the code tables from ErrorCode.
Activity
audit-core: C13 decomposed (#930, #931), C52 new finding
refactor: re-rank queue, add #931 (C52)
mikolalysenko commentedon Oct 6, 2026
[agent] Triaged as
priority:p3(cross-cutting refactor, tracking). Not a duplicate. Its children land as separate PRs; #931 is the first.Generated by Claude Code