feat(guilds): declare a second place on the guild page, for core's forum #12

Merged
whitlocktech merged 2 commits from feature/teams-phase4-forum-slot into edge 2026-08-18 14:17:52 +00:00
Member

What & why

The module half of Teams phase 4 � Forum 5a. Targets edge alongside the core
work in website#153 and the docs in docs#157.

The mirror of the activity feed, one phase later. Core owns the Team forum �
membership, manual grants and the member/guest split are all core's rules, and a
module reimplementing any of them would be reimplementing a security boundary � but
core publishes no Team page, because it does not own the word "guild". So this
module declares the place and core puts the forum in it.

TWO declarations rather than one, and that is the part worth reviewing. A slot
holds one component and the first fill wins, so folding the forum into
uo.guild.detail alongside the feed would hand core the decision about where each
of its two contributions sits on a page this module owns. Separate slots also keep
them independent: with the forum switched off, the feed renders exactly as before.

The rule this establishes for the inverted slot direction � one slot per PLACE,
not one per page
� is written into MODULE_API.md §3.7a in the docs PR.

How it was tested

  • npm test in client/ â€â€� 42 pass. The registration test now asserts the SET of
    declared slots, and that every one of them is rendered by the page that owns
    it, rather than naming a single slot twice. A slot nothing renders is a slot core
    fills into the void.
  • npm test in server/ â€â€� 428 pass, untouched by this change.
  • npm run build in client/ â€â€� the prebuilt chunk is rebuilt and committed.

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • AI tools were used. Tool(s): Claude Code. I have reviewed and understand
    every change, and take responsibility for it. AI-authored commits are
    marked with a Co-Authored-By trailer.

License

  • I agree that my contribution is licensed under this project's license
    (GNU GPL v3.0 or later), and I have the right to contribute it.

One thing that is not phase 4: the core pin

frozen-manifest has been red since Teams phase 2, on #11 as well as here, and
the red was real. The pin (website#140) predates api.registerTeamProvider, which
this module has called since phase 1 of its Teams work — so the module fails to
LOAD in the pinned checkout, and a module that does not load adds no routes, which
the job correctly reports as the module having removed everything it serves.

Bumped to edge at Teams phase 3 (website#152), the first core with both
registerTeamProvider and the roster projection this module implements. The whole
job was reproduced locally against that core: core's own manifest is current at the
new pin, the module loads, and the difference is 73 routes, all documented.
routes.manifest.json is unchanged — the expected result for a client-only change.

Not bumped to the phase 4 core, deliberately: that is website#153 and is not merged
yet, and nothing here needs it. The second slot is a client-side declaration, and
the route manifest cannot see it.

## What & why The module half of Teams **phase 4 â€â€� Forum 5a**. Targets `edge` alongside the core work in **website#153** and the docs in **docs#157**. The mirror of the activity feed, one phase later. Core owns the Team forum â€â€� membership, manual grants and the member/guest split are all core's rules, and a module reimplementing any of them would be reimplementing a security boundary â€â€� but core publishes no Team page, because it does not own the word "guild". So this module declares the place and core puts the forum in it. **TWO declarations rather than one**, and that is the part worth reviewing. A slot holds one component and the first fill wins, so folding the forum into `uo.guild.detail` alongside the feed would hand core the decision about where each of its two contributions sits on a page this module owns. Separate slots also keep them independent: with the forum switched off, the feed renders exactly as before. The rule this establishes for the inverted slot direction â€â€� **one slot per PLACE, not one per page** â€â€� is written into `MODULE_API.md` §3.7a in the docs PR. ## How it was tested - `npm test` in `client/` â€â€� 42 pass. The registration test now asserts the SET of declared slots, and that **every** one of them is rendered by the page that owns it, rather than naming a single slot twice. A slot nothing renders is a slot core fills into the void. - `npm test` in `server/` â€â€� 428 pass, untouched by this change. - `npm run build` in `client/` â€â€� the prebuilt chunk is rebuilt and committed. ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [x] AI tools were used. Tool(s): `Claude Code`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it. ## One thing that is not phase 4: the core pin `frozen-manifest` has been **red since Teams phase 2**, on #11 as well as here, and the red was real. The pin (website#140) predates `api.registerTeamProvider`, which this module has called since phase 1 of its Teams work — so the module fails to LOAD in the pinned checkout, and a module that does not load adds no routes, which the job correctly reports as the module having removed everything it serves. Bumped to `edge` at Teams phase 3 (website#152), the first core with both `registerTeamProvider` and the roster projection this module implements. The whole job was reproduced locally against that core: core's own manifest is current at the new pin, the module loads, and the difference is 73 routes, all documented. `routes.manifest.json` is unchanged — the expected result for a client-only change. Not bumped to the phase 4 core, deliberately: that is website#153 and is not merged yet, and nothing here needs it. The second slot is a client-side declaration, and the route manifest cannot see it.
wtclaude added 1 commit 2026-08-18 12:26:18 +00:00
feat(guilds): declare a second place on the guild page, for core's forum
Some checks failed
PR Checks / client-build (pull_request) Successful in 14s
PR Checks / frozen-manifest (pull_request) Failing after 34s
PR Checks / server-tests (pull_request) Successful in 8m40s
9d0a197008
The mirror of the activity feed, one phase later. Core owns the Team forum —
membership, manual grants and the member/guest split are all core's rules, and a
module reimplementing any of them would be reimplementing a security boundary — but
core publishes no Team page, because it does not own the word "guild". So this
module declares the place and core puts the forum in it.

TWO declarations rather than one, and that is the interesting part. A slot holds one
component and the first fill wins, so folding the forum into `uo.guild.detail`
alongside the feed would hand core the decision about where each of its two
contributions sits on a page this module owns. Separate slots also keep them
independent: with the forum switched off, the feed renders exactly as before.

The registration test now asserts the set of declared slots and that EVERY one of
them is rendered by the page that owns it, rather than naming a single slot twice.
A slot nothing renders is a slot core fills into the void.

Co-Authored-By: Claude <noreply@anthropic.com>
wtclaude added 1 commit 2026-08-18 12:32:03 +00:00
ci(core-ref): bump the pin past registerTeamProvider
All checks were successful
PR Checks / client-build (pull_request) Successful in 15s
PR Checks / server-tests (pull_request) Successful in 19s
PR Checks / frozen-manifest (pull_request) Successful in 42s
46e3f5a127
`frozen-manifest` has been failing since Teams phase 2, on this PR and on #11
before it, for a reason that has nothing to do with either: the pinned core
(website#140, the module-system de-UO slice) predates `api.registerTeamProvider`,
which this module has called since phase 1 of its Teams work. The module therefore
fails to LOAD in the pinned checkout — "api.registerTeamProvider is not a function"
— and a module that does not load adds no routes, which the job correctly reports
as the module having removed everything it serves.

So the red was real and was pointing at the pin, exactly as the pin's own comment
says it should: core moves for reasons that have nothing to do with this module,
and a bump is a deliberate commit saying which core the module was last proved
against.

Bumped to `edge` at Teams phase 3 (website#152) — the first core that has both
`registerTeamProvider` and the roster projection this module now implements.
Reproduced the whole job locally against that core: core's own manifest is current
at the new pin, the module loads, and the difference is 73 routes, all documented.
`routes.manifest.json` is unchanged and needed no regeneration, which is the
expected result for a client-only change.

Not bumped to the phase 4 core, deliberately: that is website#153 and is not merged
yet. Nothing in this module needs it — the second slot is a client-side
declaration, invisible to the route manifest.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech merged commit 7ce78e303c into edge 2026-08-18 14:17:52 +00:00
whitlocktech deleted branch feature/teams-phase4-forum-slot 2026-08-18 14:17:53 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/Module-uo#12
No description provided.