Skip to content

Deploy the website from its own release line - #26

Open
okcodes wants to merge 8 commits into
mainfrom
website-deploy
Open

okcodes wants to merge 8 commits into
mainfrom
website-deploy

Conversation

@okcodes

@okcodes okcodes commented Sep 10, 2026 •

Copy link
Copy Markdown
Collaborator

Wires the landing page up for GitHub Pages, following the shape already proven
in the sibling repository: a second vump project, a website-v* tag line, and a
deploy workflow gated on vump check.

Two release lines

vump.toml now declares two projects, told apart by the shape of their tag.

Project Tracks Tagged Ships
main Cargo.toml, Cargo.lock v1.2.3 the binary, via release.yml
website website/package.json website-v1.2.3 website/ to Pages, via release-website.yml

vump check infers the project from the tag, so neither workflow names
--project. The shapes cannot collide — a website tag does not start with v —
and release.yml's glob is anchored to a digit while we are here, so v* no
longer matches voldemort.

Shipping a site-only change is vump patch --project website --through push. No
vump version, nothing said to anyone pinning the binary.

website/package.json gets its version back. It was dropped when the site had
no release line, on the grounds that a number nobody maintains is a lie — vump
now keeps it in step with the tag, which is what makes it true.

The version the page states

Read at build time from website/src/content/release.json. The masthead used to
fetch it from the GitHub API on every page load: unauthenticated that is sixty
requests an hour per address, so the version would vanish for anyone behind a
busy NAT, and the page would say different things to different people.

Reading Cargo.toml instead is the obvious move and is wrong. Cargo.toml
holds the version most recently bumped, not the version most recently
published — right now it says 0.8.0-alpha.0 for a tag that was never pushed,
while the newest release is 0.7.0. The page would advertise a download with no
binaries behind it, which is this tool's own defect pointed at itself.

pnpm bump:vump picks the newest stable tag from the repository itself, so
moving the site to a new release is one offline command, not a lookup that can
be rate-limited. Pre-releases are skipped: the download button hands over the
newest stable, and stating an alpha beside it would be two answers to one
question.

Prerendering

dist/index.html now ships with the page rendered into it. A second Vite pass
builds src/entry-server.tsx, scripts/prerender.mjs inlines the result into
#root and deletes the intermediate, and main.tsx hydrates when #root
already has children.

Three things had to stop depending on the browser, none of them workarounds:
the theme now lives on the document element instead of React state (the
pre-paint script is what prevents the flash, and mirroring it into state would
have given the server HTML a theme it cannot know); the theme toggle renders
both icons and hides one in CSS, so hydration cannot swap it under the visitor;
and the entrance animations are gated on a js class, without which a
scripting-disabled client would get the prerendered markup at opacity zero —
there, and invisible.

Version badge

Fixed to the corner, not in the footer: a bug report is a screenshot, and this
needs to be in every one without the reporter scrolling first. It shows the
site's version — read from the file vump keeps in step with the tag, so it
cannot drift — and the commit the deploy was built from.

Workflows

release-website.yml builds and deploys on a website-v* tag. It uses the
composite check action rather than the build in the checkout, which is the
opposite of release.yml and deliberate: what is verified here is the website's
version, not the binary about to be published, so there is no regression an
older vump could miss — and building one would drag a Rust toolchain into a job
that ships static files.

website.yml runs typecheck, lint, format and build on pull requests touching
the site. Separate workflow with a path filter rather than a job in test.yml,
which has none and would run the Rust suite for a copy edit.

Installing is pnpm install --frozen-lockfile in both: the committed lockfile
is the declared input, so a rebuild of the same commit produces the same bytes.

Every uses: in the repository was checked against its published releases
rather than assumed. actions/checkout was a major behind and moves to v7
across all four workflows; everything else was already current.
dtolnay/rust-toolchain stays on stable, which is the moving reference that
action documents rather than a pin left behind.

release-website.yml has no workflow_dispatch. On a manual run
github.ref_name is a branch, so the version gate would have nothing to check
— a deploy here is a tagged release or it does not happen.

Address

vump.codehacks.io, at the root — so the base-path environment variable and its
.env are gone, and canonical, og:url and og:image are absolute. The custom
domain goes in the repository's Pages settings; a workflow-based deploy needs no
CNAME file.

Before the first deploy

Three things outside this branch: point the DNS at Pages, set the custom domain
and Source: GitHub Actions in the repository's Pages settings, then
vump patch --project website --through push. The root README.md gets the
link once the domain answers.

okcodes and others added 8 commits September 10, 2026 02:47
The binary and the landing page ship on different schedules. Deploying a copy
fix should not require cutting a vump release, which would tell everyone
pinning the binary that something changed when nothing did.

vump.toml now declares two projects, told apart by the shape of their tag:
`main` tracks Cargo.toml and Cargo.lock and tags `v1.2.3`, `website` tracks
website/package.json and tags `website-v1.2.3`. Each shape triggers one
workflow, and `vump check` infers the project from the tag, so neither has to
name --project. The shapes cannot collide: a website tag does not start with
`v`.

website/package.json gets its version back. It was dropped when the site had
no release line, on the grounds that a number nobody maintains is exactly the
kind of lie this repository exists to prevent — but vump now keeps it in step
with the tag, which is what makes it true rather than decorative.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The masthead used to fetch the newest release from the GitHub API on every
page load. Unauthenticated, that is sixty requests an hour per address, so the
version would simply vanish for anyone behind a busy NAT — and a landing page
that says different things to different people at different moments is not one
anybody can quote.

It is a declared input now: src/content/release.json, read at build time.

Reading Cargo.toml instead is the obvious move and is wrong. Cargo.toml holds
the version most recently bumped, which is not the version most recently
published — right now it says 0.8.0-alpha.0 for a tag that was never pushed,
while the newest release is 0.7.0. The page would advertise a download with no
binaries behind it, which is the defect this tool exists to prevent, pointed
at itself.

Pre-releases are skipped for the same reason: the button beside the number
hands over the newest stable, and stating an alpha next to it would be two
answers to one question. `pnpm bump:vump` picks the newest stable from the
repository's own tags, so pointing the site at a new release is one offline
command rather than a lookup that can be rate-limited.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The deployed page shipped an empty #root: correct in a browser, and nothing at
all to a crawler, a link preview, or an agent fetching it. That is a strange
thing for a page whose entire job is being read by someone deciding whether to
try the tool.

`vite build` still produces the client bundle; a second pass builds
entry-server.tsx to dist-ssr/, prerender.mjs inlines that HTML into #root, and
the intermediate is deleted rather than deployed. main.tsx hydrates when #root
already has children and renders normally when it does not, which is what the
dev server serves.

Three things had to stop depending on the browser for this to render on the
server, and none of them are workarounds:

The theme now lives on the document element rather than in React state. The
pre-paint script in index.html is what keeps the page from flashing the wrong
theme, and mirroring that into state would have given the server-rendered HTML
a theme it cannot know. Reading the attribute at the moment of the click
cannot drift from what is on screen.

The theme toggle renders both icons and hides one in CSS. Choosing between
them in JavaScript would mean the prerendered HTML picks a theme the visitor
may not be using, and hydration would swap it under them.

The entrance animations are gated on a `js` class the pre-paint script adds.
Without that, content held at opacity zero waiting for an observer would leave
a scripting-disabled client staring at a blank page — the prerendered markup
would be there, and invisible.

The site's own address is settled while we are here: vump.codehacks.io, at the
root, so the base-path environment variable and its .env are gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A bug report is a screenshot. The badge is fixed to the corner rather than
placed in the footer so it appears in every one of them without the reporter
scrolling to the bottom first, and it names the pair that identifies a build:
the site's version and the commit it was built from.

The version is read straight from package.json, which is the file vump keeps
in step with the website-v* tag. A separately computed value could drift from
that tag; this cannot. The commit arrives as a build-time variable the deploy
workflow sets, and reads as "local" when there is no deploy to name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
release-website.yml builds website/ and publishes it to Pages, gated on
`vump check` agreeing the tag matches website/package.json — the same gate the
binary's release has, for the same reason: find out before the work, not after
the deploy.

It uses the composite action rather than the build in the checkout, which is
the opposite of what release.yml does and deliberate. release.yml verifies the
binary it is about to publish, where an older vump cannot catch a regression in
the very code being released. Here the subject is the website's own version,
so there is no such regression to miss, and building vump would drag a Rust
toolchain and two minutes into a job that ships static files.

Installing is `pnpm install --frozen-lockfile`. The committed lockfile is the
deploy's declared input, so nothing is resolved or discovered at deploy time
and a rebuild of the same commit produces the same bytes.

website.yml runs typecheck, lint, format and build on pull requests that touch
the site, so a broken page is caught in review rather than by a failed deploy.
It is a separate workflow with a path filter rather than a job in test.yml,
which has no path filters and would otherwise run the Rust suite for a copy
edit.

Also anchors release.yml's tag glob to a digit. `v*` matches `voldemort`; it
is the same fix the sibling repository already made, and with a second tag
shape in play the trigger should be exact about which one it wants.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The action was given `working-directory`, which it does not accept. With no
package.json at the repository root — this is a Rust project with a site in a
subdirectory — it had nowhere to read a pnpm version from and stopped before
installing anything.

`package-json-file` is the input that exists, and it is the whole point of
keeping `packageManager` in website/package.json: one declared version for
local development and CI both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every `uses:` in the repository was checked against its published releases
rather than assumed. actions/checkout was a major behind and moves to v7;
setup-node, configure-pages, upload-pages-artifact, deploy-pages, attest,
upload-artifact, download-artifact and pnpm/setup were already current.
dtolnay/rust-toolchain stays on `stable`, which is a moving reference that
action documents rather than a pin left behind.

release-website.yml also loses its workflow_dispatch trigger. On a manual run
`github.ref_name` is a branch, so the version gate — `vump check` against the
pushed tag — has nothing to check and the deploy would either fail or, worse,
be made to skip the one step it exists for. A deploy is a tagged release here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This branch had an error being deployed

1 failed deployment
github-pages — 7b5d7e43 Deployed Sep 11, 2026 by okcodes via deploy #1
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.

1 participant