fix(agent-presets): let the invariant follow the roster it actually scans

The service moved its "is a roster composed" reads to the derived root set;
the invariant companion still read `config.roots`. In the shape this change
exists for — an app configures nothing and the roster is the harness home
alone — that made the advisory warning fire while the fail-loud invariant
stayed silent, so an agent could address a model against an empty global
layer unchecked.

Both now read one source: `roots` exposes the resolved set, and the invariant
asks it. That decides the behavior deliberately rather than by omission — a
composition that mounts the roster now fails an unjoined agent whether its
roots were configured or derived, and `includeUserRoot: false` with no
configured roots is how a deployment keeps its agents on the host plane. Both
shapes are pinned; the derived-only case fails against the old predicate.

Three pieces of prose went stale with the first commit: the web-app bundle
comment still called the writable root an assembly fact patched in by
AppCLIEntry (removed in the profile-plugin-bundles refactor — `composeProfile`
owns it now, and only for the shipped root), and the shipped skill and its
Agent Note still called both roots "configuration". The README gains the
resolved-roster reader and the discoverable-but-undeletable preset a second
writable root produces.
This commit is contained in:
Yichen Jiang
2026-08-11 21:13:41 +08:00
parent 101e7f2382
commit 715baae6c1
11 changed files with 60 additions and 21 deletions

View File

@@ -374,12 +374,15 @@
disabled: true
# The preset roster. `config/agent-presets/` ships with the deployment and is
# read-only (its entries carry `system` trust);
# `$DSH_HOME/.agent-presets` is where a person — or an agent — authors their own, and
# carries the same trust as shell access because a preset IS a composition.
# `roots` is an assembly fact, not user config: the shipped preset directory
# ships beside this file, so AppCLIEntry resolves it and patches it in — the
# same treatment `distIndex` gets on the webserver row.
# read-only (its entries carry `system` trust); `$DSH_HOME/.agent-presets` is
# where a person — or an agent — authors their own, and carries the same trust
# as shell access because a preset IS a composition.
#
# Only the SHIPPED root is an assembly fact: it sits beside the installed app's
# own config, so `apps/cli`'s `composeProfile` resolves and patches it in — the
# same treatment `distIndex` gets on the webserver row. The writable root is
# `dsh-agent-presets`' own default (`includeUserRoot`), so a composition that
# never reaches that patch still finds a person's presets.
- insert:
- id: agent-presets
name: '@deepseek-ai/dsh-agent-presets'