ci(pages): build the wasm bundle and publish web/ to GitHub Pages

improvise-d31's finished artifact depends on improvise-9x6 (the worker-hosted
server) through improvise-djm. The *pipeline* does not, and building it now is
what stops the delivery half from being a mystery when the worker lands: the
swap from websocket transport to worker transport then changes what is
bundled, not how it is built and shipped.

Two jobs in ci.yml rather than a second workflow. `pages-build` runs on every
push and pull request, so a change that breaks `web/build.sh` or the bundle
fails on the PR that made it. `pages-deploy` runs only on a push to main and
`needs: [test, wasm, pages-build]`, so nothing that failed `cargo test` or the
existing wasm32 gate can reach the published site — the deploy depends on
those checks instead of repeating them.

Deliberately not path-filtered. The bundle is improvise-wasm-client plus
improvise-protocol, improvise-core and improvise-formula, so a filter meaning
"skip when the bundle cannot have changed" would have to name most of the
workspace, and getting it wrong leaves a stale site with nothing saying so.

wasm-pack is a pinned release tarball, v0.15.0 — the version `nix develop`
now supplies — so the local run that produced 346 KB of wasm (120 KB gzipped)
is evidence about the CI run. The devShell was missing wasm-pack entirely:
the `wasm` job only runs `cargo check`, which does not need it, so nothing had
ever required the one tool that turns a passing check into a loadable page.

What this cannot do yet, said on the page itself rather than routed around:
web/app.js is a thin client that holds no model, so a copy served from a
static host paints an empty grid until it is pointed at an improvise-ws-server
with ?ws=. The notice is static HTML, not something app.js decides, because it
is true on every load and a page that cannot reach a server cannot be trusted
to explain why. README says the same and names the deployed URL.

Verified: cargo test --workspace 1134 passed / 0 failed, clippy clean, fmt
clean, actionlint clean, ./web/build.sh succeeds and the assemble step
produces a 388 KB site whose every reference resolves inside it. NOT verified:
the workflow has never run — GitHub Pages is not enabled on the repository
(GET /repos/fiddlerwoaroof/improvise/pages is 404), which is improvise-3gy.
The deploy job asks configure-pages to enable it; if the token may not, that
step is where the run fails and the fix is the repository setting.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EoW5BB87ZZdm96SvBTWawH
This commit is contained in:
Edward Langley
2026-09-19 18:50:15 -07:00
parent 1f4e5354de
commit 188f3e94ef
5 changed files with 167 additions and 0 deletions
+92
View File
@@ -68,3 +68,95 @@ jobs:
run: |
nix shell nixpkgs#trealla --command tpl prolog-sessions/kb.pl \
-g "(kb_consistent -> halt(0) ; (kb_report, halt(1)))"
# ---------------------------------------------------------------------------
# GitHub Pages delivery (improvise-d31).
#
# Two jobs on purpose. `pages-build` runs on every push and pull request, so
# a change that breaks `web/build.sh` or the bundle fails on the PR that made
# it — the build is a gate. `pages-deploy` runs only on a push to main and
# `needs` the two check jobs above, so nothing that failed `cargo test` or the
# wasm32 gate can reach the published site. The deploy depends on those checks
# rather than repeating them (improvise-d31 AC 2).
#
# Not path-filtered, deliberately. The bundle is `improvise-wasm-client` plus
# improvise-protocol plus improvise-core plus improvise-formula, so a filter
# that meant "skip when the bundle cannot have changed" would have to name
# most of the workspace, and the failure mode of getting it wrong is a stale
# site with no signal that it is stale. A redundant build is the cheaper error.
pages-build:
name: Browser bundle + static site
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
# Pinned release binary rather than `cargo install` (a three-minute
# source build) or a third-party action. wasm-pack runs its own bundled
# `wasm-opt`, which is why improvise-wasm-client's Cargo.toml names
# `--enable-bulk-memory`: without it the optimizer rejects the
# `memory.copy` LLVM emits regardless.
# v0.15.0 is what `nix develop` supplies, and the bundle was built and
# measured against it locally (346 KB, 120 KB gzipped). Pinning the same
# version is what makes that local run evidence about this one.
- name: Install wasm-pack
env:
WASM_PACK_VERSION: v0.15.0
run: |
set -eu
url="https://github.com/rustwasm/wasm-pack/releases/download/${WASM_PACK_VERSION}/wasm-pack-${WASM_PACK_VERSION}-x86_64-unknown-linux-musl.tar.gz"
curl -sSfL "$url" | tar -xz --strip-components=1 -C /usr/local/bin \
"wasm-pack-${WASM_PACK_VERSION}-x86_64-unknown-linux-musl/wasm-pack"
wasm-pack --version
# The same script a developer runs locally, so there is one answer to
# "how is the bundle built" rather than two that can drift.
- name: Build the wasm bundle
run: ./web/build.sh
# `web/` is the source directory: it also holds build.sh and .gitignore,
# which have no business being served. Assemble what ships.
- name: Assemble the site
run: |
set -eu
mkdir -p site
cp web/index.html web/app.js web/style.css site/
cp -rf web/pkg site/pkg
rm -f site/pkg/.gitignore site/pkg/package.json
find site -type f | sort
du -sh site
- uses: actions/upload-pages-artifact@v3
with:
path: site
pages-deploy:
name: Deploy to GitHub Pages
needs: [test, wasm, pages-build]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
# A superseded deploy is allowed to finish rather than being cancelled:
# `deploy-pages` cancelled midway can leave the Pages deployment in a
# half-applied state, and the next push republishes anyway.
concurrency:
group: pages
cancel-in-progress: false
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
# `enablement: true` asks the API to turn Pages on with source =
# GitHub Actions. It succeeds only if the repository allows the workflow
# token to do so; if it does not, this step is where the run fails and
# the fix is the repository setting, not this file (improvise-3gy).
- uses: actions/configure-pages@v5
with:
enablement: true
- id: deployment
uses: actions/deploy-pages@v4