Thirty-Two Clocks and One Legal Hold
Thirty-two retention policies are created for every workspace and every one of them is switched on. They cover operational records rather than business ones — and a legal hold placed over any of them wins, deliberately, even when the evidence for it disagrees with itself.
Somewhere in your workspace, at a quarter past two every morning, thirty-two clocks strike and rows are removed. Most organisations running this have never looked at which.
There are two completely separate retention systems in this product and confusing them is the single most common misunderstanding about how long anything is kept. One governs business records you deleted and can restore, and it ships switched off. The other governs operational records — logs, sessions, notifications, job runs — and it ships switched on.
What is being pruned, and after how long
| Window | What ages out | Why that long |
|---|---|---|
| Two years | Audit logs, document access logs, support impersonation logs, trash lifecycle events and purge reports | The evidence trail. Two years is the longest window in the set, and these are the records most likely to be asked for. |
| One year | Activity log, email logs and replies, messages, payment and provider webhook logs, integration sync logs, report runs and exports, user devices, workflow alerts and tasks | A full annual cycle, so a question about "this time last year" can still be answered. |
| Six months | Device tokens, notifications, push logs, workflow logs, runs and run events | Operationally useful and voluminous. Six months is well past the point anybody reads them. |
| Thirty days | Failed jobs, job batches, job runs, scan events, scan sessions, scanner tokens and sessions | Debugging material and transient state. A month is generous for both. |
Every one of those is created for a workspace that does not already have it, with the action set to delete and the policy active. Existing policies are left exactly as they are, so an organisation that has changed a window keeps its change.
On by default here, off by default there
The recovery centre's retention — the windows that decide when a deleted customer or item is destroyed for good — ships off, because a system that starts destroying business records on a schedule nobody consciously chose fails in a direction that cannot be undone. These thirty-two ship on, because a log nobody has read in a year is a liability rather than an asset, and a system that accumulates operational records forever eventually becomes one that cannot be backed up. Same product, opposite defaults, and both are right for what they govern.
Six tables are pruned once, not per organisation
A detail that is easy to get wrong and impossible to notice getting wrong. Most of these tables carry an organisation on every row, so the sweep runs per organisation. Six do not: failed jobs, job batches and job runs belong to the installation rather than to anybody, and the three provider webhook logs carry an organisation that may be absent, because payment providers post to a public endpoint without knowing whose account they are calling about.
Those six are pruned globally instead. Handled per organisation, the rows with no organisation would never match any sweep and would accumulate forever — which is the sort of thing discovered years later, as a table nobody can explain the size of.
A row belonging to nobody is a row every per-owner sweep skips.
A legal hold outranks all of it
A hold names a kind of record and, optionally, one specific record. While it is active, rows it covers are withheld from purging regardless of what any policy says.
It carries the things a hold needs to be defensible: a reason, who placed it, when it starts and when it expires, and — when it is lifted — who released it and why. That is enough to answer the two questions anybody asks about a hold months later, which are who decided and on what basis.
The rule when the evidence disagrees with itself
This is the most interesting decision in the whole mechanism. A row can be attributed to a held record in two different ways — through a pair of columns naming the record type and identifier, and through a different pair naming the model and identifier. Where both exist, both are checked.
And a row matching either one is kept.
That is deliberately not the strict reading. A stricter rule would require both to agree, and would destroy a row where they disagree — on the reasoning that ambiguous attribution is not attribution. The reasoning here runs the other way, and it is stated plainly in the code: the cost of keeping a row too long is storage, and the cost of destroying one under hold is the reason holds exist in the first place.
That asymmetry is the whole argument for conservative defaults in retention, and it generalises well beyond this feature. Where the two outcomes of being wrong are "some disk" and "destroyed evidence in a matter under legal hold", there is no version of the calculation that favours precision.
How to work with this
You have a retention policy of your own
Set the windows to match it, per policy
Each of the thirty-two is adjustable from one day to ten years. The defaults are a reasonable starting position rather than a recommendation.
You are under an investigation or a dispute
Place a hold before anything else
A hold names a record type and optionally one record, carries a reason and a placer, and outranks every policy while it is active.
You need a record kept longer than two years
Lengthen that policy rather than relying on a hold
A hold is for a specific matter. A standing obligation belongs in the window.
You want to know what a change would remove
Ask for a dry run
The sweep supports running a policy without deleting, which is the right way to find out what a shorter window would take with it.
What AWRA OpsHub does today
- Thirty-two retention policies created for every workspace covering logs, sessions, notifications, job records, webhook records, report runs, device records and workflow history, each with its own window and each active.
- Windows adjustable from one day to ten years per policy, with an organisation's own changes preserved when defaults are next applied.
- Six installation-level tables pruned globally rather than per organisation, so rows carrying no organisation are still swept.
- A nightly sweep at a quarter past two, running once across servers and never overlapping itself, reporting how many policies ran and how many rows were affected.
- A dry-run mode per policy, so the effect of a change can be measured before it is made.
- Legal holds naming a record type and optionally a single record, carrying a reason, a placer, a start, an expiry, and a release with its own reason and releaser.
- Two independent attribution routes from a row to a held record, with a row matching either one preserved, because destroying a row under hold is the failure the mechanism exists to prevent.
- Holds resolved once per run rather than per policy, since the hold set does not change between them.
- The span of audit-chain sequence numbers removed by a policy tracked across delete batches, so a purge of chained records is accounted for rather than leaving an unexplained break.
More we can add to your workspace
- A summary of what each nightly run removed, kept over time, so retention becomes a trend rather than a nightly event nobody sees.
- A notification when a policy is about to remove an unusually large number of rows, which is the shape of a misconfigured window.
- Retention windows expressed per record rather than per table, for organisations whose obligation varies by the subject of the record rather than by its type.
- A hold placed from the record itself, rather than by naming a record type and identifier.
- An expiring-hold reminder, so a hold with an end date is reviewed rather than lapsing quietly.
- An export of what a policy is about to remove, so records can be archived before they age out.
Where we point you to a specialist
- We will keep the conservative rule where two attributions disagree. A row that might belong to a held record is kept, because the cost of keeping it is storage and the cost of destroying it is the entire reason holds exist. Precision is the wrong objective when the two errors are that unequal.
- How long you are obliged to keep any particular record is a legal question about your organisation, your sector and your jurisdiction, and your advisers answer it. The windows here are operational defaults, not advice, and we would rather you changed them deliberately than inherited them.
- We will not prune business records on a schedule by default. Logs age out because they become a liability; invoices, customers and stock records do not, and a product that quietly destroyed them on a timer would be failing in the one direction that cannot be corrected.
A record of what each run removed, kept over time, is the contained piece here — the sweep already reports its own numbers, and keeping them turns a silent nightly deletion into something an organisation can see and question.
From a nightly sweep to a retention programme
The policies, the windows and the holds all exist and work. What a compliance function needs beyond them is visibility of what is happening and warning before it happens.
A history of what was removed
Rows removed per policy per run, kept, so retention is a trend somebody can look at rather than an event nobody sees.
A warning before a large removal
A notification when a policy is about to take an unusual volume, which is what a mistyped window looks like from the outside.
Archive before purge
An export of what a policy is about to remove, so a record can leave the system without being lost from it.
We publish scope, not dates.
Scope data retentionFive questions to ask about data retention
What is deleted automatically?
A good answer sounds like
A named list with windows.
What ours actually is
Thirty-two categories of operational record, at thirty days, six months, one year or two years, all active by default.
Are business records pruned?
A good answer sounds like
Not without a deliberate choice.
What ours actually is
No. That is a separate system governing deleted records, and it ships switched off.
Can a record be held?
A good answer sounds like
Yes, with substance.
What ours actually is
A hold names a record type and optionally one record, and carries a reason, a placer, a start, an expiry and a release with its own reason.
What happens when attribution is ambiguous?
A good answer sounds like
Preserve.
What ours actually is
The row is kept if it matches either attribution route, because destroying a held row is the failure the mechanism exists to prevent.
Can I see what a change would remove before making it?
A good answer sounds like
Yes.
What ours actually is
A policy can be applied as a dry run, which is the right way to test a shorter window.
Our take
Two things here are worth more than the feature itself. The first is having opposite defaults for two kinds of retention in the same product, and being able to say why: operational records accumulate into a liability and should age out on their own, business records should never be destroyed by a timer nobody chose. Most systems pick one posture and apply it to both, and whichever they pick is wrong for half of what they hold. The second is the rule for ambiguous attribution. Preferring to keep a row that might be under hold, and writing the reasoning down beside the code, is a small decision that will one day be the difference between an awkward conversation and an unrecoverable one. Neither of those is visible on a feature list, and both are the sort of thing worth asking any vendor to explain.
Look at your thirty-two windows once
They are running tonight whether or not anybody has read them. Half an hour comparing them against your own [retention policy](/glossary/retention-policy) is the whole of the work, and it is much easier before somebody asks for a record that aged out.
Talk through retentionFrequently asked questions
Is anything being deleted from my workspace right now?
Operational records, yes — logs, sessions, notifications, job records, webhook records and workflow history, on windows between thirty days and two years, every night at a quarter past two. Business records are not: deleted customers, items and documents are governed by a separate system that ships switched off.
Why are audit logs kept for two years and sessions for thirty days?
Because they answer different questions for different lengths of time. An audit entry may be asked for in an investigation a year and a half later; a session record is transient state that nobody reads after the session ends. The windows track how long each record stays useful rather than applying one number to everything.
Can I change the windows?
Yes, per policy, anywhere from one day to ten years. Your own changes are preserved when defaults are next applied, so adjusting a window is permanent rather than something that reverts. The dry-run mode is the right way to find out what a shorter window would take with it before you commit.
What is a legal hold and when should I place one?
A hold names a kind of record, and optionally one specific record, and withholds it from purging while active. It carries a reason, who placed it, a start and an expiry, and its release carries its own reason. Place one when a matter is live — a dispute, an investigation, an audit — and use a longer window instead when the requirement is standing rather than specific.
What happens if it is unclear whether a row is covered by a hold?
It is kept. There are two ways a row can be attributed to a held record, both are checked where both exist, and matching either is enough. That is deliberately the conservative reading: the cost of keeping a row too long is storage, and the cost of destroying one under hold is the reason the whole mechanism exists.
Why are some tables pruned globally?
Because their rows do not belong to an organisation. Failed jobs and job records belong to the installation, and provider webhook logs may carry no organisation at all — payment providers post to a public endpoint without knowing whose account they are calling about. Pruned per organisation, those rows would match nobody's sweep and accumulate indefinitely.