Done, approve, decide: how changes are grouped
The three piles at the bottom of your report, the six conditions a change must meet to be applied without asking, and the nine things we do on our own.
The bottom half of your posture report is not advice. It is a set of specific, executable changes, each one sorted into one of three piles. The piles are the product rather than a presentation choice: they are the answer to the only question that matters when software has permission to change your systems, which is where its judgement stops and yours starts.
- done
- "I have already done this." Safe, reversible, non-disruptive, already applied, and reported to you after the fact with the way to reverse it.
- approve
- "Approve these and I'll do them." One tap each, with the reasoning and the undo path shown before you tap.
- decide
- "This needs a human decision." Genuine business trade-offs the platform must not make on your behalf, phrased as business questions rather than technical ones.
The decide pile is small on purpose. If it is long, we have failed to do our job and pushed the work back to you. The done pile is also small on purpose, for a completely different reason.
What it takes to reach done
A change reaches the done pile only if it satisfies every one of the following. Not most of them. All of them.
- It grants no privilege — it does not grant, extend or elevate anybody's access.
- It embodies no business judgement — accepting it is not a trade-off only you can weigh.
- It is reversible.
- It carries a recorded undo handle — an actual reversal path, recorded at the moment the change was made.
- It is non-disruptive — it could not interrupt anyone's work even if it were wrong.
- Its kind is on an explicit closed allowlist of change types someone has justified in writing.
Failing any single one of those keeps a change out of done, and it lands in approve instead. The classifier is deny-biased at every step: anything not positively recognised as safe becomes an approval request. The trade we are making is stated plainly in the code that makes it — an unnecessary approval costs you a click, and a wrong autonomous change costs trust that does not come back.
The fourth condition is the one people ask about. Reversible in principle is not enough. If the reversal path was not recorded at the moment the change was made, "reversible" is an untested claim, and we do not want to be reconstructing one under pressure at the exact moment it turns out to matter. See Undoing a change Qorionix made.
The nine things we will ever do without asking
This is a closed allowlist, not a denylist, and the direction matters. With a denylist, a new and destructive operation added to the platform next month would be automatically applicable until somebody remembered to forbid it. With an allowlist, a new operation is not auto-applicable until a person adds it here and justifies why. The failure mode of forgetting is a redundant approval request rather than an unasked-for change to your business.
| Change kind | What it does | Why it is safe unattended |
|---|---|---|
enable_unified_audit_log | Turns on tenant audit logging. | Records more; changes nothing about access. Without it, nobody can reconstruct an incident. |
connect_log_source | Wires a log source into the platform. | Reads a stream that already exists. |
enable_mailbox_auditing | Turns on per-mailbox audit. | Records mailbox activity; no mailbox behaviour changes. |
set_log_retention | Sets a baseline retention window. | Keeps existing records longer. |
activate_detection | Enables a detection rule that needs no tuning. | Watches; does not act. |
enable_shadow_detection | Enables a behavioural detection in shadow mode, where it scores and records but never alerts. | Safe by construction — you see its false-positive rate before a single false positive reaches you. |
tag_asset_inventory | Records a discovered object in the asset inventory. | Writes to our records, not to your tenant. |
enable_signin_risk_telemetry | Starts collecting a signal your licence already includes. | Collection only; no policy is created. |
schedule_access_review | Books a review and prepares the list. | Changes no access whatsoever. The review is where the decisions happen. |
The done pile is therefore mostly logging, telemetry, inventory and shadow-mode detection. It is unglamorous by design. It is also the part that makes everything afterwards possible: an incident you cannot reconstruct is an incident you cannot answer questions about, and half of the audit obligations in your compliance section are satisfied by records rather than by policies.
Enforced in three independent places
The rules above are checked three times, by three mechanisms that do not depend on each other.
The classifier
A pure function that takes a change and returns its bucket and the reason. It is deny-biased and applies its rules in strict precedence order, so no combination of properties can route around the privilege rule. Because it is pure, every combination of inputs is exhaustively testable, and the test that enumerates them is part of the build.
A validation pass over the whole change set
Deliberately redundant with the classifier. The classifier decides; this pass refuses to ship a set the classifier got wrong. It re-checks every done-bucket change against the same six conditions and rejects the set if any one fails, before anything is stored or applied.
A database CHECK constraint
The same rule again, as a constraint on the table. A classifier regression, a bad migration, or somebody writing directly to the database with SQL still cannot land an irreversible change in the pile that gets applied without asking.
A second constraint forces any change that grants privilege into decide, at every layer. There is exactly one change kind in the system that grants a privileged role, grant_privileged_role, and it exists only so that this guardrail can be tested against a real privilege grant. Nothing in the check pack emits it.
Three enforcement points for one rule looks like belt and braces because it is. The cost of a single irreversible change applied without asking is not a bug report; it is a customer who is right never to trust the product again.
The sentence next to each change, and what it means
Every change shows you why it is in the pile it is in. These are the exact sentences the classifier produces — there is no separate marketing copy, and the reason you read is the reason the code recorded.
| What the classifier found | Pile | The sentence you see |
|---|---|---|
| The change grants, extends or elevates access. | decide | "grants, extends or elevates privileged access, which is never done autonomously and never by one tap" |
| The check declared this a business trade-off. | decide | "this is a business trade-off the platform does not have the facts to decide" |
| The change cannot be undone. | approve | "cannot be automatically reversed, so it is never applied without your approval" |
| It could be undone, but no reversal path was recorded. | approve | "no undo path was recorded, so it is not treated as reversible" |
| It could interrupt somebody working. | approve | "could interrupt N people's work if it is wrong" |
| Its kind is not on the allowlist above. | approve | "this kind of change is not on the list of changes the platform may make on its own" |
| All six conditions met. | done | "safe, reversible and interrupts nobody, so it has already been applied and can be undone in one tap" |
In the fifth row, N is the real blast radius of that change. You will see "could interrupt one person's work if it is wrong" for a single account, "could interrupt 41 people's work if it is wrong" for a tenant-wide sign-in policy, and "could interrupt people's work if it is wrong" where the count is not established. That number is the single most useful thing on the row, and it is why the approve pile is sorted with the widest-reaching changes at the top.
What is in the approve pile
Nineteen change kinds can appear here. Each one is reversible and each one shows its recorded reversal path before you tap, but every one of them touches how somebody signs in, what they can reach, or what an application can do.
| Group | Change kinds |
|---|---|
| How people sign in | require_mfa_for_admins, require_mfa_all_users, enforce_mfa_registration, require_passkey_for_admins, block_legacy_auth, require_compliant_device, enable_sspr |
| Administrative access | create_break_glass_account, remove_role_from_service_principal, remove_role_from_disabled_account |
| Mail exposure | disable_inbox_rule, remove_mail_forwarding |
| Applications | revoke_app_consent, restrict_user_consent, rotate_service_principal_credential |
| Accounts, devices and licences | disable_stale_account, remove_stale_guest, enrol_device_management, reclaim_licence |
Revoking privilege is in this pile. Granting it never is. That asymmetry is structural rather than a policy we intend to follow: the platform is not given a tool that grants a privileged role, so no amount of confidence, and no cleverly worded instruction, can produce one.
What is in the decide pile, and why each one is there
| Change kind | Why it is yours to decide |
|---|---|
separate_admin_accounts | Which person gets which account, and what breaks when their mailbox moves, is a decision about how they work day to day. |
reduce_global_admins | Which administrators lose the role is a judgement about who does which job. We cannot tell from the outside. |
disable_legacy_auth_protocol | It will break something and the platform does not know what. Finding out which printer, scanner or laptop is the work, and it is yours. |
declare_asset_criticality | Only you know which machines would stop the business. Nothing is auto-isolatable until you say so. |
set_escalation_preference | Wait or act at 3am, per class of action. Two honest answers, each with a real cost. |
restrict_guest_access | Narrowing what partners can reach is a commercial relationship decision as much as a security one. |
upgrade_licence | It costs you money. |
delete_unused_account | Destructive, and not reversible by us. |
grant_privileged_role | Exists only so the guardrail can be tested against a real privilege grant. Nothing in the check pack emits it. |
Two of these — asset criticality and the escalation preference — are on every report regardless of what discovery found, because they are the only two things about your business that cannot be discovered. They are described in How to read your posture report.
Everything above is recorded
Each of these events is written to a hash-chained audit log, with an actor recorded as human, ai or system. Chaining means a later edit to an earlier entry breaks the chain and is detectable, which is what makes the log usable as evidence rather than only as a diary.
change_set_generated the whole set was produced by a check pack run
change_proposed a change entered the approve or decide pile
change_auto_applied a done-bucket change was applied
change_accepted you approved a change
change_rejected you declined a change
change_reverted a change was undone
change_failed a change was attempted and did not succeed
bucket_denied a change was refused entry to a bucket by a guardrailbucket_denied is worth knowing about. It is the record of a guardrail firing — a change that tried to land in done and was refused. If you ever see one, it is our bug rather than your problem, and the entry exists so that we can find it and so that you can see that the refusal happened.