Shipping a change
The one thing to know
Section titled “The one thing to know”The dev branch is production. Pushing it deploys to stevendesignco.com.
main is stale and deploys nothing.
There is a gate now. dev is protected and the Q&A check has to pass before a
merge lands, so a change that breaks accessibility, reflow or contrast cannot
reach the live site by accident. Force pushes and branch deletion are off.
The protection does not apply to repository admins, which is deliberate: this is a one-person repository and locking yourself out at the wrong moment is its own risk. The gate is there to stop a mistake, not to stop you.
Work happens on a branch. A branch deploys to a password-protected review URL.
Merging into dev is the act of publishing.
The sequence
Section titled “The sequence”- Build locally and check the page you changed.
- Run the Q&A pass.
- Push the branch. Read it on the review URL.
- Open a pull request. The template carries the checks; CI runs the Q&A pass and has to go green before the merge is allowed.
- Merge to
devonly when asked to publish. - Run the Q&A pass again against the live site, rather than assuming the deploy matched.
The Q&A pass
Section titled “The Q&A pass”One command, and it is not optional for anything that touches the layout, the stylesheet or a component.
npm run dev # in one terminalnpm run qa # in anotherOr npm run ship, which runs the documentation check, the build and the Q&A
pass in order.
GitHub Actions runs the same pass on every push and every pull request, so a
branch reports for itself. That is a second pair of eyes, not a replacement for
the first: on dev the result lands after the deploy, because dev is
production. Run it on your branch before you merge.
It covers reflow and target size across eleven pages and eleven widths, axe on
every page and with every dialog open, the dialog’s keyboard behaviour, text
spacing overrides, High Contrast Mode, and inline link distinction. --pixel
adds a comparison against the live site and is worth the wait on any change that
was supposed to be invisible.
Each check is in qa/checks/, and each one opens with the defect it was written
for. They are all regressions that reached production or nearly did. The
repository’s qa/README.md has the list and the reasoning.
Three habits sit underneath it:
Check the pages you did not touch. The worst regression in the component refactor landed on three pages nobody was editing.
Check where content is reused, not only where it lives. The case study pages were correct while the dialog showing the same content was broken.
Prove a check can fail. Break the thing deliberately, watch the check name it, then put it back. A check that has only ever passed is not evidence. This is also how we learned that axe passes a link with 1.02:1 contrast and no underline, which is why there is a separate check for that.
The resume PDF is the one thing that can drift
Section titled “The resume PDF is the one thing that can drift”public/resume.pdf is a copy of the master built in the Job Hunt folder, not
something this repository generates. The build there writes a .docx and converts
it with LibreOffice; nothing in this project can reproduce that.
So when the master changes, the site does not follow. Someone has to copy the file across:
cp "~/Documents/claude/Projects/Job Hunt/resume-master-docx/Steven-Vanden-Heuvel-Resume-MASTER.pdf" public/resume.pdfThe resume page’s title line has to be changed by hand to match at the same time. It is the one place in this project where two copies of the same thing exist and nothing checks them, which is worth knowing rather than discovering.
It used to be worse. The PDF was a print of the resume page, which meant it had the site’s display font and brand styling instead of the plain ATS layout every other resume uses. A resume that looks different from the one attached to an application is not a style choice, it is a mistake.
Undoing
Section titled “Undoing”Vercel keeps the previous production deployment as an instant rollback. Before a significant release, tag the current state so there is a named point to return to:
git tag -a live-backup-YYYY-MM-DD dev -m "state before <change>"git push origin live-backup-YYYY-MM-DDRolling back is then a reset to that tag and a force-with-lease push.
Keeping the docs in step
Section titled “Keeping the docs in step”The Storybook cannot drift: it regenerates its stylesheet from the running site every build. Prose can, so there is a check rather than a good intention.
npm run check:docsIt compares your branch against dev and fails when the layout, a component, a
Storybook story or the Storybook’s own CSS changed and no documentation page
did. It also fails when stories changed without the Storybook being rebuilt.
The order to work in
Section titled “The order to work in”- Change the component.
- Change its page under
docs-site/src/content/docs/components/. If the change alters how, when or where it is used, that page is part of the change, not a follow-up. - Rebuild both:
cd storybook && npm run build, thencd docs-site && npm run build. Both need the site running on :4321, because the Storybook pulls its CSS from it. - Run
npm run check:docs. - Commit the component, the page and both builds together.
When nothing needs documenting
Section titled “When nothing needs documenting”Some changes are invisible to the people the docs serve: a refactor
with identical output, a typo in a comment. Set SKIP_DOCS_CHECK=1 and say why
in the commit message. An override with a reason is a decision; a skipped step
is an accident.
The documentation and the Storybook
Section titled “The documentation and the Storybook”The Storybook generates its stylesheet from the running site. After a change that touches shared CSS, rebuild it so its rendering and its contrast figures stay true.
This documentation is prose and does not regenerate. If you change a component’s behaviour, the page describing it is part of the change, not a follow-up.