mirror of
https://github.com/ultraworkers/claw-code.git
synced 2026-04-26 22:47:38 +08:00
roadmap: #262 filed
This commit is contained in:
parent
2a0e5de3fe
commit
0e4fd386af
19
ROADMAP.md
19
ROADMAP.md
@ -16871,3 +16871,22 @@ Dogfooded 2026-04-26 12:30 KST against the live status summaries after #260. Mul
|
||||
Concrete failure mode: downstream agents use compact summaries to decide whether a cycle was handled, but a range/count mismatch forces manual recounting and can cause skipped cycle numbers or duplicate filings. This is distinct from #259: #259 verifies source freshness against git/ROADMAP; #261 verifies the report's own derived fields after freshness is established.
|
||||
|
||||
Required fix shape: `claw dogfood status --compact` should compute and validate `pinpoint_range_start`, `pinpoint_range_end`, `pinpoint_count`, `cycle_range`, and `listed_items_count` from the same parsed ledger, not freeform text. If the rendered text contains a numeric count or range, a pre-send validator should assert `end-start+1 == listed_items_count == pinpoint_count` and emit `STATUS_COUNT_MISMATCH` instead of publishing. Acceptance: a status report cannot say “8 items (#252–#260)” while listing nine bullets; the command either corrects the count or refuses the report with the mismatched fields. **Status:** Open. Filed as ROADMAP-only dogfood pinpoint from the 2026-04-26 03:30 UTC nudge; branch verified and pushed on top of #260.
|
||||
|
||||
## Pinpoint #262 — `--max-turns N` is structurally absent from the CLI surface AND fails with two different silent shapes depending on argv position relative to `-p`: pre-`-p` raises `unknown option`, post-`-p` is silently absorbed into the prompt body via `args[index+1..].join(" ")` greedy slurp, with no diagnostic and no help-text mention
|
||||
|
||||
Dogfooded 2026-04-26 12:32 KST on `feat/jobdori-168c-emission-routing` at HEAD `2a0e5de` (post-#261 fast-forward verification onto gaebal-gajae's compact-summary self-consistency-check pinpoint). Reproduction matrix against `./rust/target/release/claw`:
|
||||
|
||||
- `claw -p "say hi" --max-turns 0` → exits with `[error-kind: missing_credentials]` (the prompt body becomes `"say hi --max-turns 0"` and dispatch proceeds normally; no flag was rejected, no diagnostic about `--max-turns`, the credential error is downstream of an already-mangled prompt).
|
||||
- `claw --max-turns 0 -p "say hi"` → exits with `[error-kind: cli_parse]` `error: unknown option: --max-turns` (rejected by `format_unknown_option` at `rust/crates/rusty-claude-cli/src/main.rs:1565` because the parse loop sees `--max-turns` BEFORE `-p` and falls into the catch-all `other if rest.is_empty() && other.starts_with('-')` arm at `main.rs:993`).
|
||||
- `claw --max-turns=0 -p "say hi"` → same `unknown option: --max-turns=0` rejection.
|
||||
- `claw "hello world" --max-turns 0` → bare-prompt branch silently accepts (positional rest collects `["hello world", "--max-turns", "0"]` because the `other` arm at `main.rs:996-999` pushes any non-flag-after-rest onto `rest`).
|
||||
|
||||
Gap. **`--max-turns` does not exist** in the claw-code CLI surface: zero entries in `CLI_OPTION_SUGGESTIONS` (`main.rs:176-194`), zero match arms in `parse_args` (`main.rs:811-1004`), zero mention in `--help` output, zero typed `MaxTurns` field on `CliAction::Prompt` (`main.rs:696-749`), zero turn-budget plumbing into `LiveCli::run_turn_with_output` or `runtime.run_turn`. The only `turns` accounting in the runtime is the post-hoc `UsageTracker::turns()` counter (`main.rs:3156, 4915, 5762`) — a read-only odometer, not an enforced ceiling. This contrasts with Claude Code (the upstream CLI) which exposes `--max-turns N` as a documented turn-budget enforcement flag and which is the canonical way operators bound runaway tool-use loops in non-interactive `-p` mode.
|
||||
|
||||
Worse, the failure mode is **structurally asymmetric depending on argv position relative to `-p`** — a property no other silent-fallback family member exhibits. The `-p` arm at `main.rs:944` does `let prompt = args[index + 1..].join(" ")`, a greedy-slurp design that consumes EVERYTHING after `-p` as prompt body without re-entering the flag-parse loop. Any unknown flag passed AFTER `-p` is silently absorbed into the user's prompt. A `--max-turns 0` passed after `-p` is not just unsupported; it is invisibly mutated into prompt content, polluting the model input with operator-intended-machine-control-tokens that the model will see as natural language. A `--max-turns 0` passed BEFORE `-p` is at least surfaced as `unknown option`. The two outcomes — silent-prompt-pollution vs. typed-cli_parse-error — for the SAME flag differ ONLY by argv position, with no documentation that the boundary exists. The `-p` greedy-slurp is the actual silent-fallback site; `--max-turns` is just one observable instance of the class.
|
||||
|
||||
Cluster delta: joins the silent-fallback / silent-drop / silent-strip / silent-coercion / silent-prompt-absorption sibling-shape cluster, **extending it from 9 to 10 members** (#258 CLI-parse empty-coercion → #260 response-envelope strip → #262 CLI-parse position-sensitive-prompt-absorption). #262 is the FIRST member where the silent shape is **conditional on argv position relative to a sibling flag**, founding the **position-sensitive-parse-asymmetry sub-shape** within the silent-fallback family: the same input text produces a typed error or silent prompt-pollution depending only on argv ordering. Distinct from #258 (`--allowedTools ""` empty-string-coercion: silent always, regardless of position) by being position-conditional. Distinct from #260 (compact-JSON envelope strip: silent always, response-side) by being request-side argv-parse. Distinct from prior unknown-option behavior (which is not silent) because the silent path is reached only when the unknown flag arrives after `-p`. Audit-completeness for the silent-fallback chain at the **numeric-flag boundary** AND the **position-sensitive-CLI-parse boundary** simultaneously — two structurally distinct surfaces audited in one pinpoint. Does NOT found a new top-level cluster (per #253 context-budget discipline preferring extension over founding); the position-sensitive-parse-asymmetry is registered as a sub-shape inside the existing silent-fallback family.
|
||||
|
||||
Required fix shape: (a) declare `--max-turns N` as a typed CLI flag with `validate_max_turns` accepting `u32` (rejecting negative and non-numeric values with a typed `MaxTurnsParseError`), thread `max_turns: Option<u32>` through `CliAction::Prompt` and `LiveCli::run_turn_with_output`, and pass it as a hard ceiling into the runtime turn loop so `runtime.run_turn` returns a typed `TurnBudgetExhausted` event when the count is reached; (b) add `--max-turns` to `CLI_OPTION_SUGGESTIONS` (`main.rs:176-194`) and to `--help` output; (c) restructure the `-p` arm at `main.rs:944` so it does NOT greedily slurp `args[index+1..].join(" ")` but instead consumes only the next argv slot as the prompt and continues the flag-parse loop, OR explicitly require `-p` to be the LAST flag (rejecting any token starting with `-` after `-p` with `error: -p must be the final flag; saw '--max-turns' after the prompt`); (d) treat `--max-turns 0` semantically as "return immediately after dispatch with `iterations: 0` and no model call" (matching upstream Claude Code's documented zero-turn behavior, useful for cost-zero parse-validation runs); (e) emit a `CliFlagWarning` structured event when `--output-format json` is active and an unknown flag is detected after `-p`, so downstream consumers can surface the would-have-been-silent prompt-pollution diagnostic; (f) add tests covering `["-p", "x", "--max-turns", "0"]`, `["--max-turns", "0", "-p", "x"]`, `["-p", "x", "--unknown-flag"]`, `["--max-turns=5", "-p", "x"]`, `["-p", "x", "--max-turns=-1"]`, and `["hello", "--max-turns", "0"]` (bare-prompt rest-positional case). Acceptance: `claw -p "x" --max-turns 0` either rejects with a typed error OR enforces the turn budget without silently mutating the prompt; `claw --max-turns 0 -p "x"` and `claw -p "x" --max-turns 0` produce structurally equivalent outcomes (no position-sensitive divergence); `claw --help` lists `--max-turns N`; downstream JSON consumers can detect the would-have-been-silent absorption case.
|
||||
|
||||
**Status:** Open. No source code changed. Filed 2026-04-26 12:32 KST. Branch: feat/jobdori-168c-emission-routing. HEAD: `2a0e5de` (post-#261 fast-forward verification onto gaebal-gajae's compact-summary self-consistency-check pinpoint). Cluster delta: silent-fallback-family extension 9→10 (no new top-level cluster founded, per #253 context-budget discipline). Position-sensitive-parse-asymmetry sub-shape introduced (request-side argv-parse layer, sibling to #258's empty-value-coercion at the same layer and #260's response-envelope-strip at the response-side serialize layer). Sibling: #258 (`--allowedTools ""` empty-coercion at CLI parse boundary, position-invariant), #260 (`--compact --output-format json` envelope strip at CLI response-envelope layer, position-invariant), #98/#136 (predecessor `--compact` silent-no-op family at the dispatch layer). Together with #258 and #260, #262 brackets the CLI parse boundary across THREE structurally distinct silent-fallback shapes: empty-value-coercion (#258), response-envelope-strip (#260), and position-sensitive-prompt-absorption-of-unknown-flag (#262). Tenth-cycle concurrent-dogfood-rebase parity confirmed local==origin==fork at HEAD `2a0e5de` before filing.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user