The roots are an assembly fact (the shipped set beside this app's config,
the user's own under $DSH_HOME) but only `dsh web` patched them in, so the
merged `dsh run` booted the roster with no roots and failed resolving
`standard`. The shared profile boot now owns the patch for every launcher;
the one-shot transcript header consequently records its composing preset,
and master's interrupt_agent tool joins the standard composition's exact
catalog.
The web YAML editor is gone. agentPreset.write (arbitrary composition
text) became agentPreset.copy { from, agentPreset, name? }: a host-side
whole-directory copy of ids the host resolves itself — symlinks
dereferenced, modes re-tightened to owner-only with owner-execute kept,
metadata rewritten to keep the source's description but never its name or
roster order. No composition text or path crosses the wire in either
authoring direction, and the entryListSchema/!!js concern dissolves with
assertComposition itself.
The settings section becomes: a read-only viewer over shipped
compositions, a copy dialog (id + optional display name) as the only
create entry, delete for custom rows, and a location action leading into
the preset's own files — agentPreset.openDocument { agentPreset } resolves
the directory host-side and opens it natively, or answers
{ opened: false, path } for the row to show as text where the deployment
has no desktop. agentPreset.list reports hasDocument beside authorable;
the gateway's nativeOpen config pins the capability where
canOpenNativePath platform detection would mislead. The privileged set is
now read/copy/openDocument/remove.
With files as the only composition editor, standing mounts grew
stamp-keyed generations: ensureStanding compares the composition file's
mtime+size and starts the next generation for later sessions, while every
joined session keeps the generation it runs on.
New keyless web lane (agent-preset-authoring, overlay pins
nativeOpen: false so goldens render one branch on every platform) drives
view/copy/reveal/delete end to end; the real-composition CLI e2e switches
to copy semantics.
`apps/cli/config/base.cordis.yml` and `web.cordis.yml` no longer exist — the
bundle split replaced them with `packages/bundle/{base,web-app}/cordis.patch.yml`
— so this file booted a path that was deleted under it and every CI run since
the merge failed at `ENOENT`.
It now boots what `dsh web` boots: an empty preset root with the two bundle
patches over it. That root sits outside the workspace, so bare plugin names
cannot resolve by Node's upward walk and the flat module fallback the preset
boot maintains is what makes them resolvable — the same mechanism, not a
test-only shim. That fallback links each package's PUBLISHED entry, so this
file now consumes the artifact plane and moves to the lane that builds first
(`.e2e.ts`, beside `built-bin.e2e.ts`), rather than the coverage lane, which
installs and runs on a clean tree.