Sessions could be archived from the sidebar row menu but never restored:
the registry-global archive set was a one-way display filter with no
inverse RPC and no surface listing its members.
WorkspaceRegistry.unarchiveSession drops one id from archivedSessionIds in
one durable write on the same operation chain as archive, with no
session-existence probe because a removal cannot introduce an unknown
referent. The Workspace controller exposes it as workspace.unarchiveSession
returning the complete archive set, which the existing archived follow
increment already propagates, so no frame type and no persisted field
changes.
The new client package dsh-client-ui-settings-unarchive-sessions owns the
restore surface: one localized settings.section page listing the archive
set joined with loaded session summaries, newest archive first, searchable
by title or workspace, with one Unarchive action per row.
- A media-named FIFO or device node is refused before the open would
block on it (pre-open isFile check); POSIX FIFO regression test added.
- The full-body stream is bounded to the stat'ed size so concurrent
appends cannot exceed the declared Content-Length.
- Error responses carry no body for HEAD requests.
- Docs no longer overclaim the replacement race: the stat-identity
comparison narrows (does not fully close) the replacement window, and
the earlier realpath-to-stat window is acknowledged. Pairs re-recorded.
range-parser never validates the range unit, so /api/file now parses only
headers that start with the bytes unit: unsatisfiable ranges answer 416,
while malformed, unknown-unit, and multi-range headers are ignored for a
full 200 body per RFC 9110. The filesystem-root workspace case stays
POSIX-only in tests (a Windows drive-root spelling cannot be constructed
portably); containment already treats any separator-terminated root the
same. Docs (README pair, Agent Note pair) re-recorded.
- HEAD never opens a file stream; GET streams are destroyed on client
abort and are never opened for already-aborted requests.
- Validation and reading bind to the same opened file: pre-open and
opened stat identities are compared, so replacement/re-linking races
are refused (dev/ino check, read through the FileHandle).
- Workspace containment compares path components, so a filesystem-root
workspace serves files instead of doubling the separator.
- Multi-range headers are ignored for a full 200 body instead of a
mislabeled single-segment 206; single-range behavior unchanged.
- Tests now cover the reviewed edges (empty path, multi-range, root
workspace, HEAD+range, mid/early abort, unreadable file, explicit
unregister-on-dispose, private outside-target directories); module
coverage is back at 100/100/100/100.
- Agent Note bilingual facts and the ui-primitives/session-controller
README pairs are synced to the shipped behavior (pairs re-recorded).
- /api/file module now exports only the SessionMediaReferences plugin
contribution; MIME and range policy helpers are module-private and
exercised entirely through the registered route.
- Replace the hand-rolled media extension table with mime-types (served
categories image/video/audio, excluding image/svg+xml) and the
hand-rolled Range parser with range-parser; keep the fail-closed
workspace containment policy.
- Spec rewritten as route-level behavior tests (12 cases) covering the
same branches; Agent Note facts updated in the same change.