diff --git a/website/MODULE_API.md b/website/MODULE_API.md
index ab34b09..74c0611 100644
--- a/website/MODULE_API.md
+++ b/website/MODULE_API.md
@@ -37,8 +37,16 @@ module chunk evaluates, which is earlier than any network round trip could answe
`module-uo`'s `coreApi: "^1.3.0"` still resolves. `api.registerTeamProvider(...)` and
`ctx.teams.publish` / `ctx.teams.reconcile` (§2.3, §2.4a) · `ctx.teams.activity.push` ·
the provider's optional `projectRoster` and `pageUrlTemplate` · `api.registerSlashCommands(...)` ·
-`registry.declareModuleSlot(...)` with `Slot` in the UI kit.
+`registry.declareModuleSlot(...)` with `Slot` in the UI kit — the ninth member of it.
+> **Amended 2026-08-19 (phase 11), on the org lead's decision.** `declareModuleSlot` takes an
+> optional `{ core }` naming which of core's contributions belongs in the declared place, and core
+> offers contributions instead of naming slots (`CORE_CONTRIBUTIONS`, §3.7a). In 1.6.0 in place, by
+> the same rule as the two amendments below: 1.6.0 has only ever been on `edge`. It is a **correction
+> and not an addition** — as first written, core filled three literal `uo.guild.*` names, so the
+> inverted direction worked for exactly one module and silently did nothing for any other, which the
+> integration kit found while trying to teach it to an audience outside this org.
+>
> **Amended 2026-08-17 (phase 3), on the org lead's decision.** Two changes.
>
> **Amended again 2026-08-18 (phase 6), on the org lead's decision.** A **ninth** member,
@@ -56,8 +64,8 @@ the provider's optional `projectRoster` and `pageUrlTemplate` · `api.registerSl
> Both assumed core rendered a Team page. It does not: **Teams is a contract primitive, not a
> surface** — core owns the tables, the sync, the access rules and the activity feed, and does not own
> the word for one, so the module that owns the vocabulary owns the page. In their place,
-> `registry.declareModuleSlot(id, name)` lets a MODULE declare a place on its own page for CORE to
-> fill, and `Slot` joins the UI kit so the module can render it. See §3.7a.
+> `registry.declareModuleSlot(id, name, { core })` lets a MODULE declare a place on its own page for
+> CORE to fill, and `Slot` joins the UI kit so the module can render it. See §3.7a.
**Every member of 1.6.0 is live as of phase 7.** `api.registerSlashCommands` was the last one still
throwing, and it now registers — the staged rollout the paragraphs above describe is finished. A
@@ -1050,7 +1058,7 @@ props is a **major** one, because that breaks a call already written. Adding an
minor (§1.1). That is a real constraint on core and it is the price of the boundary being worth
anything.
-The kit is those **eight exports** — five rows, because `PageState` contributes three. An earlier
+The kit is those **nine exports** — six rows, because `PageState` contributes three. An earlier
draft of this table listed a ninth, `AdminPage`, and core has no such component — admin views are
plain markup inside `AdminLayout`. It was struck in Phase 2 PR 7 rather than satisfied by inventing a
core component with no consumer until Phase 3; adding it later costs a minor bump, which is the case
@@ -1293,10 +1301,11 @@ forced it is worth stating because it will recur:
> only core can resolve — are contributed to it.
```js
-// In the module's entry chunk, at registration time:
-registry.declareModuleSlot(ID, 'uo.guild.header')
-registry.declareModuleSlot(ID, 'uo.guild.detail')
-registry.declareModuleSlot(ID, 'uo.guild.forum')
+// In the module's entry chunk, at registration time. The second argument names
+// which of CORE's contributions belongs in that place:
+registry.declareModuleSlot(ID, 'uo.guild.header', { core: 'team.notify' })
+registry.declareModuleSlot(ID, 'uo.guild.detail', { core: 'team.activity' })
+registry.declareModuleSlot(ID, 'uo.guild.forum', { core: 'team.forum' })
// In the module's page, from the UI kit:
@@ -1304,6 +1313,33 @@ registry.declareModuleSlot(ID, 'uo.guild.forum')
```
+**Core offers a CONTRIBUTION; it never names a slot.** This is the part a second game depends on, and
+the first cut of 1.6.0 had it the other way round — core filled the three literal names above, which
+worked for `module-uo` and silently did nothing for anybody else: a module declaring `clan.detail`
+under its own id got an empty page and no error, because "a fill for a slot nobody declared is not an
+error" is exactly the rule that makes an unknown name invisible. It also put a module identifier
+inside core, in three string literals `scripts/checkModuleIdentifiers.js` masks by construction and
+could never have caught (§5.2). Corrected inside 1.6.0, before it reached `main`.
+
+So the module says WHERE, in its own vocabulary, and WHICH of core's contributions goes there:
+
+| Contribution *(1.6.0)* | What core puts in the slot | Why it is core's |
+| --- | --- | --- |
+| `team.activity` | the Team activity feed | only core can resolve the public/members split on it |
+| `team.forum` | the Team forum panel | membership and manual grants are core's rules |
+| `team.notify` | the per-Team notification control | core resolves whether the viewer is in the Team |
+
+`options.core` is **optional** — a module may declare a place it fills itself, or one it is keeping
+empty for now. Asking for a contribution core does not offer **throws at the declaration**, and that
+asymmetry with an unfilled slot is deliberate: core's catalogue is fixed at build time and the
+module's `coreApi` range has already been checked, so an unknown contribution is always a typo or a
+version skew, and the alternative failure is a page that renders empty forever with nothing logged.
+**Adding a contribution is a minor bump**; removing one is major.
+
+More than one slot may ask for the same contribution and each gets it. Core has no reason to care how
+many places a module wants its feed in, and refusing the second would be core making a layout decision
+on a page it does not own.
+
**A module declares one slot per PLACE, not one per page.** `module-uo` declares **three** on the same
guild page — core fills them with the Team notification control, the activity feed and the Team forum
— because a slot holds one component and the first fill wins. Collapsing them would hand core the
@@ -1318,25 +1354,25 @@ readable at the fill site.
**Core fills these at MOUNT, not eagerly, and the ordering is why the call exists at all.** Core's
bundle evaluates before every module chunk (§3.1), so at the moment core would like to fill one of
-these the slot does not exist. Core registers its intent (`fillModuleSlot`, core-only) and
+these the slot does not exist. Core registers its intent (`offerCoreFill`, core-only) and
`applyCoreFills()` runs once, from `main.jsx`, after every chunk has evaluated and before the first
render.
-**A fill for a slot no installed module declares is a no-op, never an error.** The declaring module is
-simply not installed, which is the ordinary case on any deployment — the exact mirror of an unfilled
-slot rendering nothing. Note the asymmetry with §3.7, where an unknown slot throws: there, an unknown
+**A contribution nothing asks for is a no-op, never an error.** No game module is installed, which is
+the ordinary case on any deployment — the exact mirror of an unfilled slot rendering nothing. Note the asymmetry with §3.7, where an unknown slot throws: there, an unknown
name is always a typo or a version skew, because core declares before any module can name one.
**First fill still wins**, so a module that fills its own declared slot keeps it and core's fill is
skipped. That is deliberate: the module owns the page.
-**`Slot` is the eighth member of the UI kit** (§3.4) for this. A module could not render one of these
+**`Slot` is the ninth member of the UI kit** (§3.4) for this. A module could not render one of these
otherwise, and reimplementing it would mean a second error boundary with different behaviour — which
matters more here than anywhere else in the kit, because the thing being contained is *core's* content
failing inside the *module's* page.
-`declareModuleSlot` is on the `registry` object handed to modules. `fillModuleSlot` and
-`applyCoreFills` are not: filling one of these is core's, exactly as declaring a §3.7 slot is.
+`declareModuleSlot` is on the `registry` object handed to modules. `offerCoreFill`, `applyCoreFills`
+and `CORE_CONTRIBUTIONS` are not: offering into one of these is core's, exactly as declaring a §3.7
+slot is.
---
diff --git a/website/TEAMS.md b/website/TEAMS.md
index 06f5f9b..8d1e265 100644
--- a/website/TEAMS.md
+++ b/website/TEAMS.md
@@ -830,18 +830,20 @@ named for a *place* and never for a meaning):
> **Superseded 2026-08-17 (phase 3, org lead).** Both slots are gone, and the DIRECTION is what
> changed. They assumed core rendered the Team page; core renders no Team page. The replacement is
-> `registry.declareModuleSlot(id, name)` — a **module** declares a place on its own page, namespaced
-> under its own id, and **core** fills it:
+> `registry.declareModuleSlot(id, name, { core })` — a **module** declares a place on its own page,
+> namespaced under its own id, naming which of core's contributions goes there, and **core** offers it:
>
> | Slot | Declared by | Rendered in | Filled by core with | Props |
> | --- | --- | --- | --- | --- |
-> | `uo.guild.detail` | `module-uo` | its guild detail page | the Team activity feed (§4.3) | `{ externalId, moduleId }` |
-> | `uo.guild.forum` | `module-uo` | the same page, below the feed | the Team forum (Part 5) — added in phase 4 | `{ externalId, moduleId }` |
+> | `uo.guild.detail` | `module-uo` | its guild detail page | `team.activity` — the Team activity feed (§4.3) | `{ externalId, moduleId }` |
+> | `uo.guild.forum` | `module-uo` | the same page, below the feed | `team.forum` — the Team forum (Part 5), added in phase 4 | `{ externalId, moduleId }` |
>
-> Core's fills are applied at MOUNT, not eagerly: core's bundle evaluates before every module chunk,
-> so when core registers a fill the slot does not exist yet. A fill for a slot no installed module
-> declares is a no-op, not an error — the mirror of an unfilled slot rendering nothing. `Slot` becomes
-> the eighth member of the shared UI kit so a module renders the place with core's own error boundary,
+> Core's contributions are applied at MOUNT, not eagerly: core's bundle evaluates before every module
+> chunk, so when core offers one, no module-declared slot exists yet. A contribution nothing asks for
+> is a no-op, not an error — the mirror of an unfilled slot rendering nothing. **Core names the
+> contribution and never the slot** (amended phase 11, inside 1.6.0: as first built it filled the
+> literal names above, which reached `module-uo` and no other game). `Slot` becomes
+> the ninth member of the shared UI kit so a module renders the place with core's own error boundary,
> which matters here because the thing being contained is CORE's content failing inside the MODULE's
> page.
>
@@ -2547,13 +2549,16 @@ guild called "Admin" cannot put an official-looking page on the site.
>
> **So the extension slots invert, and that is a new `MODULE_API` §3.7 direction.** `team.overview`
> and `team.member.row` assumed core rendered the page. They are replaced by
-> `registry.declareModuleSlot(id, name)`: a **module** declares a place on its own page, namespaced
-> under its own id, and **core** fills it. `module-uo` declares `uo.guild.detail`; core fills it with
-> the activity feed, because only core can resolve whether a viewer is inside the Team and the
-> public/members split is a security boundary. Core's fills are applied at mount rather than eagerly —
-> core's bundle evaluates before every module chunk, so at the moment core registers a fill the slot
-> does not exist yet. `Slot` joins the shared UI kit as its eighth member so the module renders the
-> place with core's own error boundary.
+> `registry.declareModuleSlot(id, name, { core })`: a **module** declares a place on its own page,
+> namespaced under its own id, and names which of core's contributions belongs there. `module-uo`
+> declares `uo.guild.detail` and asks for `team.activity`; core offers the activity feed, because only
+> core can resolve whether a viewer is inside the Team and the public/members split is a security
+> boundary. **Core names the contribution, never the slot** — amended in phase 11, inside 1.6.0, after
+> the integration kit found that the literal-name version worked for one module and silently did
+> nothing for any other. Core's contributions are applied at mount rather than eagerly — core's bundle
+> evaluates before every module chunk, so at the moment core offers one, no module-declared slot exists
+> yet. `Slot` joins the shared UI kit as its ninth member so the module renders the place with core's
+> own error boundary.
>
> **A module names a Team in its own vocabulary**, so `GET /public/teams/by-external/:moduleId/:externalId`
> is added: core's row id and slug are core-internal and handing them to a module is how a module ends