mirror of
https://github.com/ultraworkers/claw-code.git
synced 2026-04-24 13:08:11 +08:00
ROADMAP #77: typed error-kind contract for --output-format json errors
Dogfooded 2026-04-17 against main HEAD 00d0eb6. Five distinct failure
classes (missing credentials, missing manifests, missing worker state,
session not found, CLI parse) all emit the same {type,error} envelope
with no machine-readable kind/code, so downstream claws have to regex
the prose to route failures. Success payloads already carry a stable
'kind' discriminator; error payloads do not. Fix shape proposes an
ErrorKind discriminant plus hint/context fields to match the success
side contract.
Filed in response to Clawhip pinpoint nudge 1494593284180414484 in
#clawcode-building-in-public.
This commit is contained in:
parent
00d0eb61d4
commit
d05c8686b8
22
ROADMAP.md
22
ROADMAP.md
@ -1172,3 +1172,25 @@ Original filing (2026-04-13): user requested a `-acp` parameter to support ACP p
|
||||
75. **`claw init` leaves `.clawhip/` runtime artifacts unignored** — **done (verified 2026-04-12):** `rust/crates/rusty-claude-cli/src/init.rs` now treats `.clawhip/` as a first-class local artifact alongside `.claw/` paths, and regression coverage locks both the create and idempotent update paths so `claw init` adds the ignore entry exactly once. The repo `.gitignore` now also ignores `.clawhip/` for immediate dogfood relief, preventing repeated OMX team merge conflicts on `.clawhip/state/prompt-submit.json`. Source: Jobdori dogfood 2026-04-12.
|
||||
|
||||
76. **Real ACP/Zed daemon contract is still missing after the discoverability fix** — follow-up filed 2026-04-16. ROADMAP #64 made the current status explicit via `claw acp`, but editor-first users still cannot actually launch claw-code as an ACP/Zed daemon because there is no protocol-serving surface yet. **Fix shape:** add a real ACP entrypoint (for example `claw acp serve`) only when the underlying protocol/transport contract exists, then document the concrete editor wiring in `claw --help` and first-screen docs. **Acceptance bar:** an editor can launch claw-code for ACP/Zed from a documented, supported command rather than a status-only alias. **Blocker:** protocol/runtime work not yet implemented; current `acp serve` spelling is intentionally guidance-only.
|
||||
|
||||
77. **`--output-format json` error payload carries no machine-readable error class, so downstream claws cannot route failures without regex-scraping the prose** — dogfooded 2026-04-17 in `/tmp/claw-dogfood-*` on main HEAD `00d0eb6`. ROADMAP #42/#49/#56/#57 made stdout/stderr JSON-shaped on error, but the shape itself is still lossy: every failure emits the exact same three-field envelope `{"type":"error","error":"<prose>"}`. Concrete repros on the same binary, same JSON flag:
|
||||
- `claw --output-format json dump-manifests` (missing upstream manifest files) →
|
||||
`{"type":"error","error":"Manifest source files are missing.\n repo root: ...\n missing: src/commands.ts, src/tools.ts, src/entrypoints/cli.tsx\n Hint: ..."}`
|
||||
- `claw --output-format json dump-manifests --manifests-dir /tmp/claw-does-not-exist` (directory missing) → same three-field envelope, different prose.
|
||||
- `claw --output-format json state` (no worker state file) → `{"type":"error","error":"no worker state file found at .../.claw/worker-state.json — run a worker first"}`.
|
||||
- `claw --output-format json --resume nonexistent-session /status` (session lookup failure) → `{"type":"error","error":"failed to restore session: session not found: nonexistent-session\nHint: ..."}`.
|
||||
- `claw --output-format json "summarize hello.txt"` (missing Anthropic credentials) → `{"type":"error","error":"missing Anthropic credentials; ..."}`.
|
||||
- `claw --output-format json --resume latest not-a-slash` (CLI parse error from `parse_args`) → `{"type":"error","error":"unknown option: --resume latest not-a-slash\nRun `claw --help` for usage."}` — the trailing prose runbook gets stuffed into the same `error` string, which is misleading for parsers that expect the `error` value to be the short reason alone.
|
||||
|
||||
This is the error-side of the same contract #42 introduced for the success side: success payloads already carry a stable `kind` discriminator (`doctor`, `version`, `init`, `status`, etc.) plus per-kind structured fields, but error payloads have neither a kind/code nor any structured context fields, so every downstream claw that needs to distinguish "missing credentials" from "missing worker state" from "session not found" from "CLI parse error" has to string-match the prose. Five distinct root causes above all look identical at the JSON-schema level.
|
||||
|
||||
**Trace path.** `fn main()` in `rust/crates/rusty-claude-cli/src/main.rs:112-142` builds the JSON error with only `{"type": "error", "error": <message>}` when `--output-format=json` is detected, using the stringified error from `run()`. There is no `ErrorKind` enum feeding that payload and no attempt to carry `command`, `context`, or a machine class. `parse_args` failures flow through the same path, so CLI parse errors and runtime errors are indistinguishable on the wire. The original #42 landing commit (`a3b8b26` area) noted the JSON-on-error goal but stopped at the envelope shape.
|
||||
|
||||
**Fix shape.**
|
||||
- (a) Introduce an `ErrorKind` discriminant (e.g. `missing_credentials`, `missing_manifests`, `missing_manifest_dir`, `missing_worker_state`, `session_not_found`, `session_load_failed`, `cli_parse`, `slash_command_parse`, `broad_cwd_denied`, `provider_routing`, `unsupported_resumed_command`, `api_http_<status>`) derived from the `Err` value or an attached context. Start small — the 5 failure classes repro'd above plus `api_http_*` cover most live support tickets.
|
||||
- (b) Extend the JSON envelope to `{"type":"error","error":"<short reason>","kind":"<snake>","hint":"<optional runbook>","context":{...optional per-kind fields...}}`. `kind` is always present; `hint` carries the runbook prose currently stuffed into `error`; `context` is per-kind structured state (e.g. `{"missing":["src/commands.ts",...],"repo_root":"..."}` for `missing_manifests`, `{"session_id":"..."}` for `session_not_found`, `{"path":"..."}` for `missing_worker_state`).
|
||||
- (c) Preserve the existing `error` field as the short reason only (no trailing runbook), so `error` means the same thing as the text prefix of today's prose. Hosts that already parse `error` get cleaner strings; hosts that want structured routing get `kind`+`context`.
|
||||
- (d) Mirror the success-side contract: success payloads use `kind`, error payloads use `kind` with `type:"error"` on top. No breaking change for existing consumers that only inspect `type`.
|
||||
- (e) Add table-driven regression coverage parallel to `output_format_contract.rs::doctor_and_resume_status_emit_json_when_requested`, one assertion per `ErrorKind` variant.
|
||||
|
||||
**Acceptance.** A downstream claw/clawhip consumer can switch on `payload.kind` (`missing_credentials`, `missing_manifests`, `session_not_found`, ...) instead of regex-scraping `error` prose; the `hint` runbook stops being stuffed into the short reason; and the JSON envelope becomes symmetric with the success side. **Source.** Jobdori dogfood 2026-04-17 against a throwaway `/tmp/claw-dogfood-*` workspace on main HEAD `00d0eb6` in response to Clawhip pinpoint nudge at `1494593284180414484`.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user