fix: keep failed resume side-effect free

Generated with https://github.com/Yeachan-Heo/gajae-code

Co-authored-by: Gajae Code <dev@gajae-code.com>
This commit is contained in:
bellman
2026-06-04 15:08:56 +09:00
parent b45c61eff9
commit d8535bf938
5 changed files with 201 additions and 12 deletions

View File

@@ -6377,10 +6377,10 @@ Original filing (2026-04-18): the session emitted `SessionStart hook (completed)
433. **DONE — `--output-format` selection is typed, case-insensitive, env-configurable, and auditable** — fixed 2026-06-04 in `fix: type output format selection`. `CliOutputFormat::parse` now accepts `text`/`json` in any casing, `CLAW_OUTPUT_FORMAT` seeds the default output format when no CLI output-format flag is present, explicit flags override the env default, and repeated flags emit `warning: --output-format specified multiple times; using last value '...'`. `status --output-format json` exposes `format_source`, `format_raw`, and `format_overridden`; invalid values return typed `invalid_output_format` JSON with `value`, `expected:["text","json"]`, and a recovery hint instead of `kind:"unknown"`. Top-level help documents `CLAW_OUTPUT_FORMAT`, `CLAW_LOG`, and `RUST_LOG`, and doctor system JSON surfaces those env values. Regression coverage: `output_format_flags_and_env_have_typed_contract_433` and `classify_error_kind_returns_correct_discriminants`. Verification: `cargo fmt --manifest-path rust/Cargo.toml --all -- --check`, focused output-format and classifier tests, `scripts/roadmap-check-ids.sh`, `git diff --check`, `cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --no-run`, and `cargo build --manifest-path rust/Cargo.toml --workspace --locked`.
434. **DONE — POSIX `--` and dash-prefixed shorthand prompts stay on the prompt path** — fixed 2026-06-04 in CI recovery after `41678eb` turned Rust CI red. Global argument parsing now treats `--` as an end-of-flags separator, stops JSON-output pre-scans before the separator, and forwards every following token as positional prompt text. Shorthand prompt mode accepts dash-prefixed text that is not a registered or near-miss CLI flag (`-not-a-flag`, `--bogus-flag-like literal`) while still rejecting real typo-like options such as `--resum` with the `--resume` suggestion. Direct `/status` invocation again remains REPL/session-only so the existing parser contract is restored. Help, USAGE, and rust README document the `claw -- "-prompt-with-dash"` form. Regression coverage: `parses_dash_prefixed_prompt_text_434`, plus rerun CI-red parser tests `parses_bare_prompt_and_json_output_flag` and `parses_direct_agents_mcp_and_skills_slash_commands`. Verification: `cargo fmt --manifest-path rust/Cargo.toml --all -- --check`, focused parser tests, `scripts/roadmap-check-ids.sh`, `git diff --check -- USAGE.md rust/README.md rust/crates/rusty-claude-cli/src/main.rs ROADMAP.md`, docs source-of-truth/release-readiness/unit helper checks, `cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --no-run`, `cargo build --manifest-path rust/Cargo.toml --workspace --locked`, and `cargo clippy --manifest-path rust/Cargo.toml --workspace`. Local `cargo test --manifest-path rust/Cargo.toml --workspace` still hits the pre-existing Darwin-only `runtime::worker_boot::startup_preflight_warns_when_git_metadata_is_not_writable` permission assertion after all CLI parser tests pass; the red GitHub jobs were parser failures on head `41678eb`.
434. **DONE — POSIX `--` and dash-prefixed shorthand prompts stay on the prompt path** — fixed 2026-06-04 in CI recovery after `41678eb` turned Rust CI red. Global argument parsing now treats `--` as an end-of-flags separator, stops JSON-output pre-scans before the separator, and forwards every following token as positional prompt text. Shorthand prompt mode accepts dash-prefixed text that is not a registered or near-miss CLI flag (`-not-a-flag`, `--bogus-flag-like literal`) while still rejecting real typo-like options such as `--resum` with the `--resume` suggestion. Direct `/status` invocation routes to the local status action per the resume-safe slash command contract, matching the CI-red parser regression tests restored after `7cfd83f`. Help, USAGE, and rust README document the `claw -- "-prompt-with-dash"` form. Regression coverage: `parses_dash_prefixed_prompt_text_434`, plus rerun CI-red parser tests `parses_bare_prompt_and_json_output_flag` and `parses_direct_agents_mcp_and_skills_slash_commands`. Verification: `cargo fmt --manifest-path rust/Cargo.toml --all -- --check`, focused parser tests, `scripts/roadmap-check-ids.sh`, `git diff --check -- USAGE.md rust/README.md rust/crates/rusty-claude-cli/src/main.rs ROADMAP.md`, docs source-of-truth/release-readiness/unit helper checks, `cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --no-run`, `cargo build --manifest-path rust/Cargo.toml --workspace --locked`, and `cargo clippy --manifest-path rust/Cargo.toml --workspace`. Local `cargo test --manifest-path rust/Cargo.toml --workspace` still hits the pre-existing Darwin-only `runtime::worker_boot::startup_preflight_warns_when_git_metadata_is_not_writable` permission assertion after all CLI parser tests pass; the red GitHub jobs were parser failures on head `41678eb`.
435. **`claw --resume latest` on a fresh workspace exit code is 0 in text mode but 1 in JSON mode (text mode lies about success); sibling: failed `--resume` creates the `.claw/sessions/<fingerprint>/` directory tree as a filesystem side effect of the failure** — dogfooded 2026-05-11 by Jobdori on `e29010ed` in response to Clawhip pinpoint nudge at `1503305692566655096`. Reproduction (fresh empty dir, no `.claw/`, no sessions): `claw --resume latest` (text mode) prints `failed to restore session: no managed sessions found in .claw/sessions/0ead448127a2de44/` and exits **0**. Same invocation with `--output-format json` correctly exits **1** with `kind:"session_load_failed"`. Exit-code parity broken on the same input depending on format flag. **Sibling filesystem-side-effect bug:** after the failed `--resume latest` on a fresh empty workspace, the directory `.claw/sessions/0ead448127a2de44/` (the workspace-fingerprint partition) is created on disk despite the operation failing. The user did not opt into creating workspace metadata — they asked to resume an existing session, the resume failed, and now there's a partition directory hanging around. The fingerprint directory ought to be created lazily on first successful session save, not as a side effect of every resume attempt. **Three sibling findings in the same probe:** (a) **`claw --compact` alone (no other args) drops into the interactive REPL with the ANSI welcome banner** — `--compact` is documented as a modifier that strips tool call details in text mode for piping (`--compact ... useful for piping`), not as a verb that activates the REPL. Running `claw --compact` with no positional should be a no-op or an error explaining the flag needs a subcommand or prompt; entering the REPL is the wrong default. (b) **`claw --compact "hello"` (shorthand prompt) returns `{"error":"unknown subcommand: hello.","hint":"Did you mean help","kind":"unknown"}``--compact` disables shorthand prompt mode entirely**, treating the positional as a subcommand instead of as prompt text. Users must use the explicit `prompt` verb (`claw --compact prompt "hello"`) which contradicts the `claw [flags] TEXT` usage line in `--help`. (c) `kind:"unknown"` again for the unknown-subcommand error in --compact path — same catch-all bucket bug appearing for the 11th time across pinpoints. **Required fix shape:** (a) exit code 1 for all `failed_to_restore` / `session_load_failed` text-mode failures; text mode should print to stderr and exit non-zero, not print to stdout and exit 0; (b) defer `.claw/sessions/<fingerprint>/` creation to first successful save; failed `--resume` must not leave filesystem droppings; (c) `claw --compact` alone (no positional, no subcommand, stdin is TTY) should emit `kind:"missing_argument"` with `argument:"prompt or subcommand"` rather than activating the REPL; (d) `--compact` must be transparent to shorthand prompt mode parsing — `claw --compact "hello"` is equivalent to `claw --compact prompt "hello"`, both should reach the prompt path; (e) emit typed `kind:"unknown_subcommand"` not `kind:"unknown"` for fallthrough cases. **Why this matters:** scripts that gate on `$?` after `claw --resume latest` see success on text mode and failure on JSON mode — the same operation, two outcomes. The filesystem side effect pollutes a user's worktree with workspace partitions they didn't ask for, and CI pipelines that snapshot `.claw/` size silently grow on every failed `--resume`. Cross-references #422 (exit-code parity across error envelopes), #423 (`kind:"unknown"` for `missing_argument`), #434 (shorthand prompt limitations). Source: Jobdori live dogfood, `e29010ed`, 2026-05-11.
435. **DONE — failed resume is non-zero and side-effect free; `--compact` stays a prompt modifier**fixed 2026-06-04 in `fix: keep failed resume side-effect free`. Fresh-workspace `claw --resume latest` exits 1 in text and JSON modes; text writes the restore failure to stderr, JSON writes a typed `no_managed_sessions` restore envelope to stdout, and failed lookup no longer creates `.claw/sessions/<fingerprint>/`. `SessionStore::from_cwd`/`from_data_dir` now only derive the fingerprinted path; session save remains responsible for creating it. Global `--compact` no longer starts the REPL when it has no prompt or stdin: it returns typed `missing_argument` with `argument:"prompt or subcommand"`. `claw --compact "hello"` remains shorthand prompt mode and reaches provider/auth validation rather than command-not-found. Regression coverage: `session_store_from_cwd_is_side_effect_free_until_save`, `resume_latest_missing_session_fails_without_creating_session_dirs_435`, `compact_flag_missing_argument_and_shorthand_prompt_contract_435`, and `parses_compact_flag_for_prompt_mode`; broader checks reran `runtime session_control`, `resume_slash_commands`, `output_format_contract`, `claw` bin tests, `cargo fmt --all -- --check`, `scripts/roadmap-check-ids.sh`, `git diff --check`, and `cargo build --workspace --locked`.
436. **`claw init` shipped `.claw.json` template explicitly sets `permissions.defaultMode:"dontAsk"` — every user who runs `claw init` gets a config file that disables permission prompts by default; sibling: `init` creates an empty `.claw/` directory with no settings.json template inside, and when `.claw/` already exists it skips the whole artifact (no settings template materialized)** — dogfooded 2026-05-11 by Jobdori on `b8f989b6` in response to Clawhip pinpoint nudge at `1503313241751949335`. Reproduction: `mkdir /tmp/probe && cd /tmp/probe && claw init --output-format json` returns `artifacts:[{name:".claw/",status:"created"},{name:".claw.json",status:"created"},...]`. Inspecting the created `.claw.json`: `{"permissions":{"defaultMode":"dontAsk"}}`. This is the polar opposite of safe-by-default: every user who follows the documented onboarding flow (`claw init` after `curl install.sh`) ships their workspace with permission prompts disabled. Compounds with **#428** (default runtime permission_mode is `danger-full-access`) — between the runtime default and the init template, a fresh claw setup has zero user-facing safety friction. **Sibling: `.claw/` artifact is an empty directory.** After `claw init`, `find .claw -type f` returns nothing. No `settings.json`, no template, no scaffolding — just `mkdir .claw`. The `--help` description implies init produces a usable workspace, but `.claw/settings.json` (the project-scope counterpart of `~/.claw/settings.json`) is never templated. **Sibling: `.claw/` skip-on-exists drops the entire artifact.** If `.claw/` already exists (e.g., from a partial setup, a `--resume` failure side effect per #435, or manual creation), `claw init` returns `.claw/: skipped` and does not materialize any expected sub-content. The other artifacts (`.claw.json`, `.gitignore`, `CLAUDE.md`) are still created, but a future `claw skills install` or `claw plugins enable` may expect `.claw/` to contain template files that are now missing. **Required fix shape:** (a) the shipped `.claw.json` template must default to `permissions.defaultMode:"acceptEdits"` or `"plan"` (safe-by-default modes per #428 spec) — `"dontAsk"` requires explicit opt-in; (b) `claw init` must materialize `.claw/settings.json` with documented schema defaults inside `.claw/` so the directory is useful on its own; (c) when `.claw/` already exists, `init` must report `partial` status (not `skipped`) and still try to create missing sub-files like `.claw/settings.json` without overwriting existing files; (d) emit per-sub-file artifact entries for `.claw/settings.json` and `.claw/sessions/` (skipped status if absent, deferred-to-first-save acceptable) so automation knows what's present; (e) regression test: `claw init` produces a `.claw.json` whose `permissions.defaultMode` is NOT `dontAsk`; `.claw/` contains at least one templated file. **Why this matters:** init is the primary onboarding surface. Every first-time user piping `curl install.sh | sh && claw init` gets a workspace pre-configured to skip permission prompts — and that workspace gets committed to the user's repo via the `init`-added entry. The `.claw/` empty-directory bug means feature discovery (skills, plugins) lacks the scaffolding it implies. Cross-references #428 (runtime default permission_mode), #50/#87/#91/#94/#97/#101/#106/#115/#123 (permission-rule audit), #435 (filesystem side effects on failed resume). Source: Jobdori live dogfood, `b8f989b6`, 2026-05-11.