Files
website/client/test
wtclaude 1433b60d6c
All checks were successful
PR Checks / bot-install (pull_request) Successful in 17s
PR Checks / client-build (pull_request) Successful in 23s
PR Checks / server-tests (pull_request) Successful in 8m59s
feat(modules): PublicLayout takes a shell, MODULE_API_VERSION 1.5.0
The Integration Kit's acceptance run (Phase 5 slice 3) put a cold agent in front
of the kit alone and asked it to build a module for a second game. It built one
that works — and its page rendered outside the site.

PublicLayout supplies the chrome and not the body. Every core public page wraps
its own content in `<div className="shell-... page-body">`: the centred column,
the top and bottom padding, and — through `page-body { flex: 1 }` — the thing
that pushes the footer to the bottom of the viewport. Nine of nine core pages do
it, so the omission has never shown. A module cannot do it: it receives
PublicLayout through the UI kit and those two class names appear in no contract.
The result was a page at x=0 with the footer riding up under the content, which
is the exact failure MODULE_API.md §3.4 says the kit exists to prevent.

So the wrapper moves behind the component a module already has:

  <PublicLayout shell="narrow">   // or "mid" / "wide"

`shell` is opt-in and omitting it is 1.4.0's behaviour exactly, so core's nine
pages are untouched and keep their own wrapper. An unrecognised width falls back
to narrow rather than to nothing — a module page at the wrong width still looks
like the site; a page with no wrapper does not.

1.5.0 is minor, not major. §3.4 makes *changing* a kit component's props major
because that breaks a call already written; adding an optional one breaks
nothing. module-uo's `coreApi: "^1.3.0"` still resolves.

The width map and its fallback live in client/src/lib/pageShell.js rather than in
the component, for the reason lib/adminNav.js does: the client runner has no DOM
and cannot import .jsx at all, so a rule inside a component is a rule no test can
reach. Five tests cover it, including that every width it offers is a class
theme.css actually defines — the contract now names those widths to module
authors, so a rename has to fail here instead of silently in someone's page.

Also from the same run: modules/shared.js called the UI kit "seven" members while
exporting eight (§3.4's table has five rows because PageState contributes three),
and its note said AdminPage "appears in §3.4's table" when the table dropped it in
Phase 2 PR 7.

742 server + 192 client tests pass (+5). routes.manifest.json and the OpenAPI
spec regenerate byte-identical — no route changed.

Verified in a browser against the acceptance module (MODULE_API.md §7.7), which
is the only place this seam is visible: the untouched build renders full-bleed,
and shell="narrow" lands the page in the same column as core's own.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-12 14:23:26 -05:00
..