A change to this site is a push. What happens after the push is a fixed sequence: the data
snapshots are rebuilt, the corpus slice is rendered, the publish controls scan the source, the
bundle is built and scanned again, the dependency tree is scanned and its inventory proved
ingested, the bundle is uploaded, and only then does a browser open the live site and assert on
what it actually rendered. Every step below is that sequence, with its real timings.
Change lifecycle — 6 real publishes of this site, step by step
Snapshot taken — build-time, not live
25steps in a run
7of them are gates
14m 23smedian run
4smedian queue
committed07 Oct 2026, 20:36 AEDT
queued 3swaiting for a free agent on a two-agent pool
ran 14m 07s7 of 25 steps were gates, 9m 09s of them
Sync the pitlab-docs corpus and the gate checkout4s
Emit the build-time data snapshots (fail-closed, sanitisation asserted)1m 34s
Render the public corpus slice into Starlight pages2s
Scrub gate — rendered source (fail-closed)2s
Decide whether the published set actually changed0s
Stage the checkout onto docker01 (control01/runners stay clean)4s
npm ci (pinned Node image)45s
Pre-render every Mermaid diagram to both-theme SVG1m 33s
astro build29s
Scrub gate — built bundle (fail-closed, on the real artifact)9s
Prove the scrub gate reads the set-piece data (red on a fixture per panel)55s
Trivy scan the built dependency tree and prove Dependency-Track ingested it16s
Pre-deploy artifact gate (rendered title + Pages free-tier limits)2s
Bundle gate — mermaid absent from the shipped JavaScript2s
wrangler pages deploy (direct upload)17s
Post-deploy acceptance — live page serves the rendered title0s
Rendered-DOM acceptance in a headless browser (live site)33s
Diagram legibility at a 390px viewport (live site, both themes, no-JS)2m 23s
Functional acceptance gate (service test plan)47s
Lighthouse — record the scores and hold the measured floors3m 50s
Clean up the docker01 staging directory4s
Post Checkout arronpitman-site (fresh per-run workspace)1s
Complete job0s
A run executes 25 steps against the 22 the pipeline declares: the difference is the agent's own job scaffolding — initialising, tearing the workspace down, finalising — which is real time on the clock and is shown rather than netted out. Real timings from each run's own timeline, not a diagram of the intended process. A gate is marked because of the script it runs, matched against the same gate map the CI gate panel is built from — never because its name contains the word. Two of these runs share a commit: the pipeline is triggered by pushes to two repositories, so one change can legitimately publish twice.
The queue is the part worth looking at. Median run is 14m 23s and median queue is 4s, but the spread on the queue is far wider than the spread on the run — the pool has two agents and every session in the estate shares them. Lead time for changes is a property of the queue at least as much as of the build, which is why the two are measured separately rather than summed into one reassuring number.
A step is marked as a gate because of the scripts it runs, matched against the same derived
gate map the CI gates panel is built from — one derivation behind two
panels, so they cannot come to disagree about what a gate is.
The alternative was to match the word “gate” in the step’s display name, and it is worth saying
why that was rejected: it would label a step called Bundle gate and miss Rendered-DOM
acceptance in a headless browser, which is the strictest gate in the run. An assertion that
labels the easy cases correctly and misses the important one is the shape this estate calls an
assertion that cannot fail.
Median run and median queue are measured separately and never summed into one number, because
they are different problems with different fixes. The build is bounded by what the build does.
The queue is bounded by how many agents the pool has — two — and by every other piece of work in
the estate competing for them. Lead time for changes is a property of the queue at least as much
as of the pipeline, and an estate that reports only the run time is reporting the half it
controls.
The last four steps all run after the bundle is live. That ordering is deliberate. A check
that terminates before the edge has repeatedly been green while the page was broken — a 200 from
a cached error page, a script tag that proves a file was linked rather than that anything ran, a
string present in server-sent HTML that survives a failed client render. So the acceptance gates
here open a real browser against the real deployment and assert on the rendered result. If they
refuse, the previous deployment is still the one being served.