Ticket hygiene
Two detectors for tickets that need a human nudge: work that landed but was never handed to review, and open tickets that drifted from their original scope.
Admin -> Stale tickets is one page with two independent detectors. Both
answer the same question - which tickets need a nudge? - but they derive the
signal in completely different ways, so they live in separate tabs with their
own settings and their own cost.
| Tab | Signal | Cost |
|---|---|---|
| Landed, not handed to review | structural: still in progress, has a linked commit, no activity for N working days | none, one database pass |
| AI staleness | an AI model scores how far an open ticket has drifted from its original scope (0-100) | AI tokens per scanned ticket |
Both tabs require the admin:staleness:read permission; running a scan needs
admin:staleness:scan, dismissing a row needs admin:staleness:write.
Super-admins hold all three, and every role that holds admin:system:write
receives them automatically.
Landed, not handed to review
Added in v0.177.0 This detector is structural and free: it looks at the ticket's status, its linked commits and its activity, nothing else.
The gap this closes
Review lanes and work-next --role review pick up tickets in the in review
category. An implementer who lands the commit but never moves the ticket
leaves it on in progress, where no reviewer ever looks. The work is
finished, often already released, and invisible to the whole review flow.
The rule
A ticket is flagged when all of these hold:
- its status category is in progress;
- at least one commit is linked to it, so the git integration has to be ingesting for this detector to see anything;
- nothing has happened for N working days. "Something happened" means the latest of a linked commit, a comment, or a status change;
- its delivery mode is neither epic nor admin. Neither ever expects a commit, so "has a commit but is idle" says nothing about them.
Working days exclude weekends, public holidays and company closures, using the same calendar as absence durations, so a Friday hand-off is not nagged on Monday morning. Regional holidays resolve against the ticket's first assignee; an unassigned ticket uses the region-independent holiday set.
Editing a field (title, description, labels) is deliberately not activity. Retitling a landed ticket is not handing it to review.
What happens when a ticket is flagged
- The flag is persisted and shown on the tab. When the ticket stops qualifying - someone commented, pushed or moved it - the next scan clears the flag, so the list always reflects the current state.
- The assignees are notified with the Landed but not handed to review notification. In-app delivery is on by default, email is off - a nightly hygiene nudge is not inbox-worthy. The nudge respects a cooldown, so a second scan inside that window sends nothing. An unassigned ticket is still listed for the operator, it just has nobody to notify.
- Optionally, the ticket is moved to the project's first in review status. Only when auto-move is switched on, see below.
Settings
Admin -> System Settings -> Ticket hygiene
| Setting | Default | Meaning |
|---|---|---|
| Landed-but-unreviewed threshold (working days) | 2 | Working days of silence before a landed ticket is flagged. 0 switches the detector off and empties the tab on the next pass. |
| Auto-move landed-but-unreviewed tickets to In Review | off | Move a flagged ticket to the project's first in review status. |
| Landed-but-unreviewed nudge cooldown (minutes) | 1440 | How long before the same ticket may nudge its assignees again. Matches the daily scan. |
Auto-move
Off by default on purpose: this is a nudge, not a forced transition. When you turn it on, a flagged ticket is moved once, and the transition is written to the ticket's activity feed without an actor - the activity tab shows it as "System", which is exactly what happened.
The move does not run the approval or dependency gates that a done transition runs. In review is a hand-off inside the work, not a completion claim, and the point is to make the ticket visible to a reviewer who then applies those gates. If a project has no in review status configured, the move is skipped and logged; the flag and the nudge still happen.
When it runs
- Daily in the early morning (UTC), right after the AI staleness scan.
- On demand with Scan this project now or Scan all projects now on the
tab, or through the API (
POST /admin/landed-idle/scan, optionalprojectId). A project-scoped scan only touches that project's flags.
What agents see
The detector exists so the agent that left the ticket behind notices it the next time it orients:
- The session-start briefing lists in-progress work with a
LANDED, IDLEmarker and the number of working days, together with the instruction to verify and move the ticket rather than re-implement it. - Every
work-nextanswer, including "nothing ready", carries the caller's own landed-idle tickets in that project. An agent that finds no new work is exactly the agent that should be told it left finished work on in progress.
Operator actions
- Review opens the ticket.
- Dismiss until the next scan removes the row. This is a snooze, not a mute: the next scan raises the flag again if the ticket is still landed and idle. The honest way to make it disappear is to move the ticket.
Scans and dismissals are recorded in the audit log.
AI staleness
The second tab. One AI call per eligible ticket returns a drift score with
reasons and a suggested action. Above the comment threshold the scanner writes
its assessment as a comment on the ticket; above the label threshold it also
attaches the possibly-stale label. It never edits a description and never
closes anything - triage on this page makes the final call.
| Setting | Default | Meaning |
|---|---|---|
| AI staleness scanner Added in v0.177.0 | off | Workspace switch. While it is off every entry point short-circuits, so the scan is safe to leave deployed before you opt in. Exposed in System Settings since this version; earlier releases needed a direct configuration change. |
| AI staleness: minimum ticket age (days) Added in v0.177.0 | 30 | Tickets younger than this are never scored. |
| Score for a comment | 60 | Score at or above which the scanner comments its assessment. |
| Score for the label | 80 | Score at or above which it also attaches possibly-stale. |
| Comment author | first bot account | Which user the AI comment is written as; falls back to the first super-admin. |
Runs daily in the early morning (UTC) and on demand per project from the tab.
The two detectors are independent: the landed-idle tab keeps working with no AI provider configured at all.