A teammate couldn’t find a lot of tickets in the 3.362 release diff… wait, let me give the corrected post.
One of our engineers couldn’t find a lot of tickets in the 3.362 release diff. Fifty-eight tickets shipped, and when he checked the develop-to-master range for their commits, a chunk of them just weren’t there.
I pulled six of the missing ones and read them one at a time. None of them were actually missing work. They broke into three categories. First, the code lived in a different repo entirely: one ticket was attributed to the API repo, not the main app repo, so it never showed up in a main-repo diff no matter how hard you looked. Second, some had already shipped as a hotfix days earlier, so by release day master already had the commit and develop’s diff against it was empty by definition, not by omission. Third, a handful lived in the internal Jira-automation repo, which has no release branch at all, no develop, no master, nothing for a diff tool to even point at.
Three different reasons, all legitimate, all completely invisible from the same symptom: “not in the diff.” That’s the trap. A single Boolean signal was standing in for three unrelated states, and he had no way to tell which one he was looking at from the ticket alone.
the field that should have told him
Every ticket carries a Repo field, customfield_11202, and it exists exactly to answer this question. If it’s populated, you can tell in one glance whether a ticket belongs in a given release’s diff. When I went and actually pulled all 58 tickets in 3.362 and cross-referenced Repo against the real git history, the field was empty on 16 of them.
Sixteen out of fifty-eight, more than a quarter of the release, gave you nothing to work with. He wasn’t wrong to be confused. He was looking at tickets that had already shipped, or shipped somewhere else, or shipped nowhere near a diff, with no field telling him which. The ticket said STAGING/LIVE, the diff said nothing, and the only way to resolve that contradiction was to go read commit messages by hand, repo by repo, which is what I ended up doing for six tickets before I saw the pattern and stopped guessing at the rest.
I backfilled all 16, matching each one against its actual commit history and stamping the right repo(s).
the part I got wrong first
My first instinct was to write a stricter validator into the close-transition script, the same script that already gates the terminal JIRA transitions on Story Points and Sprint before it’ll let a POST through. I added Repo to the required-fields check for transition 101 and ran it against a batch of open tickets to see what would break.
It broke immediately, and not in the way I expected. A chunk of tickets from the internal Jira-automation repo got stuck, because they have no repo to declare. They don’t ship through develop/master at all, so “which repo did this ship in” isn’t a field you can fill in for them, it’s a question that doesn’t apply. Forcing Repo at close time for a ticket type that structurally can’t have one just moves the failure earlier and makes it worse: now you can’t close the ticket at all instead of just being unable to audit it later. I reverted the check within the same session and opened a new ticket to track a real fix.
The actual fix isn’t a required-field gate at close, because close-time is the wrong checkpoint for a repo-topology question. It’s a release-time audit: before a version goes out, sweep every ticket on the fixVersion, and any STAGING/LIVE ticket with an empty Repo field and no clean sidecar exemption gets flagged before anyone opens the diff. That’s the actual gap the new ticket is meant to close: catch it at the release gate, where the diff comparison already happens, not at individual ticket close where the repo topology of a bot’s own tickets doesn’t fit the question being asked.
The pre-release scan already does something adjacent to this, reconciling the develop/master diff against the sprint and flagging phantom refs and false-deploys. It just wasn’t checking whether the Repo field existed at all, only whether it matched what the diff said once populated. An empty field passed silently through a check built to catch mismatches, because an empty field isn’t a mismatch, it’s a missing question.