mirror of
https://github.com/ultraworkers/claw-code.git
synced 2026-04-27 06:57:37 +08:00
roadmap: #272 filed
This commit is contained in:
parent
77c5e4f5cc
commit
c7d2c4e47f
33
ROADMAP.md
33
ROADMAP.md
@ -17028,3 +17028,36 @@ Gap. There is no mandatory repo-identity assertion in dogfood status generation.
|
||||
Required fix shape: (a) define a canonical dogfood target identity for each Clawhip nudge (`repo_owner/name`, `remote_url`, `branch`, `worktree_path`, required backlog file such as `ROADMAP.md`, and optional fork remote); (b) before generating status or filing a pinpoint, assert the current cwd/remotes/branch/backlog-file match that identity; (c) emit `DOGFOOD_REPO_MISMATCH` and refuse to publish if the active repo is `code-yeongyu/claw-code` or any sibling while the nudge targets `ultraworkers/claw-code`; (d) include the verified tuple in every status report as machine fields, not prose; (e) add regression coverage where two repos named `claw-code` exist and the status command must reject the wrong one despite similar names. Acceptance: a `claw-code` dogfood nudge cannot produce a status report for `code-yeongyu/claw-code`; wrong-repo analysis fails closed with a typed mismatch receipt instead of entering the public status stream.
|
||||
|
||||
**Status:** Open. No source code changed. Filed 2026-04-26 15:02 KST. Branch: feat/jobdori-168c-emission-routing. HEAD: `61be826` before filing. Cluster delta: dogfood-repo-identity-guard +1; sibling to #259 (freshness/provenance), #253 (state-vector context budget), and #269 (transport delivery), but distinct source-of-truth selection layer. Concrete delta this cycle: ROADMAP-only pinpoint appended from live wrong-repo report evidence.
|
||||
|
||||
## Pinpoint #272 — `--max-turns 0` zero-turn semantics are unspecified at the spec layer: three valid interpretations (parse-error, unlimited-sentinel, run-zero-iterations-fast-return) coexist with no canonicalization, the existing pinpoints #262 and #264 each prescribe the same fast-return resolution in passing without anchoring to upstream prior art, and the interaction matrix between `max_turns: 0` and `--allowedTools`, `--dangerously-skip-permissions`, session-state recording, hook execution, and `system_prompt` event emission is undefined
|
||||
|
||||
Dogfooded 2026-04-26 15:04 KST on `feat/jobdori-168c-emission-routing` at HEAD `29c262c` (post-rebase fast-forward onto gaebal-gajae's #271 dogfood-repo-identity-guard pinpoint). Reproduction matrix against `./rust/target/release/claw` (current built artifact, no source change required to demonstrate the gap):
|
||||
|
||||
- `claw --max-turns 0 -p "say hi"` → `[error-kind: cli_parse] error: unknown option: --max-turns` (rejected pre-`-p`, sister to #262 parse-side absence).
|
||||
- `claw -p "say hi" --max-turns 0` → `[error-kind: missing_credentials]` (silently absorbed into prompt body, sister to #262 position-sensitive prompt-pollution).
|
||||
- `claw --max-turns 0 prompt "say hi"` → `unknown option: --max-turns` (subcommand path also rejects).
|
||||
- `claw --max-turns=0 -p "say hi"` → `unknown option: --max-turns=0` (`=`-form same).
|
||||
|
||||
This confirms #262's surface verdict (the flag does not exist) and #264's runtime verdict (no typed primitive to plumb into). What remains uncovered, and what #272 catalogues, is the **spec/contract layer underneath both**: even granting #262's CLI flag and #264's `TurnBudget` struct land, the literal value `0` has at least three operationally distinct interpretations, none of which is anchored to a referenced precedent or bound by an interaction matrix in the existing audit triangle.
|
||||
|
||||
Three competing `--max-turns 0` semantics, each operationally valid, mutually inconsistent:
|
||||
|
||||
(1) **Parse-time error** (`MaxTurnsParseError: must be ≥ 1`): treats `0` as out-of-range like a negative number; matches the strict-validator family (`--reasoning-effort yolo` at `main.rs:11288-11294` rejects out-of-set values typed). Operationally useful for catching shell-substitution bugs (`--max-turns $UNSET_VAR` expanding to `0`). Cost: blocks the cost-zero parse-validation use case the existing pinpoints both endorse.
|
||||
|
||||
(2) **Unlimited sentinel** (`max_turns: 0` ≡ `usize::MAX`): C-stdlib / many Rust APIs use `0` as "no limit" (e.g. `std::io::Read::take(0)` semantics vary by trait, `tokio::sync::mpsc::channel(0)` rejects, but `tower::limit::ConcurrencyLimit::new(0)` admits zero permits). The existing `max_iterations: usize::MAX` default at `runtime/conversation.rs:181` already encodes "unlimited" as a max-int sentinel, and a careless port of that idiom could land `0`-as-unlimited. Operationally hostile: a user typing `--max-turns 0` to validate-only would instead unleash an unbounded loop.
|
||||
|
||||
(3) **Run-zero-iterations fast-return** (`Ok(TurnSummary { iterations: 0, assistant_messages: vec![], no_model_call: true })`): the resolution both #262 fix-shape (d) and #264 fix-shape (g) prescribe in passing. Operationally useful for cost-zero parse-validation ("does my CLI invocation parse, do my hooks load, do my tools register?") without consuming model tokens. But the existing pinpoints prescribe this resolution **without citing the upstream contract** (Anthropic Claude Code's documented `--max-turns 0` behavior, OpenAI Codex's analogous flag, or any Rust runtime precedent), and **without specifying the interaction matrix** below.
|
||||
|
||||
Verified concrete surface (rg across `rust/crates/`): zero `MaxTurnsZero`, zero `ZeroTurnFastReturn`, zero `no_model_call`, zero documented `0`-handling for `with_max_iterations` callers. The existing test at `runtime/conversation.rs:1768` constructs `with_max_iterations(1)` (smallest positive integer tested), not `with_max_iterations(0)` — so even the runtime primitive #264 catalogues has no test coverage for the zero-edge case. The subagent default `DEFAULT_AGENT_MAX_ITERATIONS: usize = 32` at `tools/lib.rs:3475` is also untested at boundary `0`.
|
||||
|
||||
Undefined interaction matrix (each cell needs a documented contract before any `--max-turns 0` semantics is canonical): (i) `--max-turns 0 --allowedTools "Read,Bash"` — does the empty turn still validate the allow-list (could surface `--allowedTools` parse errors typed) or skip validation (cheaper but loses the use case)? (ii) `--max-turns 0 --dangerously-skip-permissions` — does the zero-turn run still record the dangerous-permission flag in session metadata for audit, or is the session never created? (iii) `--max-turns 0` with a `.claw-session.jsonl` resume — does it append a no-op turn record (preserving session continuity), or silently no-op (saving a row but losing the audit trail of the zero-turn invocation)? (iv) `--max-turns 0` with `PreToolUse` / `PostToolUse` hooks registered — do hooks fire (giving observability of "dispatch reached") or skip (matching the no-tool-call contract)? (v) `--max-turns 0 --output-format json` — does the JSON envelope include `iterations: 0, assistant_messages: []` (consistent with #260's compact-JSON envelope shape) or emit a degenerate `null`/empty body? (vi) `--max-turns 0` and `system_prompt` event lane — does the event still emit (so consumers see the system prompt that *would* have been sent) or skip emission?
|
||||
|
||||
Gap. The spec layer is the **prerequisite that #262 and #264's fix-shapes both implicitly assume but neither documents**. #262 prescribes "return immediately after dispatch with `iterations: 0` and no model call" as the right semantic in fix-shape (d), but does not anchor that choice to a referenced upstream contract, does not address negative values explicitly (`--max-turns -1`: error or alias for unlimited?), and does not address `u32::MAX` (does any positive integer mean unlimited, or does the field have to become `Option<u32>`?). #264 prescribes the same `Ok(TurnSummary { iterations: 0, … })` in fix-shape (g) but inherits the same un-anchored decision and adds no interaction-matrix coverage. **No pinpoint in the existing turn-budget cluster catalogues the canonicalization act itself**: choosing semantic (3) over (1) and (2), citing the precedent, and binding the choice across the six interaction cells above.
|
||||
|
||||
Cluster shape novelty: completes the **turn-budget audit triangle** (#262 = CLI-parse layer, #264 = runtime-typed-primitive layer, #272 = spec/contract layer). The triangle now covers all three structural slots a single user-facing flag must occupy before it can ship: the request-shape gap (parse), the type-shape gap (primitive), and the meaning-shape gap (spec). Distinct from #262 (parse-side absence; #262 is "flag does not exist on the parser", #272 is "even if it existed, the value `0` has no canonical meaning"). Distinct from #264 (runtime-primitive absence; #264 is "the type cannot represent the budget", #272 is "the budget value `0` resolves to three different runtime behaviors"). Distinct from #266 (`RuntimeErrorKind` typed-error enum gap; #266 catalogues missing typed-error discriminants, #272 catalogues missing typed-success-with-zero-iterations contract).
|
||||
|
||||
Discovery-pattern continuation: founds the **Spec/contract-canonicalization-gap** sub-shape inside the turn-budget cluster, the FIRST pinpoint where the gap is not absent-flag (#262), absent-primitive (#264), or absent-error-kind (#266) but **absent-canonical-meaning-for-an-edge-value**. This sub-shape is portable: any other knob with a numeric or sentinel-shaped value (`--max-iterations`, `--timeout 0`, `--retries 0`, `--max-output-tokens 0`) has the same three-way ambiguity until canonicalized. Extends the audit-triangle pattern itself to a **three-layer-completeness** primitive: a single user-facing capability requires audit at parse-layer + primitive-layer + spec-layer before any of the three is shippable. Sister-shaped to #245+#250 (WebSearch client+server pair) and #262+#264 (turn-budget parse+primitive pair) but extends those bundles from 2-tuple to 3-tuple.
|
||||
|
||||
Required fix shape: (a) write a `TURN_BUDGET_SPEC.md` (or similar canonical-contract document under `docs/specs/`) that anchors `--max-turns 0` semantics to a referenced upstream precedent (Anthropic Claude Code's documented zero-turn behavior, with link), explicitly resolves the choice as semantic (3) `run-zero-iterations-fast-return`, and explicitly rejects semantics (1) and (2) with rationale; (b) define negative-value handling: `--max-turns -1` rejected at parse-time as `cli_parse` error (mirrors `--reasoning-effort yolo` typed-rejection precedent), with no alias semantics; (c) define unlimited-budget handling: introduce `--max-turns unlimited` as an explicit string sentinel OR document that no value means unlimited and unbounded loops require omitting the flag (avoid u32::MAX-as-sentinel which breaks downstream JSON consumers); (d) document the six-cell interaction matrix above with one paragraph per cell, each binding to a typed event/receipt: zero-turn run with `--allowedTools` validates the allow-list (cell i), records dangerous-permission flag in session-meta (cell ii), appends a typed `ZeroTurnInvocation` row to session.jsonl (cell iii), skips hook execution (cell iv) consistent with no-tool-call contract, emits `iterations: 0, assistant_messages: []` JSON envelope (cell v), and emits the `system_prompt` event so consumers can audit the would-have-been-sent prompt (cell vi); (e) replace `max_turns: u32` with `max_turns: TurnLimit` enum where `pub enum TurnLimit { Unlimited, ZeroFastReturn, Bounded(NonZeroU32) }` so the type system enforces the spec at compile-time and `0` cannot be confused with `unlimited` at any call site; (f) add tests for each interaction-matrix cell (i-vi) plus `TurnLimit::ZeroFastReturn` round-trip through `--output-format json`; (g) cross-reference the spec document from the `--max-turns` help text (#262 fix-shape (b) addition) and from the `TurnBudget` doc-comment (#264 fix-shape (a)) so future readers find canonical meaning before runtime behavior. Acceptance: `--max-turns 0` has exactly one documented behavior across CLI/runtime/JSON layers; the type system prevents semantics (1) and (2) from being silently introduced by a refactor; the six interaction cells each have a typed receipt; #262 and #264's fix-shapes can land knowing which `0` they are encoding; future zero-edge knobs (`--retries 0`, `--timeout 0`) have a canonicalization template to follow.
|
||||
|
||||
**Status:** Open. No source code changed. Filed 2026-04-26 15:04 KST. Branch: feat/jobdori-168c-emission-routing. HEAD: `29c262c` before filing (post-rebase fast-forward onto gaebal-gajae's #271 dogfood-repo-identity-guard pinpoint). Cluster delta: turn-budget cluster 2→3 (#262 parse-layer + #264 primitive-layer + #272 spec-layer = audit-triangle complete on a single user-facing flag); Spec/contract-canonicalization-gap sub-shape introduced (NEW sub-shape inside turn-budget cluster, portable to any sentinel-shaped numeric flag); complementary-pinpoint-pair-bundle discovery-pattern extended from 5 bundles to a first **three-tuple** (#262+#264+#272). Smaller-scope by design (matches #253-#271 context-budget discipline). Sister: #262 (parse-side; #262+#272 bracket the parse boundary's request-shape and meaning-shape gaps), #264 (primitive-side; #264+#272 bracket the runtime layer's type-shape and meaning-shape gaps), #266 (runtime-error-enum gap, parallel typed-meaning-axis but on errors not successes). Distinct from #271 (repo-identity guard at the dogfood layer; orthogonal to the turn-budget audit triangle). Distinct from silent-fallback family (catalogues silent input/output mutation; #272 catalogues missing canonical meaning at edge value). Concurrent-dogfood-rebase parity will be confirmed local==origin==fork at HEAD `29c262c+#272` after push.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user