248 Commits

Author SHA1 Message Date
YeonGyu-Kim
598ba70143 docs: ROADMAP.md cluster index for 49+ pinpoints navigation 2026-04-30 09:02:05 +09:00
YeonGyu-Kim
e5c32bfd3c docs: add ROADMAP.md extended-audit summary header (cycles #388-#415) 2026-04-30 09:02:05 +09:00
YeonGyu-Kim
4746e7777a roadmap: #196 filed — local branch namespace accumulation, no lifecycle cleanup or doctor visibility (Jobdori cycle #131) 2026-04-30 09:02:05 +09:00
YeonGyu-Kim
2f1fe0416d roadmap: #194 filed — prunable-worktree accumulation, no doctor visibility or auto-prune lifecycle 2026-04-30 09:02:05 +09:00
YeonGyu-Kim
e59bb2c16d roadmap: #136 marked CLOSED — compact+json dispatch already correct 2026-04-30 09:02:05 +09:00
YeonGyu-Kim
8e52f56ca8 ROADMAP #130: re-verify still-open on main HEAD 186d42f; add classifier-cluster pairing note
Cycle #39 dogfood re-verification of #130 (filed 2026-04-20). All 5
filesystem failure modes reproduce identically on main HEAD 186d42f,
2 days after original filing. Gap is unchanged.

## What's Added

1. **[STILL OPEN — re-verified 2026-04-22 cycle #39]** marker on the
   entry so readers can see immediately that the pinpoint hasn't been
   accidentally closed.

2. Full 5-mode repro output preserved verbatim for the current HEAD,
   so future re-verifications have a concrete baseline to diff against.

3. **New evidence not in original filing**: the classifier actively
   chose `kind: "unknown"` rather than just omitting the field. This
   means classify_error_kind() has NO substring match for "Is a
   directory", "No such file", "Operation not permitted", or "File
   exists". The typed-error contract is thus twice-broken on this path.

4. **Pairing with #247/#248/#249 classifier sweep**: the classifier-level
   part of #130 could land in the same sweep (add substring branches
   for io::ErrorKind strings). The context-preservation part (fix
   run_export's bare `?`) is a separate, larger change.

## Why Re-Verification Not Re-Filing

Per cycle #24 discipline: speculative re-filings add noise, real
confirmations add truth. #130 was already filed with exact repros, code
trace, and fix shape. My dogfood hit the same gap on fresh HEAD — the
right output is confirming the gap is still there (not filing #251 for
the same bug).

This is the same pattern as cycle #32's "mark #127 CLOSED" reality-sync:
documentation-drift prevention through explicit status markers.

## New Pattern

"Reality-sync via re-verification" — re-running a filed pinpoint's
repro on fresh HEAD and adding the timestamp + output proves the gap
is still real without inventing new filings. Cycle #24 calibration
keeps ROADMAP entries honest.

Per cycle #24 calibration:
- Red-state bug? ⚠️ borderline (errors surfaced, but kind=unknown is
  demonstrably wrong on a path where the system knows the errno)
- Real friction? ✓ (re-verified on fresh HEAD)
- Evidence-backed? ✓ (5-mode repro + classifier trace)
- Same-cycle fix? ✗ (classifier-level part could join #247/#248/#249
  sweep; context-preservation part is larger refactor)
- Implementation cost? Classifier part ~10 lines; full context fix ~60 lines

Source: Jobdori cycle #39 proactive dogfood in response to Clawhip
pinpoint nudge. Probed export filesystem errors; discovered this was
#130 reconfirmation, not new bug. Applied reality-sync pattern from
cycle #32.
2026-04-30 09:02:05 +09:00
YeonGyu-Kim
95b8eecd2f docs: cycle #32 — mark #127 CLOSED; document in-flight branch obsolescence
Cycle #32 dogfood finding: #127 was fixed on main via `a3270db` + `79352a2`
(2026-04-20), but the ROADMAP.md entry still lacked a [CLOSED] marker.
The in-flight branches `feat/jobdori-127-clean` and
`feat/jobdori-127-verb-suffix-flags` were superseded and are now obsolete.

## What This Fixes

**Documentation drift:** Pinpoint #127 was complete in code but unmarked
in ROADMAP. New contributors checking the roadmap would see it as open
work, potentially duplicating effort.

**Stale branches:** Two branches (`feat/jobdori-127-clean`,
`feat/jobdori-127-verb-suffix-flags`) contain the fix attempt bundled
with an unrelated large-scope refactor (5365 lines removed from
ROADMAP.md, root-level governance docs deleted, command infra refactored).
Their fix was superseded; branches are functionally obsolete.

## Verification

Re-verified all 4 #127 scenarios pass on main HEAD `b903e16`:

  $ claw doctor --json        → rejected with "did you mean" hint
  $ claw doctor garbage       → rejected
  $ claw doctor --unknown-flag → rejected
  $ claw doctor --output-format json → works (canonical form)

All behavior matches #127 acceptance criteria.

## Cluster Impact

Post-closure: **parser-level trust gap quintet (#108 + #117 + #119 + #122
+ #127) is 5/5 closed**. The `_other => Prompt` fall-through audit is
complete.

## Discipline Check

Per cycle #24 calibration:
- Red-state bug? ✗ (behavior is correct on main)
- Real friction? ✓ (ROADMAP drift; obsolete branches adrift)
- Evidence-backed? ✓ (dogfood probe confirmed closure; git log confirmed
  supersession; branch diff confirmed scope contamination)

## Relationship to Gaebal-gajae's Option A Guidance

Cycle #32 started by proposing separating the #127 fix from the attached
refactor. On deeper probe, discovered the fix was already superseded on
main via different commits. Option A (separate the fix) is retroactively
satisfied: the fix landed cleanly, the refactor never did.

The remaining action is governance hygiene: mark closure, document
supersession, flag obsolete branches for deletion.

## Next Actions (not in this commit)

- Delete `feat/jobdori-127-clean` locally and on fork (after confirmation)
- Delete `feat/jobdori-127-verb-suffix-flags` locally and on fork
- Monitor whether any attached refactor content should be re-proposed in
  its own scoped PR

Source: Jobdori cycle #32 dogfood in response to Clawhip 10-min nudge.
Proposed Option A (separate fix from refactor); probe revealed the fix
already landed via a different commit path, rendering the refactor-only
branch obsolete.
2026-04-30 09:02:05 +09:00
YeonGyu-Kim
dc8acf3e1c file: #161 — run_turn_loop has no wall-clock timeout, stalled turn blocks indefinitely 2026-04-30 09:02:04 +09:00
Yeachan-Heo
f7b2d8d6fe Document plugins uninstall JSON stderr-only not-found
Constraint: ROADMAP-only dogfood follow-up for 23:30 nudge on rebuilt claw git_sha 6f92e54d

Rejected: implementation change to plugin lifecycle uninstall; request was one concrete follow-up if no backlog item
Confidence: high after repeated bounded samples plus prompt list sanity check
Scope-risk: narrow
Directive: Replaces invalid hang PR #2897 with verified stderr-only JSON-mode gap
Tested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; repeated timeout 8 ./rust/target/debug/claw plugins uninstall does-not-exist --output-format json; timeout 8 ./rust/target/debug/claw plugins list --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 23:31:56 +00:00
Yeachan-Heo
31d9198a02 Document plugins update JSON stderr-only not-found
Constraint: ROADMAP-only dogfood follow-up for 23:00 nudge on rebuilt claw git_sha 5eb1d7d8

Rejected: implementation change to plugin lifecycle update; request was one concrete follow-up if no backlog item
Confidence: high after repeated bounded samples plus prompt list sanity check
Scope-risk: narrow
Directive: Replaces invalid hang PR #2894 with verified stderr-only JSON-mode gap
Tested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; repeated timeout 8 ./rust/target/debug/claw plugins update does-not-exist --output-format json; timeout 8 ./rust/target/debug/claw plugins list --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 23:02:03 +00:00
Yeachan-Heo
3b03375e69 Document plugins disable JSON stderr-only not-found
Constraint: ROADMAP-only dogfood follow-up for 22:30 nudge on rebuilt claw git_sha 0f9e8915

Rejected: implementation change to plugin lifecycle mutation; request was one concrete follow-up if no backlog item
Confidence: high after repeated bounded samples plus prompt list sanity check
Scope-risk: narrow
Directive: Replaces invalid hang PR #2891 with verified stderr-only JSON-mode gap
Tested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; repeated timeout 8 ./rust/target/debug/claw plugins disable does-not-exist --output-format json; timeout 8 ./rust/target/debug/claw plugins list --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 22:32:14 +00:00
Yeachan-Heo
ab95b75fcd Document plugins enable missing-target hang
Constraint: ROADMAP-only dogfood follow-up for 22:00 nudge on rebuilt claw git_sha ee44ff98

Rejected: implementation change to plugin lifecycle mutation; request was one concrete follow-up if no backlog item
Confidence: high after repeated bounded samples plus prompt list sanity check
Scope-risk: narrow
Directive: Keep supported lifecycle missing-target hang distinct from #348 list schema and #349 unsupported show action
Tested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; repeated timeout 8 ./rust/target/debug/claw plugins enable does-not-exist --output-format json; timeout 8 ./rust/target/debug/claw plugins list --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 22:02:04 +00:00
Yeachan-Heo
2ab26df4bd Document plugins unsupported action success-shaped JSON
Constraint: ROADMAP-only dogfood follow-up for 21:30 nudge on rebuilt claw git_sha a2a38df9

Rejected: implementation change to plugin action dispatch; request was one concrete follow-up if no backlog item
Confidence: high after repeated bounded samples
Scope-risk: narrow
Directive: Replaces invalid hang PR #2885 with verified unsupported-action classification gap
Tested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; repeated timeout 8 ./rust/target/debug/claw plugins show does-not-exist --output-format json; timeout 8 ./rust/target/debug/claw plugins list --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 21:32:19 +00:00
Yeachan-Heo
fd90c9fe67 Document plugins list prose-only JSON inventory
Constraint: ROADMAP-only dogfood follow-up for 21:00 nudge on rebuilt claw git_sha cca6f682

Rejected: implementation change to plugin list serializer; request was one concrete follow-up if no backlog item
Confidence: high after repeated bounded samples
Scope-risk: narrow
Directive: Keep plugin inventory schema issue distinct from broad help JSON opacity
Tested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; repeated timeout 8 ./rust/target/debug/claw plugins list --output-format json; ./rust/target/debug/claw plugins help --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 21:02:04 +00:00
Yeachan-Heo
c77d1a87e1 Document mcp show missing status contract gap
Constraint: ROADMAP-only dogfood follow-up for 20:30 nudge on rebuilt claw git_sha ee41b266

Rejected: implementation change to MCP show status schema; request was one concrete follow-up if no backlog item
Confidence: high after bounded successful repro
Scope-risk: narrow
Directive: Replaces invalid hang/nondeterminism PRs with verified status contract gap
Tested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; ./rust/target/debug/claw mcp show does-not-exist --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 20:33:42 +00:00
Yeachan-Heo
ca92c695f4 Document agents show help fallback gap
Constraint: ROADMAP-only dogfood follow-up for 20:00 nudge on rebuilt claw git_sha c6c01bea

Rejected: implementation change to native-agent detail dispatch; request was one concrete follow-up if no backlog item
Confidence: high
Scope-risk: narrow
Directive: Keep agent detail fallback distinct from #328/#329 native-agent source/schema issues; closed invalid hang hypotheses first
Tested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; ./rust/target/debug/claw agents list --output-format json; ./rust/target/debug/claw agents show analyst --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 20:01:42 +00:00
Yeachan-Heo
970cdc925e Document config sections identical JSON gap
Constraint: ROADMAP-only dogfood follow-up for 19:00 nudge on rebuilt claw git_sha a510f734

Rejected: implementation change to config section serialization; request was one concrete follow-up if no backlog item
Confidence: high
Scope-risk: narrow
Directive: Keep section-payload issue distinct from #344 section discovery/help
Tested: ./rust/target/debug/claw --resume latest /config env --output-format json; /config hooks; /config model; /config plugins; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 19:31:25 +00:00
Yeachan-Heo
2a08b7a35c Document config section discovery gap
Constraint: ROADMAP-only dogfood follow-up for 18:30 nudge on rebuilt claw git_sha a510f734

Rejected: implementation change to config slash dispatcher; request was one concrete follow-up if no backlog item
Confidence: high
Scope-risk: narrow
Directive: Keep /config section discovery issue distinct from #342 /commands and #343 /models correction issues
Tested: ./rust/target/debug/claw --resume latest /config help --output-format json; /config list; /config show; bare /config; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 19:00:29 +00:00
Yeachan-Heo
1283c6d532 Document resume model suggestion dead-end
Constraint: ROADMAP-only dogfood follow-up for 17:00 nudge on rebuilt claw git_sha a1bfcd41

Rejected: implementation change to slash suggestion/resume-safety logic; request was one concrete follow-up if no backlog item
Confidence: high
Scope-risk: narrow
Directive: Keep /models suggestion issue distinct from #342 /commands discovery alias
Tested: ./rust/target/debug/claw --resume latest /models --output-format json; ./rust/target/debug/claw --resume latest /model --output-format json; ./rust/target/debug/claw --resume latest /tokens --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 17:02:18 +00:00
Yeachan-Heo
c49839bb1f Document slash command discovery alias gap
Constraint: ROADMAP-only dogfood follow-up for 16:30 nudge on rebuilt claw git_sha f65b2b4f

Rejected: implementation change to slash dispatcher; request was one concrete follow-up if no backlog item
Confidence: high
Scope-risk: narrow
Directive: Keep /commands discovery issue distinct from #340/#341 stderr-only envelope items
Tested: ./rust/target/debug/claw --resume latest /commands --output-format json; ./rust/target/debug/claw --resume latest /help --output-format json; git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 16:31:03 +00:00
Yeachan-Heo
f4b74e89dd Document why /tasks JSON errors need one stdout contract
Constraint: ROADMAP-only dogfood follow-up for 16:00 nudge on rebuilt claw git_sha 58569131
Rejected: code change in the command dispatcher | request was specifically to add one ROADMAP.md-only item
Confidence: high
Scope-risk: narrow
Directive: Keep /tasks distinct from #340; this is unsupported command stub JSON, not session help
Tested: git diff --check; scripts/fmt.sh --check
Not-tested: runtime behavior change, because this commit only documents the gap
2026-04-29 16:02:10 +00:00
Yeachan-Heo
d45a0d2f5b Document stderr-only session help JSON contract gap
Capture the dogfood evidence as a roadmap item so the stdout JSON error-envelope contract can be fixed and regression-tested later.\n\nConstraint: User requested exactly one ROADMAP.md-only item #340 from current origin/main.\nConfidence: high\nScope-risk: narrow\nTested: git diff --check; scripts/fmt.sh --check\nNot-tested: Runtime behavior unchanged; documentation-only roadmap entry.
2026-04-29 15:31:59 +00:00
YeonGyu-Kim
9537c97231 docs(roadmap): add #339 — session delete not resume-safe, blocks GC automation 2026-04-30 00:18:28 +09:00
Yeachan-Heo
3efaf551ed Restore roadmap GC lifecycle detail gap
Constraint: ROADMAP.md-only restore of lost #337 from PR #2852 / Jobdori dogfood evidence
Rejected: Renumbering adjacent items | preserving existing #338 and surrounding roadmap entries keeps history stable
Confidence: high
Scope-risk: narrow
Directive: Keep #337 before #338 and do not collapse the dirty-file detail requirement into the broader help/status backlog
Tested: git diff --check; scripts/fmt.sh --check
Not-tested: Product behavior changes; documentation-only change
2026-04-29 15:09:40 +00:00
Yeachan-Heo
587bb18572 docs(roadmap): add #338 for help JSON field drift
Constraint: Respond to 14:30 dogfood nudge with one direct claw-code pinpoint.\nEvidence: rebuilt actual debug binary at git_sha 24ccb59b; compared top-level help --output-format json with resume-safe /help --output-format json.\nFinding: same help surface uses message in top-level JSON and text in slash/resume JSON.\nTested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; ./rust/target/debug/claw help --output-format json; ./rust/target/debug/claw --resume latest /help --output-format json; git diff --check; scripts/fmt.sh --check.\nNot-tested: full Rust suite; roadmap-only documentation change.
2026-04-29 14:34:26 +00:00
Yeachan-Heo
0e8e75ef75 docs(roadmap): add #329 for slash agents JSON opacity
Constraint: Respond to dogfood nudge with exactly one concrete clawability pinpoint from direct claw-code use.\nEvidence: rebuilt actual debug binary at git_sha 0f7578c0; compared resume-safe /agents --output-format json with top-level claw agents --output-format json.\nFinding: slash /agents JSON only exposes kind,text while top-level agents JSON exposes structured agents[] inventory and provenance.\nTested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; ./rust/target/debug/claw --resume latest /agents --output-format json; ./rust/target/debug/claw agents --output-format json; git diff --check; scripts/fmt.sh --check.\nNot-tested: full Rust suite; roadmap-only documentation change.
2026-04-29 14:01:36 +00:00
Yeachan-Heo
213d406cbf Record why native-agent provenance needs dogfood follow-up
Constraint: Scope requested ROADMAP.md only with exactly one new #328 pinpoint from direct claw dogfood.\nRejected: Implementing the agents-help fix now | user requested roadmap-only evidence item.\nConfidence: high\nScope-risk: narrow\nDirective: Keep agent help source roots derived from the same loader registry as agents list; do not hand-maintain a divergent root list.\nTested: cargo run --manifest-path rust/Cargo.toml --bin claw -- version --output-format json; ./rust/target/debug/claw version --output-format json; ./rust/target/debug/claw agents help --output-format json; ./rust/target/debug/claw agents --output-format json; git diff --check; scripts/fmt.sh --check\nNot-tested: Full Rust test suite; roadmap-only documentation change.
2026-04-29 13:33:23 +00:00
Yeachan-Heo
3a34d83749 Record why MCP source help needs dogfood follow-up
Constraint: Scope limited to ROADMAP.md and one new pinpoint #327 from actual rebuilt claw dogfood.
Rejected: Code fix in this branch | user requested roadmap-only filing.
Confidence: high
Scope-risk: narrow
Directive: Keep mcp help source lists derived from actual config discovery, not hard-coded partial docs.
Tested: ./rust/target/debug/claw version --output-format json; ./rust/target/debug/claw mcp --help; ./rust/target/debug/claw mcp help --output-format json; temp .claw.json mcp list proof; git diff --check; scripts/fmt.sh --check
Not-tested: Full Rust test suite, documentation-only change.
2026-04-29 13:02:27 +00:00
Yeachan-Heo
c94940effa docs: add roadmap 326 pane inventory opacity 2026-04-29 12:33:36 +00:00
Yeachan-Heo
2567cbcc78 Pin help JSON schema opacity for automation
Document the dogfood gap where help JSON stays parseable but hides command metadata inside a prose message, so future implementation can expose machine-readable command, slash-command, and resume-safety fields.\n\nConstraint: user requested ROADMAP.md-only pinpoint for issue #325 from origin/main d607ff36.\nRejected: implementing the schema now | requested fix shape is roadmap documentation only.\nConfidence: high\nScope-risk: narrow\nDirective: keep message for humans while adding schema/versioned structured help metadata when implementing.\nTested: git diff --check; scripts/fmt.sh --check\nNot-tested: runtime CLI behavior unchanged by docs-only change
2026-04-29 12:02:14 +00:00
Yeachan-Heo
cdf6282965 Record why stale binary provenance needs a roadmap pin
Constraint: Documentation-only follow-up from current main e7074f47 after PR #2838; edit scope limited to ROADMAP.md.\nRejected: Implementing provenance detection now | user requested roadmap entry only.\nConfidence: high\nScope-risk: narrow\nDirective: Future implementation should compare embedded build git_sha/build date to workspace HEAD/dirty state without leaking secrets.\nTested: git diff --check; scripts/fmt.sh --check\nNot-tested: Runtime provenance behavior; this commit only records the roadmap requirement.
2026-04-29 11:31:19 +00:00
YeonGyu-Kim
9468383b67 docs(roadmap): add #322 #323 — json stream corruption and session identity contradiction 2026-04-29 19:38:00 +09:00
Yeachan-Heo
9037430d52 docs(roadmap): add #249 issue github oauth opacity pinpoint 2026-04-29 10:01:16 +00:00
Yeachan-Heo
7676b376ae docs(roadmap): add #248 prompt-mode silent-hang pinpoint 2026-04-29 08:24:37 +00:00
Yeachan-Heo
1376d92064 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.
2026-04-29 03:31:34 +00:00
Yeachan-Heo
6db68a2baa Expose tool permission gates as structured worker blockers
Worker boot could previously stall on an interactive MCP/tool permission prompt while readiness and startup-timeout surfaces only had generic idle/no-evidence shapes. This adds a first-class blocked lifecycle state, structured event payload, startup evidence fields, and regression coverage so callers can report the exact server/tool gate instead of pane-scraping.

Constraint: ROADMAP #200 requires tool/server identity, prompt age, and session-only versus always-allow capability in status/evidence surfaces
Rejected: Treat MCP/tool prompts as trust gates | conflates distinct prompts and loses tool identity
Rejected: Leave allow-scope as pane text only | clawhip still could not classify the blocker without scraping
Confidence: high
Scope-risk: moderate
Directive: Keep tool_permission_required distinct from trust_required; downstream claws rely on server/tool payload plus allow-scope metadata
Tested: cargo test -p runtime tool_permission
Tested: cargo fmt -p runtime -- --check && cargo clippy -p runtime --all-targets -- -D warnings && cargo test -p runtime
Tested: cargo test --workspace
Not-tested: live interactive MCP permission prompt in tmux
2026-04-27 09:28:09 +00:00
Yeachan-Heo
5b910356a2 Preserve trust boundaries during pulled follow-up
The pull brought the branch current with origin/main while replaying local follow-up work. Conflict resolution kept the roadmap/progress additions and integrated the runtime event/trust changes with upstream's newer surfaces.

The trust allowlist now treats worktree_pattern as an additional required predicate, including the missing-worktree case, so auto-trust cannot fall back to cwd-only matching when a worktree constraint was declared. The runtime formatting cleanup keeps clippy/fmt green after the merge.

Constraint: Local branch was 109 commits behind origin/main with dirty tracked follow-up work.

Rejected: Drop the autostash after conflict resolution | keeping it preserves a reversible safety backup for unrelated recovery.

Confidence: high

Scope-risk: moderate

Directive: Do not relax worktree_pattern matching without preserving the missing-worktree regression.

Tested: git diff --cached --check; cargo fmt -p runtime -- --check; cargo clippy -p runtime --all-targets -- -D warnings; cargo test -p runtime; cargo test --workspace; architect verification approved

Not-tested: Live tmux/worker auto-trust behavior outside unit/integration tests
2026-04-27 09:05:50 +00:00
YeonGyu-Kim
a389f8dff1 file: #160 — session_store missing list_sessions, delete_session, session_exists — claw cannot enumerate or clean up sessions without filesystem hacks 2026-04-22 08:47:52 +09:00
YeonGyu-Kim
7a014170ba file: #159 — run_turn_loop hardcodes empty denied_tools, permission denials absent from multi-turn sessions 2026-04-22 06:48:03 +09:00
YeonGyu-Kim
986f8e89fd file: #158 — compact_messages_if_needed drops turns silently, no structured compaction event 2026-04-22 06:37:54 +09:00
YeonGyu-Kim
ef1cfa1777 file: #157 — structured remediation registry for error hints (Phase 3 of #77)
## Gap

#77 Phase 1 added machine-readable error kind discriminants and #156 extended
them to text-mode output. However, the hint field is still prose derived from
splitting existing error text — not a stable registry-backed remediation
contract.

Downstream claws inspecting the hint field still need to parse human wording
to decide whether to retry, escalate, or terminate.

## Fix Shape

1. Remediation registry: remediation_for(kind, operation) -> Remediation struct
   with action (retry/escalate/terminate/configure), target, and stable message
2. Stable hint outputs per error class (no more prose splitting)
3. Golden fixture tests replacing split_error_hint() string hacks

## Source

gaebal-gajae dogfood sweep 2026-04-22 05:30 KST
2026-04-22 05:31:00 +09:00
YeonGyu-Kim
14c5ef1808 file: #156 — error classification for text-mode output (Phase 2 of #77)
ROADMAP entry for natural Phase 2 follow-up to #77 Phase 1 (JSON error kind
classification). Text-mode errors currently prose-only with no structured
class; observability tools parsing stderr need the kind token.

Two implementation options:
- Prefix line before error prose: [error-kind: missing_credentials]
- Suffix comment: # error_class=missing_credentials

Scope: ~20 lines. Non-breaking (adds classification, doesn't change error text).

Source: Cycle 11 dogfood probe at 23:18 KST — product surface clean after
today's batch, identified natural next step for error-classification symmetry.
2026-04-21 23:19:58 +09:00
YeonGyu-Kim
4b53b97e36 docs: #155 — add USAGE.md documentation for /ultraplan, /teleport, /bughunter commands
## Problem

Three interactive slash commands are documented in `claw --help` but have no
corresponding section in USAGE.md:

- `/ultraplan [task]` — Run a deep planning prompt with multi-step reasoning
- `/teleport <symbol-or-path>` — Jump to a file or symbol by searching the workspace
- `/bughunter [scope]` — Inspect the codebase for likely bugs

New users see these commands in the help output but don't know:
- What each command does
- How to use it
- When to use it vs. other commands
- What kind of results to expect

## Fix

Added new section "Advanced slash commands (Interactive REPL only)" to USAGE.md
with documentation for all three commands:

1. **`/ultraplan`** — multi-step reasoning for complex tasks
   - Example: `/ultraplan refactor the auth module to use async/await`
   - Output: structured plan with numbered steps and reasoning

2. **`/teleport`** — navigate to a file or symbol
   - Example: `/teleport UserService`, `/teleport src/auth.rs`
   - Output: file content with the requested symbol highlighted

3. **`/bughunter`** — scan for likely bugs
   - Example: `/bughunter src/handlers`, `/bughunter` (all)
   - Output: list of suspicious patterns with explanations

## Impact

Users can now discover these commands and understand when to use them without
having to guess or search external sources. Bridges the gap between `--help`
output and full documentation.

Also filed ROADMAP #155 documenting the gap.

Closes ROADMAP #155.
2026-04-21 21:49:04 +09:00
YeonGyu-Kim
3cfe6e2b14 feat: #154 — hint provider prefix and env var when model name looks like different provider
## Problem

When a user types `claw --model gpt-4` or `--model qwen-plus`, they get:
```
error: invalid model syntax: 'gpt-4'. Expected provider/model (e.g., anthropic/claude-opus-4-6) or known alias
```

USAGE.md documents that "The error message now includes a hint that names the detected env var" — but this hint does not actually exist. The user has to re-read USAGE.md or guess the correct prefix.

## Fix

Enhance `validate_model_syntax` to detect when a model name looks like it belongs to a different provider:

1. **OpenAI models** (starts with `gpt-` or `gpt_`):
   ```
   Did you mean `openai/gpt-4`? (Requires OPENAI_API_KEY env var)
   ```

2. **Qwen/DashScope models** (starts with `qwen`):
   ```
   Did you mean `qwen/qwen-plus`? (Requires DASHSCOPE_API_KEY env var)
   ```

3. **Grok/xAI models** (starts with `grok`):
   ```
   Did you mean `xai/grok-3`? (Requires XAI_API_KEY env var)
   ```

Unrelated invalid models (e.g., `asdfgh`) do not get a spurious hint.

## Verification

- `claw --model gpt-4` → hints `openai/gpt-4` + `OPENAI_API_KEY`
- `claw --model qwen-plus` → hints `qwen/qwen-plus` + `DASHSCOPE_API_KEY`
- `claw --model grok-3` → hints `xai/grok-3` + `XAI_API_KEY`
- `claw --model asdfgh` → generic error (no hint)

## Tests

Added 3 new assertions in `parses_multiple_diagnostic_subcommands`:
- GPT model error hints openai/ prefix and OPENAI_API_KEY
- Qwen model error hints qwen/ prefix and DASHSCOPE_API_KEY
- Unrelated models don't get a spurious hint

All 177 rusty-claude-cli tests pass.

Closes ROADMAP #154.
2026-04-21 21:40:48 +09:00
YeonGyu-Kim
71f5f83adb feat: #153 — add post-build binary location and verification guide to README
## Problem

Users frequently ask after building:
- "Where is the claw binary?"
- "Did the build actually work?"
- "Why can't I run \`claw\` from anywhere?"

This happens because \`cargo build\` puts the binary in \`rust/target/debug/claw\`
(or \`rust/target/release/claw\`), and new users don't know:
1. Where to find it
2. How to test it
3. How to add it to PATH (optional but common follow-up)

## Fix

Added new section "Post-build: locate the binary and verify" to README covering:

1. **Binary location table:** debug vs. release, macOS/Linux vs. Windows paths
2. **Verification commands:** Test the binary with \`--help\` and \`doctor\`
3. **Three ways to add to PATH:**
   - Symlink (macOS/Linux): \`ln -s ... /usr/local/bin/claw\`
   - cargo install: \`cargo install --path . --force\`
   - Shell profile update: add rust/target/debug to \$PATH
4. **Troubleshooting:** Common errors ("command not found", "permission denied",
   debug vs. release build speed)

## Impact

New users can now:
- Find the binary immediately after build
- Run it and verify with \`claw doctor\`
- Know their options for system-wide access

Also filed ROADMAP #153 documenting the gap.

Closes ROADMAP #153.
2026-04-21 21:29:59 +09:00
YeonGyu-Kim
dddbd78dbd file: #152 — diagnostic verb suffixes allow arbitrary positional args, double error prefix
Filed from nudge directive at 21:17 KST. Implementation exists on worktree
`jobdori-127-verb-suffix` but needs rebase due to merge with #141.
Ready for Phase 1 implementation once conflicts resolved.
2026-04-21 21:19:51 +09:00
YeonGyu-Kim
7bc66e86e8 feat: #151 — canonicalize workspace path in SessionStore::from_cwd/data_dir
## Problem

`workspace_fingerprint(path)` hashes the raw path string without
canonicalization. Two equivalent paths (e.g. `/tmp/foo` vs
`/private/tmp/foo` on macOS) produce different fingerprints and
therefore different session stores. #150 fixed the test-side symptom;
this fixes the underlying product contract.

## Discovery path

#150 fix (canonicalize in test) was a workaround. Q's ack on #150
surfaced the deeper gap: the function itself is still fragile for
any caller passing a non-canonical path:

1. Embedded callers with a raw `--data-dir` path
2. Programmatic `SessionStore::from_cwd(user_path)` calls
3. NixOS store paths, Docker bind mounts, case-insensitive normalization

The REPL's default flow happens to work because `env::current_dir()`
returns canonical paths on macOS. But any caller passing a raw path
risks silent session-store divergence.

## Fix

Canonicalize inside `SessionStore::from_cwd()` and `from_data_dir()`
before computing the fingerprint. Kept `workspace_fingerprint()` itself
as a pure function for determinism — canonicalization is the entry
point's responsibility.

```rust
let canonical_cwd = fs::canonicalize(cwd).unwrap_or_else(|_| cwd.to_path_buf());
let sessions_root = canonical_cwd.join(".claw").join("sessions").join(workspace_fingerprint(&canonical_cwd));
```

Falls back to the raw path if canonicalize fails (directory doesn't
exist yet).

## Test-side updates

Three legacy-session tests expected the non-canonical base path to
match the store's workspace_root. Updated them to canonicalize
`base` after creation — same defensive pattern as #150, now
explicit across all three tests.

## Regression test

Added `session_store_from_cwd_canonicalizes_equivalent_paths` that
creates two stores from equivalent paths (raw vs canonical) and
asserts they resolve to the same sessions_dir.

## Verification

- `cargo test -p runtime session_store_` — 9/9 pass
- `cargo test --workspace` — all green, no FAILED markers
- No behavior change for existing users (REPL default flow already
  used canonical paths)

## Backward compatibility

Users on macOS who always went through `env::current_dir()`:
no hash change, sessions resume identically.

Users who ever called with a non-canonical path: hash would change,
but those sessions were already broken (couldn't be resumed from a
canonical-path cwd). Net improvement.

Closes ROADMAP #151.
2026-04-21 21:06:09 +09:00
YeonGyu-Kim
eaa077bf91 fix: #150 — eliminate symlink canonicalization flake in resume_latest test + file #246 (reminder outcome ambiguity)
## #150 Fix: resume_latest test flake

**Problem:** `resume_latest_restores_the_most_recent_managed_session` intermittently
fails when run in the workspace suite or multiple times in sequence, but passes in
isolation.

**Root cause:** `workspace_fingerprint(path)` hashes the path string without
canonicalization. On macOS, `/tmp` is a symlink to `/private/tmp`. The test
creates a temp dir via `std::env::temp_dir().join(...)` which returns
`/var/folders/...` (non-canonical). When the subprocess spawns,
`env::current_dir()` returns the canonical path `/private/var/folders/...`.
The two fingerprints differ, so the subprocess looks in
`.claw/sessions/<hash1>` while files are in `.claw/sessions/<hash2>`.
Session discovery fails.

**Fix:** Call `fs::canonicalize(&project_dir)` after creating the directory
to ensure test and subprocess use identical path representations.

**Verification:** 5 consecutive runs of the full test suite — all pass.
Previously: 5/5 failed when run in sequence.

## #246 Filing: Reminder cron outcome ambiguity (control-loop blocker)

The `clawcode-dogfood-cycle-reminder` cron times out repeatedly with no
structured feedback on whether the nudge was delivered, skipped, or died in-flight.

**Phase 1 outcome schema** — add explicit field to cron result:
- `delivered` — nudge posted to Discord
- `timed_out_before_send` — died before posting
- `timed_out_after_send` — posted but cleanup timed out
- `skipped_due_to_active_cycle` — previous cycle active
- `aborted_gateway_draining` — daemon shutdown

Assigned to gaebal-gajae (cron/orchestration domain). Unblocks trustworthy
dogfood cycle observability.

Closes ROADMAP #150. Filed ROADMAP #246.
2026-04-21 21:01:09 +09:00
YeonGyu-Kim
bc259ec6f9 fix: #149 — eliminate parallel-test flake in runtime::config tests
## Problem

`runtime::config::tests::validates_unknown_top_level_keys_with_line_and_field_name`
intermittently fails during `cargo test --workspace` (witnessed during
#147 and #148 workspace runs) but passes deterministically in isolation.

Example failure from workspace run:
  test result: FAILED. 464 passed; 1 failed

## Root cause

`runtime/src/config.rs::tests::temp_dir()` used nanosecond timestamp
alone for namespace isolation:

  std::env::temp_dir().join(format!("runtime-config-{nanos}"))

Under parallel test execution on fast machines with coarse clock
resolution, two tests start within the same nanosecond bucket and
collide on the same path. One test's `fs::remove_dir_all(root)` then
races another's in-flight `fs::create_dir_all()`.

Other crates already solved this pattern:
- plugins::tests::temp_dir(label) — label-parameterized
- runtime::git_context::tests::temp_dir(label) — label-parameterized

runtime/src/config.rs was missed.

## Fix

Added process id + monotonically-incrementing atomic counter to the
namespace, making every callsite provably unique regardless of clock
resolution or scheduling:

  static COUNTER: AtomicU64 = AtomicU64::new(0);
  let pid = std::process::id();
  let seq = COUNTER.fetch_add(1, Ordering::Relaxed);
  std::env::temp_dir().join(format!("runtime-config-{pid}-{nanos}-{seq}"))

Chose counter+pid over the label-parameterized pattern to avoid
touching all 20 callsites in the same commit (mechanical noise with
no added safety — counter alone is sufficient).

## Verification

Before: one failure per workspace run (config test flake).
After: 5 consecutive `cargo test --workspace` runs — zero config
test failures. Only pre-existing `resume_latest` flake remains
(orthogonal, unrelated to this change).

  for i in 1 2 3 4 5; do cargo test --workspace; done
  # All 5 runs: config tests green. Only resume_latest flake appears.

  cargo test -p runtime
  # 465 passed; 0 failed

## ROADMAP.md

Added Pinpoint #149 documenting the gap, root cause, and fix.

Closes ROADMAP #149.
2026-04-21 20:54:12 +09:00
YeonGyu-Kim
f84c7c4ed5 feat: #148 + #128 closure — model provenance in claw status JSON/text
## Scope

Two deltas in one commit:

### #128 closure (docs)

Re-verified on main HEAD `4cb8fa0`: malformed `--model` strings already
rejected at parse time (`validate_model_syntax` in parse_args). All
historical repro cases now produce specific errors:

  claw --model ''                       → error: model string cannot be empty
  claw --model 'bad model'              → error: invalid model syntax: 'bad model' contains spaces
  claw --model 'sonet'                  → error: invalid model syntax: 'sonet'. Expected provider/model or known alias
  claw --model '@invalid'               → error: invalid model syntax: '@invalid'. Expected provider/model ...
  claw --model 'totally-not-real-xyz'   → error: invalid model syntax: ...
  claw --model sonnet                   → ok, resolves to claude-sonnet-4-6
  claw --model anthropic/claude-opus-4-6 → ok, passes through

Marked #128 CLOSED in ROADMAP with repro block. Residual provenance gap
split off as #148.

### #148 implementation

**Problem.** After #128 closure, `claw status --output-format json`
still surfaces only the resolved model string. No way for a claw to
distinguish whether `claude-sonnet-4-6` came from `--model sonnet`
(alias resolution) vs `--model claude-sonnet-4-6` (pass-through) vs
`ANTHROPIC_MODEL` env vs `.claw.json` config vs compiled-in default.

Debug forensics had to re-read argv instead of reading a structured
field. Clawhip orchestrators sending `--model` couldn't confirm the
flag was honored vs falling back to default.

**Fix.** Added two fields to status JSON envelope:
- `model_source`: "flag" | "env" | "config" | "default"
- `model_raw`: user's input before alias resolution (null on default)

Text mode appends a `Model source` line under `Model`, showing the
source and raw input (e.g. `Model source     flag (raw: sonnet)`).

**Resolution order** (mirrors resolve_repl_model but with source
attribution):
1. If `--model` / `--model=` flag supplied → source: flag, raw: flag value
2. Else if ANTHROPIC_MODEL set → source: env, raw: env value
3. Else if `.claw.json` model key set → source: config, raw: config value
4. Else → source: default, raw: null

## Changes

### rust/crates/rusty-claude-cli/src/main.rs

- Added `ModelSource` enum (Flag/Env/Config/Default) with `as_str()`.
- Added `ModelProvenance` struct (resolved, raw, source) with
  three constructors: `default_fallback()`, `from_flag(raw)`, and
  `from_env_or_config_or_default(cli_model)`.
- Added `model_flag_raw: Option<String>` field to `CliAction::Status`.
- Parse loop captures raw input in `--model` and `--model=` arms.
- Extended `parse_single_word_command_alias` to thread
  `model_flag_raw: Option<&str>` through.
- Extended `print_status_snapshot` signature to accept
  `model_flag_raw: Option<&str>`. Resolves provenance at dispatch time
  (flag provenance from arg; else probe env/config/default).
- Extended `status_json_value` signature with
  `provenance: Option<&ModelProvenance>`. On Some, adds `model_source`
  and `model_raw` fields; on None (legacy resume paths), omits them
  for backward compat.
- Extended `format_status_report` signature with optional provenance.
  On Some, renders `Model source` line after `Model`.
- Updated all existing callers (REPL /status, resume /status, tests)
  to pass None (legacy paths don't carry flag provenance).
- Added 2 regression assertions in parse_args test covering both
  `--model sonnet` and `--model=...` forms.

### ROADMAP.md

- Marked #128 CLOSED with re-verification block.
- Filed #148 documenting the provenance gap split, fix shape, and
  acceptance criteria.

## Live verification

$ claw --model sonnet --output-format json status | jq '{model,model_source,model_raw}'
{"model": "claude-sonnet-4-6", "model_source": "flag", "model_raw": "sonnet"}

$ claw --output-format json status | jq '{model,model_source,model_raw}'
{"model": "claude-opus-4-6", "model_source": "default", "model_raw": null}

$ ANTHROPIC_MODEL=haiku claw --output-format json status | jq '{model,model_source,model_raw}'
{"model": "claude-haiku-4-5-20251213", "model_source": "env", "model_raw": "haiku"}

$ echo '{"model":"claude-opus-4-7"}' > .claw.json && claw --output-format json status | jq '{model,model_source,model_raw}'
{"model": "claude-opus-4-7", "model_source": "config", "model_raw": "claude-opus-4-7"}

$ claw --model sonnet status
Status
  Model            claude-sonnet-4-6
  Model source     flag (raw: sonnet)
  Permission mode  danger-full-access
  ...

## Tests

- rusty-claude-cli bin: 177 tests pass (2 new assertions for #148)
- Full workspace green except pre-existing resume_latest flake (unrelated)

Closes ROADMAP #128, #148.
2026-04-21 20:48:46 +09:00