BlogPost
AI incident updates that don't make things up
How Observer drafts incident updates from measured evidence. The facts are computed in code, the model sees a scrubbed projection of them, drafts that invent a cause or a number are refused, and a person publishes.
7 min readTaha Al-Jody
The first public update during an incident is the one most likely to be wrong. It is written fast, under pressure, by someone who is also trying to fix the problem. A language model can write that update in seconds. It can also write it wrong in seconds: a confident cause nobody confirmed, a recovery that has not happened, a duration that sounds right but was never measured.
Customers read status updates as statements of fact, and some of them quote those statements back in SLA claims and regulatory reports. So when we built AI assist into Observer, we started from one rule: the model may help with the wording, but it may not supply the facts. This post explains how that rule is enforced.
Where AI fits, and where it does not
There is a whole category of tools that use AI to investigate incidents: correlating alerts, reading logs, proposing a root cause to the engineer on call. Observer is not one of them, and it does not try to be. It answers a different question: what happened to customers, and what should they be told?
Your AI SRE finds the cause. Observer proves the impact and tells your customers.
That division shapes everything below. Observer's drafts describe impact, which Observer measures. They do not describe causes, which Observer does not know.
Step 1: the facts are computed in code
For every incident, Observer builds an evidence appendix. It is computed by ordinary code from data Observer already holds, and no model is involved:
- The impact window. When the affected checks first changed status and when they recovered, taken from the confirmed status changes (the same debounced signal that drives the status page), not from raw samples.
- What was affected. The services, the checks that changed and the worst status reached.
- Where it was seen. Which checks and agents observed it, and how widely.
- Data coverage. What share of the window actually has measurements, so a gap in monitoring is not mistaken for a clean record.
- Nearby changes, by timing only. If a deploy or configuration change happened shortly before, the appendix says it started a few minutes after that change. It never says the change caused it.
The same appendix appears in the incident editor and in the signed evidence export, so the operator, the export and the draft all work from one set of facts.
Step 2: the model sees a scrubbed projection
The model never receives the appendix itself, and it never receives your monitoring configuration. Before any draft is requested, Observer builds a minimised context:
- Services get opaque keys (
s1,s2and so on) that are mapped back after the call. Organisation, page, metric and incident identifiers are not sent. - Probe configuration, queries, thresholds, metric values, agent identifiers and environment variable references are not sent.
- Private checks are named only as "internal check".
- Free text that does go in (titles, service names, earlier public messages) is length-capped and scrubbed of anything shaped like an identifier, key, token, email address or IP address.
- From the evidence appendix, the model gets only a customer-safe projection: impact start and end times to the minute, whether impact is ongoing, its duration, the worst status, the affected service keys, how many checks changed, how widely the failures were seen and the data coverage.
Subscriber and end-user contact data is never sent. The subprocessors page lists exactly what goes to the model provider and how that provider handles it.
Step 3: the instructions forbid guessing
The model is told that it drafts for an operator who reviews every word, and that it never publishes. It is told to describe only what the signals and earlier updates show: which services, what kind of impact, since when and whether they have recovered.
It is told not to speculate about the cause. If no earlier update from the operator states a cause, the draft says the team is investigating, and it must not use causal wording at all. It is told to treat the measured evidence as authoritative: if impact is ongoing it must not say the issue is resolved, and if impact has ended it must not say it continues. It may only use a time or duration by copying it from the input, and it may not write any other number. Choices the operator has already made, such as the message status or the severity, are final.
Instructions alone are not a guarantee. Models do not always follow them. That is why the next step exists.
Step 4: drafts are checked, and refused
Every draft is checked in code before anyone sees it. A draft is refused outright, and the operator sees no suggestion at all, if any of these is true:
- It leaks an identifier. Anything shaped like an internal ID, an API key or a redaction marker.
- It makes a causal claim nobody made. Phrases such as "caused by", "due to", "root cause" or "triggered by", when no operator update has stated a cause. A cause the operator wrote may be repeated; a cause the model came up with may not.
- It contains an invented number. Every number in the draft must appear in the context the model was given. A made-up duration, time, count or percentage fails the check.
- It claims a false recovery. The draft says the impact is over while the evidence shows it ongoing, and the operator has not chosen to resolve the incident.
- It claims impact that has ended. The draft says impact continues while the evidence shows every affected check recovered and the incident is resolved.
The draft also has to have the right shape: a short title and a message of a few plain sentences. Any service it names that was not in the list it was offered is dropped. The recovery and causal checks read English and a few common equivalents in other languages; drafts in any language are still checked for leaks and invented numbers.
A refused draft is not retried with looser rules. The operator keeps writing the update, exactly as they would without AI assist. Showing nothing is better than showing something wrong.
Step 5: a person publishes
Nothing AI assist writes is published by AI assist. A draft fills the incident editor; the operator reads it, edits it and decides whether to post it. When Observer opens an incident automatically from a metric, the suggestion is made the first time someone opens that incident and is stored for review; it is never posted to the status page on its own.
Postmortem drafts follow the same idea with a tighter split. Code writes every factual section (impact, timeline, detection, resolution and every number in them) from Observer's data. The model fills four short fields: a summary, the root cause, contributing factors and suggested action items. Any field that carries a number not in the input or an internal identifier is dropped, and the root cause keeps only what an operator actually wrote. Where a field is dropped, its placeholder stays for a person to fill in.
What this looks like in practice
Suppose checkout latency crossed its unhealthy threshold at 14:05 UTC and is still high. The operator opens the incident and gets a draft along these lines:
Checkout is responding slowly
Since 14:05 UTC, some customers may see slow responses when completing an order. Our team is investigating. We will share an update as soon as we know more.
Every fact in it comes from the evidence: the service, the kind of impact and the start time. It does not say "due to a database issue", because nobody said that. It does not say "for about 20 minutes", because that number was not in the input. If the operator later posts an Identified update that names the cause, the next draft may repeat it. When the checks recover and the operator resolves the incident, the draft may say impact has ended, with the end time copied from the evidence.
Controls
AI assist is available on paid plans and can be switched off for an organisation in Settings. Translation of published messages, which uses the same provider, runs only on status pages where you turn it on. Usage is bounded by a monthly allowance, and automatic drafts for auto-created incidents have a daily cap per organisation.
Why this matters
An incident update is a record. Customers use it to decide whether to retry, whether to escalate and whether to claim a credit. Regulated customers may use it to classify their own incident, as described in DORA for SaaS vendors. A fluent paragraph that invents a cause or a recovery is worse than a slow one, because it is believed.
Grounding drafts in measured evidence, checking them in code and leaving the decision to a person keeps the speed and removes the guessing. The incidents page shows how measured status turns into a drafted incident, and the incident update templates show what a good update contains, whoever writes it.