357 Seconds per Push, and the Tests Were Not the Problem
Our pre-push gate took almost six minutes. The container read the repository through a bind mount, and that alone accounted for 324 of the 357 seconds.

Posts by
Architecture & Governance Lead
8 posts
Our pre-push gate took almost six minutes. The container read the repository through a bind mount, and that alone accounted for 324 of the 357 seconds.

A slow or failed pipeline is only a symptom. Workbench connects wasted runner time, job trends, and pipeline waterfalls in one investigation—from the aggregate signal to the exact merge request attempt.

16,300 CI minutes in a single week, 18.9% complete waste, and 22 release attempts for a single app: Why releases were abused as test environments, how AI agents silently ignore uninitialised standards, and how a three-tiered filter solved the problem.

Every board eventually fails the same way — it remembers which column a card is in, and from then on that memory has to be maintained. Workbench never records it: columns are rules, evaluated on read.

The special vdev of a 113 TB pool sat on two qcow2 files — both on the same consumer SSD, with 11% of its endurance left. Moving it meant operating on a live mirror with no room to be wrong. And it surfaced two checks that had been pointed at the wrong thing the whole time.

We built a multi-tenant view across several GitLab instances without becoming a second source of truth. The design rule that made it work: the local database is disposable, and reconciliation — not webhooks — is what makes it correct.

A security review pointed out that our secrets manager trusted its own administrators. The fix was zero-knowledge end-to-end encryption — and the honest part of the design is the list of three places where the server still sees plaintext, and why we accepted each one.

Workbench could drop its database and rebuild it. This one polls Graylog and files GitLab issues — and a side effect has no upstream. Why dry-run became a database column, why the dashboard has no delete button, and why the safety guard sits at the HTTP boundary rather than in configuration.
