Card registration order is stable only for cards one package installs
together: apply order between packages is unconstrained, so several
external cards can still reorder between boots. The note and README said
otherwise. Recorded alongside it: the redactor returns a secret reachable
only through a union, intersection, or transform verbatim, and serving
every registered namespace widens that gap to third-party schemas; and
the headline capability still lacks an assembled-composition test.
publish() now keeps its snapshot reference when neither the loaded flag
nor the dispatched namespaces moved, so an unrelated settings commit no
longer re-renders the card list.
The Agent Note claimed the plugin inventory page already exposed every
mounted plugin's effective configuration to the same browser, so the
removed allowlist blocked nothing a caller could not already read. That
is false: PluginInventoryEntry carries entryId, moduleName, enabled, and
fiberPhase, and the page's configuration row renders an enabled tag, not
a stored value. The allowlist did keep an unlisted namespace's resolved,
base, and user values off the wire; the note now says so and rests the
decision on the loopback pin, secret redaction, the user's own document,
and the fact that permission and agent-presets were already served.
The post-await disposal check reads through an opaque method, mirroring
the settings seam's isStopped(): control flow narrowed the field to false
across the await, so the lint gate saw the guard as dead.
A plugin that registered a settings namespace could not reach the browser
configuration page: the api-proxy filtered every read and gated every
write through two hardcoded namespace lists, and the plugin configuration
section rendered an unordered list of cards carrying an opaque id rather
than the namespace they edit. Both gates lived in this repository, so a
user-authored plugin was configurable only by hand-editing settings.yaml.
The proxy now serves whatever ctx.settings.describe() returns and adds no
boundary of its own; a name no registration answers folds into the seam's
own settings-rejected, and the settings-not-exposed code retires. The
settings seam is untouched: which client may read a namespace, and which
page renders it, are facts about consumers.
settings.plugin.item becomes a keyed slot whose key is the namespace a
card edits, following tool.call.toolview. The section reads describe once
and dispatches the intersection of the slot ledger and the served set, so
a namespace another surface owns renders nothing without declaring
anything, and a card for an uncomposed plugin is never dispatched.