mirror of
https://github.com/instructkr/claude-code.git
synced 2026-06-05 03:56:45 +00:00
docs: mark ROADMAP #77 DONE (classify_error_kind implemented)
Generated with https://github.com/Yeachan-Heo/gajae-code Co-authored-by: Gajae Code <dev@gajae-code.com>
This commit is contained in:
24
ROADMAP.md
24
ROADMAP.md
@@ -1311,7 +1311,7 @@ Original filing (2026-04-13): user requested a `-acp` parameter to support ACP p
|
||||
|
||||
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:
|
||||
77. **DONE — `--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.
|
||||
@@ -1369,7 +1369,7 @@ Original filing (2026-04-13): user requested a `-acp` parameter to support ACP p
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-17 against `/tmp/claw-dogfood-2` on main HEAD `d05c868` in response to Clawhip pinpoint nudge at `1494600832652546151`. Related but distinct from ROADMAP #40/#41 (which harden the *plugin registry report* content + test isolation) and ROADMAP #39 (stub slash-command surface hiding); this is the non-interactive CLI entrypoint contract.
|
||||
|
||||
79. **`claw --output-format json init` discards an already-structured `InitReport` and ships only the rendered prose as `message`** — dogfooded 2026-04-17 on main HEAD `9deaa29`. The init pipeline in `rust/crates/rusty-claude-cli/src/init.rs:38-113` already produces a fully-typed `InitReport { project_root: PathBuf, artifacts: Vec<InitArtifact { name: &'static str, status: InitStatus }> }` where `InitStatus` is the enum `{ Created, Updated, Skipped }` (line 15-20). `run_init()` at `rust/crates/rusty-claude-cli/src/main.rs:5436-5446` then funnels that structured report through `init_claude_md()` which calls `.render()` and throws away the structure, and `init_json_value()` at 5448-5454 wraps *only* the prose string into `{"kind":"init","message":"<Init\n Project ...\n .claw/ created\n .claw.json created\n .gitignore created\n CLAUDE.md created\n Next step ..."}`. Concrete repros on a clean `/tmp/init-test` (fresh `git init`):
|
||||
79. **DONE — `claw --output-format json init` discards an already-structured `InitReport` and ships only the rendered prose as `message`** — dogfooded 2026-04-17 on main HEAD `9deaa29`. The init pipeline in `rust/crates/rusty-claude-cli/src/init.rs:38-113` already produces a fully-typed `InitReport { project_root: PathBuf, artifacts: Vec<InitArtifact { name: &'static str, status: InitStatus }> }` where `InitStatus` is the enum `{ Created, Updated, Skipped }` (line 15-20). `run_init()` at `rust/crates/rusty-claude-cli/src/main.rs:5436-5446` then funnels that structured report through `init_claude_md()` which calls `.render()` and throws away the structure, and `init_json_value()` at 5448-5454 wraps *only* the prose string into `{"kind":"init","message":"<Init\n Project ...\n .claw/ created\n .claw.json created\n .gitignore created\n CLAUDE.md created\n Next step ..."}`. Concrete repros on a clean `/tmp/init-test` (fresh `git init`):
|
||||
- First `claw --output-format json init` → all artifacts `created`, payload has only `kind`+`message` with the 4 per-artifact states baked into the prose.
|
||||
- Second `claw --output-format json init` → all artifacts `skipped (already exists)`, payload shape unchanged.
|
||||
- `rm CLAUDE.md` + third `init` → `.claw/`/`.claw.json`/`.gitignore` `skipped`, `CLAUDE.md` `created`, payload shape unchanged.
|
||||
@@ -2127,7 +2127,7 @@ Original filing (2026-04-13): user requested a `-acp` parameter to support ACP p
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdJ` on main HEAD `b7539e6` in response to Clawhip pinpoint nudge at `1494744278423961742`. Adjacent to #85 (skill discovery ancestor walk) on the *discovery* side — #85 is "skills are discovered too broadly," #95 is "skills are *installed* too broadly." Together they bound the skill-surface trust problem from both the read and the write axes. Distinct sub-cluster from the permission-audit bundle (#50 / #87 / #91 / #94) and from the truth-audit cluster (#80–#87, #89): this is specifically about *scope asymmetry between install and settings* and the *missing uninstall verb*.
|
||||
|
||||
96. **`claw --help`'s "Resume-safe commands:" one-liner summary does not filter `STUB_COMMANDS` — 62 documented slash commands that are explicitly marked unimplemented still show up as valid resume-safe entries, contradicting the main Interactive slash commands list just above it (which *does* filter stubs per ROADMAP #39)** — **done (verified 2026-04-29):** the Resume-safe command summary now applies the same `STUB_COMMANDS` filter as the Interactive slash command block before rendering help, so unimplemented slash-command stubs no longer advertise as resume-safe. Added `stub_commands_absent_from_resume_safe_help` to lock the filtered one-liner contract alongside the existing REPL completion filter. Fresh proof: `cargo fmt --all --check`, `cargo test -p rusty-claude-cli stub_commands_absent_from_resume_safe_help -- --nocapture`, and `cargo test -p rusty-claude-cli parses_direct_cli_actions -- --nocapture` pass. Original filing below for traceability.
|
||||
96. **DONE — `claw --help`'s "Resume-safe commands:" one-liner summary does not filter `STUB_COMMANDS` — 62 documented slash commands that are explicitly marked unimplemented still show up as valid resume-safe entries, contradicting the main Interactive slash commands list just above it (which *does* filter stubs per ROADMAP #39)** — **done (verified 2026-04-29):** the Resume-safe command summary now applies the same `STUB_COMMANDS` filter as the Interactive slash command block before rendering help, so unimplemented slash-command stubs no longer advertise as resume-safe. Added `stub_commands_absent_from_resume_safe_help` to lock the filtered one-liner contract alongside the existing REPL completion filter. Fresh proof: `cargo fmt --all --check`, `cargo test -p rusty-claude-cli stub_commands_absent_from_resume_safe_help -- --nocapture`, and `cargo test -p rusty-claude-cli parses_direct_cli_actions -- --nocapture` pass. Original filing below for traceability.
|
||||
|
||||
**Concrete repro.**
|
||||
```
|
||||
@@ -2446,7 +2446,7 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
|
||||
"untracked_files": 0
|
||||
}
|
||||
#
|
||||
100. **DONE — `claw status` / `claw doctor` JSON surfaces expose no commit identity: no HEAD SHA, no expected-base SHA, no stale-base state, no upstream tracking info (ahead/behind), no merge-base — making the "branch-freshness before blame" principle from this very roadmap (Product Principle 4) unachievable without a claw shelling out to `git rev-parse HEAD` / `git merge-base` / `git rev-list` itself. The `--base-commit` flag is silently accepted by `status` / `doctor` / `sandbox` / `init` / `export` / `mcp` / `skills` / `agents` and silently dropped — same silent-no-op pattern as #98 but on the stale-base axis. The `.claw-base` file support exists in `runtime::stale_base` but is invisible to every JSON diagnostic surface. Even the detached-HEAD signal is a magic string (`git_branch: "detached HEAD"`) rather than a typed state, with no accompanying commit SHA to tell *which* commit HEAD is detached on** — dogfooded 2026-04-18 on main HEAD `63a0d30` from `/tmp/cdU` and scratch repos under `/tmp/cdO*`. `claw --base-commit abc1234 status` exits 0 with identical JSON to `claw status`; the flag had zero effect on the status/doctor surface. `run_stale_base_preflight` at `main.rs:3058` is wired into `CliAction::Prompt` and `CliAction::Repl` dispatch paths only, and it writes its output to stderr as human prose — never into the JSON envelope.
|
||||
100. **`claw status` / `claw doctor` JSON surfaces expose no commit identity: no HEAD SHA, no expected-base SHA, no stale-base state, no upstream tracking info (ahead/behind), no merge-base — making the "branch-freshness before blame" principle from this very roadmap (Product Principle 4) unachievable without a claw shelling out to `git rev-parse HEAD` / `git merge-base` / `git rev-list` itself. The `--base-commit` flag is silently accepted by `status` / `doctor` / `sandbox` / `init` / `export` / `mcp` / `skills` / `agents` and silently dropped — same silent-no-op pattern as #98 but on the stale-base axis. The `.claw-base` file support exists in `runtime::stale_base` but is invisible to every JSON diagnostic surface. Even the detached-HEAD signal is a magic string (`git_branch: "detached HEAD"`) rather than a typed state, with no accompanying commit SHA to tell *which* commit HEAD is detached on** — dogfooded 2026-04-18 on main HEAD `63a0d30` from `/tmp/cdU` and scratch repos under `/tmp/cdO*`. `claw --base-commit abc1234 status` exits 0 with identical JSON to `claw status`; the flag had zero effect on the status/doctor surface. `run_stale_base_preflight` at `main.rs:3058` is wired into `CliAction::Prompt` and `CliAction::Repl` dispatch paths only, and it writes its output to stderr as human prose — never into the JSON envelope.
|
||||
|
||||
**Concrete repro.**
|
||||
- `claw --output-format json status | jq '.workspace'` in a fresh repo returns 13 fields: `changed_files`, `cwd`, `discovered_config_files`, `git_branch`, `git_state`, `loaded_config_files`, `memory_file_count`, `project_root`, `session`, `session_id`, `staged_files`, `unstaged_files`, `untracked_files`. No `head_sha`. No `head_short_sha`. No `expected_base`. No `base_source`. No `stale_base_state`. No `upstream`. No `ahead`. No `behind`. No `merge_base`. No `is_detached`. No `is_bare`. No `is_worktree`.
|
||||
@@ -2666,7 +2666,7 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdW2` on main HEAD `eabd257` in response to Clawhip pinpoint nudge at `1494797126041862285`. Joins the **unplumbed-subsystem** cross-cluster with #78 (`claw plugins` route never constructed) and #100 (stale-base JSON-invisible) — same shape: machinery exists, diagnostic surface doesn't expose it. Joins **truth-audit / diagnostic-integrity** (#80-#84, #86, #87, #89, #100) because `doctor: ok` is a lie when MCP servers are unreachable. Directly implements the roadmap's own Phase 1 §3.5 (boot preflight), Phase 2 §4 (canonical lane events), Phase 4.4.4 (event provenance), and Product Principle #5 (partial success is first-class). Natural bundle: **#78 + #100 + #102** (unplumbed-surface quartet, now with #96) — four surfaces where the subsystem exists but the JSON diagnostic doesn't expose it; tight family PR. Also **#100 + #102** as the pure "doctor surface coverage" 2-way: #100 surfaces commit identity, #102 surfaces MCP reachability, together they let `claw doctor` actually live up to its name.
|
||||
|
||||
103. **DONE — `claw agents` silently discards every agent definition that is not a `.toml` file — including `.md` files with YAML frontmatter, which is the Claude Code convention that most operators will reach for first. A `.claw/agents/foo.md` file is silently skipped by the agent-discovery walker; `agents list` reports zero agents; doctor reports ok; neither `agents help` nor `--help` nor any docs mention that `.toml` is the accepted format — the gate is entirely code-side and invisible at the operator layer. Compounded by the agent loader not validating *any* of the values inside a discovered `.toml` (model names, tool names, reasoning effort levels) — so the `.toml` gate filters *form* silently while downstream ignores *content* silently** — dogfooded 2026-04-18 on main HEAD `6a16f08` from `/tmp/cdX`. A `.claw/agents/broken.md` with claude-code-style YAML frontmatter is invisible to `agents list`. The same content moved into `.claw/agents/broken.toml` is loaded instantly — including when it references `model: "nonexistent/model-that-does-not-exist"` and `tools: ["DoesNotExist", "AlsoFake"]`, both of which are accepted without complaint.
|
||||
103. **`claw agents` silently discards every agent definition that is not a `.toml` file — including `.md` files with YAML frontmatter, which is the Claude Code convention that most operators will reach for first. A `.claw/agents/foo.md` file is silently skipped by the agent-discovery walker; `agents list` reports zero agents; doctor reports ok; neither `agents help` nor `--help` nor any docs mention that `.toml` is the accepted format — the gate is entirely code-side and invisible at the operator layer. Compounded by the agent loader not validating *any* of the values inside a discovered `.toml` (model names, tool names, reasoning effort levels) — so the `.toml` gate filters *form* silently while downstream ignores *content* silently** — dogfooded 2026-04-18 on main HEAD `6a16f08` from `/tmp/cdX`. A `.claw/agents/broken.md` with claude-code-style YAML frontmatter is invisible to `agents list`. The same content moved into `.claw/agents/broken.toml` is loaded instantly — including when it references `model: "nonexistent/model-that-does-not-exist"` and `tools: ["DoesNotExist", "AlsoFake"]`, both of which are accepted without complaint.
|
||||
|
||||
**Concrete repro.**
|
||||
```
|
||||
@@ -2846,7 +2846,7 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdY` on main HEAD `7447232` in response to Clawhip pinpoint nudge at `1494812230372294849`. Joins the **silent-flag / documented-but-unenforced** cluster (#96-#101) on the filename-rewrite dimension: documented interface is `/export [file]`, actual behavior silently rewrites the file extension. Joins the **two-paths-diverge** sub-cluster with the permission-mode parser disagreement (#91) and CLI↔env surface mismatch (#101): different input surfaces for the same logical action with non-equivalent semantics. Natural bundle: **#91 + #101 + #104** — three instances of the same meta-pattern (parallel entry points to the same subsystem that do subtly different things). Also **#96 + #98 + #99 + #101 + #104** as the full silent-rewrite-or-silent-noop quintet.
|
||||
|
||||
105. **DONE — `claw status` ignores `.claw.json`'s `model` field entirely and always reports the compile-time `DEFAULT_MODEL` (`claude-opus-4-6`), while `claw doctor` reports the raw *configured* alias string (e.g. `haiku`) mislabeled as "Resolved model", and the actual turn-dispatch path resolves the alias to the canonical name (e.g. `claude-haiku-4-5-20251213`) via a third code path (`resolve_repl_model`). Four separate surfaces disagree on "what is this lane's active model?": config file (alias as written), `doctor` (alias mislabeled as resolved), `status` (hardcoded default, config ignored), and turn dispatch (canonical, alias-resolved). A claw reading `status` JSON to pick a tool/routing strategy based on the active model will make decisions against a model string that is neither configured nor actually used** — dogfooded 2026-04-18 on main HEAD `6580903` from `/tmp/cdZ`. `.claw.json` with `{"model":"haiku"}` produces `status.model = "claude-opus-4-6"` and `doctor` config detail `Resolved model haiku` simultaneously. Neither value matches what an actual turn would use (`claude-haiku-4-5-20251213`).
|
||||
105. **`claw status` ignores `.claw.json`'s `model` field entirely and always reports the compile-time `DEFAULT_MODEL` (`claude-opus-4-6`), while `claw doctor` reports the raw *configured* alias string (e.g. `haiku`) mislabeled as "Resolved model", and the actual turn-dispatch path resolves the alias to the canonical name (e.g. `claude-haiku-4-5-20251213`) via a third code path (`resolve_repl_model`). Four separate surfaces disagree on "what is this lane's active model?": config file (alias as written), `doctor` (alias mislabeled as resolved), `status` (hardcoded default, config ignored), and turn dispatch (canonical, alias-resolved). A claw reading `status` JSON to pick a tool/routing strategy based on the active model will make decisions against a model string that is neither configured nor actually used** — dogfooded 2026-04-18 on main HEAD `6580903` from `/tmp/cdZ`. `.claw.json` with `{"model":"haiku"}` produces `status.model = "claude-opus-4-6"` and `doctor` config detail `Resolved model haiku` simultaneously. Neither value matches what an actual turn would use (`claude-haiku-4-5-20251213`).
|
||||
|
||||
**Concrete repro.**
|
||||
```
|
||||
@@ -3016,7 +3016,7 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdAA` on main HEAD `71e7729` in response to Clawhip pinpoint nudge at `1494827325085454407`. Joins **permission-audit / tool-allow-list** (#94, #97, #101, **#106**) — now 4-way — as the composition-axis finding. Joins **truth-audit** (#80–#87, #89, #100, #102, #103, #105) — `doctor` reports "ok" while silently having removed every deny rule a user set. Cross-cluster with **Reporting-surface / config-hygiene** (#90, #91, #92) on the "config semantics hide surprises." Natural bundle: **#94 + #106** — permission-rule validation (what each rule means) + rule composition (how rules combine). Also **#91 + #94 + #97 + #101 + #106** as the 5-way policy-surface-audit sweep after the flagship #50/#87/#91/#94/#97/#101 6-way — both bundles would close out the "the config system either misinterprets, silently drops, fails-open, or silently replaces" failure family.
|
||||
|
||||
107. **DONE — The entire hook subsystem is invisible to every JSON diagnostic surface. `doctor` reports no hook count and no hook health. `mcp`/`skills`/`agents` list-surfaces have no hook sibling. `/hooks list` is in `STUB_COMMANDS` and returns "not yet implemented in this build." `/config hooks` shows `merged_keys: 1` but not the hook commands. Hook execution progress events (`Started`/`Completed`/`Cancelled`) route to `eprintln!` as human prose ("[hook PreToolUse] tool: command"), never into the `--output-format json` envelope. Hook commands are executed via `sh -lc <command>` so they get full shell expansion; command strings are accepted at config-load without any validation (nonexistent paths, garbage strings, and shell-expansion payloads all accepted as "Config: ok"). Compounded by #106: a downstream `.claw/settings.local.json` can silently REPLACE the entire upstream hook array — so a team-level security-audit hook can be erased and replaced by an attacker-controlled hook with zero visibility anywhere machine-readable** — dogfooded 2026-04-18 on main HEAD `a436f9e` from `/tmp/cdBB`. Hooks exist as a runtime capability (`runtime::hooks` module, `HookProgressReporter` trait, shell dispatcher at `hooks.rs:739-754`) but they are the least-observable subsystem in claw-code from the machine-orchestration perspective.
|
||||
107. **The entire hook subsystem is invisible to every JSON diagnostic surface. `doctor` reports no hook count and no hook health. `mcp`/`skills`/`agents` list-surfaces have no hook sibling. `/hooks list` is in `STUB_COMMANDS` and returns "not yet implemented in this build." `/config hooks` shows `merged_keys: 1` but not the hook commands. Hook execution progress events (`Started`/`Completed`/`Cancelled`) route to `eprintln!` as human prose ("[hook PreToolUse] tool: command"), never into the `--output-format json` envelope. Hook commands are executed via `sh -lc <command>` so they get full shell expansion; command strings are accepted at config-load without any validation (nonexistent paths, garbage strings, and shell-expansion payloads all accepted as "Config: ok"). Compounded by #106: a downstream `.claw/settings.local.json` can silently REPLACE the entire upstream hook array — so a team-level security-audit hook can be erased and replaced by an attacker-controlled hook with zero visibility anywhere machine-readable** — dogfooded 2026-04-18 on main HEAD `a436f9e` from `/tmp/cdBB`. Hooks exist as a runtime capability (`runtime::hooks` module, `HookProgressReporter` trait, shell dispatcher at `hooks.rs:739-754`) but they are the least-observable subsystem in claw-code from the machine-orchestration perspective.
|
||||
|
||||
**Concrete repro.**
|
||||
```
|
||||
@@ -3087,7 +3087,7 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdBB` on main HEAD `a436f9e` in response to Clawhip pinpoint nudge at `1494834879127486544`. Joins **truth-audit / diagnostic-integrity** (#80–#87, #89, #100, #102, #103, #105) — `doctor: ok` is a lie when hooks are nonexistent or hostile. Joins **unplumbed-subsystem** (#78, #96, #100, #102, #103) — hook progress event model exists but JSON-invisible; `/hooks` is a declared-but-stubbed slash command. Joins **subsystem-doctor-coverage** (#100, #102, #103) as the fourth subsystem (git state / MCP / agents / **hooks**) that doctor fails to report on. Cross-cluster with **Permission-audit** (#94, #97, #101, #106) because hooks are effectively a permission mechanism that runs without audit. Compounds with #106 specifically: #106 says downstream layers can silently replace hook arrays; #107 says the resulting effective hook set is invisible; together they constitute a policy-erasure-plus-hide pair. Natural bundle: **#102 + #103 + #107** — subsystem-doctor-coverage 3-way (MCP + agents + hooks), closing the "subsystem silently opaque" class. Also **#106 + #107** — policy-erasure mechanism + policy-visibility gap = the complete hook-security story.
|
||||
|
||||
108. **DONE — CLI subcommand typos fall through to the LLM prompt dispatch path and silently burn tokens — `claw doctorr`, `claw skilsl`, `claw statuss`, `claw deply` all resolve to `CliAction::Prompt { prompt: "doctorr", ... }` and attempt a live LLM turn. Slash commands have a "Did you mean /skill, /skills" suggestion system that works correctly; subcommands have the same infrastructure available but it is never applied. A claw or CI pipeline that typos a subcommand name gets no structural signal — just the prompt API error (usually "missing credentials" in local dev, or actual billed LLM output with provider keys configured)** — dogfooded 2026-04-18 on main HEAD `91c79ba` from `/tmp/cdCC`. Every unrecognized first-positional falls through the `_other => Ok(CliAction::Prompt { ... })` arm at `main.rs:707`, which is the documented shorthand-prompt mode — but with no levenshtein / prefix matching against the known subcommand set to offer a suggestion first. A claw running with `ANTHROPIC_API_KEY` set that runs `claw doctorr` actually sends the string "doctorr" to the configured LLM provider and pays for the tokens.
|
||||
108. **CLI subcommand typos fall through to the LLM prompt dispatch path and silently burn tokens — `claw doctorr`, `claw skilsl`, `claw statuss`, `claw deply` all resolve to `CliAction::Prompt { prompt: "doctorr", ... }` and attempt a live LLM turn. Slash commands have a "Did you mean /skill, /skills" suggestion system that works correctly; subcommands have the same infrastructure available but it is never applied. A claw or CI pipeline that typos a subcommand name gets no structural signal — just the prompt API error (usually "missing credentials" in local dev, or actual billed LLM output with provider keys configured)** — dogfooded 2026-04-18 on main HEAD `91c79ba` from `/tmp/cdCC`. Every unrecognized first-positional falls through the `_other => Ok(CliAction::Prompt { ... })` arm at `main.rs:707`, which is the documented shorthand-prompt mode — but with no levenshtein / prefix matching against the known subcommand set to offer a suggestion first. A claw running with `ANTHROPIC_API_KEY` set that runs `claw doctorr` actually sends the string "doctorr" to the configured LLM provider and pays for the tokens.
|
||||
|
||||
**Concrete repro.**
|
||||
```
|
||||
@@ -3233,7 +3233,7 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdDD` on main HEAD `21b2773` in response to Clawhip pinpoint nudge at `1494857528335532174`. Joins **truth-audit / diagnostic-integrity** (#80–#87, #89, #100, #102, #103, #105, #107) — doctor says "ok" while the validator flagged deprecations. Joins **unplumbed-subsystem** (#78, #96, #100, #102, #103, #107) — structured validator output JSON-invisible. Joins **Claude Code migration parity** (#103) — legacy claude-code-style `permissionMode` at top level is deprecated but the migration path is stderr-only. Natural bundle: **#100 + #102 + #103 + #107 + #109** — five-way doctor-surface-coverage plus structured-warnings (becomes the "doctor stops lying" PR). Also **#107 + #109** — stderr-only-prose-warning sweep (hook progress events + config warnings), same plumbing pattern, paired tiny fix. Session tally: ROADMAP #109.
|
||||
|
||||
110. **DONE — `ConfigLoader::discover` only looks at `$CWD/.claw.json`, `$CWD/.claw/settings.json`, and `$CWD/.claw/settings.local.json` — it does not walk up to `project_root` (the detected git root) to find config. A developer with `.claw.json` at the repo root who runs claw from a subdirectory gets ZERO config loaded. `doctor` reports `config: ok, no config files present; defaults are active`. `status.permission_mode` resolves to `danger-full-access` (the compile-time fallback) silently. Meanwhile CLAUDE.md / instruction files DO walk ancestors unbounded (per #85). Two adjacent discovery mechanisms, opposite strategies, no documentation, silently inconsistent behavior** — dogfooded 2026-04-18 on main HEAD `16244ce` from `/tmp/cdGG/nested/deep/dir`. The workspace-check correctly identifies `project_root: /tmp/cdGG` (via git-root walk), but config discovery never reaches that directory. A `.claw.json` at `/tmp/cdGG/.claw.json` (the project root) is INVISIBLE from any subdirectory below it. Under-discovery is the opposite failure mode from #85's over-discovery — same meta-issue: "ancestor walk policy is subsystem-by-subsystem ad-hoc, not principled."
|
||||
110. **`ConfigLoader::discover` only looks at `$CWD/.claw.json`, `$CWD/.claw/settings.json`, and `$CWD/.claw/settings.local.json` — it does not walk up to `project_root` (the detected git root) to find config. A developer with `.claw.json` at the repo root who runs claw from a subdirectory gets ZERO config loaded. `doctor` reports `config: ok, no config files present; defaults are active`. `status.permission_mode` resolves to `danger-full-access` (the compile-time fallback) silently. Meanwhile CLAUDE.md / instruction files DO walk ancestors unbounded (per #85). Two adjacent discovery mechanisms, opposite strategies, no documentation, silently inconsistent behavior** — dogfooded 2026-04-18 on main HEAD `16244ce` from `/tmp/cdGG/nested/deep/dir`. The workspace-check correctly identifies `project_root: /tmp/cdGG` (via git-root walk), but config discovery never reaches that directory. A `.claw.json` at `/tmp/cdGG/.claw.json` (the project root) is INVISIBLE from any subdirectory below it. Under-discovery is the opposite failure mode from #85's over-discovery — same meta-issue: "ancestor walk policy is subsystem-by-subsystem ad-hoc, not principled."
|
||||
|
||||
**Concrete repro.**
|
||||
```
|
||||
@@ -3748,7 +3748,7 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdPP` on main HEAD `ca09b6b` in response to Clawhip pinpoint nudge at `1494917922076889139`. Joins **Permission-audit / tool-allow-list** (#94, #97, #101, #106) as 5th member — this is the init-time ANCHOR of the permission-posture problem: #87 is absence-of-config, #101 is fail-OPEN on bad env var, **#115** is the init-generated dangerous default. Joins **Silent-flag / documented-but-unenforced** (#96–#101, #104, #108, #111) on the third axis: not a silent flag, but a silent setting (the generated config's security implications are silent in the init output). Cross-cluster with **Reporting-surface / config-hygiene** (#90, #91, #92, #110) on the structured-data-vs-prose axis: `claw init --output-format json` wraps all structure inside `message`. Cross-cluster with **Truth-audit** on "Next step: Review and tailor the generated guidance" phrasing — misleads by omission. Natural bundle: **#87 + #101 + #115** — "permission drift at every boundary": absence default + env-var bypass + init-generated default. Also: **#50 + #87 + #91 + #94 + #97 + #101 + #115** — flagship permission-audit sweep now 7-way. Session tally: ROADMAP #115.
|
||||
|
||||
116. **DONE — Unknown keys in `.claw.json` are strict ERRORS, not warnings — `claw` hard-fails at startup with exit 1 if any field is unrecognized. Only the FIRST error is reported; all subsequent validation messages are lost. Valid Claude Code config fields (`apiKeyHelper`, `env`, and other Claude-Code-native keys) trigger the same hard-fail, so a user renaming `.claude.json → .claw.json` for migration gets `"unknown key \"apiKeyHelper\"" ... exit 1` with zero guidance on what to delete. The error goes to stderr as structured JSON (`{"type":"error","error":"..."}`) but a `--output-format json` consumer has to read BOTH stdout AND stderr to capture success-or-error — the stdout side is empty on error. There is no `--ignore-unknown-config` flag, no `strict` vs `warn` mode toggle, no forward-compat path — a claw's future-self putting a single new field in the config kills every older claw binary** — dogfooded 2026-04-18 on main HEAD `ad02761` from `/tmp/cdRR`.
|
||||
116. **Unknown keys in `.claw.json` are strict ERRORS, not warnings — `claw` hard-fails at startup with exit 1 if any field is unrecognized. Only the FIRST error is reported; all subsequent validation messages are lost. Valid Claude Code config fields (`apiKeyHelper`, `env`, and other Claude-Code-native keys) trigger the same hard-fail, so a user renaming `.claude.json → .claw.json` for migration gets `"unknown key \"apiKeyHelper\"" ... exit 1` with zero guidance on what to delete. The error goes to stderr as structured JSON (`{"type":"error","error":"..."}`) but a `--output-format json` consumer has to read BOTH stdout AND stderr to capture success-or-error — the stdout side is empty on error. There is no `--ignore-unknown-config` flag, no `strict` vs `warn` mode toggle, no forward-compat path — a claw's future-self putting a single new field in the config kills every older claw binary** — dogfooded 2026-04-18 on main HEAD `ad02761` from `/tmp/cdRR`.
|
||||
|
||||
**Concrete repro.**
|
||||
```
|
||||
@@ -4021,7 +4021,7 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdTT` on main HEAD `b9331ae` in response to Clawhip pinpoint nudge at `1494940571385593958`. Joins **Silent-flag / documented-but-unenforced** (#96–#101, #104, #108, #111, #115, #116, #117) as 13th member — more severe than #111 (3-way collapse vs 2-way). Joins **Truth-audit / diagnostic-integrity** on the help-vs-implementation-mismatch axis. Cross-cluster with **Parallel-entry-point asymmetry** (#91, #101, #104, #105, #108, #114, #117) on the "multiple surfaces with distinct-advertised-but-identical-implemented behavior" axis. Natural bundle: **#111 + #118** — dispatch-collapse pair: `/providers` → `Doctor` (2-way) + `/stats`+`/tokens`+`/cache` → `Stats` (3-way). Complete parser-dispatch audit shape. Also **#108 + #111 + #118** — parser-level trust gaps: typo fallthrough (#108) + 2-way collapse (#111) + 3-way collapse (#118). Session tally: ROADMAP #118.
|
||||
|
||||
119. **DONE — The "this is a slash command, use `--resume`" helpful-error path only triggers for EXACTLY-bare slash verbs (`claw hooks`, `claw plan`) — any argument after the verb (`claw hooks --help`, `claw plan list`, `claw theme dark`, `claw tokens --json`, `claw providers --output-format json`) silently falls through to Prompt dispatch and burns billable tokens on a nonsensical "hooks --help" user-prompt. The helpful-error function at `main.rs:765` (`bare_slash_command_guidance`) is gated by `if rest.len() != 1 { return None; }` at `main.rs:746`. Nine known slash-only verbs (`hooks`, `plan`, `theme`, `tasks`, `subagent`, `agent`, `providers`, `tokens`, `cache`) ALL exhibit this: bare → clean error; +any-arg → billable LLM call. Users discovering `claw hooks` by pattern-following from `claw status --help` get silently charged** — dogfooded 2026-04-18 on main HEAD `3848ea6` from `/tmp/cdUU`.
|
||||
119. **The "this is a slash command, use `--resume`" helpful-error path only triggers for EXACTLY-bare slash verbs (`claw hooks`, `claw plan`) — any argument after the verb (`claw hooks --help`, `claw plan list`, `claw theme dark`, `claw tokens --json`, `claw providers --output-format json`) silently falls through to Prompt dispatch and burns billable tokens on a nonsensical "hooks --help" user-prompt. The helpful-error function at `main.rs:765` (`bare_slash_command_guidance`) is gated by `if rest.len() != 1 { return None; }` at `main.rs:746`. Nine known slash-only verbs (`hooks`, `plan`, `theme`, `tasks`, `subagent`, `agent`, `providers`, `tokens`, `cache`) ALL exhibit this: bare → clean error; +any-arg → billable LLM call. Users discovering `claw hooks` by pattern-following from `claw status --help` get silently charged** — dogfooded 2026-04-18 on main HEAD `3848ea6` from `/tmp/cdUU`.
|
||||
|
||||
**Concrete repro.**
|
||||
```
|
||||
@@ -4120,7 +4120,7 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
|
||||
|
||||
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdUU` on main HEAD `3848ea6` in response to Clawhip pinpoint nudge at `1494948121099243550`. Joins **Silent-flag / documented-but-unenforced** (#96–#101, #104, #108, #111, #115, #116, #117, #118) as 14th member — the fall-through to Prompt is silent. Joins **Claude Code migration parity** (#103, #109, #116, #117) as 5th member — users coming from Claude Code muscle-memory for `claude <verb> --help` get silently billed. Joins **Truth-audit / diagnostic-integrity** — the CLI claims "missing credentials" but the true cause is "your CLI invocation was interpreted as a chat prompt." Cross-cluster with **Parallel-entry-point asymmetry** (#91, #101, #104, #105, #108, #114, #117) — another entry point (slash-verb + args) that differs from the same verb bare. Natural bundle: **#108 + #117 + #119** — billable-token silent-burn triangle: typo fallthrough (#108) + flag swallow (#117) + known-slash-verb-with-args fallthrough (#119). All three are silent-money-burn failure modes with the same underlying cause: too-narrow parser detection + greedy Prompt dispatch. Also **#108 + #111 + #118 + #119** — parser-level trust gap quartet: typo fallthrough (#108) + 2-way slash collapse (#111) + 3-way slash collapse (#118) + known-slash-verb fallthrough (#119). Session tally: ROADMAP #119.
|
||||
|
||||
120. **DONE — `.claw.json` is parsed by a custom JSON-ish parser (`JsonValue::parse` in `rust/crates/runtime/src/json.rs`) that accepts trailing commas (one), but silently drops files containing line comments, block comments, unquoted keys, UTF-8 BOM, single quotes, hex numbers, leading commas, or multiple trailing commas. The user sees `.claw.json` behave partially like JSON5 (trailing comma works) and reasonably assumes JSON5 tolerance. Comments or unquoted keys — the two most common JSON5 conveniences a developer would reach for — silently cause the entire config to be dropped with ZERO stderr, exit 0, `loaded_config_files: 0`. Since the no-config default is `danger-full-access` per #87, a commented-out `.claw.json` with `"defaultMode": "default"` silently UPGRADES permissions from intended `read-only` to `danger-full-access` — a security-critical semantic flip from the user's expressed intent to the polar opposite** — dogfooded 2026-04-18 on main HEAD `7859222` from `/tmp/cdVV`. Extends #86 (silent-drop) with the JSON5-partial-tolerance + alias-collapse angle.
|
||||
120. **`.claw.json` is parsed by a custom JSON-ish parser (`JsonValue::parse` in `rust/crates/runtime/src/json.rs`) that accepts trailing commas (one), but silently drops files containing line comments, block comments, unquoted keys, UTF-8 BOM, single quotes, hex numbers, leading commas, or multiple trailing commas. The user sees `.claw.json` behave partially like JSON5 (trailing comma works) and reasonably assumes JSON5 tolerance. Comments or unquoted keys — the two most common JSON5 conveniences a developer would reach for — silently cause the entire config to be dropped with ZERO stderr, exit 0, `loaded_config_files: 0`. Since the no-config default is `danger-full-access` per #87, a commented-out `.claw.json` with `"defaultMode": "default"` silently UPGRADES permissions from intended `read-only` to `danger-full-access` — a security-critical semantic flip from the user's expressed intent to the polar opposite** — dogfooded 2026-04-18 on main HEAD `7859222` from `/tmp/cdVV`. Extends #86 (silent-drop) with the JSON5-partial-tolerance + alias-collapse angle.
|
||||
|
||||
**Concrete repro.**
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user