A safety net that scales on triggers, not vibes

Process debt accretes one 'just to be safe' rule at a time. Our dev safety net attaches an explicit, checkable trigger to every escalation — so guardrails grow deliberately.

A worn wooden handrail running down a staircase, its finish rubbed smooth where hands have gripped it.

Every engineering organization accumulates process the same way. An incident happens, someone adds a rule to make sure it will not recur, and nobody removes it later. Repeat for a few years and you have a gauntlet of gates whose original reasons are lost, each one a small tax on every change, none of them safe to touch because no one remembers what they were guarding against. We wrote our development safety net to fail the opposite way: deliberately minimal today, with an explicit, checkable trigger attached to every future escalation.

Warn today, enforce at the edge

Right now the local layer is intentionally light. The git hooks that run on a developer's machine warn rather than block — they nudge rather than stop you — because the real enforcement lives server-side, on the branch that actually matters. A secret scan runs on every push and again in continuous integration, currently in a soft mode that reports without failing the build, but running the exact same invocation it will use the day it becomes hard. A worktree garbage collector cleans up stale branches dry-run-first, acting only on signals it can confirm, and doing nothing at all when it is unsure. The theme is consistent: local tooling assists, the server decides, and nothing destructive happens without certainty.

This restraint is a choice. It would be easy to make every hook blocking and every scan hard on day one. We deliberately did not, because a gate that fires before it needs to is pure friction, and friction on an AI-native factory is expensive at scale.

Restraint is not the same as leniency, though. The guards that do exist are the ones that guard against harm we have actually seen. Production deploys, for instance, run through a wrapper that refuses to ship if a live function would silently disappear — a rule that exists because an unguarded deploy once deleted functions in production, and we did not want to relive it. The lightness is at the local, reversible layer; the irreversible edges are held firmly.

The scale table

The part we are most deliberate about is how the net gets stricter over time. Instead of hardening on a hunch, each escalation has a measurable trigger written down in advance. The soft secret scan flips to hard after a defined quiet period — a set number of clean pushes or a fixed number of days, whichever comes first. Continuous integration splits into parallel lanes only once it genuinely outgrows a single one, and when it does, a fan-in gate keeps the one required check intact so the rule around it never has to change. Required reviews rise from zero the moment any automation gains the ability to merge. Ownership rules and code-owner review arrive with the second human on the repository, starting with the highest-blast-radius paths. A merge queue turns on when enough changes are in flight at once to warrant it. And the whole net graduates from a single repository's rules to shared organization-wide rules the moment a second repository needs the same protections. Each rule names the exact condition that will bring it into being, so the safety net grows on evidence rather than anxiety.

Writing the triggers down does something quietly powerful: it makes 'should we add this gate yet?' a question with an answer. Either the condition has fired or it has not. There is no debate to have and no judgment call to relitigate, which is precisely what keeps process debt from creeping in one cautious rule at a time.

Cleaning up after a fast fleet

A fleet that opens many short-lived branches needs a way to reap the dead ones, and here too the design refuses to guess. Because changes land by squash-merge, a merged branch never actually becomes part of the main line's ancestry — so the usual 'is this branch merged?' check is blind to exactly the branches you most want to clean up. Rather than trust that flawed signal, the cleanup asks the source of truth directly, treating a branch as reapable only when the record shows its pull request was merged and its tip matches what was merged. And it runs dry-run-first: with no way to confirm, it does nothing at all. Even the housekeeping is fail-closed.

This matters more in an AI-native org

It would be reasonable to assume that when coding agents produce most of your changes, you should armor everything upfront. We think the opposite is true. The more of your throughput comes from a fast fleet, the more every unnecessary gate costs you, because it slows the whole factory rather than one person. So each gate has to earn its place with a condition you can check, not a feeling you can cite. The guards that do exist — the ones that permission-block dangerous actions — are there because a real failure mode was observed and named. The ones that do not exist yet are waiting on their triggers.

Check it, don't vibe it

That phrase is the whole philosophy in four words. A safety net should be a contract about the future, not a museum of past scares — and like everything else in the factory, it is versioned in the repository, reviewed like code, and allowed to change only when the evidence says it should. Guardrails that grow on triggers instead of vibes stay legible, stay minimal, and stay trusted, which is exactly what you want from the thing standing between a change and production.

This note describes the implementation as it stood when it was written. Figures are counted from the repository; they are not published benchmarks or a performance guarantee.