THROWAWAY BRANCH — evidence for the Phase 1 contract, never merged. See
modules/uo/SPIKE.md and docs/website/MODULE_API.md Part 7.
The six public spawn-atlas routes now live in modules/uo/, reached only through
the ctx/register surface, with the client half loading as a prebuilt ESM chunk.
All three exit criteria met:
• zero internal-file imports from the module into core; the built chunk has
zero bare import specifiers and bundles no React
• routes.manifest.json AND routes.guards.json are byte-identical
• /uo/atlas renders from /modules/uo/entry.js under script-src 'self' with
zero CSP violation reports
729 core tests and 81 module tests pass. Verified end to end against the real
database: the schema fragment replays after core's, onBoot runs the atlas
refresh, and the six API URLs answer unchanged.
Two things the spike changed in the contract:
• ctx.express / ctx.validator. A module lives outside server/, so Node never
reaches server/node_modules and require('express') fails outright — the
server-side twin of the one-React rule, which §2.6 had only for the client.
• window.__rg.jsxRuntime, so a module can build with the automatic JSX
runtime its tooling already assumes rather than being forced to classic.
And it confirmed §6.1 empirically: regenerating the OpenAPI spec silently
deleted all 361 lines of the atlas paths with "Swagger-autogen: Success", while
the route manifest kept all six in the same run. That is exactly the
static-analysis-vs-runtime split the fragment merge exists to prevent.
Co-Authored-By: Claude <noreply@anthropic.com>
2.5 KiB
module-uo — the Phase 1 spike
This branch is evidence, not implementation. spike/module-atlas is cut from edge and is
never merged. Phase 2 rebuilds the loader properly, with the installed_modules table, the full
state machine and the admin panel behind it; Phase 3 does the real extraction.
What it demonstrates, and the results, are written up in
docs/website/MODULE_API.md Part 7. In one line: the six
public spawn-atlas routes now live in a module, at byte-identical URLs, with the client half loading
as a prebuilt ESM chunk under script-src 'self'.
Reproducing it
# 1. build the module's client chunk (its CI would do this and ship the result)
cd modules/uo/client && npm install && npm run build # → dist/entry.js
# 2. build core's client
cd ../../../client && npm install && npm run build
# 3. run the server against the local MariaDB
cd ../server && npm start
Then:
/uo/atlasand/uo/atlas/lizardmanrender from the module's chunk.GET /api/v1/public/atlas/*answers exactly as before —npm run routes:manifest -- --checkreports the surface unchanged.npm testinserver/(core, 729) andnode --testinmodules/uo/server/(module, 81).
dist/entry.js is committed here only because this branch is the evidence for a design
decision and a reviewer should be able to inspect the built artifact without a toolchain. A real
module publishes it from CI into its release bundle and never commits it.
What in here is not design
Three things are consequences of stopping at six routes, spelled out in MODULE_API.md §7.5:
- Core reaches into this module twice —
server/src/router/v1/admin/shardAtlas.controller.jsandserver/test/atlasController.test.js. The five admin atlas routes sit inside the/shardadmin prefix core still owns, so they cannot move until the whole prefix does. server/utils/visibility.jsis a copy of core'sutils/shardVisibility.js, which core still needs for the shard routes not yet extracted. Two caches over one table, briefly.- There is no
swagger-fragment.json— it needs core's merge helper on the other side, which is Phase 2.
Also note the table names here are shard_*, not uo_*. That is deliberate and grandfathered by an
allowlist in the loader: renaming twenty-seven live tables is a data migration this workstream does
not do. Every module written after this one carries its id as a table prefix.