Safety limits
Safety limits put a deliberate pause between an unexpected change and the system it could affect. They are not a health score and they do not make a bad change safe. They stop a planned write, name the condition that fired and give an administrator the evidence needed to fix, reset or release it.
Three controls share this work:
- Sync circuit breakers judge the proposed difference before an import or synchronization applies it.
- The reconciliation breaker counts the removals reconciliation is about to make on a system over a rolling window and holds them when a share of the system would go at once. The same ledger also judges two removals nobody decides one by one: the certification deadline and a sunset. See Reconciliation.
- Provisioning caps count write operations over a time window and stop, throttle or alert when a configured ceiling is reached.
A rule is not a trip
A circuit-breaker rule defines what to watch and where: its thresholds, object kind, system scope, priority and action. A trip records one system breaching that rule during one run.
That distinction is load-bearing. A tenant-wide rule can protect every system, but a breach pauses only the system whose proposed change crossed the threshold. The same rule remains armed for the rest of the estate. Resetting one system's trip does not silently release another system.
The trip leads with the condition that actually fired — for example, “change 88.4% exceeded the 20% limit” — and carries the actual value for every other configured condition. It never presents a generic list of possible causes as though each were equally likely.
What a breaker can watch
A breaker judges one kind of change, or every kind when no narrower kind is selected:
| Kind | The proposed difference it judges |
|---|---|
| Identities | People or workforce identities arriving from a source |
| Business objects | Governed context records such as departments or projects |
| Object memberships | Membership edges between those records |
| Accounts | Accounts in a connected target system |
| Entitlements | Groups, roles or comparable access objects |
| Grants | Assignments between an account and an entitlement |
Each kind is measured against its own baseline. The platform does not blend a large stable account population with a small but completely replaced entitlement set and call the combined percentage safe.
Breakers can use percentage thresholds or absolute ceilings for creates,
updates, deletions and total change. Per-attribute conditions can narrow the
question further: a run that blanks department for hundreds of identities is
different from one that changes hundreds of unrelated fields. Membership and
grant edges have no attributes, so the editor does not offer field conditions
that could never fire.
A percentage condition only counts on a system that holds at least 10 rows of that kind, or on a run that changes at least 10 of them. Two changed rows out of two is 100%, but it is not the event a percentage is meant to catch. Deleting every row of a system of two or more still trips, and absolute ceilings and field conditions are not affected.
Which rule wins
One effective rule answers the safety question for a system and object kind. Resolution is first-match-wins, in this order:
- A rule naming the object kind outranks an all-kinds rule.
- Within that, a system-specific rule outranks the tenant-wide fallback.
- Priority orders rules with the same specificity.
- A stable business identifier breaks a remaining tie.
This makes two necessary shapes possible at the same time: a tenant-wide safety floor and an explicit exception for a system with legitimate high churn. The coverage view names which rule is effective and flags an exception that is looser than its fallback. “Covered” alone would hide the decision that matters.
A source that disables accounts or terminates identities in place, instead of dropping them, is judged like one that deletes them: a status change to disabled counts as a disable in the breaker, in a held run's preview and in the run summary. Enabling an account again stays an update.
The reconciliation breaker
The reconciliation breaker has its own card on the Safety Limits page. It shows the grant counter, the account counter and the counting window (default 24 hours, at most 168), and one edit saves all five values. A per-system exception can change the grant share, the account share or the window, and a value that is looser than the tenant default is marked as such. When it holds a system, the hold names the counter that fired and the window, shows a chip for each condition, and the release dialog says how many removals were kept. Releasing lets exactly those removals through and needs a reason.
Removals nobody decided, outside reconciliation
Two automatic removals used to bypass the ledger: the revokes a certification deadline runs on undecided items, and the revokes a deprecation plan's sunset cascades. Both now pass the same ledger as reconciliation: the same counters, the same default window and thresholds, the same hold and the same release with a mandatory reason. They cannot exceed the limit on their own, and an approved plan or a configured deadline action is not a pre-authorisation.
- A held removal is held, not failed. The grant or account stays as it is and the target is not called. The hold appears as the ordinary Safety Limits hold, with its card and inbox item.
- Certification deadline. Only a removal that no person decided is judged: a grant revoked at the deadline, and each grant and the disable of an account whose item expired undecided. A reviewer's own rejection is not judged. When a removal is held, the human-decided sources are still withdrawn and the decision stands; after a release, reconciliation removes exactly what the hold kept.
- Sunset. The plan keeps cascading past a held revoke. It is not retired: it
returns to Deprecated with the held count on its summary, an audit event
(
deprecation.sunset_held) and a note on the plans page. The scheduler does not ask again while a hold is open. After a release, the next sweep removes exactly what was kept and retires the plan; after a reset it asks again and the ledger judges anew. A sunset that is half done cannot be cancelled (the request is refused with a 409 conflict, and the plans page hides the rollback box and says why). - Population is the system's, not the role's. Three holders of a role on a system of forty grants all go. Three holders that are every grant on the system hold the third, because a full wipe of a population of two or more always trips. A one-grant system is not a wipe. A deadline that would revoke both grants of a two-grant system holds the second.
- If the ledger cannot record a charge, the removal is held (fail closed).
- A person's own decision is not judged. An administrator's direct revoke, a reviewer's decision, a retire and an emergency (lockout, break-glass) are people deciding. A test inventories every code path that reaches the removal API and fails when a new one does not declare which door it uses.
An approved batch shows its size. Approving a batch of provisioning changes is a person's decision too, so the breaker does not judge it. Instead the approval screens (the batch lane, the confirm dialog and the review drawer) say what share of the system's live grants the batch removes, for example "Removes 40% of the 100 live grants on AD", next to the system's limit. From the count at which the breaker would hold the same removals made automatically, the figure turns red with that warning. The count follows the breaker's own rules, the floor and the full-wipe rule included, so the warning and the breaker agree. After an approver rejects some items, the drawer measures again for what is still approved.
Provisioning caps
A provisioning rule carries a list of independent caps. Each cap states:
- what it counts — every write, a class such as create or revoke, or one specific operation such as account disable or grant;
- over which window — so one rule can express both a short burst ceiling and a sustained daily ceiling;
- per what — the whole system, one identity, one account or one entitlement;
- whether it applies only to privileged operations.
Breaching several caps reports all of them. Reporting only the first would invite an administrator to raise the wrong ceiling and retry. A cap that cannot identify its configured subject is skipped rather than widened silently to the whole system.
Caps proposed from observed volume. For each system with at least 7 active days of writes, the page proposes caps for create, revoke and modify from the last 30 days: the busiest hour and the busiest 24 hours of a normal day (the busiest 10% of days set aside), times a margin of 1.5 (1.25 and 2 can be chosen), never below 10. Each proposal says whether the system's current cap fits, is too tight or is loose, and replays the window against it. Every number is editable and nothing applies until the administrator confirms; applying updates the system's own rule or creates an exception for it. The go-live readiness board lists these proposals too.
First sync and intentional release
A connector's first baseline sync does not trip a change breaker: there is no prior connector state to protect, and a 100% net-new difference is expected. The exemption belongs to that connector's first run, not to the tenant's total record count.
For a later held run, release is deliberately reviewable:
- Inspect the condition that fired and the stored proposed difference.
- Correct the source, mapping or threshold when the change is wrong.
- Reset and run again, or issue a one-shot release when the change is intended.
- Record a non-empty reason for the release.
A reset does not switch the sync back on. Resetting a breaker or a system, or discarding a held run, leaves the paused sync paused unless the administrator ticks "turn the sync back on" in the dialog; the box starts unticked. Before, every clear re-enabled a connector whose source still differed, and the next run tripped again. Approving or releasing a held run still resumes the sync.
A repeat is not a new decision. When a held run proposes the same difference as a run
that was already settled in the last seven days, with no landed sync in between, the system
stays held but the run is filed as a repeat of the earlier one and audited
(sync.held_run_repeat_suppressed) instead of raising a new urgent item. Context and
people-CSV imports do not dedupe this way yet.
A one-shot release is consumed once. It is not the same as disabling the rule, and every other safety limit continues to apply. If an old trip has no stored preview, the portal says so instead of inventing one; the trip can still be released, but never without an audit reason.
Known boundaries
- A safety limit judges the difference the connector and mapping produced. It cannot prove that the source data itself is correct.
- An alert-only action reports a breach without pausing the connector. The rule's configured action therefore matters as much as its threshold.
- A first-sync exemption means initial population must be reviewed through the onboarding and preview controls rather than treated as breaker evidence.
- The ledger bounds a removal that no person decided. A person revoking in bulk (for example an administrator retiring a non-human identity) is not held by it.
- Disabling a rule is configuration, not a one-run exception. It removes that protection until somebody enables it again.
Further reading: Reconciliation · Imports and schedules · Failed Jobs Queue · Operating rhythm