Accepted

ADR 0056 — Themed 404 fallback via the page template

A theme without a dedicated 404 template renders not-found pages through its own page template, not the bundled default

The public render handler returns a 404 for any path that does not resolve to a published document or route. Before this decision, a theme could override the 404 by shipping a templates/404.js, but if it did not, the not-found page fell back to the bundled default theme's template — styled only with the active theme's design tokens. For a heavily-customised theme (the first-party Almanac is a good example: serif type, parchment ground, a monogram logo) the token overlay was not enough: the 404 still rendered the default theme's markup and chrome, so it read as a different website. None of the four first-party themes ship a 404 template, so every themed deployment hit this seam.

Decision

renderNotFound resolves a theme for the 404 in three ordered steps. First, the active theme's dedicated templates/404.js, if it ships one. Second — and this is the new step — the active theme's templates/page.js, invoked with a synthetic 'Page not found' document, so the not-found page is rendered inside the theme's full header / nav / footer chrome. Third, the bundled default template, used only when there is no active theme (or both themed paths throw), still rendered in the active theme's tokens.

The synthetic document is deliberately minimal: a title of 'Page not found' and one or two core/paragraph blocks (the path hint is shown only for a real sub-path, never for the bare site root, matching the bundled template). It carries no fielded data and an empty slug, so a content-type-aware theme falls through to its generic prose layout rather than a recipe or event treatment. It uses no link marks — the theme's own navigation already supplies the way home — so the fallback does not depend on any theme's inline-link rendering.

Consequences

Every theme, current and future, gets a themed 404 with zero per-theme work and without re-signing any theme bundle. A theme that wants a bespoke 404 (custom copy, illustration, search box) still ships templates/404.js and takes precedence. The enumeration defence from ADR 0016 is preserved: all not-found kinds (including preview-token failures) produce the same synthetic-document render, so the response shape never reveals which kind of 'not found' the request hit. If a theme's page template throws on the synthetic document, the handler degrades to the bundled template rather than 5xx-ing. The HTTP 404 status is unchanged — it is set by the caller, independent of which template rendered the body.

Trade-off accepted: a theme-supplied page template renders the not-found body, so the 404's layout matches that theme's single-document view. A theme whose page template assumes a richer document than the synthetic one will still render (fields render only when present), but its 404 may look plainer than a hand-built one — which is the cue for that theme to ship templates/404.js.