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 18smedian run
4smedian queue
committed07 Oct 2026, 20:36 AEDT
queued 4swaiting for a free agent on a two-agent pool
ran 14m 20s7 of 25 steps were gates, 9m 49s of them
Sync the pitlab-docs corpus and the gate checkout4s
Emit the build-time data snapshots (fail-closed, sanitisation asserted)1m 27s
Render the public corpus slice into Starlight pages3s
Scrub gate — rendered source (fail-closed)1s
Decide whether the published set actually changed0s
Stage the checkout onto docker01 (control01/runners stay clean)4s
npm ci (pinned Node image)44s
Pre-render every Mermaid diagram to both-theme SVG1m 36s
astro build34s
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)57s
Trivy scan the built dependency tree and prove Dependency-Track ingested it36s
Pre-deploy artifact gate (rendered title + Pages free-tier limits)3s
Bundle gate — mermaid absent from the shipped JavaScript1s
wrangler pages deploy (direct upload)18s
Post-deploy acceptance — live page serves the rendered title0s
Rendered-DOM acceptance in a headless browser (live site)32s
Diagram legibility at a 390px viewport (live site, both themes, no-JS)2m 22s
Functional acceptance gate (service test plan)46s
Lighthouse — record the scores and hold the measured floors3m 42s
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 18s 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.