# Privacy policy — Outlier

This is written from the architecture rather than from a template. The source
is not public, so the honest version of that claim is narrower than it sounds:
what you can check is [the method page](/method),
which prints the whole arithmetic, and the app's Forge manifest, which Atlassian
shows you before installing and which either declares an external host or does
not.

Last reviewed: 2026-08-30.

## Who this covers

Outlier is a Jira dashboard gadget built on Atlassian Forge, to be
distributed through the Atlassian Marketplace. It runs inside Atlassian's
infrastructure. It has no servers, no database and no backend of its own.

**Who is responsible for what.** For the ticket data the app reads, the
controller is your own organisation: it is your Jira site, your data, and your
agreement with Atlassian. Outlier is a processor acting on your instruction —
its code runs inside your site, and what it reads does not leave it.

For anything sent to the address below, the controller is **Oleksandr Chmut**,
a sole trader registered in Ukraine, trading as oc — the vendor on the
Marketplace listing. That covers the message, the address it came from, and
whatever the sender chose to put in it.

Reading this page makes you a third: Cloudflare serves it, and the request
that fetched it is a request to a server somewhere. The vendor is the
controller for that too, and the section on cookies says exactly what is
collected.

Contact: support@chmut.com.

## The basis for processing

For the ticket data, the basis is your organisation's rather than ours: the
app processes it under your instruction, on whatever lawful basis you rely on
to run your Jira site. We do not choose the purpose and cannot change it.

For a support message, the basis is legitimate interest — answering a question
somebody chose to ask, and keeping the exchange long enough to answer follow-up
about the same thing. It is not used for anything else: there is no marketing,
no profiling, no list, and nowhere it is sent.

For the contact details attached to a paid licence, which Atlassian passes to
the vendor rather than the person giving them to us, the basis is also
legitimate interest: a vendor has to be able to reach the organisation that
bought the thing, about the thing it bought. The interest is that narrow, and
the section on sub-processors says what is done with them.

For this page, the basis is legitimate interest in knowing that a documentation
site is being read and is not broken, and the interest is served by counts
rather than by anything about a reader.

## What the app reads

From Jira, as the app or as the person looking, depending on the request:

- **Three fields per ticket** — `created`, `updated`, `status`.
- **The ticket's changelog**, from which the app keeps *when a status changed*
  and *the name of the field that changed*.
- **A board's configuration and its saved filter**, to work out which tickets
  are in scope.
- **`labels`**, and only while somebody is configuring a gadget, over up to 500
  tickets, so the form can offer the labels that board actually uses.
- **The board's open sprints**, and only if a gadget was configured to frame
  the card by them. What is kept from a sprint is its name and how much of the
  work in flight sits outside it.

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
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; the first survives
being checked.

## What it asks for

The list an administrator approves at installation, because that screen is the
first thing a security review looks at and it should not be the one place this
document is silent.

Every entry that reads Jira is read-only; the app has no write scope of any
kind. The one that is not a read is `storage:app`, which is the permission to
keep anything at all — the section below on what is stored is entirely about
what it allows, and a list of permissions that left it out would be describing
an app with nowhere to put its arithmetic. It is longer
than the single `read:jira-work` most gadgets ask for, and deliberately so:
that one line grants comments, attachments, worklogs and the whole of every
issue, which would have put "we never read the content of your tickets" beside
a permission granting exactly that.

```
read:board-scope:jira-software        read:issue-details:jira
read:board-scope.admin:jira-software  read:issue-meta:jira
read:project:jira                     read:issue.changelog:jira
read:sprint:jira-software             read:issue-type-hierarchy:jira
read:filter:jira                      read:field:jira
read:jql:jira                         read:field.default-value:jira
read:status:jira                      read:field.option:jira
read:project-role:jira                read:field-configuration:jira
read:application-role:jira            read:audit-log:jira
read:avatar:jira                      read:user:jira
storage:app                           read:group:jira
```

Most of that list is one endpoint's price. Nine of them —
`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` and `read:project:jira` — are what
Jira requires as a **set** to call the endpoint that returns a saved filter.
The app reads one field from that response, `jql`, and never calls a user, a
group or an avatar endpoint at all. It cannot: there is no code that does.

`read:audit-log:jira` belongs to the second group, with `read:issue-details`,
`read:issue-meta` and `read:issue.changelog` — the search that finds the work
in flight and the changelog every fact here is derived from. Jira attaches it
to that call; the app reads no audit log.

Those two are named because they are the ones that look wrong on the screen —
an avatar and an audit log, in a gadget that reads three fields. Naming them is
the point of printing the list: it 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:** its id, when it entered and left each status, and whether it
  is resolved. No summary, no description, no comments, no assignee, no story
  points.
- **Per column:** counts and durations derived from the above, and the
  **status names**, because a column has to be called something on the card.
- **Per board:** the board and filter ids, the timezone and working week, the
  labels a gadget is narrowed by, and — where the card is framed by sprints —
  the name of the open sprint. Not the query: it is composed from those when it
  is needed, and kept nowhere.

**One of those carries text a person wrote, and it is named rather than
buried.** The labels are whatever your team calls things, and they cannot be
stripped: a query narrowed by different words is a query over a different
population.

There were two. The board's query is composed from that board's own saved
filter, and 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. It is no longer stored: nobody types a query into this
app, every clause of it comes from Jira, and the board id, the filter id and
the labels are enough to compose it on the pass that needs it. Said here rather
than quietly removed, because this page was the place the problem was written
down.

**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, rather than by intention.

That is a claim about *fields*, and it used to need saying twice, because the
stored query was one string and a check that refuses a column called `assignee`
cannot read inside a query somebody else wrote. Now it needs saying once: the
query is not kept, so there is no string for a name to be buried in. What is
kept about a board is three identifiers and the labels your team chose.

## 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 app
  meets the conditions of Atlassian's *Runs on Atlassian* programme: the
  manifest declares no external domain, no remote and no outbound fetch.
  Whether the badge is granted is Atlassian's to decide and not ours to
  announce — what you can check today is the manifest itself, which 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.

One control is the exception to the second of those, and it is named here
rather than found later. **Ask Rovo why** appears only where your site has
Rovo, and only when you press it. It opens *your* Rovo, in your own instance,
under your own permissions and on your own credits, with the card's text as the
question — the same text the copy button puts on your clipboard, and nothing
more. The answer goes to you. We never see it, and nothing about it comes back
to us.

## How long it is kept

- A resolved ticket's derived facts: **400 days**, counted from the day it
  closed.
- An **unresolved** ticket's derived facts: kept while the board is watched,
  with no age limit, and this is deliberate rather than an omission. A ticket
  that has sat untouched for a year is the most interesting thing this product
  can find, and expiring it would make a board look calm exactly where it is
  not. What bounds it is the board rather than the clock: the two rules below.
- A board nobody has opened: collection stops after **30 days**, and everything
  derived from that board is deleted after **90**.
- On uninstall: the app deletes its own rows rather than leaving them to
  Forge's 28-day retention window. A board large enough not to fit in the time
  the platform allows is reported rather than silently half-deleted — the run
  records what it could not finish, and Forge's own 28-day window then removes
  whatever is left, so the outcome is the platform's default rather than an
  indefinite remainder. Write to the address above if you need that confirmed
  for a particular site; it is the one path here where deletion is not
  immediate, and it should not have to be discovered.

- When a subscription lapses, collection stops with it. What was already
  derived falls under the same two rules as any unwatched board — nothing is
  collected after that day, and everything derived from the board is deleted
  after 90. Uninstalling does it immediately.

Collection runs on a schedule of the app's own rather than when somebody looks
at a dashboard, so processing happens without a person present — for the boards
that are being watched, and only those. Nothing in it 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.

## Cookies and tracking

**The gadget:** none. No cookies, no tracking pixel, no analytics script, and
nothing loaded from any host.

**This page** is not the gadget. Three things about it, said here because a
reader who opens developer tools after a sentence claiming "no analytics"
should find that sentence was about the right thing:

- It is served by Cloudflare, which sees the request that fetched it.
- It carries Cloudflare Web Analytics — a script that sets no cookie and
  identifies no visitor, and records that a page was fetched.
- Every page runs one script of our own — 193 lines, comments included — and
  all of it is layout and reach. It measures the header so an anchored heading
  lands below it; it makes a wide table or code block reachable from a
  keyboard; on a page with a contents list it marks which section you are
  reading; it opens folded sections while the page is printing, so nothing is
  hidden on paper; and it makes a Copy button copy, by reading text already in
  the page and calling the clipboard, with a fallback for browsers that refuse
  it. It fetches nothing, stores nothing, and sets nothing that outlives the
  tab.

## Where it is held

In your own Atlassian site's Forge storage, in the realm your site is pinned
to. Because Outlier stores in-scope end-user data exclusively in Forge hosted
storage — it declares no external domain, no remote and no outbound fetch —
Atlassian handles hosting, pinning and migration between realms, and the app is
shown as `PINNED` in an administrator's data residency view. If you migrate
your site to another realm, the app's data migrates with it.

One distinction is worth stating rather than leaving to be discovered:
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". Residency covers where data is *stored*. Where a given invocation *runs*
is Atlassian's to decide, and 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, and they are named here because "none" without them
would be true only of the half a reader is not asking about:

- **Apple** hosts the support mailbox, so a message sent to the address above
  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. They are never joined to anything read from a
  board, because there is nothing to join them to: no record the app stores
  names a person.
- **Cloudflare** serves this page, and sees the request that fetched it.

None of the three touches Jira data. All three are listed so the answer stays
true when somebody checks it rather than only when it was written.

## Your rights

The data stays inside your own Atlassian site, and your agreement with
Atlassian covers the platform holding it — not this app, which is a third
party to it. Uninstalling the app deletes what it stored, with the one exception the retention section names: 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. A request about specific data
should go to your Jira administrator first, since they control the site and we
do not hold a copy to search.

For a support message, where the vendor is the controller, write to the address
above to ask what is held, to have it corrected, or to have it deleted. You can
also **object to it being kept at all**: the basis is legitimate interest, so
an objection is a right rather than a request, and the answer is deletion
unless the exchange is still open. The same address handles a request to
restrict processing while a question about it is being settled.

Support correspondence 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, and everything the vendor controls here rests on
legitimate interest. Said
here rather than left out, 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

This is **version 1** of this policy, and the date it was last reviewed is at
the top. Both change together, so a reader who kept a copy can tell whether
they are holding the current one.

A change that alters what is collected, what is kept, how long, or who else
sees it is announced on the listing thirty days before it takes effect, and
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, and it would be strange to
hold the arithmetic to a rule the policy about your data was not held to.
