---
title: "The release said LIVE. The code was not."
canonical: https://dxdev.com/blog/2026-05-12_release-said-live/
datePublished: 2026-05-12
---
While cutting the next release, `git log master..hotfix/3.348.12` returned commits on a ticket JIRA called shipped. ITEM-6934 was STAGING/LIVE, Fix Version 3.348.12 stamped, transition 101 already fired. The final merge to master had never run.

## How the wrong state looked official

The HTO Hotfix Release Flow ends in a merge to master, a tag push, and Bamboo deploying on that push. Transition 101, which moves a ticket to STAGING/LIVE, belongs at that final step, not before.

What happened on 3.348.12 was that the agent working the ticket fired transition 101 at the develop merge, one step early. It identified the develop merge as a milestone and fired as instructed, which was correct by the spec it had. The spec did not say: only fire this after master is also merged. The transition accepted the input, JIRA updated, and the agent moved on.

So JIRA showed the ticket as LIVE because a transition had fired. The fix version was stamped because the transition payload included it. Every JIRA field that tracks doneness agreed: the ticket was done. The repo said otherwise, and nothing was checking the repo.

The process produced confident-looking state without grounding it in the artifact that actually mattered.

## Running the release after the fact

I had to run the real flow for 3.348.12 after discovering the drift. `hotfix/3.348.12` still existed with the right commits, so the merge-to-master step was one command, Bamboo deployed on push, same as it would have originally.

From a user perspective nothing broke, since the code was already in develop and had been through staging. The master lag was a process gap, not a functional one.

But that framing obscures something. The gap was real enough that `git log master..hotfix/3.348.12` returned unmerged commits on a ticket JIRA called shipped. Any automation reading JIRA status to make downstream decisions would have been working off a lie. Any audit treating STAGING/LIVE as "merged to master" would have been wrong. I had one case of each in my own tooling, and I had to manually reconcile both after finding the drift.

## What I added to close the gap

I updated `ben_hq/jira/item_close.py`, the orchestrator that drives JIRA transitions when a ticket closes. It now checks `git log origin/master..hotfix/<version>` before allowing a LIVE transition on any hotfix ticket. If the hotfix branch has commits that master does not, the script halts with an explicit error. The close fails closed: no ticket reaches LIVE status while the repo says the merge is pending.

Beyond that guard, I added a PreToolUse hook in Claude Code's settings to block any agent-initiated call that would trigger transition 101 outside of `item_close.py`. An agent working on a hotfix ticket cannot fire STAGING/LIVE as a side effect of closing a subtask or resolving a field. The transition has to come through the orchestrator, where the repo check lives.

I also added paired-numbering comments to the workflow documentation. The Hotfix Release Flow doc now ties each step to its expected JIRA state change: develop merge to transition 101, master merge to the final close fields, tag push to Fix Version. If someone reads the doc after a partial run, the pairing shows which repo step corresponds to which JIRA state.

## The pattern behind the failure

I had a mental model that said: if JIRA says a thing is done, that is a reliable signal it is done. That model was built on successful releases where JIRA state and repo state happened to agree, not on any structural guarantee they would agree.

Process debt, in this shape, is a workflow that accepts a false final state. Transition 101 fired because firing it was valid by the spec at that moment. The spec was incomplete, but nothing in the process surfaced that. A workflow step that changes ticket status should be structurally unable to run without first verifying the repo state it is supposed to reflect.

The PreToolUse hook and the `item_close.py` guard do not make the process smarter. They remove the path where the wrong state can be produced at all, which is a different thing than documentation or runbooks that rely on correct execution at runtime.

## The open question is not really open

The skeleton I was working from asked: what other status transitions still rely on trust instead of repository-verified checks? For HTO, the answer is at least one more. The CODING transition, which fires when a branch is cut and work starts, has no assertion that the branch actually exists on the remote. An agent can fire it before pushing. I know this because I can read `item_close.py` and see what it asserts and what it does not.

There is a ticket open for it, and the fix will follow the same pattern: one more assertion in `item_close.py` before the CODING transition fires.

Before the guard landed in `item_close.py`, `git log master..hotfix/3.348.12` could return commits on any ticket JIRA called LIVE. Every STAGING/LIVE status stamped by transition 101 was a claim about the repo that nobody in the pipeline had verified.
