Skip to main content

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.

Written for the business owner9 min readUpdated

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.

The complete auto-apply allowlist. Nothing outside this list is ever applied without your approval.
Change kindWhat it doesWhy it is safe unattended
enable_unified_audit_logTurns on tenant audit logging.Records more; changes nothing about access. Without it, nobody can reconstruct an incident.
connect_log_sourceWires a log source into the platform.Reads a stream that already exists.
enable_mailbox_auditingTurns on per-mailbox audit.Records mailbox activity; no mailbox behaviour changes.
set_log_retentionSets a baseline retention window.Keeps existing records longer.
activate_detectionEnables a detection rule that needs no tuning.Watches; does not act.
enable_shadow_detectionEnables 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_inventoryRecords a discovered object in the asset inventory.Writes to our records, not to your tenant.
enable_signin_risk_telemetryStarts collecting a signal your licence already includes.Collection only; no policy is created.
schedule_access_reviewBooks 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.

  1. 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.

  2. 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.

  3. 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.

The bucket reason shown to you, and what the classifier found to produce it
What the classifier foundPileThe 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.

The nineteen approve-bucket change kinds, grouped by what approving one actually does
GroupChange kinds
How people sign inrequire_mfa_for_admins, require_mfa_all_users, enforce_mfa_registration, require_passkey_for_admins, block_legacy_auth, require_compliant_device, enable_sspr
Administrative accesscreate_break_glass_account, remove_role_from_service_principal, remove_role_from_disabled_account
Mail exposuredisable_inbox_rule, remove_mail_forwarding
Applicationsrevoke_app_consent, restrict_user_consent, rotate_service_principal_credential
Accounts, devices and licencesdisable_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

The nine decide-bucket change kinds and the fact the platform does not have
Change kindWhy it is yours to decide
separate_admin_accountsWhich person gets which account, and what breaks when their mailbox moves, is a decision about how they work day to day.
reduce_global_adminsWhich administrators lose the role is a judgement about who does which job. We cannot tell from the outside.
disable_legacy_auth_protocolIt 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_criticalityOnly you know which machines would stop the business. Nothing is auto-isolatable until you say so.
set_escalation_preferenceWait or act at 3am, per class of action. Two honest answers, each with a real cost.
restrict_guest_accessNarrowing what partners can reach is a commercial relationship decision as much as a security one.
upgrade_licenceIt costs you money.
delete_unused_accountDestructive, and not reversible by us.
grant_privileged_roleExists 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.

Audit events recorded against changes
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 guardrail

bucket_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.

Was this article wrong?

If a procedure here does not match what you see, or a limit we described has changed, tell us and we will fix the page. Email us about this article, or see how to get help if you need an answer rather than a correction.

Everything in your posture report