fix(modules): a site runs one module; the installer refuses a second #204

Merged
whitlocktech merged 2 commits from fix/one-module-per-site into main 2026-09-26 22:28:59 +00:00
Member

The org lead's rule, settled 2026-09-23 during Rust phase 9: a site runs one module. Docs: MODULE_SYSTEM.md §2.5 and decision 35 (docs PR alongside).

Why now

Core allows one Team provider per deployment, and a second registration fails that module's whole load. The loader scans modules alphabetically. Rust phase 9 gives module-rust a Team provider, so installing it beside module-uo would take uo down, not rust.

What changed

  • install() refuses any install whose id differs from a module already on the volume. It answers 409, before the artifact is downloaded.
  • An upgrade of the installed module is still accepted. To change game, remove the module first.
  • The admin panel and the MODULES declaration share this path. A declaration naming two modules installs the first and reports the second as refused, and the boot does not fail.
  • "Installed" means what the loader would scan: a directory named with a module id that holds a module.json. Scratch and aside directories don't count.
  • A directory placed on the volume by hand is not policed. That stays the developer's escape hatch.
  • The OpenAPI spec is regenerated for the new 409 on POST /admin/modules.

Verified

  • 3 new tests in moduleInstall.test.js:
    • a different module is refused, and its artifact is never fetched;
    • an upgrade still works, and removing the module frees the site for another;
    • the "what counts as installed" rule holds.
  • moduleInstall, moduleDeclared and adminModules: 66/66 pass.
  • The full server suite: 2061 pass, 2 fail. The 2 are routeManifest, and they fail identically on a clean main in my checkout, because website/modules/ there holds locally installed modules that change the live route stack. CI has none.

AI disclosure

Written with Claude Code (Opus 5.5).

🤖 Generated with Claude Code

https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY

The org lead's rule, settled 2026-09-23 during Rust phase 9: **a site runs one module.** Docs: `MODULE_SYSTEM.md` §2.5 and decision 35 (docs PR alongside). ### Why now Core allows **one** Team provider per deployment, and a second registration fails that module's whole load. The loader scans modules alphabetically. Rust phase 9 gives module-rust a Team provider, so installing it beside module-uo would take **uo** down, not rust. ### What changed * `install()` refuses any install whose id differs from a module already on the volume. It answers **409**, before the artifact is downloaded. * An **upgrade** of the installed module is still accepted. To change game, remove the module first. * The admin panel and the `MODULES` declaration share this path. A declaration naming two modules installs the first and reports the second as refused, and the boot does not fail. * "Installed" means what the loader would scan: a directory named with a module id that holds a `module.json`. Scratch and aside directories don't count. * A directory placed on the volume by hand is not policed. That stays the developer's escape hatch. * The OpenAPI spec is regenerated for the new 409 on `POST /admin/modules`. ### Verified * 3 new tests in `moduleInstall.test.js`: * a different module is refused, and its artifact is never fetched; * an upgrade still works, and removing the module frees the site for another; * the "what counts as installed" rule holds. * `moduleInstall`, `moduleDeclared` and `adminModules`: 66/66 pass. * The full server suite: 2061 pass, 2 fail. The 2 are `routeManifest`, and they fail identically on a clean `main` in my checkout, because `website/modules/` there holds locally installed modules that change the live route stack. CI has none. ### AI disclosure Written with Claude Code (Opus 5.5). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 1 commit 2026-09-23 06:27:17 +00:00
fix(modules): a site runs one module; the installer refuses a second
All checks were successful
PR Checks / client-build (pull_request) Successful in 33s
PR Checks / bot-tests (pull_request) Successful in 34s
PR Checks / server-tests (pull_request) Successful in 13m28s
e4f088e90b
A site is one game, and the module contract already has singletons that
assume it. registerTeamProvider holds one value per deployment, and a
second module registering one fails that module's whole load. The loader
scans alphabetically, so installing module-rust (which gains a Team
provider in its phase 9) beside module-uo would have taken uo down, not
rust.

install() now refuses, with 409 and before the artifact is downloaded,
any install whose id differs from a module already on the volume. An
upgrade of the installed module is still accepted; to change game,
remove the module first. Both install surfaces share this path, so a
MODULES declaration naming two modules installs the first and reports
the second as refused without failing the boot.

"Installed" means what the loader would scan: a directory named with a
module id that holds a module.json. An install's scratch directory and a
swap's aside copy do not count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
whitlocktech approved these changes 2026-09-26 22:22:49 +00:00
whitlocktech added 1 commit 2026-09-26 22:23:03 +00:00
Merge branch 'main' into fix/one-module-per-site
All checks were successful
PR Checks / client-build (pull_request) Successful in 33s
PR Checks / bot-tests (pull_request) Successful in 32s
PR Checks / server-tests (pull_request) Successful in 5m47s
a169a463a5
whitlocktech scheduled this pull request to auto merge when all checks succeed 2026-09-26 22:23:14 +00:00
whitlocktech merged commit 1a76b98d76 into main 2026-09-26 22:28:59 +00:00
whitlocktech deleted branch fix/one-module-per-site 2026-09-26 22:29:00 +00:00
Sign in to join this conversation.
No description provided.