Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ permissions:
id-token: write

concurrency:
group: pages-${{ github.event_name }}-${{ github.ref }}
group: pages-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
Expand Down Expand Up @@ -99,9 +99,8 @@ jobs:
retention-days: 30

deploy:
# Keep production deployment manual until the Astro cutover is complete.
# Pushes and pull requests still build and validate the full Pages artifact.
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main'
# Publish validated main updates; pull requests only build and check.
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
concurrency:
group: pages-production
cancel-in-progress: false
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/workers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ jobs:
if: inputs.operation == 'deploy' && inputs.environment == 'production' && (inputs.worker == 'both' || inputs.worker == 'redirects')
run: npx wrangler deploy --env production --config workers/redirects/wrangler.jsonc

- name: Preserve origin fallback for production redirects
if: inputs.operation == 'deploy' && inputs.environment == 'production' && (inputs.worker == 'both' || inputs.worker == 'redirects')
run: node scripts/set-redirects-fail-open.mjs

- name: Deploy email Worker to production
if: inputs.operation == 'deploy' && inputs.environment == 'production' && inputs.worker == 'email'
run: npx wrangler deploy --config workers/email/wrangler.jsonc
Expand Down
49 changes: 34 additions & 15 deletions docs/deployment-runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ small Pages fallback files.
As checked on 5 September 2026, Cloudflare is authoritative for `gecode.dev`.
Cloudflare proxies the apex GitHub Pages A records and the `www` CNAME to
`gecode.github.io` with Full (strict) TLS and Always Use HTTPS. GitHub Pages
still serves the active website. All nine historical documentation versions
and both latest aliases now use R2. Astro has not been deployed.
serves the Astro active website and mail archive. All nine historical
documentation versions and both latest aliases use R2. Classic active-site
URLs redirect to their canonical directory URLs through the redirect Worker.

Cloudflare Email Routing is ready. Its managed MX, SPF, and DKIM records are
authoritative, both forwarding destinations are verified, and the catch-all
Expand All @@ -39,41 +40,54 @@ records the local fixes, rollback build, verification limits and remaining
work. Phases 2–4 below describe the original migration sequence; DNS delegation
and infrastructure setup are largely complete. Staging deployment through
GitHub and clean-checkout website CI pass. The website migration is merged
in PR #7, with follow-up fixes in PRs #8 and #9; Pages remains manual.
in PR #7, with follow-up fixes in PRs #8 and #9.
Production deployment and canary cleanup passed. The final checks completed
on 5 September at about 14:15 UTC. Continue with the one-day documentation
soak; do not deploy Astro before 6 September, 16:30 Europe/Stockholm.
on 5 September at about 14:15 UTC. The cutover gate is a fresh passing production smoke check, a review of
Worker errors, passing website CI and a verified rollback archive. A fixed
24-hour wait is not required; the owner approved proceeding on this basis.

Astro deployment [33972798507](https://github.com/Gecode/gecode.github.io/actions/runs/33972798507)
and redirect deployment [33973076305](https://github.com/Gecode/gecode.github.io/actions/runs/33973076305)
succeeded on 5 September. All 23 canonical pages and classic redirects pass
live checks, including query preservation. Archive search and thread reading
work at mobile width; documentation smoke checks still pass. Redirect Worker version `1165ee03-782b-4f83-a687-0164a68d3087` is live. All twelve
redirect routes fail open to Pages fallbacks; both documentation routes remain
fail closed. The production redirect workflow sets and verifies this route
setting on every deployment with `scripts/set-redirects-fail-open.mjs`.
The pre-cutover Worker query reported 1,116 requests and zero
execution errors from 14:10 to 14:45:53 UTC.

## Cutover overview

Keep each traffic change separate. Finish the preparation and bulk transfer
without changing production, move DNS while GitHub Pages still serves the
entire old site, move documentation, and publish Astro only after the
documentation path has soaked.
documentation health checks pass and rollback is ready.

| Phase | When | Mostly unattended work | Attended checkpoint | Safe state afterward |
| --- | --- | --- | --- | --- |
| 1. Land deployment code | Now | Run CI on a pull request; build the Pages artifact without deploying it. | Review and merge the Worker, publication-tool, runbook, and manual-only Pages workflow changes. | The public site is unchanged. |
| 2. Prepare Cloudflare and GitHub | After phase 1; no maintenance window required | Create the pending zone, bucket, lifecycle rule, environments, and secrets. | Verify the Email Routing destinations and prepare the disabled routing Worker. | The public site is unchanged; Cloudflare has no traffic. |
| 3. Copy documentation | After the R2 token exists; run overnight if useful | Upload and verify 6.4.0, then all historical immutable versions. | Review the manifests and representative files before DNS delegation. | GitHub Pages still serves production; R2 holds a verified copy. |
| 4. Delegate DNS | In a short attended window after phases 2 and 3 | Wait for nameserver propagation and the Cloudflare zone to become active. | Test the website, TLS, apex redirect, and every mail alias. Restore the Namecheap nameservers if any of them fail. | GitHub Pages still serves the entire site through Cloudflare. No Worker production routes exist. |
| 5. Move documentation | After DNS is stable; use a separate attended window | Let the production documentation routes soak for at least one day. | Test one version through the canary route, deploy the production routes, retest, and remove the canary. | R2 serves `/doc/*` and `/doc-latest/*`; GitHub Pages still contains the old documentation for quick rollback. |
| 6. Publish Astro | After the documentation soak; use a separate attended window | Let the Pages deployment and monitoring run. | Deploy the reviewed Astro artifact and check the parity routes at desktop and mobile sizes. | Astro serves the website; R2 continues to serve documentation. Redeploy the previous Pages artifact to roll back Astro. |
| 5. Move documentation | After DNS is stable; use a separate attended window | Check production documentation responses and Worker errors before proceeding. | Test one version through the canary route, deploy the production routes, retest, and remove the canary. | R2 serves `/doc/*` and `/doc-latest/*`; GitHub Pages still contains the old documentation for quick rollback. |
| 6. Publish Astro | After documentation health checks pass; use a separate attended step | Let the Pages deployment and monitoring run. | Deploy the reviewed Astro artifact and check the parity routes at desktop and mobile sizes. | Astro serves the website; R2 continues to serve documentation. Redeploy the previous Pages artifact to roll back Astro. |
| 7. Enable permanent active-site redirects | After Astro is confirmed healthy, either later that day or the next day | Monitor redirect and origin errors. | Deploy the redirect Worker and test every classic active-site `.html` URL. | Classic URLs return `308`; Pages fallback files remain available if the redirect Worker fails. |
| 8. Add release automation and the web manual | After the cutover is stable | Build, validate, upload, and verify future documentation from release workflows. | Approve immutable publication and the separate `latest` change. | New Doxygen and modeling-manual releases follow the coordinated release pipeline. |

Phases 2 and 3 contain most of the work and can run while unattended. Phases 4
through 7 are deliberately short and separated by stable, working states. At
no point does a scheduled wait require `gecode.dev` to be unavailable.

Do not deploy the active-site redirect Worker before phase 6. The current
Jekyll origin serves `/download.html` and similar classic URLs but returns 404
Do not deploy the active-site redirect Worker before phase 6. The pre-cutover
Jekyll origin served `/download.html` and similar classic URLs but returned 404
for their new directory forms. The Astro artifact includes fallback redirect
files, so deploying the redirect Worker after Astro is safe.

Keep the Pages deploy job manual-only throughout the migration. Pushes and pull
requests still build and validate the artifact. Restore automatic default-branch
deployment in a separate change after the Astro deployment is stable.
Pages now deploys validated pushes to `main`; manual deployment from `main`
remains available. Pull requests only build and check. Push and manual runs
share concurrency for their branch so builds cannot publish out of order,
and production deployments are serialized.

The first R2 migration does not depend on the rewritten *Modeling and
Programming with Gecode* site. Reserve `modeling/` in each release tree now and
Expand Down Expand Up @@ -358,7 +372,9 @@ bucket-wide deletion.
During the first canary, remove the canary route to return that version to the
existing GitHub Pages archive. Before the Astro cutover, remove the production
documentation routes for the same rollback. If Astro itself must be rolled
back, redeploy a retained, verified Pages artifact. New Pages artifacts have 30-day
back, disable the Pages workflow and cancel pending/running push and manual
deployments before restoring a retained, verified Pages artifact. Rerunning
`pages.yml` rebuilds Astro; it does not restore the classic archive. New Pages artifacts have 30-day
retention. The July 2026 artifact has expired; prepare the small classic-site
rollback described below before the first cutover. Remove
the redirect Worker while the old artifact is active because that artifact
Expand All @@ -385,7 +401,10 @@ the existing Bundler dependencies installed. It creates
an existing output directory. The 5 September rehearsal produced 91,168,795
uncompressed bytes. A verified copy is retained at
`/Users/zayenz/gecode/website-rollback/classic-site-2026-07-15.tar.gz`;
restore its contents as the Pages artifact when needed.
restore its contents as the Pages artifact when needed. Executable restoration
instructions are retained beside it as `restore-classic-pages.md`. They use a
temporary payload branch and a manual restore workflow on `main`, preserving
the existing Pages environment restrictions.

Before Astro, removing the documentation routes restores the existing origin
archive. After Astro, restore the previous Worker deployment for a serving
Expand Down
45 changes: 24 additions & 21 deletions docs/migration-readiness-review-2026-09-05.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ trees were preserved.

DNS migration, full historical R2 verification, staging/canary checks and the
production documentation cutover are complete. The final production checks
passed on 5 September at about 14:15 UTC. Jekyll still serves the active website.
Allow at least one day of documentation soak before the separate Astro cutover
(no earlier than 6 September, 16:30 Europe/Stockholm). Future coordinated releases have a
passed on 5 September at about 14:15 UTC. Astro and active-site redirects
were subsequently deployed and verified on the same day.
The owner approved proceeding after fresh production health checks, passing
website CI and verification of the retained rollback archive; no fixed
24-hour wait is required. Future coordinated releases have a
working local preparation slice; their publication coordinator is unfinished.

The hosting arrangement is Cloudflare DNS/proxy, Workers and private R2, with
Expand All @@ -24,12 +26,12 @@ or Workers is a separate project and is unnecessary for this cutover.
| --- | --- |
| DNS | Cloudflare nameservers `milan` and `tegan` are authoritative; the zone is active. MX and SPF use Cloudflare Email Routing. |
| TLS | Cloudflare uses Full (strict) and Always Use HTTPS. Public HTTP redirects to HTTPS and the apex redirects to `www`. GitHub reports `https_enforced: false`; reconcile the origin setting separately. |
| Production website | `/download.html` returns 200; `/download/` returns 404. Jekyll remains live. |
| Production website | Astro is live. All 23 canonical pages return 200; their classic URLs return 308 with queries preserved. The twelve redirect routes fail open to Pages fallbacks. |
| Production documentation | All nine historical versions and both aliases use R2. Only `/doc/latest/...` is indexable. The two production route patterns are fail-closed; the canary and superseded routes have been removed. |
| Staging documentation | The reviewed Worker was deployed through GitHub. Its tests and live HTTP smoke checks pass for immutable 6.4.0, both aliases, canonical links, redirects, static assets and PDF range behavior. |
| R2 | Public `r2.dev` access is disabled. The 14-day lifecycle applies only to staging. All nine archives were fully verified: 52,385 objects / 1,138,898,740 bytes, with no missing objects or hash failures. The 326 historical image-map MIME declarations are documented below. |
| Email | Email Routing destinations and catch-all Worker configuration are present. Real delivery and delivery alerts were not exercised. |
| GitHub | The latest production Pages run remains the [15 July deployment](https://github.com/Gecode/gecode.github.io/actions/runs/29430643821). The [5 September staging Worker run](https://github.com/Gecode/gecode.github.io/actions/runs/33964652752) passed. The migration is merged on `main`; clean-checkout [CI passed](https://github.com/Gecode/gecode.github.io/actions/runs/33967188164), with Pages deployment skipped. |
| GitHub | [Astro deployment](https://github.com/Gecode/gecode.github.io/actions/runs/33972798507) and [redirect deployment](https://github.com/Gecode/gecode.github.io/actions/runs/33973076305) passed. Validated `main` pushes deploy automatically; PRs only build and check. |
| Deployment credentials | All three Cloudflare environments now contain the account ID and dedicated `gecode-github-workers` token. Production accepts only `main` and `release/*-website` branches; the existing `zayenz` reviewer and approval settings were preserved. |

## Fixes completed
Expand Down Expand Up @@ -82,11 +84,11 @@ After Astro, recover the previous Worker deployment for serving failures.
Changing `LATEST_DOC_VERSION` repairs aliases only, not explicit version URLs.
Do not delete immutable R2 objects during rollback.

## Remaining cutover sequence
## Cutover sequence and completion

1. **Website code landed.** The migration, archive and Worker changes are on
`main`, and clean-checkout CI passed. Pages deployment remains manual and
the classic rollback archive is retained outside the checkout. MPG and
`main`, and clean-checkout CI passed. The classic rollback archive and
executable restoration instructions are retained outside the checkout. MPG and
release-support changes still need separate commits and producer rehearsal.
2. **Deployment access verified.** The dedicated Worker token is installed in
`cloudflare-staging`, `cloudflare-canary` and `cloudflare-production`.
Expand All @@ -97,20 +99,21 @@ Do not delete immutable R2 objects during rollback.
3. **Operational checks partly complete.** Historical uploads and fail-closed
documentation routes are verified. Native documentation logs are enabled.
Real mail delivery and useful failure alerts remain to be checked; redirect
routes will be checked after Astro. Keep the current DNS delegation.
routes now have their verified fail-open setting. Keep the current DNS delegation.
4. **Canary documentation verified.** The 6.4.0 deployment passed HTML, source
folding, changelog fragment, CSS/JS/image, PDF ranges, missing paths,
canonical links and sitemap checks. Ordinary Jekyll pages remain unchanged.
canonical links and sitemap checks. Ordinary Jekyll pages stayed unchanged during this step.
5. **Documentation moved.** Production routes, every historical version and
both aliases pass verification. The canary is removed. Allow at least one
day with the Jekyll origin still available as fallback before Astro.
6. **Publish Astro.** Deploy `build:pages` from reviewed `main`. Verify ordinary
pages, downloads, publications, archive search/browsing and mobile layout,
plus R2 documentation. The Pages artifact must contain no documentation tree.
7. **Enable redirects and routine updates.** Deploy the classic URL redirect
Worker only after directory routes work. Check query and fragment behavior;
documentation and archive `.html` URLs remain content. Once stable, enable
automatic `main` Pages deployment and record the deployed Worker revision.
both aliases pass verification. The canary is removed. Before Astro, check
public documentation and Worker errors again and verify the rollback archive.
6. **Astro published.** The reviewed `main` artifact passed CI and deployed.
All 23 canonical pages, downloads, publications, archive search-to-thread
navigation and mobile layout pass. R2 documentation smoke checks pass.
7. **Redirects and routine updates enabled.** All classic active-site URLs
redirect after the directory routes were verified. Documentation and archive
`.html` URLs remain content. Validated `main` pushes deploy automatically.
Production redirect deployments also set and verify route fail-open behavior.
Live redirect Worker version: `1165ee03-782b-4f83-a687-0164a68d3087`.

The installed Worker token has Account Settings Read, Workers Scripts Write
and Workers R2 Storage Read, plus Zone Read and Workers Routes Write scoped to
Expand Down Expand Up @@ -269,7 +272,7 @@ Completed locally:
- The 91 MB classic rollback build from the exact July commit succeeds.

Still required: a complete coordinated Gecode producer rehearsal, the
documentation soak, Astro cutover, real mail delivery, and failure-alert setup.
real mail delivery and failure-alert setup.
Clean-checkout CI and internal lychee checks pass; nonblocking external checks
include new Astro URLs that are not live yet and broken historical external links. The archive browser samples are not
include broken historical external links. The archive browser samples are not
an exhaustive accessibility or Lighthouse audit.
Loading
Loading