docs/design/daemon-multi-workspace-session-file-ops.md
Final implementation design. This document supersedes the Phase 2a primary-only statement for live-session rewind snapshots, rewind, and shell.
The daemon exposes singular session APIs, while a multi-workspace daemon owns one bridge per workspace runtime. Most live session routes already resolve the session owner, but rewind snapshots, rewind, and shell were still bound to the primary bridge or rejected a secondary owner. That made a valid live secondary session indistinguishable from an unsupported route to clients.
Keep the singular REST API and resolve the owning live runtime on every request:
GET /session/:id/rewind/snapshots uses owner-aware read routing.POST /session/:id/rewind and POST /session/:id/shell use owner-aware
mutable routing and the shared session archive coordinator._qwen/session/shell.The workspace registry searches all live bridge summaries for the session id.
Exactly one trusted owner dispatches to that runtime. No owner returns
404 session_not_found; an untrusted owner returns 403 untrusted_workspace;
multiple owners return 500 ambiguous_session_owner. All three outcomes occur
before the target bridge operation runs. Persisted sessions must first be loaded
or resumed into a runtime.
Rewind and shell retain mutate({ strict: true }). Shell additionally requires
effective shell enablement, a valid session-bound client id, and a non-empty
command. Rewind forwards an optional client id and accepts rewindFiles only
when omitted or boolean. Omitted means true; any other JSON type returns
400 invalid_rewind_files_flag.
Shell starts in the owning session workspace cwd and is not a filesystem path
sandbox. Rewind restores only snapshots recorded for edit and write_file.
It does not undo shell, Git, script, or manual changes. File restore is
best-effort: the conversation may already be rewound when the response reports
rewound: false with filesFailed[]. Active prompts retain 409 session_busy
and Retry-After: 5; invalid targets retain 400 invalid_rewind_target.
Web Shell continues to request rewindFiles: false.
The existing ~/.qwen/file-history/<sessionId> layout is unchanged. A live UUID
collision therefore fails closed through owner ambiguity rather than selecting
the primary runtime.
multi_workspace_session_rewind is advertised only while more than one runtime
exists. multi_workspace_session_shell additionally requires effective session
shell enablement, which means both the enable flag and a configured token.
Client preflight is additive:
session_rewind.session_rewind and
multi_workspace_session_rewind.session_shell_command.session_shell_command and
multi_workspace_session_shell.ACP-native clients use initialize _qwen.methods; the daemon does not advertise
an ACP rewind vendor method.
Unit coverage pins owner dispatch, zero calls to non-owning bridges, trust and
ambiguity failures, strict validation order, rewindFiles semantics, SDK REST
fallback, unchanged shell transport, conditional capability advertising, and
the absence of ACP rewind mappings. ACP workspace tests retain the invariant
that an A connection cannot operate a B session while a workspace-qualified B
shell succeeds.
The E2E scenario creates a session and tracked edits in workspace B, verifies snapshots and shell cwd are B-scoped, checks both rewind file modes, proves a shell-created file survives rewind, and records busy, partial restore, and untrusted-secondary outcomes.