82 tickets, one priority, zero signal

82 tickets sat in “Highest” in the JIRA queue for a legacy SaaS product, assigned to me, unresolved. When I pulled the full history on them, 75 had been re-stamped to Highest on the same day. Not over a stressful week, not as an accumulation. Same day. Whatever had generated that batch, it wasn’t triage, it was a bulk update, and it had quietly erased any ordering the priority field used to carry.

I only noticed because someone asked me for a sorted summary of what was pending in my Highest queue, and I went to go get it.

The CLI that couldn’t answer the question

ops-tools has a wrapper for that JIRA, invoked as ops-cli next and ops-cli view. next is described as “oldest ticket in my working queue (priority=Working, assigned to me).” I ran it expecting it to hand me something close to what I needed, the top of the pile.

It returned two tickets. Because next only reads from the Working priority tier, not Highest, and Working had exactly two items in it. That command was built to answer “what’s the next thing I touch right now,” a single-item pull from a tiny, already-curated bucket. It was never built to rank 82 tickets against each other, and running it against the wrong tier told me nothing about the 75-ticket pile actually blocking the view. That was the wrong turn: I’d assumed a CLI wrapper named after the exact workflow I wanted would do the ranking for me. It didn’t, because it wasn’t built to, and the ten minutes I spent poking at --help output and re-running next against the wrong tier was the cost of finding that out.

So I went around it and queried JIRA directly.

What the raw counts showed

jql = 'assignee = "ops.staff" AND resolution = Unresolved'

282 unresolved tickets total. Broken out by priority:

Highest: 82, High: 136, Working: 2, Medium: 60, Lowest: 1, Low: 1

Of the 82 Highest, 7 were sitting in a Parked/Waiting dev-status, which left 75 that were both unresolved and actionable. Comparing created against updated on those 75 confirmed the bulk-stamp: same-day timestamp, no other differentiation. The priority field had stopped meaning “prioritized.” It had become a dumping ground that happened to be labeled Highest.

Scoring what the field couldn’t tell me

The fix wasn’t to argue with whoever ran the bulk update, or to hand-retriage 75 tickets one at a time in JIRA. It was to build a second, derived ranking on top of the same 75 tickets using fields that were still carrying real information, even after priority had flattened out.

I pulled four fields per ticket to stand in for RICE:

  • Reach: components and labels, as a proxy for how much of the product surface a fix touches.
  • Impact: the problem description, stored in an ADF (Atlassian Document Format) custom field, customfield_10104, parsed with adf_to_text() into plain text so I could actually read what was broken.
  • Confidence: a dev-status custom field, customfield_10514, whose values (Prepared, Prototype, Parked, Waiting) told me how far along the diagnosis already was.
  • Effort: story points, customfield_10022.

None of those four fields is “priority.” That’s the point. Priority had been overwritten by whatever process stamped 75 tickets Highest in one pass. Reach, impact, confidence, and effort hadn’t been touched by that pass, so they still carried the differentiation the priority field had lost.

The fetch script itself hit one dumb snag on the way: my first version tried to write the pulled JSON straight into a scratchpad path under the session’s project directory, and it failed with a plain FileNotFoundError, because that directory didn’t exist yet and nothing had created it. Small, but it meant the second script had to build the fetch and the write in one pass instead of assuming a working directory was already there for me. Cheap lesson, still a lesson: don’t assume scaffolding exists just because the path looks conventional.

A ticket, not a retriage

Once the four inputs were in, I scored and ranked all 75, then wrote the whole ranked list into a new ticket created just to hold it, type “NO CODE,” rather than going back and rewriting the priority field on 75 live tickets. Editing the field directly would have meant touching JIRA history on every one of those tickets and asserting an ordering I’d have to defend line by line. Writing the ranking into its own ticket kept the underlying data untouched and gave anyone who opened the queue a real answer to “what’s actually next,” sourced from fields that hadn’t been flattened by the same bulk action that broke priority in the first place.

The failure mode generalizes past this one queue. Any status field that gets touched by bulk operations, whether it’s a priority flag, a workflow state, or a label, is going to decay toward uselessness the same way: not because anyone lied about it, but because a single sweep can overwrite months of individual judgment in one commit. The fields that survive that kind of sweep are the ones nobody bulk-edits, like story points, descriptions, and dev-status notes tied to actual work done. When the field you trust goes flat, the move isn’t to fight the flattening. It’s to find the fields the flattening didn’t reach and rank against those instead.