How to measure your Jira linking rate
A repeatable way to work out what share of your merged code actually connects to a Jira issue, including the key-matching traps that make the first number you get wrong.
Someone above you has asked what shipped last quarter, and the honest answer is that you can account for maybe two thirds of it. The rest exists as merged pull requests that connect to no Jira issue. Before you fix that you need to know how big it is, and “linking rate” is the number that says so.
It is a simple metric with three or four ways to get it wrong. Here is how to get a number you can defend.
Define it before you measure it
Linking rate is the share of merged code changes in a window that resolve to exactly one Jira issue. Every clause in that sentence is doing work.
Merged, not opened. Open pull requests are in flight and may still get their key. Counting them makes your number look worse than reality and makes it move for reasons that have nothing to do with behaviour.
Code changes, not commits. Count pull requests. Commit counts are dominated by whoever rebases most and tell you about git habits rather than traceability.
In a window. Fix it, usually a calendar month or a quarter. Rolling windows are harder to explain in a room.
Exactly one issue. A pull request referencing seven keys is not seven times as traceable. Usually it is a batch merge or someone pasting a sprint’s worth of keys. Count it, but count it separately, because it behaves differently.
And decide your exclusions up front, in writing: bot-authored dependency bumps, automated release commits, reverts. These will never carry keys and including them permanently depresses your number for no useful reason. Whatever you exclude, write it down, because the first question anyone asks about a number like this is what is in it.
Measure from the git side, not from Jira
The instinct is to start in Jira, because that is where the reporting lives. Resist it. Jira can only tell you about issues it knows about, and the entire point of this exercise is to find work Jira has never heard of. If you measure from Jira you are measuring the numerator against itself.
So: pull the list of merged pull requests from GitHub, GitLab or Bitbucket for the window, and match against the key pattern. Every one of those hosts exposes merged pull requests over its API with the fields you need, and every one paginates, so expect a loop rather than a single call.
The pattern itself is where people go wrong. A Jira key looks like an uppercase project prefix, a hyphen, and a number. The naive regular expression for that shape produces false positives immediately: UTF-8, SHA-256, ISO-8601, an old key from a tracker you migrated off, an AWS instance type, half a date. If you have ever seen a linking rate report claim a hundred and four percent coverage, this is why.
The fix is one extra step. Pull the actual list of project keys from your Jira instance and constrain the pattern to those prefixes only. Then, for each candidate match, confirm the issue exists. That second confirmation catches typos, deleted issues, and keys from a project that was archived two reorganisations ago.
Two details about Jira keys specifically that will bite you. When a project key is renamed, Jira retains the old key so old references still resolve, which is good for humans and confusing for scripts, because the same issue can appear under two strings in your history. And when an issue moves between projects it acquires a new key. If you are counting distinct issues rather than distinct pull requests, deduplicate on the issue id you get back from the lookup, never on the string you matched.
Then check the reverse direction
The git-side number tells you about unlinked code. The Jira-side number tells you about unevidenced work, and it is often the more uncomfortable of the two.
Query issues that reached a done state during your window, and check how many have any development activity attached. Where source control is connected to Jira, that activity appears on the issue as branches, commits and pull requests. Jira can surface some of this in filters, but the exact syntax available for querying development data depends on how the connection was made and which version you are on, so use the field autocomplete in your own instance rather than copying a query from anywhere. Failing that, the same answer is available by looking up each closed issue against the set of keys you matched on the git side, which you already have.
An issue closed with no code behind it is not automatically wrong. Plenty are duplicates, configuration changes, or decisions. But if a quarter of your closed issues have nothing attached, your delivery reporting is largely self-reported, and that is worth knowing before someone else works it out.
The number you get first
- Regex on the general key shape
- Includes bots and release automation
- Counts commits, not pull requests
- One repository, presented as the org
The number you can defend
- Constrained to real project keys, then verified
- Documented exclusions
- Pull requests merged in a fixed window
- Per repository, with the spread shown
What to do with the number
Report it per repository, not as one average. Linking rate is almost never uniformly distributed. One team with a strong habit and one team with none average out to a mediocre figure that describes neither and prompts a blanket intervention that annoys the compliant team. The spread is the finding.
Sample the misses by hand before acting. Take twenty unlinked pull requests and read them. You will usually find two or three distinct causes, not one: a team using a different tracker, a repository where everything is done through a terminal, a bot you forgot to exclude, and genuine untracked work. Each needs a different response and only the last is a behaviour problem.
Fix the cheap causes first. Adding a pull request template with a key line, and telling people that a key in the title works when the branch is already named, closes more of the gap than anything else you can do in a week.
Re-run it monthly and keep the definition frozen. A linking rate that moves because someone changed the exclusions is not a trend, and you will be asked.
Keeping this current across a lot of repositories is where the scripting starts to cost more than it returns, and it is the point at which continuous reconciliation between source control and the tracker becomes a tooling question rather than a scripting one. That is what GroundTruth does, with full two-way sync for Jira. But for one or two repositories, a scheduled script and a spreadsheet is genuinely the right tool and you should not buy anything.
Where this breaks down
A high linking rate proves association, not quality. Every pull request can carry a valid key while the issues themselves say “various fixes” and carry no acceptance criteria. You have made the work traceable, not legible, and the two get conflated in exactly the meeting where this number gets presented.
Chasing a hundred percent creates its own damage. Hard enforcement produces keys copied from whatever issue was nearest, and issues created solely to satisfy the check. Both look like compliance and both degrade the data. Somewhere between eighty and ninety percent with honest exclusions beats ninety-nine with pressure behind it.
The number can move without behaviour changing. A team joins with a different convention, a repository is archived, a bot starts opening more pull requests. Annotate the series with what changed, or someone will read a step change as a result.
It may not be your bottleneck. Poor linking is a symptom, and if the underlying problem is that requirements are vague and review is overloaded, better keys will not touch it. Measure this because you need traceability, not because it is the easiest thing to count.
The takeaway
Measure from the git side, constrain your key pattern to real project keys and then verify each match, freeze your exclusions in writing, and report per repository rather than as one average. Then check the reverse direction, because closed issues with no code behind them is the number that changes conversations.
If you do one thing this week: pull last month’s merged pull requests, match them against your actual project keys, and read twenty of the misses. The causes will not be what the team assumed.