Skip to content

ci: dual-publish docs to github pages and vercel - #194

Merged
armcconnell merged 8 commits into
mainfrom
chore/dual-publish-docs
Aug 10, 2026
Merged

ci: dual-publish docs to github pages and vercel#194
armcconnell merged 8 commits into
mainfrom
chore/dual-publish-docs

Conversation

@armcconnell

@armcconnell armcconnell commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Serves the docs at docs.doublezero.xyz (Vercel, new canonical) while docs.malbeclabs.com keeps running on GitHub Pages unchanged.

Design and plan: PR #193 (.specs/2026-08-10-docs-dual-publish-*.md).

Why a second origin

GitHub Pages allows one custom domain and matches it against the incoming Host header, so a second hostname can't just be another DNS record pointing at malbeclabs.github.io — GitHub would 404. Adding Vercel as a real second origin is the only option needing no cutover, so the existing hostname has zero downtime.

Summary

  • One mkdocs build feeds both deploys via the same tar artifact, so byte-identical output across origins is provable rather than aspirational.
  • site_url moves to docs.doublezero.xyz, consolidating canonical tags, sitemap.xml, robots.txt, and .well-known on the future hostname even for pages served from the legacy one.
  • site_name changes to DoubleZero. Note this is a single shared build, so the header and <title> change on both origins.
  • 26 absolute docs.malbeclabs.com cross-links converted to relative mkdocs links across 17 files and 8 locales. Five links in the same tenant table were already relative, so the absolute ones were the inconsistency.
  • --strict added, so broken internal links now fail CI.
  • Fork PRs skip the Vercel job because they can't receive secrets; they still get the build as validation. pull_request_target deliberately not used — it would expose the Vercel token to untrusted PR code.
  • docs/CNAME unchanged. Pages keeps docs.malbeclabs.com.

Incidental: untracked site/ (was gitignored but still tracked, so any local build dirtied 190+ files); dropped contents: write and the git-credentials step, since Pages is build_type=workflow and deploy-pages never pushes a branch.

Current state

docs.doublezero.xyz is live and serving. docs.malbeclabs.com still serves its own build with no redirect. Merging converges them.

Testing Verification

Verified against a live Vercel deployment before CI was wired, to settle assumptions rather than trust them:

  • .well-known/ dot-directory is served at the edge (index.json, SKILL.md, mcp/server-card.json all 200). This was the main risk: actions/upload-artifact drops hidden files by default, which is why both deploys route through a tar.
  • Missing paths return a real 404 with the styled MkDocs page, not a 200 or a bare Vercel error.
  • All 8 locales serve on both the new origin and in-build.
  • Deployed .well-known SHA-256 matches the local build, confirming the edge serves the same bytes.
  • /setup and /setup/ share the identical canonical, so trailing-slash variants consolidate instead of duplicating.
  • Link conversion checked per locale: relative hrefs stay inside their locale prefix (../DZ%20Mainnet-beta%20Connection/ from /es/tenant//es/…), and every localized target exists.
  • Angle-bracket link destinations chosen empirically — percent-encoded %20 wasn't assumed to survive mkdocs' file lookup, so one link was converted and its rendered href inspected before the other 25.
  • Build diff asserted programmatically as exactly the expected 35 files.
  • Let's Encrypt cert valid, Cloudflare grey cloud confirmed (resolves to Vercel IPs, not proxy IPs).
  • docs.malbeclabs.com confirmed returning 200 with an empty redirect target throughout.

translate.yml pushed 4921f21 (21 localized files, 1459 insertions). Confirmed it did not clobber the link conversion: no absolute links returned, all 14 localized tenant/troubleshooting files kept their relative destinations, and --strict still passes.

After merge

Digest parity across origins currently differs by design, since main still serves the old build. Post-merge, sitemap.xml and .well-known/* should match byte for byte; llms.txt embeds site_name as its H1 so it matches too under this shared build. Needs verifying once merged.

armcconnell and others added 7 commits August 10, 2026 16:36
The tenant table and troubleshooting pages hardcoded
https://docs.malbeclabs.com for 26 cross-links, while the other five
links in the same tenant table were already relative. Relative links
resolve on whichever hostname served the page and are validated by
mkdocs at build time.

Angle-bracket destinations are used because the target filenames contain
spaces; percent-encoding is not reliably decoded before mkdocs' file
lookup.
Canonical tags, sitemap.xml, robots.txt, and the .well-known agent
discovery files now point at docs.doublezero.xyz. A single build carries
a single site_url, so pages served from docs.malbeclabs.com will carry
the new canonical and stop competing for indexing.

docs/CNAME is deliberately unchanged: GitHub Pages keeps serving
docs.malbeclabs.com.
Converts the same tar that GitHub Pages receives into a Build Output API
v3 directory, so both origins serve byte-identical content. Extracts with
tar rather than cp because the .well-known dot-directory is silently
skipped by shell globs and some copy tools.

.gitignore additions for .vercel and .env* come from `vercel link`.
site/ was already listed in .gitignore but remained tracked from before
that rule existed, so any local `mkdocs build` overwrote 190+ tracked
files and dirtied the repo. The directory is generated on every build and
deployed from CI, so it does not belong in version control.

Files remain on disk; only tracking is removed.
Split the single build-and-deploy job so one mkdocs build feeds two
deploy targets. Both consume the same tar artifact, which is what makes
byte-identical output across the two origins provable rather than
aspirational, and sidesteps upload-artifact dropping hidden files.

GitHub Pages deploys on push to main exactly as before. Vercel deploys
production on main and a preview on same-repo pull requests. Fork PRs
skip the Vercel job because they cannot receive secrets; they still get
the build as validation. pull_request_target is deliberately not used.

Adds --strict so broken internal links fail CI, verified adoptable
against a warning-free baseline. Drops contents:write and the git
credentials step: Pages is configured with build_type=workflow, so
deploy-pages uploads an artifact and never pushes a branch.
@armcconnell
armcconnell marked this pull request as ready for review August 10, 2026 22:55
@armcconnell

Copy link
Copy Markdown
Contributor Author

Ready to merge: docs.doublezero.xyz is live

The sequencing hazard that kept this in draft is cleared. docs.doublezero.xyz now resolves and serves the site, so merging no longer risks pointing canonical tags at a dead hostname.

Verified on the live new origin:

  • Root 200, missing paths return a genuine 404 with the styled MkDocs page
  • All 8 locales serving (/, /es/, /fr/, /it/, /ja/, /ko/, /pt/, /zh/)
  • All machine endpoints serving: .well-known/agent-skills/index.json, .well-known/mcp/server-card.json, llms.txt, llms-full.txt, sitemap.xml, robots.txt
  • Let's Encrypt certificate valid through Nov 8, Cloudflare grey cloud confirmed (resolves to Vercel IPs, not proxy IPs)

Verified the legacy origin is untouched:

  • docs.malbeclabs.com returns 200 with an empty redirect target, so it serves its own content rather than redirecting
  • docs/CNAME still reads docs.malbeclabs.com

Note on the auto-translate commit

translate.yml fired on this PR and pushed 4921f21, rewriting 21 localized files (1459 insertions). Checked specifically whether it clobbered the relative-link conversion, since that was the plausible failure mode:

  • No absolute docs.malbeclabs.com links reappeared
  • All 7 localized tenant files kept ](<DZ Mainnet-beta Connection.md>) and ](<DZ Testnet Connection.md>)
  • All 7 localized troubleshooting files kept ](<setup.md>)
  • mkdocs build --strict still exits 0 on the merged result

Its CI runs initially landed as action_required because github-actions[bot] triggered them; approved, and both are green on 4921f21.

Remaining after merge

Digest parity between the two origins currently differs, which is expected while main still serves the old build. Once this merges, both origins should serve byte-identical content for .well-known/agent-skills/index.json, llms.txt, and sitemap.xml. I'll run that check post-merge.

@Jared-dz
Jared-dz self-requested a review August 10, 2026 23:37

@Jared-dz Jared-dz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is certainly a PR.

@armcconnell
armcconnell merged commit 125e4a6 into main Aug 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants