The regression for `PresetTree.write` lived two layers up, so this layer's own
assertion could not fail: it checked the file after an ordinary teardown, and
the Loader's unload listener returns early when the whole tree is being
disposed, so the override never ran. Moves the self-disposing-row test down to
the layer that adds the override, in a temp root so a committed fixture cannot
be damaged by the run that proves the bug.
The package landed here with one store spec; the rest of its tests were written
three layers up, so this layer and the two above it failed the per-file
coverage gate on 191 locations while every test passed.
Adds the node half's invariant companion, the two components, the registration
apply, and the stores' failure paths. `currentValue` drops a `?? ''` that an
empty roster already returned before reaching — the same shape the later layer
arrived at, so the two converge instead of conflicting.
The cordis preset moved `bash-env`, the `subagents` registry, and its
spawn/fork backends into entry-local realms. A host row that injects a service
is the criterion for host-plane ownership: `apps/cli/src/web.ts` injects
`bash-env`, and `dsh-host-apiproxy` injects `subagents` to answer the
browser's cross-session queries, so both waited forever for a service only
sessions provided. A provider name also registers once, so the second session
would have collided regardless.
This layer introduces the preset, so it is where the plane belongs — a later
layer already corrected it, which left this layer and the docs one unmountable
on their own. The composition test stops disabling `api-gateway` with it: the
row whose pending injection names the break cannot be the row the test turns
off, so the boot audit now covers the whole host-plane injection graph.
Same required field as the standard preset: master made
`allowParallelInProgress` mandatory on dsh-tool-todo, and a preset that names
the row owns the choice.
master made `allowParallelInProgress` a required field on dsh-tool-todo, so
every composition must choose it. The base patch was updated with the field,
but the Web surface takes `tool-todo` from the mounted preset instead, and
that row carried no config — so the `standard` preset failed to mount and
every session on the Web surface died at setup.
Also make the preset tree's write test reach the override. Tearing the agent
down stops in the loader's own "tree is being disposed" case before any write;
a live row reconfiguring itself is the trigger that actually gets there.
ChatView's bottom-follow recognized only wheel gestures as reader input,
so touch panning, scrollbar dragging, and keyboard paging could not leave
the bottom of a streaming transcript. Replace the wheel listener with
device-agnostic attribution: a scroll position deviating from the
observed-top ledger of the last delivered or written scrollTop is reader
input. Adds keyboard-paging and touch-style fling e2e scenarios (red under
the old implementation) and the bilingual Agent Note triplet.
Moving `web-agent-presets` to the built lane took its coverage with it, and the
per-file gate named what it had been the only reach for: the session header's
`agentPreset` type check, and the preset subtree's `write()` override. Neither
belonged to a real-composition boot — a header validation case and a subtree
behaviour are package-level facts.
The `write()` test states why the override exists: the inherited method
persists the tree whenever the Loader thinks the config moved, and disposing an
agent disposes its subtree, so inheriting it truncates the shipped preset to
`[]` the first time a session ends.