From 1376d92064776cc02be8b3e5d570984815a82460 Mon Sep 17 00:00:00 2001 From: Yeachan-Heo Date: Wed, 29 Apr 2026 03:31:34 +0000 Subject: [PATCH] Filter stub commands from resume-safe help Keep claw --help's resume-safe slash command summary aligned with the interactive command list by filtering STUB_COMMANDS and adding regression coverage. --- ROADMAP.md | 2 +- progress.txt | 11 ++++++++++ rust/crates/rusty-claude-cli/src/main.rs | 27 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 688fe16..fbe1547 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2128,7 +2128,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)** — dogfooded 2026-04-18 on main HEAD `8db8e49` from `/tmp/cdK`. The `render_help` output emits two separate enumerations of slash commands; only one of them applies the stub filter. The Resume-safe summary advertises `/budget`, `/rate-limit`, `/metrics`, `/diagnostics`, `/bookmarks`, `/workspace`, `/reasoning`, `/changelog`, `/vim`, `/summary`, `/brief`, `/advisor`, `/stickers`, `/insights`, `/thinkback`, `/keybindings`, `/privacy-settings`, `/output-style`, `/allowed-tools`, `/tool-details`, `/language`, `/max-tokens`, `/temperature`, `/system-prompt` — all of which are explicitly in `STUB_COMMANDS` with "Did you mean" guards and no parse arm. +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. **Concrete repro.** ``` diff --git a/progress.txt b/progress.txt index 3914a31..d7953a1 100644 --- a/progress.txt +++ b/progress.txt @@ -365,3 +365,14 @@ US-021 COMPLETED (Request body size pre-flight check - from dogfood findings) - Tests: 5 new tests for size estimation and limit checking PROJECT STATUS: COMPLETE (21/21 stories) + +Iteration 2026-04-29 - ROADMAP #96 COMPLETED +------------------------------------------------ +- Pulled origin/main: already up to date. +- Selected ROADMAP #96 as a small repo-local Immediate Backlog item: the `claw --help` Resume-safe command summary leaked slash-command stubs despite the main Interactive command listing filtering them. +- Files: rust/crates/rusty-claude-cli/src/main.rs, ROADMAP.md, progress.txt. +- Changed help rendering to filter `resume_supported_slash_commands()` through `STUB_COMMANDS` before building the Resume-safe one-liner. +- Added `stub_commands_absent_from_resume_safe_help` regression coverage so future stub additions cannot leak into the Resume-safe summary. +- Targeted verification: `cargo test -p rusty-claude-cli stub_commands_absent_from_resume_safe_help -- --nocapture` passed; `cargo test -p rusty-claude-cli parses_direct_cli_actions -- --nocapture` passed. +- Format/check verification: `cargo fmt --all --check`, `git diff --check`, and `cargo check -p rusty-claude-cli` passed. +- Broader clippy note: `cargo clippy -p rusty-claude-cli --all-targets -- -D warnings` is blocked by pre-existing `clippy::unnecessary_wraps` failures in `rust/crates/commands/src/lib.rs` (`render_mcp_report_for`, `render_mcp_report_json_for`), outside this diff. diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index 9d9df4f..1098cd8 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -8952,6 +8952,7 @@ fn print_help_to(out: &mut impl Write) -> io::Result<()> { writeln!(out)?; let resume_commands = resume_supported_slash_commands() .into_iter() + .filter(|spec| !STUB_COMMANDS.contains(&spec.name)) .map(|spec| match spec.argument_hint { Some(argument_hint) => format!("/{} {}", spec.name, argument_hint), None => format!("/{}", spec.name), @@ -13000,6 +13001,32 @@ UU conflicted.rs", ); } } + + #[test] + fn stub_commands_absent_from_resume_safe_help() { + let mut help = Vec::new(); + print_help_to(&mut help).expect("help should render"); + let help = String::from_utf8(help).expect("help should be utf8"); + let resume_line = help + .lines() + .find(|line| line.starts_with("Resume-safe commands:")) + .expect("resume-safe command line should exist"); + let resume_roots = resume_line + .trim_start_matches("Resume-safe commands:") + .split(',') + .filter_map(|entry| entry.trim().strip_prefix('/')) + .filter_map(|entry| entry.split_whitespace().next()) + .collect::>(); + + for stub in STUB_COMMANDS { + assert!( + !resume_roots.contains(stub), + "stub command /{stub} should not appear in resume-safe command list" + ); + } + + assert!(resume_roots.contains(&"status")); + } } fn write_mcp_server_fixture(script_path: &Path) {