Skip to content

fix(jira): key task presets on statusCategory instead of resolution - #16809

Closed
pax-d wants to merge 2 commits into
stablyai:mainfrom
pax-d:fix/jira-preset-status-category
Closed

pax-d wants to merge 2 commits into
stablyai:mainfrom
pax-d:fix/jira-preset-status-category

Conversation

@pax-d

@pax-d pax-d commented Aug 27, 2026 •

Copy link
Copy Markdown

ELI5

Orca's Jira tab has four preset filters (Assigned, Reported, Done, All Open). They decide whether an issue is finished by looking at Jira's resolution field. That field is not filled in automatically - a Jira admin has to add a "Set Issue Resolution" post-function to the workflow, and plenty of projects never do. In those projects every issue keeps an empty resolution forever, so Orca thinks finished work is still open, and the Done tab comes up almost empty. This switches the presets to statusCategory, which Jira always fills in no matter how the workflow is set up.

What Changed

filterToJql() in src/main/jira/jira-issue-search.ts now builds all four preset queries from statusCategory instead of resolution:

Preset Before After
Assigned assignee = currentUser() AND resolution = Unresolved assignee = currentUser() AND statusCategory != Done
Reported reporter = currentUser() AND resolution = Unresolved reporter = currentUser() AND statusCategory != Done
Done assignee = currentUser() AND resolution IS NOT EMPTY assignee = currentUser() AND statusCategory = Done
All Open resolution = Unresolved statusCategory != Done

ORDER BY updated DESC, the function signature, and every other code path are unchanged. The function is now exported so it can be unit tested. The Jira tab's raw JQL search box is untouched.

Added src/main/jira/jira-issue-search.test.ts.

Why

This is a correctness bug, not a preference.

resolution is a Jira system field, but nothing populates it on its own. It is set by a workflow post-function on the transition into a done status. Company-managed projects created without that post-function leave resolution null on every issue, permanently. Team-managed projects generally look fine because they fill it on the move into the Done category - which is exactly what makes this easy to miss.

Two things then go wrong:

  1. In JQL, resolution = Unresolved is effectively an alias for resolution IS EMPTY. A null resolution matches it, so completed issues are returned as open by Assigned, Reported, and All Open.
  2. resolution IS NOT EMPTY matches nothing, so Done comes up empty.

There is a mirror-image failure in the other direction: if a workflow reopens an issue without clearing resolution, that genuinely open issue vanishes from Assigned.

Measured on one project of a Jira Cloud site whose Done transition has no resolution post-function (counts from the REST API):

statusCategory = Done         1782
resolution IS NOT EMPTY        131
resolution IS EMPTY           1652
resolution = Unresolved       1652   <- identical to IS EMPTY

The Done preset misses 1,651 of 1,782 completed issues, and those same issues show up under Assigned as if they were still open.

statusCategory has none of this coupling. Every status maps to exactly one of To Do, In Progress, or Done, and that mapping is a property of the status itself rather than of the workflow. It is long-standing JQL on both Cloud and Server/DC; I verified the queries against Cloud, and the authType === 'server' branch in this file selects a different search endpoint rather than different query semantics, so it is unaffected either way.

This also lines up with the repository's provider-neutral guidance in CONTRIBUTING: keying generic behavior on resolution assumes a per-organization workflow configuration, and silently misbehaves for organizations that do not share it.

On the Done literal

statusCategory = Done uses an English literal, so I checked whether it survives a non-English Jira instance rather than assuming it. On a Jira Cloud site running a Korean locale, where the category's display name renders as 완료:

statusCategory = Done      1782
statusCategory != Done        1
statusCategory = done      1782
statusCategory = 3         1782
statusCategory = "완료"        0   <- localized display name does NOT match

The English literal is the form JQL accepts; the localized display name is the one that fails. So the readable literal is also the portable one, and there is no reason to reach for the numeric category ID.

Linked Issue

Fixes #16808

Visual Proof

Both shots are the Assigned preset's query, run against a project whose Done transition has no resolution post-function. Issue titles and assignee names are blurred; the Key and Status columns are what matter.

Before - resolution = Unresolved, the current preset query. Every row carries a "Done" status badge, in a filter that is supposed to list open work. The result header reads Done 50 / 50 shown.

BEFORE

After - statusCategory != Done, this PR's query. 0 shown, empty state. That is the correct answer: I have no open issues assigned to me in that project.

AFTER

Two notes on how these were produced:

  • I ran the preset queries through the Jira tab's search box rather than rebuilding the app, since this change only alters the string filterToJql() returns. The rendered result is what the preset produces.
  • I added a project = ... clause to both queries to isolate the affected project. The presets themselves are site-wide, and without that clause the 50-row cap fills up with issues from projects that do populate resolution, which hides the bug rather than showing it.

For the Done preset the same site gives 115 issues before and 1,160 after, but that pair does not make a useful screenshot: both sides hit the 50-row cap and look identical. The counts are in the Why section above.

Testing

New unit tests in src/main/jira/jira-issue-search.test.ts cover all four presets, assert that no preset JQL contains resolution, and assert the ORDER BY updated DESC suffix is preserved.

I checked that they actually catch this regression rather than just passing: reverting filterToJql() to the old implementation fails 5 of the 6, and restoring the fix passes all 6.

Verified locally on Linux (Node 24, matching engines):

  • pnpm lint, pnpm typecheck, pnpm build - clean
  • pnpm test - one failure, which predates this change and is unrelated to it (details below). src/main/jira is fully green: 8 files, 89 tests
  • The changed-code gates CI runs on a PR - check:code-quality:changed, check:react-doctor:changed, check:zustand-selector-fanout, the reliability / max-lines / runtime-electron ratchets, and the root-directory guard - all clean

On that one failure: my first full run showed 15 failures across 14 files, but 13 of those files were my environment rather than the code. Twelve src/main/browser/*.electron.test.ts files need xvfb-run, which I had not installed, and tests/e2e/cross-version-wire/cross-version-browser-placement.unit.test.ts needs tag v1.4.184 present locally, which my --depth 50 clone lacked. After installing xvfb and fetching the tag, 13 of the 14 pass.

The one that remains is src/shared/runtime-client-export-parity.test.ts, which hard-codes the expected export list of runtime-types. TERMINAL_PTY_DEGRADATION_CAPABILITY and TERMINAL_UNAVAILABLE_ERROR_CODE were added in 5631aa0 (#16398) without updating that list. It reproduces on a clean checkout of main with nothing applied, so I left it alone rather than widen this PR's scope. Happy to file it separately.

The behavior change was also exercised against a live Jira Cloud site by running the before and after JQL through the REST API; the counts above come from that site.

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

AI Disclosure

Written with Claude Code (Claude Opus 5). The JQL claims here were checked against a live Jira Cloud instance rather than taken from the model.

Review

  • Cross-platform: no platform-specific code. The change is four string literals in a pure function; no paths, shells, processes, or shortcuts involved.
  • SSH/remote/local: none. filterToJql() produces a JQL string that is sent to the Jira REST API over HTTP by the existing caller. No local filesystem or process assumptions are added or removed.
  • Agent/integration compatibility: this makes the Jira integration less dependent on a per-organization assumption. statusCategory is supported on Jira Cloud and Server/DC alike, so the existing authType === 'server' search-path branch in this file keeps working unchanged. No other integration or git provider touches this function.
  • Performance: none. Same number of queries, same maxResults, same fields. statusCategory is an indexed system field like resolution.
  • UI quality: no UI change. The presets now return the issues their labels already promised; the rendering path is untouched.
  • Security: no new input reaches the JQL string. All four queries remain hard-coded constants with no interpolation, so there is no new injection surface, and no credential, token, or user data handling is touched.
  • Backwards compatibility: projects that do populate resolution correctly see the same issues as before, because for them "resolution is set" and "status is in the Done category" agree. Only the misconfigured-workflow case changes, and it changes to the correct result.

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Security: no change to credential handling or request construction; the queries stay constant strings.
  • Cross-platform: no platform-conditional code.
  • Remote SSH: unaffected; this runs in the main process and talks to the Jira REST API.
  • Mobile: no mobile-specific code paths touched.
  • Backwards compatibility: see Review. Correctly configured projects are unaffected.
  • Performance: no additional requests or work in any hot path.

Checklist

  • This PR is small and focused
  • I explained what changed and why (including ELI5)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

Author

X: @chung297

@coderabbitai

coderabbitai Bot commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 757c44f1-bf09-4bde-9951-35b6b13288cb

📥 Commits

Reviewing files that changed from the base of the PR and between 377ed1a and 1c1d24f.

📒 Files selected for processing (1)
  • src/main/jira/jira-issue-search.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/jira/jira-issue-search.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

filterToJql is now exported from jira-issue-search.ts. Its presets use statusCategory to distinguish done and non-done issues. The assigned and reported filters use currentUser(). The done filter selects assigned issues with Done status. Tests cover all presets, verify that queries omit resolution, and verify descending update ordering.

Priority: ➖ Normal — Impact reflects medium issue severity.

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 1c1d2

Jira preset filters now use status categories for open and done issue selection, with tests covering each preset. No current merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: Jira task presets now use statusCategory instead of resolution.
Description check ✅ Passed The description covers the required sections, explains the problem and solution, links issue #16808, includes visual proof, documents testing and the known unrelated test failure, and addresses compat…
Linked Issues check ✅ Passed The implementation satisfies issue #16808 by changing all four Jira preset filters from resolution-based checks to statusCategory-based checks. The added tests cover each preset and preserve ordering …
Out of Scope Changes check ✅ Passed The changes remain within scope. Exporting filterToJql and adding unit tests directly support verification of the Jira filter correction; no unrelated product or infrastructure changes are included.
  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pax-d

pax-d commented Sep 8, 2026

Copy link
Copy Markdown
Author

No CI has run on this PR. PR Checks and PR test LoC are in action_required on
head 1c1d24fd and need a maintainer to approve the runs. track-community-pr is
pull_request_target, which is why it's the only check present.

  • src/main/jira/jira-issue-search.ts has no commits on main since this branch was
    cut. No rebase needed; PR is MERGEABLE.
  • Local: vitest run src/main/jira/jira-issue-search.test.ts 6/6, oxlint and
    oxfmt --check clean.
  • CodeRabbit Docstring Coverage is 33% (threshold 80%). filterToJql is documented;
    the other two counted functions are it() callbacks in the new test file.

Fixes #16808.

@pax-d pax-d closed this Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Jira preset filters key on resolution, so they show the wrong issues in projects without a resolution post-function

1 participant