<!-- Generated from data-retention.html at build time. Do not edit. -->

> Canonical: https://antifailure.dev/data-retention

> How long each thing is kept, how it goes away, and where the period is not exact.

# How long each thing is kept, and how it goes away.

Every period below is one the running system already enforces, or one this page says plainly that it does not. A retention promise the code cannot keep is worse than no promise, because somebody plans around it.

## What is kept, and for how long.

| Run events | A whole number of months, set per deployment. The staging control plane keeps twelve. Unset would keep everything forever, and this is stated because it is the default the software ships with. |

| Account and organization records | For as long as the account exists. There is no automatic expiry, and pretending otherwise would be inventing a sweep that nothing runs. |

| Audit entries | For the life of the organization. The log is hash chained, so removing one entry breaks the verification of every entry after it. Selective deletion from the audit log is therefore not offered rather than quietly unreliable. |

| Sessions | Thirty days at the most, with no extension. Expired rows are deleted by a sweep every five minutes. The stored value is a hash, so an expired row does not hold a usable token even before it is swept. |

| Command line sign-in codes | Fifteen minutes of validity, and the row is removed twenty four hours after it expires. Expiry is checked on every read, so a late sweep costs table size and nothing else. |

| Model provider keys | Removal is an endpoint you can call, not a request you have to send us, and it stops the key working immediately. It marks the record revoked rather than deleting the row, so the encrypted value remains until the row is removed with the organization. Rotating a key does the same to the one it replaces. |

| Contact form messages | Kept until you ask for removal, which is carried out by hand: the role serving public requests holds insert and no select on that table, so there is deliberately no endpoint that reads one back or deletes one. An operator reads the queue on a separate credential and marks each one handled, which is how a request for removal reaches somebody. |

| Careers applications | Removed from the live database by the scheduled maintenance pass once they are older than 180 days, whether reviewed or not. An operator can remove an application sooner. If maintenance fails, removal waits for the next successful pass. Audit records retain a record identifier and action, not the applicant's answers. Existing backups expire on their separate recovery schedule. |

| Database backups | Thirty-five days of point-in-time recovery on production, fourteen on staging. A deletion is reflected in every backup only after that window has passed. |

| Analytics events | Raw analytics events are kept for as long as the deployment sets, and the daily counts computed from them outlive that: a count of page views by channel has nothing in it that identifies anybody. An event carries a keyed hash of the organization rather than its identifier, so the store can count organizations and cannot name one. |

| Operational logs | Ninety days on production and thirty on staging, in Azure Monitor. They hold request paths, status codes and timings, and never a request body, a token or a snapshot. |

| Masked dumps | No deployment stores any today. The storage account for them is not created unless it is explicitly enabled. If it is enabled, a deleted blob is recoverable for thirty days. |

## What the event retention actually does , including the part that is not exact.

The events table is partitioned by month on the timestamp the sender stamped, and retention drops whole partitions. A daily pass creates the months ahead first and unconditionally, because a partitioned table with no partition for an incoming row does not slow down, it fails. Only then does it drop what the retention window has condemned.

Two consequences follow, and both are stated because a customer who plans around a precise number would be planning around the wrong one.

- Granularity is a month, not a day. An event survives until the whole month it occurred in falls outside the window, so it can outlive a twelve month retention by up to a month and a day.

- A drop is permanent. Archiving a month to a file before dropping it is supported by the code and is not switched on in any deployment, so a dropped month is gone rather than moved.

- A late event that arrived after its month was already gone lands in a default partition and is pruned by age, a bounded number of rows per pass, rather than dropped with its month.

- If the daily pass fails, nothing is dropped. An archive that fails costs a retention run rather than the events.

## How to have data deleted, and what happens then.

| How to ask | Write to the privacy contact once it is published. Until then, open a GitHub private vulnerability report, which reaches a person who can act on it without posting anything publicly. Mail is not a route: the domain publishes no mail exchanger, so a request sent to any address at antifailure.dev is delivered nowhere. |

| What happens | Somebody with database access carries the request out by hand. There is no account deletion endpoint and no organization deletion endpoint, so this page does not describe a self-service path that does not exist. |

| How long it takes | Days rather than seconds, and no shorter commitment is made while the work is manual. |

| Backups | A deletion applies to the live database immediately and to backups only as they age out, over the thirty-five day recovery window on production and fourteen on staging. Restoring a backup within that window restores the deleted rows, and any deletion request is applied again afterwards. |

| The audit log | Entries about an organization are removed with the organization. They are not removed individually, for the chaining reason above. |

| A person who asks to be removed | Their personal fields are erased and the account row is kept. The row is kept by choice, not because the database refuses: the audit log references it with ON DELETE SET NULL and the delete would succeed. What it would also do is set a column that is inside the hash chain to null, so every entry that person ever wrote would stop hashing to its recorded hash and the organization’s audit log would report itself as altered. Erasing the fields removes the personal data; deleting the row would remove the ability to prove nothing else had been changed. |

The privacy contact is the one value this page cannot supply: privacy contact to be supplied . It is left blank rather than pointed at an address nobody monitors.

An operator running their own control plane sets these periods themselves. The variables and what each one does are in the control plane reference .

- Privacy Notice What we collect and never take. Read

- Data Processing Agreement Roles, security measures, and obligations. Read

- Subprocessors Who receives data, and who deliberately does not. Read

## Know what happens before you deploy.

Create a disposable production twin for every risky change. Catch migration failures before they reach customers.
