This is the documentation built into Sojourn, published so you can read it before you install anything. It is the same text the app shows behind its Help button, generated from the app’s own source, so the two cannot say different things. It explains how every figure is defined, which are exact and which are approximate, where the data lives, and what the app will refuse to do.
Every time an issue changes status, Jira records the change in that issue’s history. This app reads those records and turns them into PERIODS: one row for every stretch of time an issue spent in one status, from the moment it entered to the moment it left.
An issue contributes a period only once it LEAVES a status. The stretch it is in right now has no end yet, so it is counted separately, in the "Now" and "Open time" columns, and is never added to the totals or averages. Mixing the two is the most common way a time-in-status number becomes quietly wrong: a ticket that has sat in Review for a year would otherwise drag the average down every day it stays there.
Issues created before the app was installed are included in full. The history comes from Jira’s own changelog, not from watching changes as they happen.
This matters most when you compare against another time-in-status tool. Averages here divide by COMPLETED PERIODS, the count shown in the column beside them, and not by issues, so a tool that divides by issues reports a larger average on exactly the same data: 4-7 times larger in this app’s own test corpus, where issues revisit a status four to seven times on average. Neither figure is wrong. This one answers how long a single stay in the status lasts; the other answers how much time an issue spends there in total across every visit.
The reason this app divides the way it does is that the denominator is then something you can see and check: the Periods column IS the divisor, the open periods are in their own column and are in no average at all, and clicking a project icon - or the key itself, where a project has no icon - opens the distribution the number was computed over, one line per duration band with the count and the share in each. An average whose denominator is not on the screen cannot be checked by the person reading it.
The Date range button limits the report to the time that falls between two dates. Time outside them is not counted. A period that began before the first date counts from that date, and a period still running on the last date is reported as OPEN rather than completed, because it had not finished. The counts, totals and averages are over that time only.
THIS DOES NOT CHANGE WHICH ISSUES APPEAR. To narrow that, put a clause like created >= -90d in the Scope (JQL) box. The two controls answer different questions and confusing them gives a plausible wrong number: one narrows the TIME being measured, the other narrows the ISSUES being measured.
The button carries the range it holds, and the line under the controls names the window the report was actually built with. Those are two different things on purpose: the first is what you typed and the second is what the query used, and if a range is ever refused the page says so rather than showing figures under a window it did not apply.
The date range does not reach the cycle and lead time table. Those are folded once per issue, as a single span each, so there are no period boundaries for a date window to cut. The section says so beside the table rather than looking narrowed.
You choose which statuses count as "in progress" and which count as "done". Lead time is from the issue being created to the first time it reaches a done status. Cycle time is the time it spent in the in-progress statuses.
BLOCKED TIME IS A THIRD LIST, AND THE APP WILL NOT GUESS IT. It is the time an issue spent in the statuses you group as Blocked, summed over its whole life rather than over one pass, and it appears as one column beside cycle and lead time on the same set of issues the row counts. Until you name those statuses in Edit definition the column is empty and says why: a status called Blocked on one board is ordinary work on another, and a figure inferred from a word would be a number under a heading that does not mean what it says.
THE FILTER "Only issues with blocked time" NARROWS THE TABLE TO ISSUES THAT HAVE SOME, and nothing else about the table changes. An issue with no completed blocked period is not an issue with blocked time, and neither is one whose blocked time under working hours is nought because all of it fell outside your calendar - both are left out, for the same reason a zero-length period is left out of every average.
BLOCKED TIME FOLLOWS THE METRIC’S CLOCK. Choose a working-hours metric and the blocked column is working hours too, so the two figures on one row are always measured the same way. It is also a metric in its own right - pick it and the count, total, average, median and p90 in this table are blocked time, with its own distribution behind each row, because it is a span like the others rather than a special case.
CHANGING THE BLOCKED LIST INVALIDATES THE STORED FIGURES, exactly as changing the in-progress or done list does, and the table says so and offers to rebuild rather than showing figures computed under a definition you have replaced. An instance that has never named a Blocked group is not affected by this at all.
A re-opened issue has more than one pass through the workflow, and those passes can differ enormously. In this app’s own test corpus one issue has two legitimate cycle times that differ by a factor of 595. So three figures are stored rather than one: the SUM over every pass, the SPAN of the pass that completed, and the sum within that completing pass. They are different questions and the app refuses to pick one for you.
If you change what "in progress" or "done" means, every stored figure is stale by definition. The app REFUSES to chart the old numbers under the new definition and asks you to rebuild instead. It will not quietly show you a mixture.
TWO CONTROLS AT THE TOP OF THE PAGE DO NOT REACH THIS TABLE, and the section says so in a line under its heading whenever either is on. The dates do not apply here: cycle and lead time are folded once per issue, as a single span each, so there are no period boundaries for a date window to cut, and these figures cover every issue in the rollup. Narrowing them by date is not in this version.
The Working hours toggle does not apply here either, for the same reason: a cycle span is folded once per issue rather than read from the period rows that toggle switches between. This table has its own Metric control instead - pick a working-hours metric there to see these figures inside your calendar.
THE STATUS GROUPS TABLE HAS A ROW CALLED "Working time", AND IT IS NOT THIS NUMBER. It is a rollup of the report table above it: the completed PERIODS spent in the in-progress statuses, on the same per-period denominator as every other row up there. The figures in this section are per ISSUE - one span each, folded once - so the two answer different questions and do not agree, and neither is wrong. The group used to be called "Cycle time" as well, which put one name over two different numbers on one screen; it was renamed rather than explained away.
EVERY ROW OF THIS TABLE OPENS ITS OWN DISTRIBUTION, the same way the report table’s rows do: click the project icon - or the key itself, where a project has no icon - and the shape behind the average opens as a chart and as a table of duration bands, one line each with how many ISSUES fell in it. The bands are counted exactly; only the median and the p90 are read by interpolation inside a band, which is the bound stated beside the table. It follows whichever metric the Metric control is set to and is titled with it, because one project row has a different distribution behind it for each of the eight. There are no working-hours figures in it - out-of-hours time and after-hours activity are facts about a status period, and a row here is one span per issue - and the distribution exports to CSV or Excel like every other view.
Some completed issues have no cycle-time span at all, and the count of them is printed under the table. That is not an error: the pass that finished such an issue never entered a status you marked in progress. They are counted in the rollup and excluded from the span figures, which is why the two counts beside the table differ.
A SPAN OF ZERO IS A DIFFERENT CASE AGAIN, and it is counted apart rather than averaged in. An issue with NO span never entered an in-progress status; an issue with a ZERO span has one whose value is nought - under a working-hours metric that means every minute of its work fell outside your calendar, and under an elapsed one that it was created and completed inside the same millisecond. Neither is a very fast issue, and letting either into an average would drag it towards nothing while looking like speed. The count is printed under the table whenever there is one.
These are two different figures and the difference between them matters more than either of them. The after-hours COUNT is a column in both tables on the page. Both figures appear in full in the drill-down behind any row, and as columns in the export.
OUT-OF-HOURS TIME is how long a period’s clock ran outside your working calendar - elapsed time minus the time inside the calendar, holidays included. IT DOES NOT MEAN ANYONE WAS WORKING. An issue waiting in a queue overnight, over a weekend or over a public holiday collects out-of-hours time while nobody is anywhere near it. It is a fact about the clock and about nothing else, and treating it as a measure of effort would be wrong in a way the number itself cannot tell you about.
AFTER-HOURS ACTIVITY is a count of status changes whose timestamp falls outside your working calendar. A status change is a person moving an issue, recorded in Jira’s own history with the moment it happened - so a status change timestamped at 23:40 on a Sunday is evidence that somebody was working then. This is the only figure here that can be read that way, and it is shown out of the total number of status changes so the share is visible rather than implied. Creating an issue is not a status change and is not counted.
BOTH FOLLOW THE CALENDAR YOU SET, including its holidays, and both are worked out when an issue’s history is read. A store read before a calendar was set has neither, and every one of these figures reads n/a until you set your working hours and rebuild - never a zero, which would claim none of the time and none of the changes were outside working hours, a different statement from not knowing. The same applies if you CHANGE the calendar: the stored figures belong to the old one, so they are refused until a rebuild works them out under the new one.
A DATE RANGE AFFECTS THEM DIFFERENTLY, and the app refuses rather than guesses. Out-of-hours time is NOT shown when a date range is set: a period cut by the range contributes only part of its time, and the share of that part which fell inside working hours cannot be recovered from what is stored, because working hours are not spread evenly through a period. After-hours activity is unaffected - a status change happens at a single moment, so it is either inside the range or outside it. One consequence worth knowing: with a date range set, a period is counted by when it COMPLETED and a status change by when it HAPPENED, so the two figures are about slightly different sets.
ONE OF THE TWO IS IN THE MAIN TABLES AND THE OTHER IS NOT, and which is which is a width decision rather than a judgement about the figures. After-hours activity is a count, so it fits beside columns of days and seconds: it is a column in the report table and in the status-groups table. Out-of-hours TIME is another duration, and a table already as wide as it can be at a half-screen window would have had two of them colliding - a number that collides with the one beside it is worse than a number one click away - so it lives in the drill-down and in the export.
THE "Now" NUMBER ON EACH STATUS ROW IS A LINK. Press it and you get the periods still open in that status, oldest first, each one linked to its issue in Jira. It is the one place in this app that leads to an action rather than to another number.
EVERY ROW IS A PERIOD, NOT AN ISSUE, and the heading says so. A period is one stay in one status. An issue can only be in one status at a time, so the same key appearing twice in one list would mean the store holds two open periods for it - which is a fault worth seeing, so the list never quietly removes the duplicate.
THE AGE COLUMN FOLLOWS THE WORKING HOURS TOGGLE, and its heading says which clock is in force. With the toggle off it is elapsed time. With the toggle on and a calendar saved it is time inside your working hours, worked out live up to this moment. With the toggle on and NO calendar saved it reads n/a, exactly as the after-hours column does in that state - there is no clock to measure against, and a zero would be a claim rather than a gap.
A DATE RANGE INCLUDES A PERIOD THAT STARTED BEFORE IT. The list and the Now count use one and the same rule for WHICH periods appear, so they cannot disagree: a period counts if it had not left the status by the end of the range, however long before the range it began. An issue that has been sitting in Triage since last year is the first thing such a list should show you, not the first thing it hides.
THE AGE IS MEASURED FROM WHEN THE ISSUE ENTERED THE STATUS, and not from the start of the date range. Those are different numbers for every period that began before the range, and the age is the one a worklist needs: "sitting here for 240 days" is the fact you act on, and clipping it to the range would understate exactly the oldest rows - the ones this list exists to put in front of you. The Open time column in the table above is a total FOR THE RANGE and is clipped to it, so that column and these ages legitimately differ. They answer different questions and neither is a rounding of the other.
AT MOST A HUNDRED ROWS, and if there are more the list says so in as many words: it shows the hundred OLDEST. Separately, and in its own sentence, it tells you if any of the rows it fetched are not visible to you in Jira. Those are two different facts - one is a cap, the other is your permissions - and merging them into a single "showing 96 of 250" would let you believe the cap explained something it did not.
THE ISSUES IN A LIST ARE CHECKED AGAINST YOUR OWN PERMISSIONS, one by one, every time you open it. That is a stricter check than the report as a whole gets: a report is limited to projects you can browse, and within such a project an issue security level can still hide an individual issue from you. Aggregates cannot see that; a list of issues can, and does.
THE LINK IS OFFERED WHEN THE TABLE IS GROUPED BY STATUS ONLY. Group by assignee or by issue type and the Now numbers become plain text, because a list that matched one of those rows would be one person’s open work listed issue by issue - and this app does not build per-person time-in-status, which is the thing this whole category is most often misused for. Switch the grouping back to Status only and the links return.
A DISTRIBUTION BAND OPENS THE SAME WAY, and it answers a different question. The count beside a band in the distribution lists the COMPLETED periods in that band, LONGEST FIRST, with the start and the end of each one and the duration it was counted under. That is history rather than a worklist: the Now list is the one that leads to work, and this one tells you whether a long tail is a single pathological ticket or forty ordinary ones. The duration shown is the one the band was counted under, read from the store rather than worked out again, which is why the rows add up to the bar.
A BAND CANNOT BE OPENED WHEN A DATE RANGE AND WORKING HOURS ARE BOTH IN FORCE, and the reason is the same one that makes the figures trustworthy elsewhere. Working time for a period the range cuts in half has to be worked out one period at a time rather than read from storage, so the list could not be guaranteed to contain exactly the periods the bar counted - and a list quietly shorter than the number above it is worse than no list. Clear the date range, or switch Working hours off, and the bands open again.
ONE ISSUE’S WHOLE HISTORY IS A TAB IN THAT SAME LIST. Press History on any row and the tab beside it shows every period that issue has spent in every status, in the order it lived them: the status, when it entered, when it left, and how long that took. The period it is in right now is listed too, with "open" where its end would be, because a story with the current chapter missing is not the story.
THE HISTORY TAB IS NOT NARROWED BY THE DATE RANGE, and it says so on the tab. Every other list here answers a question the controls at the top asked, so the range narrows it. This one answers what happened to one ticket, and a history with part of it cut out is not a history - you would compare it against Jira, find periods missing, and be right to stop trusting the tables it came from.
THE TOTALS UNDER THAT TAB ARE THE ISSUE’S OWN, and they are counted by the same rule the report table counts by: completed periods only, and a period whose clock never ran is named separately rather than averaged in. So the durations on the tab add up to that issue’s share of the row you opened, exactly - which is the property every number in this app is arranged to have, one click deeper again.
WITH THE WORKING HOURS TOGGLE ON, THE TAB SHOWS A WORKING-HOURS COLUMN BESIDE THE ELAPSED ONE, read from storage rather than worked out at the moment you look, so it is the same figure the tables above were built from. If no working calendar has been saved there is nothing to show and the tab says that, rather than printing zeros that would claim the work happened outside your hours.
THE HISTORY TAB IS CHECKED AGAINST YOUR PERMISSIONS TWICE, and neither check trusts the other. The list only offers History on issues it was able to show you, and opening one asks Jira again, as you, about that single issue - because an issue security level sits below the project permission and no project-level answer can see it. A refusal is one sentence with nothing beside it.
A HISTORY LONGER THAN TWO HUNDRED PERIODS IS SHOWN AS ITS FIRST TWO HUNDRED, oldest first, and the tab says so in its own sentence. The totals under it are still the whole issue’s, never the visible page’s: a table whose sums quietly excluded what the cap hid would be short of the row it was opened from with nothing saying why.
THE STATUS-GROUP ROWS DO NOT DRILL IN THIS VERSION. Their Now numbers are plain text. A group is a set of statuses, so its worklist would be a combination across all of them, and that is a different question this version does not answer rather than one it answers badly.
THE LIST IS ONLY AS FRESH AS THE HISTORY IT COMES FROM, which is the line under the main table. Between an issue being deleted in Jira and the app noticing, a Now count can be one higher than the list beneath it - and the second line above is what tells you.
AN ISSUE THAT WAS MOVED TO ANOTHER PROJECT IS SHOWN UNDER THE KEY IT HAS NOW. Opening the list asks Jira what became of every key it could not account for, so a moved issue is re-keyed and listed rather than counted as one you cannot see. Its age does not restart: a move changes an issue’s key, not how long it has been sitting where it is.
Counts, totals, averages, minima and maxima are EXACT. They are computed from every period, not from a sample.
WHAT "EVERY PERIOD" MEANS, precisely, because two kinds are counted apart from the rest and both are named on screen. A period still running has no end yet, so it is in the Now and Open time columns and in no average. A period with a duration of ZERO under the metric you are looking at is counted apart too: under working hours that is a period whose clock ran entirely outside your calendar, and under elapsed time it is one that began and ended inside the same millisecond. The averages divide by what is left, the count of what is left is the column beside them, and the count of what was set aside is printed under the table - so the two add up to every closed period in scope and you can check that they do.
Medians and 90th percentiles are read from a histogram of durations rather than by sorting every period, which is what keeps them fast on a large instance. That makes them approximate, and the page and every export state by how much: the sentence under the table gives the bound that applies to the figures beside it. Counts, totals, averages, minima and maxima are exact and are not read from the histogram at all.
THE DISTRIBUTION CHART’S HORIZONTAL AXIS IS LOGARITHMIC, and it is captioned as such under the chart itself. Every bar is one duration band, the bands are equal in ratio rather than in width - each covers a fixed percentage more time than the one before it - and they are drawn equally wide. So two bars the same distance apart near the left of the chart cover far less time than two the same distance apart near the right, and the shape is a shape of counts rather than an area you can compare across the axis. The heights are exact counts; the table under the chart gives both edges of every band in figures, which is what to read when a number matters more than the shape.
The resolution of that histogram is not a setting. The app uses the finest resolution your store will serve for the grouping you asked for, and steps to a coarser one only if the store refuses - so the bound you are shown is the best this report could do, and it is stated rather than assumed.
Very large reports cannot be built at the finest resolutions. The resolution is not a control you are offered, so there is none to be sent to: the app has already stepped down the whole ladder on your behalf before it says anything. If every resolution it can serve was refused it says that, and asks for a smaller question - one project, or a JQL matching fewer issues - rather than failing, or silently coarsening the chart underneath you and leaving the stated accuracy behind.
The working-hours toggle re-reports every duration as the time inside your working calendar. A ticket raised on Friday afternoon and picked up on Monday morning shows as a few hours rather than three days.
Set your working days, hours, timezone and holidays with the Working hours button. UNTIL YOU DO, NO WORKING-HOURS FIGURE IS WORKED OUT AT ALL. The app does not fall back to a built-in week: a working-hours figure computed in someone else’s timezone is worse than no figure at all, and a column quietly derived from hours you never gave is a wrong number presented as a measurement. So the app asks for the calendar, says the figures are absent until it has one, and rebuilds them once it does.
Working-hours figures are worked out once, when an issue’s history is read. If you change the calendar afterwards, the stored figures belong to the old one, and the app REFUSES to show them under the new definition, and asks you to rebuild instead. Elapsed-time figures are unaffected and stay available throughout.
A PERIOD WHOSE CLOCK RAN ENTIRELY OUTSIDE YOUR WORKING HOURS HAS NO WORKING TIME, and it is counted separately rather than averaged in as a very fast period. A ticket that sat in a queue over a weekend, or an automation that moved an issue at three in the morning, has zero working-hours time - which is a different fact from taking a moment, and folding the two together would drag every average and median towards nothing. The count is printed under the table and in the drill-down behind any row, and it is a column in the export. It is the same treatment time in a status RIGHT NOW gets, for the same reason: a number that is not a duration does not belong in an average of durations. Switching Working hours off shows those periods as the elapsed time they really took.
Business time is real elapsed time inside the calendar, not a nominal count of working days, so a day on which the clock changes for daylight saving is 23 or 25 hours and is reported as such. Business time is never greater than elapsed time, and the app checks that on the stored data rather than trusting the arithmetic.
Periods stored before a calendar was configured have no business figure. They are reported as having no data, never as zero.
The scope box accepts JQL, and that is also how you report on a DATE RANGE. Two examples that work today: created >= -90d for issues raised in the last ninety days, and resolved >= startOfQuarter() for this quarter’s completed work. Combine them with anything else the same way: created >= -30d AND project = ENG.
THE REPORT COVERS ONLY PROJECTS YOU CAN BROWSE IN JIRA. Two people looking at the same scope can see different numbers, and that is correct rather than a fault: every figure on this page - the tables, the averages, the medians, the distributions, cycle and lead time, the counts under them - is worked out over your own projects only. The line beside the totals says how many projects were included. It never says what was left out: Jira does not confirm that a project you cannot browse exists, and this app does not either. Within a project you CAN browse, an aggregate may still include an issue that an issue security level hides from you; per-issue lists do not.
TWO CONTROLS NARROW A REPORT, AND THEY ANSWER DIFFERENT QUESTIONS. The Scope (JQL) box chooses WHICH ISSUES the report covers. The Date range button chooses HOW MUCH OF EACH PERIOD counts. They are often confused, so it is worth being exact: scoping to created >= -90d reports on issues raised in the last ninety days, counting all of their time however far back it runs; setting the Date range to the last ninety days reports on every issue, counting only the time that fell inside those ninety days. Either can be used alone, and they combine.
What the Date range button does, precisely. Only time between the two dates is counted. A period that began before the first date counts from that date rather than from when it started, and a period still running on the last date is reported as OPEN rather than completed - it had not finished, and this app never folds unfinished time into an average. Counts, totals and averages are over that time only, and the Periods column is still exactly the number the average divides by. The button says which dates are in force, so a narrowed report cannot look like a full one. Cycle and lead time are folded once per issue and have no period boundaries to cut, so the dates do not apply to them and that section says so rather than quietly ignoring them.
Which clauses are fast, stated precisely because the difference is seconds. Project, issue type, assignee, current status and CREATED-date comparisons against a literal date are answered from the app’s own store with no call to Jira. Everything else - including relative dates like -90d, any JQL function such as startOfQuarter(), and resolved, which the app does not store - is put to Jira, and the issues Jira returns become the scope. That is correct for any JQL and it costs a round trip: on this app’s own test instance a literal-date scope answers in well under a second while created >= -90d over 1,856 issues took eight.
A clause the app cannot answer from its own store is put to Jira instead, and the issues Jira returns are the scope. What the app will not do is APPROXIMATE one: a JQL that Jira itself rejects, or a scope too large to resolve inside a single request, is refused with the reason, and the page tells you the numbers are unscoped. A report silently scoped by something other than what you typed is the failure this avoids.
Export produces CSV in four parts: the report rows, the status-group rollup, the cycle and lead time table, and a provenance block recording the scope, the resolution and the error bound that applied when the file was made. The provenance is what makes the file readable six months later. Each part downloads as its own dated file, in CSV or Excel, and the text of every part stays on screen to copy.
Excel is offered beside CSV because a CSV has a separator and Excel expects a different one in some locales - where it expects a semicolon, a comma-separated file opens as a single column. The .xlsx has no separator to disagree about, and its counts and durations arrive as numbers rather than as text that looks like numbers, so a column can be summed or charted without being converted first. Both files carry the same columns in the same order: they are written from one definition.
The cycle file carries ALL EIGHT cycle and lead-time metrics, not the one the table is showing: they are folded in a single pass, and a file whose contents depended on which dropdown was open could not be reconciled against anything later. It is one row per grouping per metric, with the metric named in its own column. The provenance records which statuses counted as in progress, which as done, and the calendar the four working-hours metrics were folded under - the app refuses to SHOW figures built under a definition that no longer applies, so a file must not leave without recording its own. A date range does not apply to these figures and the provenance says so.
Every duration is an integer millisecond count rather than a formatted string, and the headline duration columns carry a decimal-hours twin beside them, so nothing downstream has to parse a duration. The column names and their order are stable across releases, so a spreadsheet or BI job built against them keeps working.
Everything this app stores is held in Atlassian’s own infrastructure, in storage provisioned for this installation of the app on your site. Nothing is sent to the vendor, and nothing is sent to any third party. The app makes no outbound network requests at all: it can only talk to your Jira site.
What is stored: for each issue, its key, project, type, current status, assignee display name and creation time; and for each status period, the status, when it started, when it ended, and how long it lasted. The issue summary, the description, comments, attachments and custom fields are never read and never stored. The app does not request them from Jira at all.
The app reads Jira as ITSELF when it BUILDS your history - a background build has no user to run as - so the store holds every project the app can see. What you are SHOWN is a different question: every report is restricted to the projects you personally can browse in Jira, checked as you, on every load, with no caching, so a permission change takes effect immediately. Its settings are instance-wide: the working calendar and the cycle time definition belong to the site, not to you, and anyone who can open the app can change them, which marks the stored working-hours and cycle figures as needing a rebuild. The one thing kept per user is the view you last chose.
TWO SMALL DIAGNOSTIC LEDGERS SIT BESIDE THE HISTORY and neither grows without bound. One records the five-minute keep-warm ping and holds a fortnight of it; the other records when each status change arrived, so the app can tell you whether it is keeping up, and holds thirty days. Older rows are deleted rather than archived. Neither is used for a report and neither is ever sent anywhere.
Uninstalling the app removes its storage, on Atlassian’s own deletion timetable for app data rather than instantly. There is no copy anywhere else, because there was never anywhere else for a copy to be.
WITHOUT AN ACTIVE SUBSCRIPTION the reports and the export are not available and the app stops reading Jira, but NOTHING IS DELETED. The history already worked out stays where it is and appears again as soon as a subscription is active - there is no re-import and no waiting for a rebuild. Whether this site has a subscription is told to the app by Atlassian on each request; it is not stored here and it is not sent anywhere.
The first build reads every issue the app can see and derives its history. It is resumable: if it is interrupted it continues from where it stopped rather than starting again, and it will tell you on this page if it has stopped and needs resuming.
DELETED, MOVED AND ARCHIVED ISSUES ARE FOLLOWED TOO, and this is what keeps the numbers honest over months rather than days. Delete an issue and its whole history leaves this app - not just the period it was sitting in, all of it - because an issue nobody can find is not part of what your process did. It is never "closed" with an end time instead: that would invent a duration and put it into your averages. Move an issue between projects and it keeps ONE history under its new key rather than becoming two issues. Both happen within seconds when Jira tells the app directly, and within the hour otherwise - deleting a whole PROJECT sends no message about its individual issues, and archiving an issue sends none at all, so an hourly check is what catches those. If a check ever finds an implausible number of issues missing at once it removes nothing and waits: a bad answer from Jira must not be able to empty this store.
ALL OF THAT KEEPING-UP STOPS WHEN A SUBSCRIPTION LAPSES, on purpose. Neither the hourly check nor the live listener runs for an unlicensed installation, so none of your Jira request budget is spent on an app you are not paying for. Nothing is deleted when that happens - the history simply stops being brought up to date, and starts again from where it left off once a subscription is active.
After the first build the app keeps up automatically as issues change status. It does not need to be re-run.
The app limits itself to 25 requests per second against your Jira site regardless of what the rate limits would allow, so building history does not slow Jira down for anyone else.
Averages divide by COMPLETED PERIODS, the count beside them, and not by issues. So a tool that averages per issue reports several times more on the same data (4-7x on this app’s own test corpus). Both are legitimate, and this one answers how long a single stay in the status lasts.
After-hours changes counts status changes timestamped outside your working calendar, holidays included. A status change is somebody moving an issue, so one outside working hours is evidence that a person acted then - it is a count of actions, not an amount of time. Creating an issue is not a status change and is not counted. Open a row to see it against the total number of changes, alongside out-of-hours time. "n/a" means the figure has not been worked out for those rows yet - rebuild to see it.
Sojourn is a Jira Cloud app by Lichen. Privacy policy · Support: support@lichenapps.com