ReadonlydeclarationCapability declaration — reuses the existing <cap>-capability.ts (id, gate, schema).
Optional ReadonlymoduleGate of createModule when the module's activation key differs from the capability's own gate — the sub-feature case.
permalink owns no module of its own (two boot hooks drive it), but it embarks
share (S13 F7), whose ShareModule is gated on the sub-key
modules.permalink.share.enabled (opt-out), NOT on modules.permalink.enabled.
Share has no capability declaration of its own by design, and the registry ignores
a second register() on the same id — so the gate cannot be expressed as a second
declaration. It is expressed here, as an optional FIELD (the contract's doctrine),
evaluated by evaluateGate() with exactly the same semantics as a declaration gate.
Absent → the declaration's own gate applies (the common case).
Assigns the capability's public facade(s) onto the GeoLeaf namespace.
This is the former "layer B" — the window.GeoLeaf.* writes moved out of
the monolithic globals.{ui,api,geojson}.ts. Called by Pass 1 of the preset loop
(presets/apply-preset.ts), ungated. Must be idempotent and additive — the kernel
facades are written first, at import, by the globals.*.ts chain (phase A).
(This used to say "composed by the boot via the module-setup seam". That was wrong
even then — registerGlobals was always driven by apply-preset.ts — and the seam
itself is gone since S6 Lot 5.)
the boot-populated GeoLeaf global namespace.
OptionalcreateFactory for the capability's lifecycle module (ICoreModule).
Absent for the three pull-based capabilities — they answer when asked and subscribe to nothing, so there is no lifecycle to drive:
cluster — pure resolvers queried on demand ;taxonomy — supplies paint expressions and symbol ids to whoever asks ;vector-tiles — publishes the _VectorTiles seam; the GeoJSON loader reads it
back lazily through _loaderDeps.getVectorTiles().⚠️ This list said cluster, taxonomy, permalink until CAPACITÉS S10, and it was wrong
in both directions — the same error was copied into ARCHITECTURE.md and the
CDC_technique.md §P2-14 table. permalink DOES declare a createModule: it builds
ShareModule, the module of its share/ sub-feature, which is exactly why it also
declares CapabilityInstaller.moduleGate. What permalink lacks is a lifecycle
of its own — that one lives in capabilities/permalink/share/lifecycle.ts. And
vector-tiles, the genuine third member, was named nowhere.
pwa and offline are absent too, but for the other reason: they are app-global and
express their lifecycle through CapabilityInstaller.sharedLifecycle below.
The rule is pinned by __tests__/capabilities/scaffold-taxonomy.test.js, which derives
each family from the installers rather than from a list — so this comment cannot drift
again without a red test.
OptionalsharedPre-map lifecycle driven by the kernel shared module — the app-global case.
pwa (step #7) and offline (step #8) own no ICoreModule: they are app-global,
and their lifecycles must run on the post-merge config, inside SharedModule.init()
(which runs after the profile resources load). Before S4 that was expressed by
shared.module.ts statically importing PwaLifecycle and OfflineLifecycle —
a kernel module hard-wired to two optional capabilities, which pinned both into the
eager closure of every bundle no matter what its manifest said. That was THE anchor
blocking tree-shaking.
Expressing it as an optional FIELD (the contract's doctrine) inverts the dependency:
SharedModule receives the entry's installers and calls whatever contributed itself.
An entry that omits pwa simply has no contributor — and the capability tree-shakes out.
Execution order is the manifest order. ⚠ No pair of contributors depends on it — this
line read « pwa MUST precede offline: offline reads modules.pwa.enabled and refuses
to start its engine without it » until 08/08/2026. The refusal is real; the ordering it
was used to justify is not, because that flag lives in the merged config bag handed to
every contributor. Measured: __tests__/presets/shared-lifecycle-order.test.ts (7.4).
the GeoLeaf namespace and the fully merged config.
OptionalsharedTears down what CapabilityInstaller.sharedLifecycle started, called from
SharedModule.destroy(). Same inverted dependency: the kernel calls whatever
contributed itself and imports no capability.
Without this, an app-global capability keeps its module-level state across a
create → destroy → recreate cycle: the lifecycle runs again on a state that was
never reset. Capabilities driven by their own *.module.ts already reset in that
module's destroy(); this is the equivalent for the ones SharedModule drives.
Runs in reverse manifest order (mirror of sharedLifecycle) — a real mechanism,
asserted by __tests__/config/s15-modules-storage-init.test.js. ⚠ The reason this line
gave for it was not: it read « …, so a capability is torn down before the one it depends
on: offline (#8) then pwa (#7) » until 08/08/2026. No sharedTeardown of the shipped
manifest reads another's state, and SLO-06 measured the teardown effects invariant under
both orders. The mirror is kept for symmetry with sharedLifecycle, not for a dependency.
Self-sufficient installer for one in-core capability.
Regroups the 3 static-anchoring layers of a capability behind a single import site, so a preset embarks a capability by importing ONLY its
install.ts:window.GeoLeaf.*assignments) — registerGlobals ;