refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD across contents and paths, upstream package/repo coordinates -> @golem15/msd-core and golem15com/msd-core. Deep links into upstream history, sibling upstream packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is. Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line, package/plugin identity, regenerated lockfile, install-tree fixtures, derived registries and benchmark baseline; migration checksum baseline re-locked (MSD keeps its own install state, so no install had applied the old sums); sort-order and regex-escaped expectations in tests adjusted.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# How overlay capabilities compose
|
||||
|
||||
> **Explanation** — This document describes *why* GSD composes first-party and
|
||||
> **Explanation** — This document describes *why* MSD composes first-party and
|
||||
> third-party capabilities the way it does, and *what the precedence and conflict
|
||||
> rules are*. It is not a step-by-step guide; for the consumer lifecycle see
|
||||
> [Install your first capability](../tutorials/install-your-first-capability.md),
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
## The central idea: the registry is a module, not a data file
|
||||
|
||||
GSD's capabilities — first-party and third-party alike — are described by a single
|
||||
MSD's capabilities — first-party and third-party alike — are described by a single
|
||||
**capability registry**: a composed object that every consumer (the loop resolver,
|
||||
the config loader, the surface command, `gsd capability list`) reads to learn which
|
||||
the config loader, the surface command, `msd capability list`) reads to learn which
|
||||
skills, agents, config keys, and loop hooks exist.
|
||||
|
||||
The first-party registry is *frozen and generated*: it is built at release time from
|
||||
@@ -41,7 +41,7 @@ second-class citizen: once it composes cleanly, it participates in the loop exac
|
||||
as a shipped one does.
|
||||
|
||||
The interesting question is everything that can go wrong while composing two sources
|
||||
that were authored independently — and what GSD does about each case. That is the rest
|
||||
that were authored independently — and what MSD does about each case. That is the rest
|
||||
of this document.
|
||||
|
||||
---
|
||||
@@ -58,28 +58,28 @@ before surface and config**, not after them.
|
||||
The capability now exists *on disk*.
|
||||
2. **Load / compose (with the project-scope consent gate)** is what `loadRegistry`
|
||||
does. As it composes each overlay it applies the composition gates — id/skill/agent/
|
||||
config/family collisions, the `engines.gsd` re-check, and, for a *project-scoped*
|
||||
config/family collisions, the `engines.msd` re-check, and, for a *project-scoped*
|
||||
overlay, **the project-scope consent gate**. That gate runs *inside* `loadRegistry`,
|
||||
before any of the overlay's fragments are even materialised: a project overlay is
|
||||
inert (discovered-but-inactive) until a matching record exists in your user-owned
|
||||
consent store. This is the security gate described in
|
||||
[the trust model](capability-trust-model.md#the-project-scope-trust-boundary). A
|
||||
capability that fails any composition gate — consent included — never enters the
|
||||
registry the rest of GSD reads, so it cannot reach the later stages at all.
|
||||
registry the rest of MSD reads, so it cannot reach the later stages at all.
|
||||
3. **Surface** decides which of the *composed* registry's skills are projected into the
|
||||
host runtime. This is the install-profile and `/gsd-surface` layer — a capability's
|
||||
host runtime. This is the install-profile and `/msd-surface` layer — a capability's
|
||||
skills can be on the surface or held back without uninstalling it. It only ever sees
|
||||
capabilities that already cleared composition.
|
||||
4. **Config activation** decides, per loop hook, whether it fires. A hook's `when`
|
||||
key (a dotted config key) gates it: a `step` or `gate` whose key is falsy does not
|
||||
run. This is the `gsd capability set <id> --gate <key>=<bool>` and `/gsd-settings`
|
||||
run. This is the `msd capability set <id> --gate <key>=<bool>` and `/msd-settings`
|
||||
layer — again, only for capabilities that survived composition.
|
||||
|
||||
This document is about what `loadRegistry` does at the moment of composition — stage 2,
|
||||
which sits between install and the later surface/config stages and contains the consent
|
||||
gate. A capability that is installed but skipped at composition (including for missing
|
||||
consent) never reaches the surface or config stages, because it is not in the registry
|
||||
the rest of GSD reads.
|
||||
the rest of MSD reads.
|
||||
|
||||
---
|
||||
|
||||
@@ -87,20 +87,20 @@ the rest of GSD reads.
|
||||
|
||||
`loadRegistry` scans two install roots, in this order:
|
||||
|
||||
- **Global** — `$GSD_HOME/.gsd/capabilities/<id>/` (where `GSD_HOME` defaults to your
|
||||
- **Global** — `$MSD_HOME/.msd/capabilities/<id>/` (where `MSD_HOME` defaults to your
|
||||
home directory). This is under your own control and is trusted without a per-project
|
||||
record.
|
||||
- **Project** — `<projectRoot>/.gsd/capabilities/<id>/`. This lives inside a repository
|
||||
- **Project** — `<projectRoot>/.msd/capabilities/<id>/`. This lives inside a repository
|
||||
and is therefore only as trustworthy as the repository; it is gated by the consent
|
||||
store.
|
||||
|
||||
The roots are deduplicated by their *canonical* (symlink-resolved) physical path, so a
|
||||
single directory is never scanned twice — and, crucially, so a symlinked `GSD_HOME`
|
||||
single directory is never scanned twice — and, crucially, so a symlinked `MSD_HOME`
|
||||
that physically *is* the project root cannot smuggle an in-repo bundle into the trusted
|
||||
global slot. When the global and project roots resolve to the same physical directory
|
||||
(or distinctness cannot be proven), the surviving scope escalates to the more
|
||||
restrictive `project` — consent-required. This is a deliberately conservative choice:
|
||||
when GSD cannot prove a global root is distinct from your project tree, it treats it as
|
||||
when MSD cannot prove a global root is distinct from your project tree, it treats it as
|
||||
project-scoped rather than risk granting trusted-global activation to repo-plantable
|
||||
content.
|
||||
|
||||
@@ -129,9 +129,9 @@ overlay is rejected if it collides on any of:
|
||||
|
||||
Two further rules protect the first-party namespace directly:
|
||||
|
||||
- **Reserved prefixes.** The `gsd-`, `gsd-core-`, and `anthropic-` id prefixes are
|
||||
- **Reserved prefixes.** The `msd-`, `msd-core-`, and `anthropic-` id prefixes are
|
||||
reserved. An overlay whose id begins with one is rejected outright — a third party
|
||||
cannot publish `gsd-security` and borrow the implicit trust of the GSD namespace.
|
||||
cannot publish `msd-security` and borrow the implicit trust of the MSD namespace.
|
||||
- **Cross-capability invariants.** Each candidate overlay is added to the merged
|
||||
capability map and the *full* cross-capability validation suite (contract roles,
|
||||
`consumes`-satisfiability, owner uniqueness, config-key exclusivity, `requires`
|
||||
@@ -142,12 +142,12 @@ Two further rules protect the first-party namespace directly:
|
||||
|
||||
The asymmetry is intentional and follows directly from the trust model's central
|
||||
thesis — *artifact parity is not trust parity*. A third-party capability is allowed to
|
||||
ship the same kinds of artifacts as GSD Core, but first-party capabilities carry an
|
||||
authority third-party ones do not: their provenance is the GSD release process itself.
|
||||
ship the same kinds of artifacts as MSD Core, but first-party capabilities carry an
|
||||
authority third-party ones do not: their provenance is the MSD release process itself.
|
||||
If a collision could let an overlay shadow a first-party skill, agent, or command, then
|
||||
installing a capability could silently *replace* a shipped behaviour — the install would
|
||||
be the attack. By making first-party unconditionally win every collision, GSD
|
||||
guarantees that no installed capability can ever redefine what GSD Core does. An overlay
|
||||
be the attack. By making first-party unconditionally win every collision, MSD
|
||||
guarantees that no installed capability can ever redefine what MSD Core does. An overlay
|
||||
can only *add*; it can never *override*.
|
||||
|
||||
---
|
||||
@@ -167,8 +167,8 @@ for any of these reasons:
|
||||
- it fails structural or cross-capability validation;
|
||||
- it collides with first-party or an already-accepted overlay (the precedence rule
|
||||
above);
|
||||
- its `engines.gsd` range does not satisfy the running GSD version (the load-time
|
||||
re-gate, which mirrors the install-time gate so an upgrade of GSD itself can retire an
|
||||
- its `engines.msd` range does not satisfy the running MSD version (the load-time
|
||||
re-gate, which mirrors the install-time gate so an upgrade of MSD itself can retire an
|
||||
incompatible overlay);
|
||||
- it carries an in-flight `_pending` install/upgrade marker (deferred until
|
||||
reconciliation completes);
|
||||
@@ -204,14 +204,14 @@ to the operator at all.
|
||||
|
||||
So, per the maintainer decision on [#2009](https://github.com/open-gsd/gsd-core/issues/2009),
|
||||
composition treats gates like steps and contributions for control flow — the loop always
|
||||
proceeds — but never silently. When a capability that declares a gate is skipped, GSD
|
||||
proceeds — but never silently. When a capability that declares a gate is skipped, MSD
|
||||
records its gate points in `_overlay.incompatibleGateCapIds` and `_overlay.blockedGates`,
|
||||
and the loop resolver **injects no gate** at each of those extension points. The loop
|
||||
**fails open**, but loudly: it emits a warning through two channels — stderr (the channel
|
||||
host workflows/agents see when they run `gsd_run loop render-hooks <point>`) and the
|
||||
host workflows/agents see when they run `msd_run loop render-hooks <point>`) and the
|
||||
`loop render-hooks` JSON envelope's top-level `warnings` array. The warning names the
|
||||
skipped capability, why it could not be loaded (for example, an incompatible
|
||||
`engines.gsd` range), and the exact remediation — `gsd capability remove <id>` — so the
|
||||
`engines.msd` range), and the exact remediation — `msd capability remove <id>` — so the
|
||||
operator sees the missing control on every pass through the loop until they act on it,
|
||||
instead of the loop halting project-wide over a single incompatible overlay.
|
||||
|
||||
@@ -229,7 +229,7 @@ canonical builder (`buildRegistry`) materialises the merged registry — a topol
|
||||
cycle that only appears across the combined set, a config-slice shape problem, a format
|
||||
mismatch. An unguarded failure there would crash every consumer of the registry.
|
||||
|
||||
The fallback is uncompromising: if the whole-set build fails, GSD **discards every
|
||||
The fallback is uncompromising: if the whole-set build fails, MSD **discards every
|
||||
overlay** and returns the frozen first-party registry, plus a warning recording why. The
|
||||
loop keeps running with exactly the shipped capabilities and none of the overlays. Two
|
||||
details make this safe rather than merely convenient:
|
||||
@@ -241,7 +241,7 @@ details make this safe rather than merely convenient:
|
||||
still **surfaces a loud warning** (stderr + envelope `warnings`) at its gate points
|
||||
rather than vanishing silently (#2009).
|
||||
|
||||
The principle is the same at every layer: when GSD cannot compose an overlay, it removes
|
||||
The principle is the same at every layer: when MSD cannot compose an overlay, it removes
|
||||
the overlay's *additions* but never silences a *control* — a missing gate always
|
||||
surfaces, even though, per #2009, it no longer blocks the loop.
|
||||
|
||||
@@ -251,14 +251,14 @@ surfaces, even though, per #2009, it no longer blocks the loop.
|
||||
|
||||
A subtle but important design choice: the merged registry is materialised by the **same**
|
||||
`buildRegistry` function that produces the first-party registry, run over a map of
|
||||
first-party capabilities *plus* the accepted overlays. GSD does not have one code path
|
||||
first-party capabilities *plus* the accepted overlays. MSD does not have one code path
|
||||
that builds the first-party views and a separate path that bolts overlay views on.
|
||||
|
||||
The reason is drift. Every derived view — `bySkill`, `byLoopPoint`, the config schema,
|
||||
the cluster map, profile membership — is a projection of the capability set. If overlays
|
||||
were projected by a different builder, those projections could diverge from the
|
||||
first-party ones in subtle ways, and an overlay capability might behave *almost* like a
|
||||
first-party one but not quite. By forcing both through the single canonical builder, GSD
|
||||
first-party one but not quite. By forcing both through the single canonical builder, MSD
|
||||
guarantees that an accepted overlay is indistinguishable from a first-party capability in
|
||||
every derived view — which is exactly the artifact-parity promise the platform makes.
|
||||
|
||||
@@ -276,7 +276,7 @@ The overlay model rests on a few rules applied consistently:
|
||||
per [#2009](https://github.com/open-gsd/gsd-core/issues/2009), **fails open** for gates
|
||||
too (a missing control, no gate injected) — but loudly, via a warning (stderr + the
|
||||
envelope's `warnings` array) that names the load failure and its
|
||||
`gsd capability remove <id>` remediation.
|
||||
`msd capability remove <id>` remediation.
|
||||
- A whole-set compose failure **falls back to first-party**, clearing command roots and
|
||||
still surfacing dropped gates as loud warnings.
|
||||
- One canonical builder materialises both first-party and overlay views, so an accepted
|
||||
@@ -295,5 +295,5 @@ single incompatible overlay.
|
||||
- [The capability trust model](capability-trust-model.md) — the security side of the same boundary
|
||||
- [Capability Overlay (Configuration)](../CONFIGURATION.md#capability-overlay-installed-third-party-capabilities) — the operator-facing view of the same rules
|
||||
- [Capability manifest reference](../reference/capability-manifest.md) — the field-level conformance invariants
|
||||
- [`gsd capability` command reference](../reference/gsd-capability-command.md)
|
||||
- [`msd capability` command reference](../reference/msd-capability-command.md)
|
||||
- [Install your first capability](../tutorials/install-your-first-capability.md)
|
||||
|
||||
Reference in New Issue
Block a user