ADR-030: Documentation Hosting Strategy¶
Status¶
Accepted Date: 2026-04-05
Context¶
cosalette's documentation is built with Zensical and was previously deployed to GitHub
Pages on every push to main. The published documentation therefore always reflects
the development branch, not the latest release. Users following the official docs may
encounter features, APIs, or configuration options that have not yet been included in
any published package version.
A secondary problem: PR authors have no way to preview documentation changes before merging. Reviewing rendered MkDocs output from raw Markdown is error-prone, especially for navigation changes and content involving custom macros or diagrams.
Constraints¶
- cosalette releases are infrequent relative to
maincommits — the gap between what users run and what docs describe can be significant. - GitHub Pages supports only a single deployment per repository on free plans, ruling out branch-based multi-deployment strategies.
- The project already uses surge.sh for preview deployments in cosalette-apps — a proven pattern for ephemeral hosting.
Decision¶
Adopt a three-tier documentation hosting strategy:
| Tier | Host | URL | Updated When |
|---|---|---|---|
| PR Preview | surge.sh | cosalette-pr-{N}.surge.sh |
Every PR push; torn down on PR close |
| Main (dev) | surge.sh | cosalette-main.surge.sh |
Every push to main |
| Official (release) | GitHub Pages | ff-fab.github.io/cosalette/ |
Only on release-please releases |
1. PR Preview — surge.sh¶
A CI job deploys the built MkDocs site to cosalette-pr-{N}.surge.sh (where N is
the PR number) on every push to a pull request. A bot comment is created or updated on
the PR with the preview URL using peter-evans/find-comment@v3 and
peter-evans/create-or-update-comment@v4, maintaining a single comment per PR rather
than appending a new one on every push.
When the PR is closed or merged, a pull_request_target job tears down the deployment
by publishing a blank page to the same subdomain. pull_request_target is used for
teardown because it runs in the base-branch context where SURGE_TOKEN is available.
The teardown job never executes PR code — it only deploys a static empty directory
using the PR number extracted from the event context, eliminating the trusted-context
risk associated with pull_request workflows.
Fork PRs gracefully skip the preview deploy: SURGE_TOKEN is not exposed to fork
workflows, so the deploy step is skipped without failing the run.
2. Main (dev) — surge.sh¶
A CI job deploys to cosalette-main.surge.sh on every push to main. This provides
contributors and maintainers a stable link to current development documentation without
polluting the official URL.
3. Official (release) — GitHub Pages¶
The GitHub Pages deployment is decoupled from main pushes and triggered exclusively
by release-please release events. The official URL (ff-fab.github.io/cosalette/)
always reflects the latest published release, not the development branch.
Decision Drivers¶
- Users reading official docs must not encounter unreleased features
- PR authors need rendered doc previews before merge
- surge.sh is already used by cosalette-apps — reuse a proven pattern over introducing a new service
- GitHub Pages free tier permits only one deployment per repository
pull_request_targetteardown safely handles credential access without executing untrusted PR code
Considered Options¶
| Option | Description | Pros | Cons | Chosen |
|---|---|---|---|---|
| A: Three-tier (PR preview + dev + release gate) | PR preview on surge.sh, dev on surge.sh, release on Pages | Solves all three problems; proven pattern | Requires SURGE_TOKEN secret; three CI jobs |
Yes |
B: Status quo (single Pages deployment on main push) |
Single deployment updated on every main push |
Zero additional setup | Docs always ahead of releases; no PR preview | No |
| C: Versioned docs (mike / MkDocs-versioning) | Version switcher with full history | Proper version selector UI | Persistent hosted state required; significant tooling overhead | No |
| D: Two-tier only (no PR previews) | Release gate only, no per-PR preview | Simpler CI than Option A | PR authors cannot preview doc changes | No |
| E: Branch-based GitHub Pages | Multiple branches mapped to Pages paths | Pure GitHub, no third-party | Requires Pages Pro/Teams; not available on free plan | No |
Consequences¶
Positive¶
- The official URL always matches the latest published release — unreleased features are not surfaced to users following official docs
- PR authors receive a rendered preview URL as a bot comment on every push, eliminating the need to build docs locally before review
cosalette-main.surge.shprovides a stable dev-docs link for contributors without interfering with the official URL- Teardown on PR close avoids accumulating stale surge deployments over time
- Fork PRs are handled gracefully — no CI failure when
SURGE_TOKENis absent
Negative¶
SURGE_TOKENmust be configured as a repository secret; deployments on fork PRs are silently skipped- Three separate CI jobs (pr-preview, main-deploy, release-deploy) add marginal pipeline complexity compared to a single deploy job
- surge.sh is a third-party service dependency for two of the three tiers — an outage or pricing change would affect PR previews and dev docs (the official GitHub Pages tier is unaffected)
2026-04-05