diff --git a/ROADMAP.md b/ROADMAP.md index 45064a7..4dd8327 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1310,3 +1310,30 @@ Original filing (2026-04-13): user requested a `-acp` parameter to support ACP p **Blocker.** None. Scope is ~30 lines across `session_control.rs:516-526` (re-shape the two helpers to accept the resolved path and optionally enumerate sibling partitions) plus the call sites that invoke them plus one unit test. No runtime behavior change; just error-copy accuracy + optional sibling-partition enumeration. **Source.** Jobdori dogfood 2026-04-17 against `/tmp/claw-d4` on main HEAD `688295e` in response to Clawhip pinpoint nudge at `1494615932222439456`. Adjacent to ROADMAP #21 (`/session list` / resumed status contract) but distinct — this is the error-message accuracy gap, not the JSON-shape gap. + +81. **`claw status` reports the same `Project root` for two CWDs that silently land in *different* session partitions — project-root identity is a lie at the session layer** — dogfooded 2026-04-17 on main HEAD `a48575f` inside `~/clawd/claw-code` (itself) and reproduced on a scratch repo at `/tmp/claw-split-17`. The `Workspace` block in `claw status` advertises a single `Project root` derived from the git toplevel, but `SessionStore::from_cwd` at `rust/crates/runtime/src/session_control.rs:32-40` uses the raw **CWD path** as input to `workspace_fingerprint()` (line 295-303), not the project root. The result: two invocations in the same git repo but different CWDs (`~/clawd/claw-code` vs `~/clawd/claw-code/rust`, or `/tmp/claw-split-17` vs `/tmp/claw-split-17/sub`) report the same `Project root` in `claw status` but land in two separate `.claw/sessions//` dirs that cannot see each other's sessions. `claw --resume latest` from one subdir returns `no managed sessions found` even though the adjacent CWD in the same project has a live session that `/session list` from that CWD resolves fine. + + **Concrete repro.** + ``` + mkdir -p /tmp/claw-split/sub && cd /tmp/claw-split && git init -q + claw status # Project root = /tmp/claw-split, creates .claw/sessions// + cd sub + claw status # Project root = /tmp/claw-split (SAME), creates sub/.claw/sessions// + claw --resume latest # "no managed sessions found in .claw/sessions/" — wrong, there's one at /tmp/claw-split/.claw/sessions// + ``` + Same behavior inside claw-code's own source tree: `claw --resume latest /session list` from `~/clawd/claw-code` lists sessions under `.claw/sessions/4dbe3d911e02dd59/`, while the same command from `~/clawd/claw-code/rust` lists different sessions under `rust/.claw/sessions/7f1c6280f7c45d10/`. Both `claw status` invocations report `Project root: /Users/yeongyu/clawd/claw-code`. + + **Trace path.** + - `rust/crates/runtime/src/session_control.rs:32-40` — `SessionStore::from_cwd(cwd)` joins `cwd / .claw / sessions / workspace_fingerprint(cwd)`. The input to the fingerprint is the raw CWD, not the git toplevel / project root. + - `rust/crates/runtime/src/session_control.rs:295-303` — `workspace_fingerprint(workspace_root)` is a direct FNV-1a of `workspace_root.to_string_lossy()`, so any suffix difference in the CWD path changes the fingerprint. + - Status command — surfaces a `Project root` that the operator reasonably reads as *the* identity for session scope, but session scope actually tracks CWD. + + **Why this is a clawability gap and not just a UX quirk.** Clawhip-style batch orchestration frequently spawns workers whose CWD lives in a subdirectory of the project root (e.g. the `rust/` crate root, a `packages/*` workspace, a `services/*` path). Those workers appear identical at the status layer (`Project root` matches) but each gets its own isolated session namespace. `--resume latest` from any spawn location that wasn't the exact CWD of the original session silently fails — not because the session is corrupt, not because permissions are wrong, but because the partition key is one level deeper than the operator-visible workspace identity. This is precisely the kind of split-truth the ROADMAP's pain point #2 ("Truth is split across layers") warns about: status-layer truth (`Project root`) disagrees with session-layer truth (fingerprint-of-CWD) and neither exposes the disagreement. + + **Fix shape (≤40 lines).** Either (a) change `SessionStore::from_cwd` to resolve the project root (git toplevel or `ConfigLoader::project_root`) and fingerprint *that* instead of the raw CWD, so two CWDs in the same project share a partition; or (b) keep the CWD-based partitioning but surface the partition key and its input explicitly in `claw status`'s `Workspace` block (e.g. `Session partition: .claw/sessions/4dbe3d911e02dd59 (fingerprint of /Users/yeongyu/clawd/claw-code)`), so the split between `Project root` and session scope is visible instead of hidden. Option (a) is the less surprising default; option (b) is the lower-risk patch. Either way the fix includes a regression test that spawns two `SessionStore`s at different CWDs inside the same git repo and asserts the intended identity (shared or visibly distinct). + + **Acceptance.** A clawhip-spawned worker in a project subdirectory can `claw --resume latest` against a session created by another worker in the same project, *or* `claw status` makes the session-partition boundary first-class so orchestrators know to pin CWD. No more silent `no managed sessions found` when the session is visibly one directory up. + + **Blocker.** None. Option (a) touches `session_control.rs:32-40` (swap the fingerprint input) plus the existing `from_cwd` call sites to pass through a resolved project root; option (b) is pure output surface in the status command. Tests already exercise `SessionStore::from_cwd` at multiple CWDs (`session_control.rs:748-757`) — extend them to cover the project-root-vs-CWD case. + + **Source.** Jobdori dogfood 2026-04-17 against `~/clawd/claw-code` (self) and `/tmp/claw-split-17` on main HEAD `a48575f` in response to Clawhip pinpoint nudge at `1494638583481372833`. Distinct from ROADMAP #80 (error-copy accuracy within a single partition) — this is the partition-identity gap one layer up: two CWDs both think they are in the same project but live in disjoint session namespaces.