Files
callstack__agent-device/scripts/__tests__
Nicolas Bataille ed8d5efb00 fix(daemon): address cwd-scoped sessions by their store key, not their public name (#2068)
* fix(daemon): address cwd-scoped sessions by their store key, not their public name

An implicitly cwd-scoped session is NAMED `default` and STORED under
`cwd:<hash>:default`. Three surfaces built caller-facing text from the name, so
each pointed at something that does not exist:

- `DEVICE_IN_USE` reported `session "default"` and its recovery hint said
  `agent-device close --session default`. `--session` marks the session
  explicit, which disables cwd scoping, so following the hint addressed a
  different, absent session: `SESSION_NOT_FOUND`, and the device stayed held —
  the residual half of #2031 that #2057's superseded-daemon reconciliation does
  not cover.
- `session list` reported `sessionStateDir` and `runnerLogPath` under
  `<state>/sessions/default`, a directory that is never created; the session's
  real artifacts sit in `<state>/sessions/cwd_<hash>_default`, which is what
  `open` already answers with.

`SessionStore.entries()` exposes the key alongside the record, and
`buildSessionRecoveryHint` takes the session's address explicitly. Call sites
that only hold the session the current request named pass its name — the address
there — so their text is unchanged, as are explicitly named sessions everywhere.

Live before/after on an iOS simulator: `open` (cwd-scoped default), then
`open --session qa` on the same device. Before, the hint's own `close --session
default` answered `SESSION_NOT_FOUND` and the retry failed again; after, the
hint names `cwd:8bea844ab16aa9b3:default`, that close releases the device, and
the retry opens.

Refs #2031, #1394

* fix(daemon): thread the resolved session address through every recovery producer

The store key a request resolves — `cwd:<hash>:default` for an implicit
session — was known upstream but dropped before the selector-conflict and
lock-conflict producers, which then named `SessionState.name`. Both emitted
`close --session default`, the unreachable recovery this PR fixes for
DEVICE_IN_USE: `--session` marks the session explicit, so that command
addresses a different session.

`SessionRef` ({ address, session }) now carries the pair, so a recovery
producer cannot be handed a record whose address was never resolved.
`buildSessionRecoveryHint`, `assertSessionSelectorMatches` and
`applyRequestLockPolicy` take it; `prepareLockedRequestBinding` and the
Maestro replay route build it from the store key they already hold.

Replaces the broad `SessionStore.entries()` with the store's own narrow
lookups — `lookup`, `findByDevice`, `listRefs` — so callers receive the
session with its address instead of enumerating raw key/record tuples.

`session list` reports `address` alongside `name`, through the client
contract and serializer, so its discovery output names a value `--session`
accepts.

Regressions run the production routes, not the helpers: router-level
device-in-use, selector-conflict, lock-policy-conflict and `session list`
cases open an implicit session and read the address back off the store, plus
a typed-Maestro selector-conflict case. Each was observed red against the
pre-fix behavior it pins.

Refs #2031, #1394.

* fix(daemon): doctor names same-device sessions by address; green the fallow gate

- sessionChecks enumerated same-device sessions by SessionState.name:
  the printed close --session default was the exact unreachable
  recovery this PR removes elsewhere, the name-based dedupe hid two
  cwd-scoped default sessions from each other, and the evidence
  sessionStateDir pointed at <state>/sessions/default, which never
  exists. Candidates now come from listRefs() and report addresses.
- findByDevice joins values/delete in .fallowrc.json usedClassMembers
  (same resolution false positive on this class; the call site is
  session-open-execution.ts).
- the scoped-paths test narrows its response once instead of nine
  optional-chaining hops, which tripped the CRAP gate.

* style: format .fallowrc.json

---------

Co-authored-by: Michał Pierzchała <thymikee@gmail.com>
2026-08-27 11:06:32 +02:00
..