Skip to content

Commit 3848ea6

Browse files
committed
ROADMAP ultraworkers#118: /stats, /tokens, /cache all collapse to SlashCommand::Stats; 3-way dispatch collapse with 3 distinct help descriptions
Dogfooded 2026-04-18 on main HEAD b9331ae from /tmp/cdTT. Three slash commands collapse to one handler: $ claw --help | grep -E '^\s*/(stats|tokens|cache)\s' /stats Show workspace and session statistics [resume] /tokens Show token count for the current conversation [resume] /cache Show prompt cache statistics [resume] Three distinct promises. One implementation: $ claw --resume s --output-format json /stats {"kind":"stats","input_tokens":0,"output_tokens":0, "cache_creation_input_tokens":0,"cache_read_input_tokens":0, "total_tokens":0} $ claw --resume s --output-format json /tokens {"kind":"stats", ...identical...} $ claw --resume s --output-format json /cache {"kind":"stats", ...identical...} diff /stats /tokens → empty diff /stats /cache → empty kind field is always 'stats', never 'tokens' or 'cache'. Trace: commands/src/lib.rs:1405-1408: 'stats' | 'tokens' | 'cache' => { validate_no_args(command, &args)?; SlashCommand::Stats } commands/src/lib.rs:317 SlashCommandSpec name='stats' registered commands/src/lib.rs:702 SlashCommandSpec name='tokens' registered SlashCommandSpec name='cache' also registered Each has distinct summary/description in help. No SlashCommand::Tokens or SlashCommand::Cache variant exists. main.rs:2872-2879 SlashCommand::Stats handler hard-codes 'kind': 'stats' regardless of which alias invoked. More severe than ultraworkers#111: ultraworkers#111: /providers → Doctor (2-way collapse, wildly wrong category) ultraworkers#118: /stats + /tokens + /cache → Stats (3-way collapse with THREE distinct advertised purposes) The collapse hides information that IS available. /stats output has cache_creation_input_tokens + cache_read_input_tokens as top-level fields, so cache data is PRESENT. But /cache should probably return {kind:'cache', cache_hits, cache_misses, hit_rate}, a cache-specific schema. Similarly /tokens should return {kind:'tokens', conversation_total, turns, average_per_turn}. Implementation returns the union for all. Fix shape (~90 lines): - Add SlashCommand::Tokens and SlashCommand::Cache variants - Parser arms: 'tokens' => SlashCommand::Tokens 'cache' => SlashCommand::Cache 'stats' => SlashCommand::Stats - Handlers with distinct output schemas: /tokens: {kind:'tokens', conversation_total, input_tokens, output_tokens, turns, average_per_turn} /cache: {kind:'cache', cache_creation_input_tokens, cache_read_input_tokens, cache_hits, cache_misses, hit_rate_pct} /stats: {kind:'stats', subsystem:'all', ...} - Regression per alias: kind matches, schema matches purpose - Sweep parser for other collapse arms - If aliasing intentional, annotate --help with (alias for X) Joins Silent-flag/documented-but-unenforced (ultraworkers#96-ultraworkers#101, ultraworkers#104, ultraworkers#108, ultraworkers#111, ultraworkers#115, ultraworkers#116, ultraworkers#117) as 13th — more severe than ultraworkers#111. Joins Truth-audit on help-vs-implementation mismatch axis. Cross-cluster with Parallel-entry-point asymmetry on multiple- surfaces-identical-implementation axis. Natural bundles: ultraworkers#111 + ultraworkers#118 — dispatch-collapse pair: /providers → Doctor (2-way, wildly wrong) /stats+/tokens+/cache → Stats (3-way, distinct purposes) Complete parser-dispatch audit shape. ultraworkers#108 + ultraworkers#111 + ultraworkers#118 — parser-level trust gaps: typo fallthrough (ultraworkers#108) + 2-way collapse (ultraworkers#111) + 3-way collapse (ultraworkers#118) Filed in response to Clawhip pinpoint nudge 1494940571385593958 in #clawcode-building-in-public.
1 parent b9331ae commit 3848ea6

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

ROADMAP.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3800,3 +3800,85 @@ ear], /color [scheme], /effort [low|medium|high], /fast, /summary, /tag [label],
38003800
**Blocker.** None. Parser refactor is localized to one arm. Compatibility concern: anyone currently relying on `-p` greedy absorption (unlikely because it's silently-broken) would see a behavior change. Deprecation warning for one release softens the transition.
38013801
38023802
**Source.** Jobdori dogfood 2026-04-18 against `/tmp/cdSS` on main HEAD `f2d6538` in response to Clawhip pinpoint nudge at `1494933025857736836`. Joins **Silent-flag / documented-but-unenforced** (#96–#101, #104, #108, #111, #115, #116) as 12th member — `-p` is an undocumented-in-`--help` shortcut whose silent greedy behavior makes flag-order semantics invisible. Joins **Parallel-entry-point asymmetry** (#91, #101, #104, #105, #108, #114) as 7th — three entry points (`claw prompt TEXT`, bare positional `claw TEXT`, `claw -p TEXT`) with subtly different arg-parsing semantics. Joins **Truth-audit** — the parser is lying about what it parsed when `-p` is present. Joins **Claude Code migration parity** (#103, #109, #116) as 4th — users migrating `claude -p "..." --model ..."` silently get corrupted prompts. Cross-cluster with **Silent-flag** quartet (#96, #98, #108, #111) now quintet: #108 (subcommand typos fall through to Prompt, burning billed tokens) + **#117** (prompt flags swallowed into prompt text, ALSO burning billed tokens) — both are silent-token-burn failure modes. Natural bundle: **#108 + #117** — billable-token silent-burn pair: typo fallthrough + flag-swallow. Also **#105 + #108 + #117** — model-resolution triangle: `claw status` ignores .claw.json model (#105) + typo'd `claw statuss` burns tokens (#108) + `-p "test" --model sonnet` silently ignores the model (#117). Session tally: ROADMAP #117.
3803+
3804+
118. **Three slash commands — `/stats`, `/tokens`, and `/cache` — all collapse to `SlashCommand::Stats` at `commands/src/lib.rs:1405` (`"stats" | "tokens" | "cache" => SlashCommand::Stats`), returning bit-identical output (`{"kind":"stats", ...}`) despite `--help` advertising three distinct capabilities: `/stats` = "Show workspace and session statistics", `/tokens` = "Show token count for the current conversation", `/cache` = "Show prompt cache statistics". A claw invoking `/cache` expecting cache-focused output gets a grab-bag that says `kind: "stats"` — not even `kind: "cache"`. A claw invoking `/tokens` expecting a focused token report gets the same grab-bag labeled `kind: "stats"`. This is the 2-dimensional-superset of #111 (2-way dispatch collapse) — #118 is a 3-way collapse where each collapsed alias has a DIFFERENT help description, compounding the documentation-vs-implementation gap** — dogfooded 2026-04-18 on main HEAD `b9331ae` from `/tmp/cdTT`.
3805+
3806+
**Concrete repro.**
3807+
```
3808+
# Three distinct help lines:
3809+
$ claw --help | grep -E "^\s*/(stats|tokens|cache)\s"
3810+
/stats Show workspace and session statistics [resume]
3811+
/tokens Show token count for the current conversation [resume]
3812+
/cache Show prompt cache statistics [resume]
3813+
3814+
# All three return identical output with kind: "stats":
3815+
$ claw --resume s --output-format json /stats
3816+
{"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":0,"kind":"stats","output_tokens":0,"total_tokens":0}
3817+
3818+
$ claw --resume s --output-format json /tokens
3819+
{"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":0,"kind":"stats","output_tokens":0,"total_tokens":0}
3820+
3821+
$ claw --resume s --output-format json /cache
3822+
{"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"input_tokens":0,"kind":"stats","output_tokens":0,"total_tokens":0}
3823+
3824+
# diff /stats vs /tokens → identical
3825+
# diff /stats vs /cache → identical
3826+
# kind field is always "stats", never "tokens" or "cache"
3827+
```
3828+
3829+
**Trace path.**
3830+
- `rust/crates/commands/src/lib.rs:1405-1408` — the 3-way collapse:
3831+
```rust
3832+
"stats" | "tokens" | "cache" => {
3833+
validate_no_args(command, &args)?;
3834+
SlashCommand::Stats
3835+
}
3836+
```
3837+
Parser accepts all three verbs, produces identical enum variant. No `SlashCommand::Tokens` or `SlashCommand::Cache` exists.
3838+
- `rust/crates/rusty-claude-cli/src/main.rs:2872-2879` — the Stats handler:
3839+
```rust
3840+
SlashCommand::Stats => {
3841+
...
3842+
"kind": "stats",
3843+
...
3844+
}
3845+
```
3846+
Hard-codes `"kind": "stats"` regardless of which user-facing alias was invoked. A claw cannot tell from the output whether the user asked for `/stats`, `/tokens`, or `/cache`.
3847+
- `rust/crates/commands/src/lib.rs:317` — `SlashCommandSpec{ name: "stats", ... }` registered. One entry.
3848+
- `rust/crates/commands/src/lib.rs:702` — `SlashCommandSpec{ name: "tokens", ... }` registered. Separate entry with distinct `summary` and `description`.
3849+
- `rust/crates/commands/src/lib.rs` — `/cache` similarly gets its own `SlashCommandSpec` with distinct docs.
3850+
- So: three spec entries (each with unique help text) → one parser arm (collapse) → one handler (`SlashCommand::Stats`) → one output (`kind: "stats"`). Four surfaces, three aliases, one actual capability.
3851+
3852+
**Why this is specifically a clawability gap.**
3853+
1. *Help advertises three distinct capabilities that don't exist.* A claw that parses `--help` to discover capabilities learns there are three token-and-cache-adjacent commands with different scopes. The implementation betrays that discovery.
3854+
2. *`kind` field never reflects the user's invocation.* A claw programmatically distinguishing "stats" events from "tokens" events from "cache" events can't — they're all `kind: "stats"`. This is a type-loss in the telemetry/event layer: a consumer cannot switch on `kind`.
3855+
3. *More severe than #111.* #111 was `/providers` → `SlashCommand::Doctor` (2 aliases → 1 handler, wildly different advertised purposes). #118 is 3 aliases → 1 handler, THREE distinct advertised purposes (workspace statistics, conversation tokens, prompt cache). 3-way collapse with 3-way doc mismatch.
3856+
4. *The collapse loses information that IS available.* `Stats` output contains `cache_creation_input_tokens` and `cache_read_input_tokens` as top-level fields — so the cache-focused data IS present. But `/cache` should probably return `{kind: "cache", cache_hits: X, cache_misses: Y, hit_rate: Z%, ...}` — a cache-specific schema. Similarly `/tokens` should probably return `{kind: "tokens", conversation_total: N, turns: M, average_per_turn: ...}` — a turn-focused schema. Implementation returns the union instead.
3857+
5. *Joins truth-audit.* Three distinct promises in `--help`; one implementation underneath. The help text is true for `/stats` but misleading for `/tokens` and `/cache`.
3858+
6. *Joins silent-flag / documented-but-unenforced.* Help documents `/cache` as a distinct capability. Implementation silently substitutes. No warning, no error, no deprecation note.
3859+
7. *Pairs with #111.* `/providers` → `Doctor`. `/tokens` + `/cache` → `Stats`. Both are dispatch collapses where parser accepts multiple distinct surface verbs and collapses them to a single incorrect handler. The `commands/src/lib.rs` parser has at least two such collapse arms; likely more elsewhere (needs sweep).
3860+
3861+
**Fix shape — introduce separate SlashCommand variants, separate handlers, separate output schemas.**
3862+
1. *Add `SlashCommand::Tokens` and `SlashCommand::Cache` enum variants.* ~10 lines.
3863+
2. *Parser arms.* `"tokens" => SlashCommand::Tokens`, `"cache" => SlashCommand::Cache`. Keep `"stats" => SlashCommand::Stats`. ~8 lines.
3864+
3. *Handlers with distinct output schemas.*
3865+
```json
3866+
// /tokens
3867+
{"kind":"tokens","conversation_total":N,"input_tokens":I,"output_tokens":O,"turns":T,"average_per_turn":A}
3868+
3869+
// /cache
3870+
{"kind":"cache","cache_creation_input_tokens":C,"cache_read_input_tokens":R,"cache_hits":H,"cache_misses":M,"hit_rate_pct":P}
3871+
3872+
// /stats (existing, possibly add a `subsystem` field for consistency)
3873+
{"kind":"stats","subsystem":"all","input_tokens":I,"output_tokens":O,"cache_creation_input_tokens":C,"cache_read_input_tokens":R,...}
3874+
```
3875+
~50 lines of handler impls.
3876+
4. *Regression test per alias: `kind` matches invocation; schema matches advertised purpose.* ~20 lines.
3877+
5. *Sweep parser for other collapse arms.* `grep -E '"\w+" \| "\w+"' rust/crates/commands/src/lib.rs` to find all multi-alias arms. Validate each against help docs. (Already found: `#111` = doctor|providers; `#118` = stats|tokens|cache. Likely more.) ~5-10 remediations if more found.
3878+
6. *Documentation: if aliasing IS intentional, annotate `--help` so users know `/tokens` is literally `/stats`.* E.g. `/tokens (alias for /stats)`. ~5 lines.
3879+
3880+
**Acceptance.** `/stats` returns `kind: "stats"`. `/tokens` returns `kind: "tokens"` with a conversation-token-focused schema. `/cache` returns `kind: "cache"` with a prompt-cache-focused schema. `--help` either lists the three as distinct capabilities and each delivers, OR explicitly marks aliases. Parser collapse arms are audited across `commands/src/lib.rs`; any collapse that loses information is fixed.
3881+
3882+
**Blocker.** Product decision: is the 3-way collapse intentional (one command, three synonyms) or accidental (three commands, one implementation)? Help docs suggest the latter. Either path is fine, as long as behavior matches documentation.
3883+
3884+
**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.

0 commit comments

Comments
 (0)