Skip to main content

How alerts are grouped into incidents

Why one attack should produce one incident rather than forty alerts: windowed aggregation, risk per entity, and the one unified incident object that now merges notable events and risk incidents.

Written for whoever runs IT13 min readUpdated

A single break-in produces a great many individually correct observations. A password-spraying run is hundreds of failed sign-ins. Ransomware encrypting a file share is thousands of file modifications. If each observation became an alert, the alert queue would be the attack, rendered unreadable.

So the platform collapses observations into findings, and findings into incidents. This article explains the two mechanisms that do it — windowed aggregation inside a single rule, and risk accumulated per entity across rules — and it is honest about which half of that you can see today.

Why the naive design fails

The binding constraint for a business without a security team is not detection coverage. It is alert volume. The industry figures the design was built against are stark: an average of 2,992 alerts a day, 63% of them never addressed at all, and 76% of teams naming alert fatigue as a top challenge. Adding more rules to a pipeline that alerts once per rule per event makes that worse rather than better.

Which leads to the design decision the whole module rests on: a detection does not create work for a person directly. It deposits a scored, entity-tagged finding. Only accumulation across findings is allowed to create an incident.

Stage one of grouping: aggregation inside a rule

An evaluated event passes through four stages, set out in Alert severity, and what a match actually means. Stage three is the aggregator, and it is where a failed sign-in becomes twenty failed sign-ins from one address in five minutes. It sees only events that already matched the rule, which matters more than it sounds — see the section on the defect this replaced.

Where the input comes from is the question to ask first, and it is the one the callout above answers. Today the only events that reach stage one are those posted to the platform's internal ingest endpoints, which is not the path any of the log collectors use. Both halves are built and correct on their own; the join between them is missing. Until it lands, the practical reading is that your log collection delivers search, evidence and retention, and your Microsoft 365 and Google Workspace alerting should stay switched on rather than being retired on the assumption that we have replaced it. Connecting your first log source carries the source-by-source detail.

Five settings on each rule control it, and all five are tunable per organisation:

Group key
The rule's group-by fields, which determine what counts as the same thing happening again. A key renders as source_ip=203.0.113.5, or several fields joined together. The fields are sorted before the key is built, so the key does not depend on the order the rule happened to list them in. A rule with no group-by has a single global bucket.
Time window
How far back the count reaches. The default is five minutes where a rule does not state one, and an unparseable or non-positive value falls back to the same default rather than becoming infinite.
Threshold
How many matching events in the window are needed. A threshold of zero or less is normalised to one — so a rule with no threshold fires on every match, which is the single-event case, and it is still cooldown-limited.
Distinct field
Counts distinct values rather than events. This is the difference between brute force and password spraying: one address, twenty failures versus one address, twenty different accounts. If an event does not carry the distinct field at all, it is dropped from the window entirely rather than counted — counting it would inflate the distinct count with an empty value.
Minimum events
A persistence floor checked after the threshold; both must hold. With a distinct field in play this is what lets a rule ask for breadth and depth at once — twenty distinct accounts, from at least fifty attempts.
Cooldown
After the rule fires for a group key, it stays quiet for that key for the cooldown period. Without it, crossing a threshold emits a fresh alert for every subsequent matching event — which is exactly the forty alerts problem, and the cooldown is the cheapest fix for it.

A cooldown that swallows an alert is reported rather than hidden, so the console can say 12 further occurrences suppressed instead of quietly losing them. That distinction is worth internalising: those twelve events were seen, counted and folded into the same finding. Nothing was excluded. That is not the same as a suppression from your own suppression list, which drops events before the rule ever looks at them — see Suppressing a false positive.

Two honest limits on the aggregator

A bucket holds at most 4,096 events. Beyond that the oldest are discarded, the newest are kept, and the finding is flagged as truncated — meaning its count is a floor rather than an exact figure. A flood therefore degrades the accuracy of a distinct count rather than the memory of the process. If you see a truncated finding, treat the number as at least this many.

The aggregator's state is held in memory, and it is sized for the event rates a small business actually produces rather than for a large enterprise. Two consequences follow, and neither is hidden in our own source comments: a restart loses every in-flight window and every running cooldown, so a threshold half-crossed at the moment of a deployment starts again; and where the platform runs as more than one process, each process counts its own share, so a threshold can take longer to cross than the arithmetic suggests. A distributed version would keep the same decision logic behind a shared store. It is not built.

Why the aggregator exists at all

This is worth reading because it is the clearest example in the product of a detection that looked like it worked and did not.

The previous threshold path asked the database to count events matching the group key inside the window — and that count did not apply the rule's own conditions. So ten failed logins from one address in five minutes actually fired on ten events of any kind whatsoever from that address. On any busy source it was a permanent alert generator that could never be tuned into usefulness, because the thing it was counting was not the thing it claimed to be counting.

It also could not express a distinct count or a cooldown at all. Which is why the password-spraying rule counted attempts grouped by both address and account — and therefore detected ordinary brute force while reporting itself as spraying. Both are fixed. Both were the kind of fault that produces confident output for years.

Stage two of grouping: risk per entity

Aggregation collapses many events into one finding from one rule. It cannot join a suspicious sign-in to a mailbox rule created an hour later to a large upload that evening, because those are three different rules. Joining them is what the risk layer is for.

Every finding that fires deposits one or more signals. A signal carries the rule, its severity, its base score, its ATT&CK tactics and techniques, its data source, the group key and the contributing event identifiers. Signals are keyed to an entity — a user, a host, or a source address — taken from the entity kinds the rule declares.

Entity attribution is deliberately strict. If a rule declares that its risk attaches to a host but the event does not carry a host, that produces no signal for that kind rather than a signal keyed on an empty string. The alternative would merge every anonymous event in your tenant into one enormous fictional entity with a spectacular risk score, which is worse than having no risk picture at all. Source addresses are also treated as weaker identity than users and hosts, because network address translation makes an address a poor name for anybody.

How the score is built, and why one loud rule cannot dominate

A signal's base score comes from the rule's risk score, or from its severity if none is set: critical 100, high 80, medium 60, low 40, informational 20.

Repeat firings of the same rule against the same entity are then damped geometrically — the nth firing contributes the base score divided by two to the power of n minus one. The consequence is the important part: one rule can never contribute more than twice its base score against one entity, however often it fires. So three different medium detections outweigh one medium detection firing thirty times, which is the correct ordering and is not what plain addition gives you. Without damping, one chatty rule would dominate every entity it touched.

The accumulated total is deliberately not capped, because clamping would hide the difference between an entity sitting at 80 and one sitting at 400. A separate normalised value, capped at 100, is what a display would show.

The two things that open an incident

The default risk policy. Every tenant currently gets these values, because per-tenant policy storage is not wired.
SettingDefaultWhat it means
Score window24 hoursHow far back signals count towards the score. The window is the decay — signals older than this stop counting, and there is no other ageing mechanism.
Score threshold75Accumulated score at which an incident opens. This is the figure the product's own market analysis specifies, on a 0-100 entity scale.
Diversity window7 daysThe longer window used for the second trigger, because attack chains unfold over days, not hours.
Minimum distinct tactics3Three different stages of an attack chain against one entity is the signal, and it is worth surfacing at a score well below the threshold.
Minimum distinct data sources2So that one noisy sensor cannot fake breadth. The equivalent commercial product asks for four; a small estate has far fewer connected sources, so the floor here is two.
Maximum signals per incident150Beyond this, further signals still move the score but are not listed individually.
Critical score120At or above this the incident is critical rather than high. Four or more distinct tactics also makes it critical regardless of score.

The score threshold is checked first. If it is not met, tactic diversity is checked over the longer window. Either one opens an incident, recorded with the reason — score_threshold or attack_tactic_diversity.

Tactic diversity is the more interesting of the two, and it is the one that catches things no single rule was confident enough to alert on. One weak signal repeated four hundred times is still one tactic from one source and will never satisfy it. Four different weak signals against the same account, from different telemetry, is a shape that deserves a person. The policy validator enforces the principle directly: a diversity floor below two is rejected with tactic-diversity floor must be at least 2; a single tactic is not a chain.

One incident per entity, not one per signal

Once an entity has an open incident, later signals for that entity are appended to it rather than opening a second one. That append behaviour is where the noise reduction actually comes from. Exactly one moment in an incident's life is created — which is the moment worth notifying you about — and everything after it is updated, meaning work happened and no new alert was needed.

The incident's derived fields are recomputed from the live window rather than patched as signals arrive, which is what makes signals ageing out of the window lower the score. When the signal cap is reached, the incident keeps the highest-scoring signals rather than the most recent ones, because somebody opening a capped incident needs the worst things in it, not the latest things. The count that was dropped from the list is recorded, so it is clear that those signals moved the score even though they are not itemised.

An incident describes itself in a fixed shape. A diversity-triggered incident is titled Multi-stage activity on user:[email protected] (4 ATT&CK tactics); a score-triggered one, Elevated risk on host:LAPTOP-14 (score 82). The summary names the signal count, how many distinct detections produced them, the tactics, the data sources and the contributing rule identifiers.

Closing an incident clears the entity's accumulated signals as well as setting the status, so a closed incident does not immediately reopen from the same evidence. That is deliberate and it mirrors how the mature products in this space behave, but it is worth knowing: closing is a statement that you have dealt with the evidence, not merely that you have read it.

Why a quiet rule still contributes

Risk is fed before the fourth evaluation stage decides whether to raise an alert. That ordering is the entire reason a rule can ship in shadow mode rather than being switched off: its finding is real, it has already been recorded, and it accumulates against the entity — it simply does not interrupt anybody.

This is what makes a rule worth shipping quiet. A rule that fires on every uncovered single-factor sign-in is useless as an alert in an organisation midway through a Conditional Access rollout, and genuinely valuable as a contribution to the risk score of the specific accounts where the gap is worst. Shadow detections, and why some rules stay quiet covers which rules are quiet and what each is waiting for.

Two couplings are worth knowing because neither is obvious. Risk is fed only when the aggregator actually fires, so a match swallowed by a cooldown contributes no risk either — the cooldown quietens the score as well as the queue. And a rule that declares no risk entities at all contributes nothing to risk, by construction: there is nothing for the signal to attach to. If you lengthen a cooldown to reduce noise, you are also reducing what that rule contributes to an entity's picture, and that is the trade you are making.

The one incident object

Everything above this section describes how a finding accumulates into risk and how risk opens something. What it opens has changed. There used to be two separate things that could be called an incident here: a notable event and a risk incident, each with its own table, its own endpoints and its own console screen. A single siem_incidents object now exists, and it is the one both older concepts feed.

What the new object adds, and what is real and console-backed today:

  • Entities, a timeline, comments and tasks — an incident is a real working surface now, not just a scored row. You can read what touched it, leave a note, and track a task against it.
  • Evidence and bookmarks attached to the incident itself.
  • Similar-incident suggestion — incidents sharing an entity within the last 30 days are surfaced against each other, so a pattern spread across more than one open incident is not something you have to notice by eye.
  • Grouping, refined from the entity-level append behaviour described above: a new finding appends to an existing incident, rather than opening a second one, when it shares the same rule, the same primary entity, the incident is still open, and it is within 24 hours of the incident's activity. Outside any of those four conditions, a new incident opens instead.
  • A full lifecycle with classification, and a console screen for all of the above.

What this section is explicitly not claiming, stated because each of the following is something a reasonable person would expect a mature incident feature to have and none of them is here yet: an investigation graph linking incidents and entities visually; a dedicated page per entity rather than per incident; SLA-breach alerting — the due-date column exists in the schema, and nothing reads or acts on it yet; a dedicated severity-override control beyond editing the incident normally; bulk actions across more than one incident at a time; bidirectional ticket sync; and an AI-written incident narrative.

What can happen automatically once an incident opens or changes is a separate mechanism, covered in full in Automation rules and proposals — notify, assign, tag, close and enrich actions can run for real, with precise, worth-reading caveats on the two remaining action types.

What is wired, and what to do in the meantime

Honest status of each mechanism in this article, as of 2026-09-21.
MechanismStatus
Windowed aggregation — threshold, distinct count, minimum events, cooldownLive and correct on the internal service ingest path. Not reached by a stream rule from events arriving over a log collector — a scheduled rule can reach them instead, see Scheduled detection rules and templates.
Alerts, their statuses and their triage statesLive. See Alert states and who owns one.
Entity risk scoring, damping, windowing and incident openingLive and persisted. See The risk screen for the console surface built on it.
The unified incident object — entities, timeline, comments, tasks, evidence, similar-incident, grouping, lifecycleLive and persisted, with a console screen, described above. Old notable-event and risk-incident ids and their read endpoints are preserved and still answer unchanged.
Automatic action on incident create/update — notify, assign, tag, close, enrich, run a playbook, create a ticketPartially wired, with precise per-action and per-trigger caveats. See Automation rules and proposals.
Investigation graph, per-entity pages, SLA-breach alerting, bulk actions, bidirectional ticket sync, AI-written narrativeNot built.
Correlation chains as a runtime sequence evaluatorChains ship as validated content; the sequence evaluator is not observable in the live ingest path.

For a stream rule reacting to a log-collector source, the grouping you get is still per-rule, for the reason given at the top of this article — that specific gap has not closed. The practical advice there is unchanged too: batch your medium and low alerts, read them together weekly, and look for the same person, host or address appearing across several unrelated rules. A scheduled rule, or a rule reading events from the internal service ingest path, does not have that limitation, and its findings do open and group into the real incident object described above.

What to read next

  1. Alert severity, and what a match actually means — the four stages, and how to triage without training.
  2. Tuning a detection rule — changing the windows, thresholds and cooldowns described above.
  3. What to do when an alert arrives — the playbook for the ones that reach you.
  4. Automation rules and proposals — what can run automatically once an incident opens or changes.
  5. The risk screen — the console surface for entity risk and the older risk-incident concept, still live and unchanged.

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 logs and detection