Privacy policy — Outlier
This page is written from the architecture, not from a template. The source is not public, but two things are checkable without it. The method page prints the whole arithmetic. The app's Forge manifest is shown to you by Atlassian before you install, and it either declares an external host or does not.
Last reviewed: 2026-11-01.
This is version 5. The app has not changed since version 4; this site has: it now has a support form, and this edition says what the form sends and the check that runs before it does: The support form. See Changes.
At a glance
- Your Jira sitethree fields per ticket and its changelog, for the boards a gadget watches. Read on the app's own schedule as the app, and each time a card is drawn or a rule asks for it, as that person.
- Outlier, inside Atlassiankeeps when each ticket entered and left each status, in Forge storage on your own site. The rest of the changelog is discarded where it arrives.
- The vendorthe contact details on a paid licence, from Atlassian, and whatever you write to support. Application logs of counts, durations and field names. Ten of the app's logging statements name a card or its board, and a failed request to Jira is logged with the ids in its path. Never ticket content, as the security page sets out.
- Anywhere elsenothing. The manifest declares no external domain, no remote and no outbound fetch.
Every record the app keeps, and how long it lives, is in one table under How long it is kept. Uninstalling the app deletes its rows, with one exception for a board too large to finish.
Contact: support@chmut.com.
Who this covers
Outlier is a Jira dashboard gadget built on Atlassian Forge. It is distributed through the Atlassian Marketplace. It runs inside Atlassian's infrastructure. It has no servers, no database and no backend of its own.
| Who | Their part |
|---|---|
| Your organisation | Controller for the ticket data the app reads. It is your Jira site, your data and your agreement with Atlassian |
| Outlier | Processor for that data, acting on your instruction. Its code runs inside your site, and what it reads does not leave it |
| The vendor, Oleksandr Chmut, trading as oc | Controller for anything sent to the support address, for the contact details on a paid licence, and for visits to this site |
| Atlassian, Apple, Cloudflare | Around the app rather than in it. See Sub-processors |
The vendor is Oleksandr Chmut, a sole trader registered in Ukraine, trading as oc, and the vendor on the Marketplace listing. For a support message that covers the message, the address it came from, and whatever the sender chose to put in it.
This site is covered too. outlier.chmut.com is a set of pages — this policy, the method, the security page, pricing and the rest — and Cloudflare serves every one of them. A request that fetched one is a request to a server somewhere, and the vendor is the controller for that too. Cookies and tracking says exactly what is collected.
The basis for processing
| Data | Basis | What that interest is, and no wider |
|---|---|---|
| The ticket data | Your organisation's, not ours: whatever lawful basis you rely on to run your Jira site | The app processes it under your instruction. We do not choose the purpose and cannot change it |
| A support message | Legitimate interest | Answering a question somebody chose to ask, and keeping the exchange long enough to answer follow-up about the same thing |
| The contact details on a paid licence | Legitimate interest. Atlassian passes them to the vendor; the person did not give them to us | A vendor has to be able to reach the organisation that bought the thing, about the thing it bought |
| A visit to this site | Legitimate interest | Knowing that a documentation site is being read and is not broken. Served by counts, and by nothing that identifies a reader |
| The check on the support form | Legitimate interest | Keeping a form on a static site from being used by scripts to send mail. It runs only on the support page, and only to decide whether a message is sent |
A support message is not used for anything else. There is no marketing, no profiling, no list, and nowhere it is sent. Sub-processors says what is done with the licence contacts.
What the app reads
From Jira, as the app or as the person looking, depending on the request.
| What | When | Why |
|---|---|---|
Three fields per ticket: created, updated, status | Each collection pass, for the boards being watched. And each time a card is drawn or a rule asks for it, for up to 300 tickets in flight, as that person | When the ticket moved |
| The ticket's changelog | With the three fields, on the same occasions | The app keeps when a status changed and the name of the field that changed |
| A board's configuration and its saved filter | Each collection pass. The configuration also each time a card is drawn or a rule asks for it, as that person | To work out which tickets are in scope, and whether that person can see the board at all |
labels, over up to 500 tickets | Only while somebody is configuring a gadget | So the form can offer the labels that board actually uses |
issuetype, over the same tickets | Only while somebody is configuring a gadget | So the form can offer the kinds of work that board actually carries |
| The site's status names, one list for the whole Jira | Each collection pass with a board due | A column has to be called something on the card, and it has to be classified. A status the app has never seen is a column it cannot judge |
| The boards you can open, by name | Setting up a gadget, and drawing the card | So a gadget can be pointed at one, and so the card can say which board it is watching |
| Which tickets each board still holds, by id and nothing else | Only after a board is forgotten, by the hourly sweep, as the app, until every ticket row has been checked | To delete the rows of tickets no board left on the site holds. Per ticket |
| The board's open sprints | Only if a gadget was configured to frame the card by them, each time that card is drawn or a rule asks for it | The card prints a sprint's name and how much of the work in flight sits outside it. What is stored of a sprint is its id |
Collection runs on a schedule of the app's own, not when somebody looks at a dashboard. So processing happens without a person present, for the boards that are being watched, and only those.
The card reads Jira too. Each time it is drawn, or an Automation rule asks for its morning, it reads the work in flight again, as the person looking or the person whose rule it is. That read writes no row per ticket. What it keeps is the two rows per card, when the board was last looked at and whether it still means what the gadget was set up against in the board's rows, and the day it rendered in the installation's row.
What is used, and what is dropped
Stated precisely, because it is the claim a security review will test.
- Jira's changelog endpoint has no field filter. The response therefore does carry the old and new text of summary and description edits, and the name of whoever made each change.
- All of it is discarded at the boundary. Nothing derived from it is computed and nothing derived from it is written anywhere.
The honest sentence is "the app reads only how tickets moved", not "content is never sent to us". The second would be easy to disprove with a proxy. The first survives being checked.
What it asks for
The list an administrator approves at installation. That screen is the first thing a security review looks at, so this page is not silent about it.
read:board-scope:jira-software
read:board-scope.admin:jira-software
read:project:jira
read:sprint:jira-software
read:filter:jira
read:jql:jira
read:status:jira
read:project-role:jira
read:application-role:jira
read:avatar:jira
storage:app
read:issue-details:jira
read:issue-meta:jira
read:issue.changelog:jira
read:issue-type-hierarchy:jira
read:field:jira
read:field.default-value:jira
read:field.option:jira
read:field-configuration:jira
read:audit-log:jira
read:user:jira
read:group:jira- Every entry that reads Jira is read-only. The app has no write scope of any kind.
storage:appis the one that is not a read. It is the permission to keep anything at all. What the app stores is entirely about what it allows.- The list is longer than the single
read:jira-workmost gadgets ask for, on purpose. That one line grants comments, attachments, worklogs and the whole of every issue. It would have put "we never read the content of your tickets" beside a permission granting exactly that.
Most of the list is one endpoint's price.
| Scopes | Why they are there |
|---|---|
Nine: read:application-role:jira, read:avatar:jira, read:filter:jira, read:group:jira, read:issue-type-hierarchy:jira, read:jql:jira, read:project-role:jira, read:user:jira, read:project:jira | Jira requires them as a set to call the endpoint that returns a saved filter. The app reads one field from that response, jql. It never calls a user, a group or an avatar endpoint. It cannot: there is no code that does |
Five: read:audit-log:jira, read:avatar:jira, read:field-configuration:jira, read:issue-details:jira, read:issue-meta:jira | Jira requires them as a set to call the search that finds the work in flight. Jira attaches read:audit-log:jira to that call. The app reads no audit log |
read:issue.changelog:jira, with read:avatar and read:issue-meta | The changelog endpoint, for a ticket whose history is too long to arrive with the search. It is the one call that needs read:issue.changelog |
The first two rows are there because they look wrong on the screen: an avatar and an audit log, in a gadget that reads three fields. Printing the list makes the shape of the request checkable against Jira's own documentation rather than against our word.
What the app stores
In Atlassian Forge storage, on your own site. Nothing anywhere else.
Per ticket
One row per ticket: when it entered and left each status, and whether it is resolved. A resolved ticket's row lives 400 days from the day it closed; an unresolved one has no age limit while a board on the site holds it. When a board is forgotten, the rows of its tickets that no other board holds go with it.
The ticket row and the index of when each is due, in full
- In it: its id and its key, the
ACME-123you see on the card and click through to. When it entered and left each status. Whether it is resolved. - Not in it: no summary, no description, no comments, no assignee, no story points.
- Written: by collection, and by the one-off walk through a board's history, for the boards being watched.
- Why: it is what the changelog is reduced to. Everything else in it is discarded.
- Lives: resolved, 400 days, counted from the day it closed, or until no board on the site holds it, if that is sooner. Unresolved, with no age limit, for as long as a board on the site holds it.
- Deleted by: the 400 days, for a resolved ticket. A board that stops being read: once it is forgotten, the hourly sweep asks Jira which of the site's tickets the boards left still hold, a hundred at a time, and deletes the rows no board holds. The last board on the site to be forgotten: then every ticket's row goes, up to five hundred an hour. Uninstalling the app.
An unresolved ticket has no age limit on purpose. A ticket that has sat untouched for a year is the most interesting thing this product can find. Expiring it would make a board look calm exactly where it is not. The boards bound it, not the clock.
A ticket's row belongs to the site, not to a board. Two boards that hold the same ticket share one row, so forgetting a board cannot delete its tickets on the spot: another board may hold the same one. Instead the hourly sweep checks every ticket row against the queries of the boards left, asking Jira as the app, and deletes the rows none of them holds. A board nobody has opened for thirty days still counts until it is forgotten in its turn. A request that fails deletes nothing, and the check is asked again an hour later. The check keeps no list of a forgotten board's tickets: what it keeps is where it has got to.
When each resolved ticket is due:
- In it: for each week, the ids of the resolved tickets whose 400 days end in it, and the moment each one does.
- Not in it: no ticket key and no status.
- Why: so deletion reads the week that is due, not every ticket row on the site.
- Written: by collection and the walk, as they write a resolved ticket.
- Lives: until its week comes due and the rows it names are deleted.
- Deleted by: the hourly sweep, as its tickets go. The last board on the site that stops being read. Uninstalling the app.
Per column
Counts and durations per column, derived from the ticket rows, with the status names and no ticket key. Kept while the board is read; a month of finished stays older than 360 days goes sooner.
The column rows and the copy a card reads, in full
- In it: counts and durations derived from the per-ticket rows. The status names, because a column has to be called something on the card.
- Not in it: no ticket key and no ticket id. A finished stay is kept as when it ended and how many working days it took, filed by the month it ended in.
- Written: by collection, for the boards being watched.
- Lives: while the board is read. A month of finished stays older than the widest window a norm reads, 360 days, is deleted before then.
- Deleted by: a board that stops being read. Uninstalling the app.
One more row per board copies the norms and how far each column still learning has got, so a card reads one row rather than several. Collection writes it when either changes. Nothing in it is not already in the rows above, and it lives and goes with them.
Per site
The list of status ids and names your Jira defines, the same list any user of your site can see. Kept until the app is uninstalled.
The site's status list, in full
- In it: the list of status ids and names your Jira defines. It is the same list any user of your site can see. It is read from Jira, not derived from anything.
- Why: so a card need not ask Jira for it every time somebody opens a dashboard.
- Written: by collection, and only when Jira's list differs from the one kept.
- Lives: until the app is uninstalled.
Per board
Three rows for each board a gadget points at: its settings, how it was last read, and how far the walk through its history has got. All three live while the board is read. The labels a gadget is narrowed by are kept, and they are text a person wrote; the query is not. The record of the last read can name a ticket key, when the read failed on one.
The three board rows, the labels and the query, in full
Its settings:
- In it: the board and filter ids. The timezone, the working week and the working hours. The labels and kinds of work a gadget is narrowed by. The columns a team named as review. The ids of the gadgets that point at it, and the days it was first and last looked at.
- Not in it: the query. It is composed from the board id, the filter id and the labels on the pass that needs it, and kept nowhere. Nor a sprint's name: a card framed by sprints prints it, and keeps only the sprint's id, in what the card last said.
- Written: each time a card is drawn or a rule asks for it, and by collection when the board's saved filter changes.
- Lives: while the board is read.
- Deleted by: a board that stops being read. Uninstalling the app.
How it was last read:
- In it: when collection last read the board, how many tickets it saw and wrote, and whether that read was complete. Whether reading the board is failing, since when, and how many times in a row. The message of the last failure: it names the path Jira was asked, with the query removed and the ids left in, so a board id, a filter id, or the key of a ticket whose history was being paged. When the board's own filter last moved.
- Kept of the query: a short hash of it. It answers the one question it was kept for: whether the board still means what this gadget was set up against. It cannot be read back.
- Why: so a card can say how fresh it is, and say a board has gone dark rather than look calm.
- Written: by each collection pass, at the end of the walk through the board's history, and when a card is drawn.
- Lives: while the board is read. Each write replaces the last.
- Deleted by: a board that stops being read. Uninstalling the app.
The walk through its history:
- In it: how far the one-off walk through the board's history has got: the moment it reached, and the ids of the tickets at that edge. Counts of what it has read, and the ids of the columns it found. While it runs, each unfinished stay it saw, as a column, its role and a number of working days. Those are emptied when the walk finishes.
- Not in it: no ticket key.
- Why: a walk takes many invocations, and each has to know where the last one stopped.
- Written: by the walk, a chunk at a time, when a board is first set up or needs reading again.
- Lives: while the board is read.
- Deleted by: a board that stops being read. Uninstalling the app.
The labels carry text a person wrote, and they are named here rather than buried. They are whatever your team calls things. They cannot be stripped: a query narrowed by different words is a query over a different population.
The query is not kept because it can name a person. It is composed from the board's own saved filter. A saved filter quite ordinarily reads assignee in (...) or reporter = "someone@example.com", so an address belonging to a person could sit in a stored row. Nobody types a query into this app. Every clause of it comes from Jira.
Per card
Two rows for each card, both written when the card is drawn or a rule asks for it: what the card last said, and its last 60 mornings as counts per age. Both live while the board is read.
The two card rows, in full
Neither is written by collection.
What the card last said:
- In it: the ticket keys it named and the columns it showed. For each column, how much work was in flight and how much was past the usual wait, and the usual wait a named column was measured against. Whether the card spoke on each of the last ten mornings: the row of squares. The ids of the sprints it was framed by. When it was drawn, and which version of the method its reader was last told about. The same again for the morning before.
- Why: so the next morning can tell what is new from what was already said, and tick off only what a reader was shown.
- Written: when a card is drawn or a rule asks for it, on a working morning, and only when it has something to add.
- Lives: while the board is read. Each write replaces the last.
- Deleted by: a board that stops being read. Uninstalling the app.
The last sixty mornings, as ages:
- In it: for each morning, for each column work can wait in, how many tickets had stood there for how many whole working days. A count per age.
- Not in it: no ticket key and no ticket id.
- Why: it is the sample for checking whether the setting chosen at install is still the one this board would choose.
- Written: when a card is drawn or a rule asks for it, on a working morning whose read was current and complete.
- Lives: the last 60 mornings. An older one is dropped as a new one is added.
- Deleted by: a board that stops being read. Uninstalling the app.
Per installation
Three rows, each one for the whole site and none about a board: the days a card rendered in its first thirty days here, where deletion last stopped, and how far the check of ticket rows after a forgotten board has got.
The three installation rows, in full
The first thirty days:
- In it: the day a card first rendered here, and the day offsets on which one rendered again, for thirty days and never after. A date and a list of whole numbers.
- Not in it: no identifier, and nothing that could become one.
- Why: it answers whether the app was used rather than merely installed.
- Written: when a card renders, in those first thirty days.
- Lives: until the app is uninstalled.
- Deleted by: uninstalling the app, with everything else.
Where deletion last stopped:
- In it: a position in the app's own storage, the last week of due tickets cleared, and when it ran.
- Why: each pass deletes a capped number of rows, so the next one has to know where the last one stopped.
- Written: by the hourly sweep that deletes expired rows.
- Lives: until the app is uninstalled.
- Deleted by: uninstalling the app, with everything else.
How far the check of ticket rows has got:
- In it: whether a check is owed, a position in the app's own storage, and how many boards have been forgotten since it began.
- Not in it: no ticket id, no board id. The point of it is that no list of a forgotten board's tickets stays behind.
- Why: the check after a board is forgotten runs over many hourly passes, so each has to know where the last one stopped.
- Written: when a board is forgotten, and by each sweep that checks a page of rows.
- Lives: until every ticket row has been checked against the boards left.
- Deleted by: the sweep that finishes the check. Uninstalling the app.
No per-person field
No per-person field, anywhere. Not assignee, not reporter, not the account id of whoever moved a ticket. This is enforced by a check that refuses such a field at the boundary, not by intention.
That is a claim about fields. A check that refuses a column called assignee cannot read inside a string somebody else wrote. The query is not kept, so there is no such string for a name to be buried in. What is kept about a board is identifiers and the labels your team chose.
When a board stops being read
| What happens | What follows |
|---|---|
| Nothing reads a board: no dashboard opened, no rule asking for its morning | Collection stops after 30 days, and everything kept for that board is deleted after 90 |
| A subscription lapses | Collection stops with it. What was already derived falls under the same two rules: nothing is collected after that day, and everything kept for the board is deleted after 90 |
| The app is uninstalled | The app deletes its own rows at once, rather than leaving them to Forge's 28-day retention window |
The per-ticket rows are not the board's. A ticket two boards hold has one row, so the rows of a forgotten board's tickets go once the hourly sweep finds that no board left on the site holds them. Per ticket says how.
A board too large to delete in the time the platform allows is reported, not silently half-deleted. The run records what it could not finish. Forge's own 28-day window then removes whatever is left. So the outcome is the platform's default, not an indefinite remainder.
It is the one path here where deletion is not immediate. Write to the address above if you need it confirmed for a particular site.
What the app never does
- Send anything to any host other than your own Atlassian site. There is no analytics endpoint, no vendor backend and no third-party service. The manifest declares no external domain, no remote and no outbound fetch, and Atlassian has granted the app its Runs on Atlassian badge on that basis: it is under Trust signals on the listing. The manifest itself is what Atlassian shows you before you install.
- Send anything to a language model from the pipeline. Every number on the card is arithmetic and every sentence is written. Nothing is generated, and the product works unchanged for a site with no AI of any kind.
- Produce any output about an individual person. Nothing in collection decides anything about a person. There is no profiling, no scoring and no automated decision with a legal or similarly significant effect, because there is no per-person output for one to be made from.
Ask Rovo why
One control is the exception to the second of those.
- Where: only where your site has Rovo, and only if the platform says the person reading has it.
- When: only when you press it.
- What it opens: your Rovo, in your own instance, under your own permissions and on your own credits.
- The question: the card's text, the same text the copy button puts on your clipboard. With it, the ticket keys the card counted rather than listed, one sentence saying what an Outlier card is, and the request itself.
- Nothing new in it: no kind of data the card does not already show you. Ticket keys, column names, and how long work has been waiting.
- The answer: goes to you. We never see it, and nothing about it comes back to us.
- No model of ours: none is deployed by this app, and none is called on its behalf.
How long it is kept
Each record's lifetime is set out in its own section above. This table is the index.
| Record | Lives until |
|---|---|
| Per ticket, resolved | 400 days after it closed, or sooner when no board on the site holds it |
| Per ticket, unresolved | No age limit while a board on the site holds it |
| Per ticket, when each resolved one is due | Its week comes due and the rows it names are deleted |
| Per column | The board stops being read; a month of finished stays older than 360 days, sooner |
| Per column, the copy a card reads | The board stops being read; each write replaces the last |
| Per site | The app is uninstalled |
| Per board, its settings | The board stops being read |
| Per board, how it was last read | The board stops being read; each write replaces the last |
| Per board, the walk through its history | The board stops being read |
| Per card, what the card last said | The board stops being read; each write replaces the last |
| Per card, the last sixty mornings | The newest 60 mornings are kept; all of them go when the board stops being read |
| Per installation, the first thirty days | The app is uninstalled |
| Per installation, where deletion last stopped | The app is uninstalled |
| Per installation, how far the check of ticket rows has got | The check finishes |
| Anything kept for a board nobody reads | Collection stops after 30 days; deleted after 90. Its tickets' rows go once no board left holds them |
| Everything the app stores, on uninstall | Deleted at once; a board too large to finish, by Forge's own 28-day window |
| A message sent through the support form | 30 days in the form's database, or sooner on request. Answering it starts support correspondence |
| Support correspondence | 24 months, or sooner on request |
| The contact details on a paid licence | While the licence is live, and for a year after it ends |
Cookies and tracking
The gadget: none. No cookies, no tracking pixel, no analytics script, and nothing loaded from any host.
This site is not the gadget. It loads one analytics script on every page and, on the support page alone, Cloudflare's check that a person is sending the form. All of it is listed here.
- Cloudflare serves it, and sees each request that fetched a page.
- Cloudflare Web Analytics is a script that sets no cookie and identifies no visitor. For each page fetched it records the page, the page that linked to it, the visitor's country, the kind of device, the browser and operating system, how the page was reached, and how quickly it loaded and responded. The vendor sees those as totals and averages.
- Cloudflare Turnstile runs on the support page and nowhere else. Before the form sends, it reads signals from the browser and the connection, the IP address among them, to tell a person from a script, and gives the form a token saying which. What Cloudflare does with those signals is set by its own terms for Turnstile.
- One script of our own handles layout and keyboard reach. It fetches nothing, stores nothing, and sets nothing that outlives the tab.
Every page runs one script of our own — 256 lines, comments included.
What the script does, line by line
- measures the header, so an anchored heading lands below it;
- makes a wide table or code block reachable from a keyboard;
- on a page with a contents list, marks which section you are reading;
- opens folded sections while the page is printing, so nothing is hidden on paper;
- keeps a screenshot in the theme you are reading in when you change that theme, and opens one over the page when you ask for a closer look;
- makes a Copy button copy, by reading text already in the page and calling the clipboard, with a fallback for browsers that refuse it.
The support form
The support page has a form. It is another way to write to support@chmut.com, not a different thing.
- What it sends: the address you type, your name if you type one, and the message. Nothing about you is added to them: not the page that led you to the form, not your IP address. What is kept beside them is the time it arrived and which product's form it came through.
- The route: the form posts to a Cloudflare Worker at this site's own address. The Worker asks Turnstile whether the token is valid and was issued for this site, passing your IP address along with the token, and nowhere else. It then keeps the message in a Cloudflare D1 database held in the European Union, where support reads it. If it cannot keep it, its log says why and does not name the sender.
- Kept for 30 days, answered or not, and then deleted by a daily sweep. A request to support@chmut.com has it deleted sooner.
- The answer comes from support@chmut.com, so from there the exchange is support correspondence like any other, and kept as long as that is.
Where it is held
In your own Atlassian site's Forge storage, in the realm your site is pinned to.
- Outlier stores in-scope end-user data exclusively in Forge hosted storage. It declares no external domain, no remote and no outbound fetch.
- So Atlassian handles hosting, pinning and migration between realms. The app is shown as
PINNEDin an administrator's data residency view. - If you migrate your site to another realm, the app's data migrates with it.
Residency covers where data is stored, not where it runs. Atlassian's documentation notes that Forge "may sometimes execute an app's invocation from a location other than the location where the host Atlassian app is". Where a given invocation runs is Atlassian's to decide. In every case it is Atlassian's own infrastructure. Nothing in this app reaches any other host.
Sub-processors
None for the app. Nothing it reads leaves your Atlassian site, so there is no third party to name: no analytics, no vendor backend, no model, no host of ours anywhere in the path.
Three exist around it. "None" without them would be true only of the half a reader is not asking about.
| Who | What it does |
|---|---|
| Apple | Hosts the support mailbox, so a message sent to the address above, and the answer to one sent through the support form, is stored on iCloud. That is the correspondence the vendor controls, not anything from your board |
| Atlassian | Passes the vendor the contact details attached to a paid licence: a technical contact and a billing contact, which your organisation gave them rather than us. The vendor is the controller for those, uses them only to answer a question about the licence, and keeps them while it is live and for a year after it ends |
| Cloudflare | Serves this site, sees each request that fetched a page, and receives what the analytics script in Cookies and tracking reports. On the support page it runs the check named there, and keeps a message sent through the form for 30 days, in the European Union |
The licence contacts are never joined to anything read from a board. There is nothing to join them to: no record the app stores names a person.
None of the three touches Jira data. All three are listed so the answer stays true when somebody checks it, not only when it was written.
Your rights
| Data | Where the request goes |
|---|---|
| The ticket data | Your Jira administrator first. They control the site, and we do not hold a copy to search |
| A support message | The vendor, who is the controller. Write to the address above to ask what is held, to have it corrected, or to have it deleted |
The ticket data stays inside your own Atlassian site. Your agreement with Atlassian covers the platform holding it. It does not cover this app, which is a third party to it. Uninstalling the app deletes what it stored, with the one exception: a board too large to finish inside the time the platform allows leaves a remainder, which the platform's own 28-day window then removes.
For a support message:
- You can object to it being kept at all. The basis is legitimate interest, so an objection is a right rather than a request. The answer is deletion unless the exchange is still open.
- You can ask to restrict processing while a question about it is being settled, at the same address.
- It is deleted after 24 months, or sooner on request. A figure rather than a criterion: "as long as needed to answer a follow-up" is unauditable, and a mailbox with no rule in it is a mailbox that keeps everything.
- Portability does not apply to any of it. The right covers data processed on consent or on a contract. Everything the vendor controls here rests on legitimate interest. It is said here because a list of rights that names five and skips one reads as an oversight.
If you are in the EU or the UK and believe either has been handled wrongly, you can complain to your national supervisory authority. You are not required to raise it with us first, though we would rather you did.
Changes
Version 5 adds the support form: what it sends, the check that runs before it does, and the 30 days Cloudflare keeps it for. The app has not changed since version 4, and neither has what is kept from support correspondence or for how long.
It takes effect at once rather than after thirty days' notice. It covers only a message you choose to send through the form, which did not exist before, so nothing already collected goes anywhere new.
Version 4 is the first edition laid out for reference. It names records the earlier editions left out, and corrects one place where they were wrong, both set out below.
The app changed once since version 3. Every edition said that what was kept for a board nobody reads is deleted after 90 days. Until this edition took effect, the app kept an open ticket's row for as long as any other board on the site was read, because two boards that hold a ticket share its row. It now checks each such row against the boards left and deletes the ones none of them holds: Per ticket. That was a fault in the app, not in the editions, and the fix makes it keep less, not more. So it takes effect without the thirty days' notice below, which is owed for keeping more or for longer.
Nine things earlier editions left out, version by version
Nine times an edition has been narrower than the product rather than wrong about it. Each time the categories of data were unchanged.
- Version 1 described the Rovo question as the card's text and nothing more.
- Version 2 listed what is stored per ticket, per column, per site and per board without naming the row kept for the installation itself.
- Version 3 did not say that the vendor can read the app's logs, which carry counts, durations and field names, name a card or its board in ten places, and log a failed request with the ids in its path. At a glance now does.
- Version 3 did not say that a card reads the work in flight each time it is drawn or a rule asks for it, as that person. What the app reads now does.
- Version 3 did not name the two rows kept for each card: what the card last said, and its last sixty mornings as ages. Per card now does.
- Version 3 did not name the row kept for how each board was last read, whose last failure can name a ticket key. Per board now does.
- Version 3 did not name the row kept for the walk through a board's history, which holds the ids of the tickets at its edge. Per board now does.
- Version 3 did not name the index of when each resolved ticket is due, which holds ticket ids. Per ticket now does.
- Version 3 did not name the row where deletion last stopped, and called the installation's row the only one not about a board. Per installation now does.
An earlier edition also named the board's query among the records carrying text a person wrote. It is no longer stored, and Per board says what is kept instead.
The one place the first three editions were wrong
The first three editions listed the open sprint's name among what is kept per board. A card prints it and stores only the sprint's id.
Every earlier edition is published below with its own digest. All of them change together, so a reader who kept a copy can tell whether they are holding the current one.
| Change | What happens |
|---|---|
| Alters what is collected, what is kept, how long, or who else sees it | Announced on the listing thirty days before it takes effect. The previous version stays available on request |
| Anything smaller: a clearer sentence, a corrected figure | Moves the review date and not the version |
The method has been versioned from the beginning. It would be strange to hold the arithmetic to a rule the policy about your data was not held to.
This edition
The file below is the authoritative text of this edition. This page renders it and adds navigation and this block, so the page and the file are not byte-identical - it is the file that governs, and the digest is over the file.
Current — in force from 2026-11-01 — privacy.md 39 KB
c27efa01be62eb184bafc085c1d6d4c144fe3fa224e66c135c28dda836da25c3
Earlier editions, with the dates each was in force
Earlier — in force 2026-10-06 to 2026-11-01 — privacy-2026-10-06.md 36 KB
998d2d0a453fbce9dc97311816da898a479d343fdabc544afd7f1c3ebf2413cf
Earlier — in force 2026-09-19 to 2026-10-06 — privacy-2026-09-19.md 19 KB
549a9078b4b4481809eba0903786f107349e8dadca5c2d729e77f5f1464e1f1c
Earlier — in force 2026-09-01 to 2026-09-19 — privacy-2026-09-01.md 19 KB
054c5540bd3e0ceca232ecf5e59f0589ee59d346df70bcd4b8ea62c90f8ee0f9
Earlier — in force 2026-08-30 to 2026-09-01 — privacy-2026-08-30.md 17 KB
b25d445fc6e6115bc72de2c8721fbac673744e1d40fa4ce15e7c9f353f1ba843
Check it in one line, and the output is the answer rather than something to compare
against: curl -sL https://outlier.chmut.com/privacy.md | shasum -a 256. With the file
already downloaded, shasum -a 256 privacy.md says the same.
On Windows, Get-FileHash privacy.md -Algorithm SHA256 in PowerShell,
which prints in capitals - the comparison is case-insensitive.
The .md files download rather than open in most browsers,
which is what the digest is computed over. The digest is published by us: it shows the
file has not drifted or been altered in transit, and it is not a third-party
attestation.