Accepted
ADR 0035 — Public base URL is a setting
The canonical public origin is a versioned setting captured by the first-run wizard and editable in admin settings, not a deploy-time variable
Decision
The public base URL — the canonical origin Cusp uses to build absolute links for sitemaps, RSS feeds, OpenGraph tags, the admin's view-live links, and password-reset emails — is a versioned setting. The first-run wizard captures it and admin settings edits it.
The resolver has one source: the site.public_base_url setting. When it is unset the resolver returns null, and callers handle null on their own terms — the sitemap and feed generators skip generation rather than emit relative URLs, OpenGraph falls back to relative, and a password-reset email is dropped rather than sent with a placeholder link, logging a warning and recording the missing-origin state for the admin health surface.
Why it is a setting, not a variable
A deploy-time variable defaults to empty, so a fresh one-click deploy would carry an empty canonical origin for the lifetime of the deployment unless the deployer edited the config and redeployed. Editor-first means editors never edit a Wrangler variable — switching to a custom domain should be edit the setting and save, not redeploy.
Wizard capture and live editing
The setup wizard prefills the value from the origin the editor is currently using to reach the wizard, which is the canonical origin in the overwhelming common case — a one-click deploy lands the editor on a workers.dev URL, and a custom-domain deployer reaches the wizard on the custom domain. An advanced disclosure lets the editor edit the prefilled value before submitting, validated as an http or https URL.
The setting is editable later from admin settings through the typed-settings path. Saving a new value fires a one-shot sitemap and feed regeneration and purges the settings and navigation surrogate keys site-wide, so the canonical origin propagates without waiting for the next publish. Because it is on the versioned-write path like every other site setting, site-wide time travel reconstructs the canonical origin at any historical timestamp.
Two canonical origins, on purpose
The setting is the content canonical origin. The security canonical origin is the per-request host, and the two stay independent. Preview-token domain-locking binds a token to the request hostname at issuance and compares against the request hostname at validation; it does not read the setting. A multi-host deployment mid-migration can point the setting at its preferred host for content URLs while still issuing per-host preview links that work only at the host the editor was on when they generated them.
Consequences
- Editors set the canonical origin in the wizard with a sensible prefill and never open the Wrangler config; moving to a custom domain is a setting edit, not a redeploy.
- The setting is versioned, so historical canonical origins reconstruct under time travel; the data model collapses to one source for content URLs and one source for security boundaries.
- A deployment whose wizard was never completed has a null canonical origin, so the sitemap and feeds are not generated and OpenGraph loses absolute URLs in that window — but the wizard gates everything past setup, so the window is bounded, and an unconfigured forgotten-password attempt is a no-op rather than an email carrying a placeholder URL.
- Considered and rejected: deriving the origin from the Host header (couples canonical-URL truth to an attacker-controlled header), a setting-plus-allowlist hybrid (two configurations and more failure modes for little gain), and keeping a deploy-time variable as a fallback (a variable change needs a redeploy — the failure mode this decision removes).