Merge pull request 'docs(website): record the edge branch strategy and the Module-uo repo' (#123) from docs/module-system-edge into main

Reviewed-on: #123
This commit is contained in:
2026-08-10 07:32:55 +00:00

View File

@@ -291,12 +291,17 @@ than by review.
### 2.3 Module packaging — one repo, one bundle ### 2.3 Module packaging — one repo, one bundle
`RunicGateway/module-uo`, GPL-3.0-or-later, CI shaped like the other repos. Server and client halves **`RunicGateway/Module-uo`** — `https://gitea.whitlocktech.com/RunicGateway/Module-uo.git`, note the
live side by side and version together, so a route and the screen that calls it can never be capital `M`, matching `Android-app`'s casing rather than the lowercase directory name. The repo
mismatched: exists but is **empty** as of 2026-08-10: no branches, no initial commit. Its first commit needs the
usual scaffolding — `README.md`, `LICENSE.md` (GPL-3.0-or-later), `CONTRIBUTING.md` with the
AI-disclosure clause, the PR template, and CI.
Server and client halves live side by side and version together, so a route and the screen that
calls it can never be mismatched:
``` ```
RunicGateway/module-uo RunicGateway/Module-uo
module.json id, version, coreApi range, mounts, extensions module.json id, version, coreApi range, mounts, extensions
server/ routers, controllers, models, utils server/ routers, controllers, models, utils
server/db/schema.sql fragment replayed by ensureSchema() server/db/schema.sql fragment replayed by ensureSchema()
@@ -307,6 +312,10 @@ RunicGateway/module-uo
Release artifact: `module-uo-<version>.tar.gz` plus a manifest carrying its `sha256`. Release artifact: `module-uo-<version>.tar.gz` plus a manifest carrying its `sha256`.
The module's **id** is `uo` — that is what appears in `module.json`, in `installed_modules`, in the
`modules/<id>/` path and in the URL segment. `Module-uo` is the repository; `module-uo` elsewhere in
this document names the module and its artifact, not the repo.
`module.json` declares a `coreApi` semver range, checked at boot against a `MODULE_API_VERSION` `module.json` declares a `coreApi` semver range, checked at boot against a `MODULE_API_VERSION`
constant in core; a mismatch fails **loudly** rather than silently. This is a separate number from constant in core; a mismatch fails **loudly** rather than silently. This is a separate number from
`PROTOCOL_VERSION`, which versions the shard wire and says nothing about a website module. `PROTOCOL_VERSION`, which versions the shard wire and says nothing about a website module.
@@ -364,6 +373,10 @@ Phase 1 prototypes exactly this before anything is committed to it (§2.7).
### 2.7 Phases ### 2.7 Phases
**Phase 0 — unblock CI and scaffold the repo.** Land the one-line `pr-checks.yml` trigger fix on
`website` `main` (§2.9), cut `edge` from `main`, and give `Module-uo` its initial commit (§2.3).
Nothing else can be trusted until the first of these is done.
**Phase 1 — API contract + spike (blocking).** Merge this document. Write the contract at **Phase 1 — API contract + spike (blocking).** Merge this document. Write the contract at
`docs/website/MODULE_API.md`. Then a throwaway spike on an unmerged branch moving `docs/website/MODULE_API.md`. Then a throwaway spike on an unmerged branch moving
**`/api/v1/public/atlas/*`** behind the proposed surface — the smallest honest test: five routes, **`/api/v1/public/atlas/*`** behind the proposed surface — the smallest honest test: five routes,
@@ -439,7 +452,37 @@ Two consequences, both accepted:
separate Android module plan. App Links verification itself is unaffected — the manifest's intent separate Android module plan. App Links verification itself is unaffected — the manifest's intent
filters only cover `/mobile/callback` and `auth/callback`. filters only cover `/mobile/callback` and `auth/callback`.
### 2.9 Process obligations ### 2.9 Branch strategy — `edge`, then one cutover
All website work lands on an **`edge`** branch and reaches `main` as a single cutover at the end,
the same shape used for [protocol v3](../link/v3.md) and the Android theming workstream. Nothing
half-extracted is ever on `main`: a core that has grown a module loader but not yet lost its UO code
is a coherent state, and a core mid-extraction is not.
`edge` does not exist on `website` today — the protocol v3 cutover landed and the branch was cleaned
up, so it is cut fresh from `main`. `Module-uo` develops on its own `main` from its first commit;
it has no cutover to perform, since nothing depends on it until the website cutover lands.
**Phase 0, and it blocks everything: the CI trigger.** `website/.gitea/workflows/pr-checks.yml`
declares:
```yaml
on:
pull_request:
branches: [main]
```
So a PR into `edge` runs **no checks at all** — no server tests, no client build, no bot install.
This is the same trap that let all nine Android M12 phase PRs merge with zero CI. It matters more
here than it did there, because Phase 2's exit criterion *is* a CI result: a zero-line
`routes.manifest.json` diff and a passing test suite. Running the whole workstream blind and
discovering the breakage at cutover is the expensive version of this.
The fix is one line — `branches: [main, edge]` — and it must land on `website` `main` **before** the
first module PR, not alongside it. `build-images.yml` is untouched: it triggers on push to `main`, so
images are published and production rolls at the cutover and at no point before it, which is correct.
### 2.10 Process obligations
Every server-side PR runs `npm run swagger`, `npm run routes:manifest` (the diff is reviewed, not Every server-side PR runs `npm run swagger`, `npm run routes:manifest` (the diff is reviewed, not
merely regenerated) and `npm test`, and carries a matching edit to `BACKEND_DESIGN.md`. Module merely regenerated) and `npm test`, and carries a matching edit to `BACKEND_DESIGN.md`. Module
@@ -462,3 +505,5 @@ Conventional Commits, the AI-disclosure trailer, branches cut from an up-to-date
| 8 | SPA pages namespaced: `/uo/*`, `/admin/uo/*`, `/player/uo/*` | §2.8 | | 8 | SPA pages namespaced: `/uo/*`, `/admin/uo/*`, `/player/uo/*` | §2.8 |
| 9 | Clean break — no redirects, no nav-override migration; site is not public yet | §2.8 | | 9 | Clean break — no redirects, no nav-override migration; site is not public yet | §2.8 |
| 10 | Client half loads as a prebuilt ESM chunk with React shared via a core global | §2.6 | | 10 | Client half loads as a prebuilt ESM chunk with React shared via a core global | §2.6 |
| 11 | Website work lands on `edge` and reaches `main` as one cutover at the end | §2.9 |
| 12 | The module repo is `RunicGateway/Module-uo`; the module id is `uo` | §2.3 |