Skip to content

MAF-20888: feat(website): serve the documentation site from docs.moreh.io - #179

Open
seongsu-dev wants to merge 10 commits into
mainfrom
MAF-20888-docs-domain-cutover
Open

MAF-20888: feat(website): serve the documentation site from docs.moreh.io#179
seongsu-dev wants to merge 10 commits into
mainfrom
MAF-20888-docs-domain-cutover

Conversation

@seongsu-dev

@seongsu-dev seongsu-dev commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Serve the MIF documentation site from its production domain, docs.moreh.io.

docs.moreh.io is served by the publish-build branch of moreh-dev/docs.moreh.io-published, and its content is a separate Retype-built site last updated 2026-03-25. The MIF Docusaurus documentation has been sitting on a temporary host, test-docs.moreh.io.

This PR points the MIF documentation deployment at publish-build directly. Neither the custom-domain binding nor the Pages configuration is touched, so no certificate is reissued and no GitHub settings change is required.

Warning

Merging this PR runs the deployment workflow immediately, which switches docs.moreh.io to the new site. The merge is the cutover.

Why this approach

Why not move the domain onto the test-docs.moreh.io repositorydocs.moreh.io responds with strict-transport-security: max-age=31556952 (one year). Moving the domain to another repository opens a window while GitHub reissues the certificate, and during it a browser that has seen the site shows an error the visitor cannot click through. GitHub does not guarantee how long that takes.

Why not repoint the Pages source at mainPUT /repos/.../pages requires admin on that repository, and the documentation maintainers hold push. That would gate both the cutover and every future rollback on reaching one of four repository admins. Publishing onto publish-build keeps both within push permission.

Changes

In this repository

File Change
.github/workflows/cd-docs.yaml Deployment target test-docs.moreh.iodocs.moreh.io-published, branch mainpublish-build. Adds workflow_dispatch for re-runs
website/static/CNAME test-docs.moreh.iodocs.moreh.io
website/docusaurus.config.ts Updates url, and adds @docusaurus/plugin-client-redirects with 15 redirects from the retired Retype paths
website/package.json, package-lock.json Adds the redirects plugin, pinned to the core version 3.10.0 — a range resolves to a newer patch and nests a duplicate @docusaurus/core under the plugin
skills/guide-heimdall/SKILL.md, skills/guide-odin/SKILL.md Updates the documentation host; the guide-odin table is padded to a fixed width and is realigned
docs/specs/2026-09-04-docs-domain-cutover.md The implementation plan and its observed results

Of the 21 non-root Retype paths, the 15 with a Docusaurus counterpart are redirected. The six without one — auto_scaling, context_length_aware_routing, expert_parallelism, load_aware_routing, resource_allocation, and the additional benchmarking page — will return 404. Migrating that content is out of scope.

Outside this repository — two state changes the diff cannot show

Neither lands in any git history, so they are recorded here.

Repository Change Reason Undo
moreh-dev/docs.moreh.io-published Created branch retype-archive at 837780c8 The deployment force-pushes over publish-build, so the site being served today is archived for rollback Delete the branch
moreh-dev/docs.moreh.io Disabled the retype-action-publish.yml workflow (disabled_manually) It force-pushes to publish-build whenever the publish branch is updated, which after the cutover would silently replace the live site with the Retype build gh workflow enable "Publish the final version to GitHub Pages" --repo moreh-dev/docs.moreh.io

retype-archive was checked for content, not just for the commit: it carries the Retype site and a CNAME of docs.moreh.io. Without that file a restore would bring the content back but drop the custom domain.

The sibling workflow retype-action-main.yml (the internal preview, mainmain-build) is deliberately left enabled. The internal Retype site is not part of this cutover.

main in moreh-dev/docs.moreh.io is 6 commits ahead of publish. Those 6 were never published to docs.moreh.io, so nothing that was live is lost by this cutover.

Manual steps remaining after merge

  1. Confirm the deployment succeeded and the live site responds, including the redirects.
  2. Delete the test-docs.moreh.io CNAME record in Cloudflare.
  3. Disable Pages on moreh-dev/test-docs.moreh.io and archive the repository.
  4. Update the test-docs.moreh.io links in moreh-dev/offline_installer (README.md, tools/moai-deploy.sh) and moreh-dev/moai-engine (.agents/skills/vllm-rocm-build/SKILL.md) — tracked separately.

The procedures are in Tasks 7 through 9 of docs/specs/2026-09-04-docs-domain-cutover.md.

Rollback

Situation Action Recovery time
The new site is broken after the cutover Force-push retype-archive back onto publish-build One Pages build; domain and certificate untouched
The deployment token cannot push to the new target Nothing to undo — the push is rejected, so publish-build and docs.moreh.io are unchanged. Fix the token scope and re-run Immediate

Every row is executable with push permission, and none waits on a certificate.

Testing

  • cd website && npm run build passes. onBrokenLinks is "throw", so a redirect destination that fails to resolve breaks the build rather than production.
  • All 15 redirects verified by reading the destination out of each emitted page and comparing it against the map: 0 mismatches. Each destination was also confirmed to be built.
  • build/CNAME reads docs.moreh.io; all 50 sitemap entries carry the new host and none carries the old one.
  • No file in the build output still mentions test-docs.moreh.io.
  • The redirect stubs stay out of sitemap.xml, which holds 50 entries.
  • The workflow YAML was parsed and its env block asserted — grep alone cannot catch an indentation slip in the on: block.
  • A repository-wide grep for test-docs.moreh.io returns nothing outside docs/specs/, where the document names the host it is retiring.

Whether MIF_DOCS_TOKEN can write to docs.moreh.io-published cannot be checked in advance, since its value is an organization secret. gitgod-bot holds admin on that repository; if the token's scope turns out to be too narrow the push is rejected, the workflow fails, and the live site is untouched.

seongsu-dev and others added 10 commits September 4, 2026 16:16
Record the implementation plan for serving the MIF Docusaurus site at
docs.moreh.io and retiring test-docs.moreh.io.

The plan retargets the docs deployment at moreh-dev/docs.moreh.io-published,
the repository that already owns the docs.moreh.io Pages custom domain, rather
than moving the domain onto moreh-dev/test-docs.moreh.io. The domain carries
HSTS with a one-year max-age, so releasing and re-binding it would open an
outage window that visitors cannot click through while GitHub reissues the
certificate. Retargeting leaves the binding untouched, makes removal of the
previous site implicit, and reduces rollback to a Pages source branch switch.

Client-side redirects cover the 15 Retype paths that have a Docusaurus
equivalent. Migrating the pages that exist only on the Retype site is out of
scope.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Steps 1 and 2 ran: gitgod-bot resolves to admin on docs.moreh.io-published,
matching its permission on the repository the docs already deploy to, and
MIF_DOCS_TOKEN is an organization secret exposed to moreh-dev/mif with
cd-docs.yaml as its only consumer in the organization.

Step 3 stays open because the token's type and repository allowlist are
readable only by an organization secrets administrator.

Executing the task showed the gate was drawn too wide. Task 6 Steps 1 to 3
push to the new target while its Pages source still points at publish-build,
so a rejected push fails the workflow without touching the live site and
answers the scope question for free. Move the gate to Task 6 Step 4, the
Pages source switch, which is the first irreversible action.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…saurus routes

docs.moreh.io is served today by a Retype site whose paths are snake_case and
carry no /docs/ prefix. Once this site takes over the domain, every existing
deep link would 404. GitHub Pages offers no server-side redirect, so emit the
redirects as static pages at build time.

Fifteen Retype paths have a Docusaurus equivalent and are mapped. Six have no
counterpart and will 404: /features/auto_scaling,
/features/context_length_aware_routing, /features/expert_parallelism,
/features/load_aware_routing, /best_practices/resource_allocation, and
/benchmarking/more_benchmarking_for_deepseek_r1_671b_on_amd_mi300x_gpus/
performance_with_prefix_cache_and_load_aware_routing.

The plugin is pinned to the core version rather than a caret range. A range
resolves to the newest 3.10.x while the lockfile holds the rest of the tree at
3.10.0, which makes npm nest a second copy of @docusaurus/core under the
plugin instead of sharing the host instance.

Verified: docusaurus build passes with onBrokenLinks set to throw, all 15
pages emit a refresh pointing at the mapped destination, every destination is
built, and the redirect pages stay out of sitemap.xml.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The install command as written used a caret range. npm resolved it to 3.10.2
while the lockfile held the rest of the tree at 3.10.0 and nested a duplicate
@docusaurus/core under the plugin, which breaks the shared-core contract a
Docusaurus plugin relies on. Replace it with a command that reads the core
version and installs that exact version, and add a step that fails on the
duplicate by checking the dedupe output and the lockfile diff size.

Replace the existence check in Step 5 with one that reads the target out of
each emitted page, compares it against the map, confirms the destination is
built, and asserts the entry count. Checking only that a file exists proves
the plugin ran, not that any redirect goes where it should. Add a step
confirming the redirect stubs stay out of sitemap.xml.

Also list package-lock.json in the file tables, which the commit step already
staged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…h.io

static/CNAME is copied into the build output and is what GitHub Pages reads
from the published branch to keep the custom domain bound, so it has to name
the domain the site will actually answer on. url drives canonical links,
Open Graph tags, and the sitemap.

Verified: docusaurus build passes, build/CNAME reads docs.moreh.io, all 50
sitemap entries carry the new host, and no file in the build output still
mentions test-docs.moreh.io.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lished

docusaurus deploy pushes the build output to the repository named by
PROJECT_NAME. Point it at moreh-dev/docs.moreh.io-published, which already
holds docs.moreh.io as its GitHub Pages custom domain, so the domain binding
and its certificate are never released during the cutover. DEPLOYMENT_BRANCH
was already main, which becomes that repository's Pages source.

Add workflow_dispatch so the deployment can be run and re-run on demand. The
workflow otherwise fires only on pushes touching website/**, which would force
an unrelated content commit to retry a failed cutover. The trigger becomes
available once this file is on the default branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both skills point readers at the published documentation as a fallback when
the local path is unavailable, so the host has to match where the site will
actually be served.

Realign the guide-odin reference table. Its columns are padded to a fixed
width and the new host is five characters shorter, which left every data row
short of the header rule.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 3 counted sitemap hits with grep -c, but sitemap.xml is emitted as a
single line, so that reports 1 regardless of how many entries carry the host.
Count occurrences and sweep the whole build output instead.

Task 4 verified the workflow with grep alone, which cannot see an indentation
slip in the on: block. Add a YAML load that prints the triggers and the deploy
env. Note that workflow_dispatch only becomes selectable once the file is on
the default branch, so the first deployment must come from the push trigger.

Task 5 expected a repository-wide grep for the old host to return nothing, but
this plan names that host throughout as its subject, so the check could never
pass. Exclude docs/specs and say why. Add a step for the fixed-width table in
guide-odin, which the five-character-shorter host leaves misaligned.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Deploy to publish-build rather than main. GitHub Pages serves docs.moreh.io
from docs.moreh.io-published on publish-build, so writing there makes the
deployment itself the cutover and removes the settings change entirely.

The reason is permission, not elegance. Repointing Pages at another branch
needs PUT /repos/.../pages, which requires admin on that repository, and the
docs maintainers hold push. Routing the cutover through a settings change
would make it, and every future rollback, wait on one of four repository
admins. Deploying onto publish-build keeps both within push permission.

Two protections that the other placement gave for free are bought back
beforehand: the Retype build that publish-build carried is archived to a
retype-archive branch so rollback stays a single force-push, and the Retype
publish workflow in moreh-dev/docs.moreh.io is disabled so it can no longer
force-push over the live site.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Record the choice between the two placements for the build inside the chosen
approach, and why the second wins: repointing the Pages source needs admin on
docs.moreh.io-published, which the docs maintainers do not hold, so it would
gate both the cutover and every rollback on someone else's availability.

Restructure the two tasks that change as a result. Task 6 becomes the
preparation the new placement requires — archive the served branch, prove the
archive holds the site and its CNAME, disable the Retype publish workflow —
and its first three steps are done. Task 7 becomes the cutover, which is now
the merge itself, and verifies that the Pages configuration and certificate
were never touched.

Rewrite the rollback table: every row is now executable with push permission
and none waits on a certificate. Task 1 Step 3 loses its gate, since a token
too narrow to write to the target now yields a red workflow over an unchanged
site.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 4, 2026 09:23
@seongsu-dev
seongsu-dev requested a review from a team as a code owner September 4, 2026 09:23

Copilot AI 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.

🔵 Needs a closer look

Merging triggers an immediate production domain cutover via a cross-repository Pages publish, which warrants final human verification of the live deployment/redirect behavior and rollback readiness.

Pull request overview

This PR switches the MIF Docusaurus documentation site to be served from the production domain docs.moreh.io by retargeting the deployment to the existing Pages-served branch (publish-build) of moreh-dev/docs.moreh.io-published, and adds client-side redirects for key legacy Retype paths to preserve deep links.

Changes:

  • Retarget docs deployment workflow to push to moreh-dev/docs.moreh.io-published on publish-build, and add workflow_dispatch for manual reruns.
  • Update the published site’s custom domain (website/static/CNAME) and Docusaurus url to https://docs.moreh.io/.
  • Add @docusaurus/plugin-client-redirects and configure redirects for legacy Retype routes; update skill references and add a detailed cutover runbook/spec.
File summaries
File Description
.github/workflows/cd-docs.yaml Deploys docs to docs.moreh.io-published / publish-build and adds manual trigger.
website/static/CNAME Updates GitHub Pages custom domain to docs.moreh.io.
website/docusaurus.config.ts Updates canonical site URL and adds Retype→Docusaurus redirect map via client-redirects plugin.
website/package.json Adds @docusaurus/plugin-client-redirects dependency.
website/package-lock.json Locks the added redirect plugin at the resolved version.
skills/guide-heimdall/SKILL.md Updates documentation URLs from test-docs.moreh.io to docs.moreh.io.
skills/guide-odin/SKILL.md Updates documentation URLs from test-docs.moreh.io to docs.moreh.io.
docs/specs/2026-09-04-docs-domain-cutover.md Adds the cutover implementation plan, verification steps, and rollback procedure.
Review details

Files not reviewed (1)

  • website/package-lock.json: Generated file
  • Files reviewed: 7/8 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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.

3 participants