Designing guardrails that do not block the work
The failure mode of an approval gate is not that it lets bad actions through. It is that it gets switched off in week three because it asked about everything.
Daniel Reyes
Principal Engineer
Every governance layer starts the same way. Someone reasonable proposes that automated systems should not take irreversible actions without a human signing off. Everyone agrees. The gate ships. Three weeks later it is disabled, because it fired on four hundred routine actions and one that mattered, and nobody could tell which was which.
The problem is not the idea. It is that 'requires approval' was modelled as a property of the action, when it is really a property of the action's blast radius.
Blast radius, not action type
Deleting a row is not inherently dangerous. Deleting a row in a staging database seeded four minutes ago is noise. Deleting a row in the billing table of a production tenant with nine hundred active users is the thing the gate exists for. Same verb, four orders of magnitude apart in consequence.
- Is the effect reversible, and if so, for how long and by whom?
- How many records, users or dollars does it touch?
- Is the target production, and is it someone else's data?
- Has this exact action shape been approved before, by whom, and how recently?
A policy written against those four dimensions asks for approval roughly two per cent as often as one written against action names, and it asks about the right things.
Approval fatigue is a security vulnerability
A gate that fires on everything trains the people behind it to approve without reading. That is strictly worse than no gate, because it manufactures a signed audit trail for decisions nobody made.
This is not a hypothetical. It is the well-documented outcome of every alerting system that cried wolf, and approvals behave exactly like alerts. The design target is not 'catch everything'. It is 'never ask twice about the same safe thing, and never fail to ask about the dangerous one'.
Make the safe path the fast path
The best guardrail is one an engineer would choose even if it were optional. That means the approved route has to be quicker than the unapproved one: pre-scoped credentials that are easier than fetching a key by hand, a dry-run that returns a real diff in under a second, a rollback that is one command rather than an incident.
policy: production-writes
when:
environment: production
reversible_within: < 5m # anything undoable in five minutes passes
records_affected: "> 100"
require:
approvals: 1
from: [oncall, data-owner]
auto_approve_if:
identical_action_approved_within: 24hThat last clause does most of the work. A reconciliation job running every hour asks once a day, not twenty-four times, and the audit trail still records every execution against the approval that authorised it.
Log the refusals too
Teams instrument what the system did. Almost nobody instruments what it tried to do and was stopped from doing, which is the more interesting dataset by a wide margin. It tells you where your policy and reality disagree, and one of those two is usually wrong in a way worth knowing about.