---
title: "JIRA Showed Done While Only One Sub-Branch Sat on origin/develop"
canonical: https://dxdev.com/blog/jira-said-shipped-git-said-no/
datePublished: 2026-05-21
---
The JIRA ticket said Done, the Claude session was closed and CI had passed, but only one of its ten sub-branches was on `origin/develop`.

We found it during a read-only review pass, not a release. That is the only reason it did not go to production with nine-tenths of the change missing.

The ticket was a moderately complex feature across the platform's codebase. The work spread across multiple branches that had to land on develop in a specific order. At some point in the close sequence, either we or Claude reported success after the first branch landed, and nobody checked the others. JIRA moved to Done and the session ended. The remaining branches sat in git, attached to a ticket the system believed was finished.

## How the close workflow allowed it

The close workflow at the time was human-reported. You merged the branch, ran CI, posted a comment and moved the JIRA status. Each step had ceremony around it. None of them required the closer to prove that every branch was on develop before JIRA could transition.

A status field is not evidence. A comment is not evidence. CI passing on a branch that never merged is not evidence. The only thing that counts is whether the SHA is reachable from `origin/develop`, and nothing in the workflow checked that.

The platform's codebase runs across four local clones, the base checkout through clone four. Develop is the release branch and master is prod. The preview branch is preview only. In that shape, "merged to develop" is the gate for any ticket that touches customer-facing code. Close without verifying that gate and you are filing paperwork on a thing that did not happen.

## The guardrails we landed in clone three

The same day we found the gap, we wrote what we called Appendix C into the workflow docs in clone three. It holds three rules, now encoded as checks in the close orchestrator.

**Contaminated develop is refused.** If a develop branch contains a recovery revert that has not been cleared, the close process halts with a named error instead of a status transition. This check runs before anything else.

**Dirty worksite is refused.** If the worksite still has an uncommitted diff or a stale branch reference, close halts outright.

**Preview-branch checks are widened.** The preview-branch verification now confirms that the shipped feature SHA is reachable from the preview tip. Before, it only confirmed that the branch existed.

Writing those three checks took about forty minutes. Encoding the rule in the docs had taken two seconds and accomplished nothing. The codebase had the written rule for weeks. A written rule can be skipped under time pressure, and apparently it had been.

## The backport problem was a separate failure mode

The same audit surfaced a second pattern. Hotfix branches were occasionally handled by [merging master into develop](/everyday-ai/update-that-was-about-to-bring-the/) instead of cherry-picking the fix commit onto develop explicitly. Those are different operations.

A master-to-develop merge, in a repo where the preview branch has diverged from develop, can pull in preview-specific commits transitively. This had happened at least once. We built a hotfix-backport tool that enforces the cherry-pick path and refuses to run if it detects that master has commits not reachable from the preview branch. The tool is not clever. It makes the right operation the only operation available.

## The same day, twice more

May 21 also produced an exit-survey mailer that overwrote a live customer row, and a retro-script build we had been deferring because we had no systematic way to catch corrective patterns across sessions. Three different failure modes, one shape: a system that could report success while the actual state was wrong.

The overwrite happened because an identity-insert script assumed existence meant consent. The JIRA gap happened because status transitions assumed ceremony meant verification. The retro gap was subtler. We were catching individual mistakes but missing the meta-pattern of which rules we kept re-learning.

A [green checkmark is only a signal](/blog/dont-trust-the-green-deploy-grep-the-live-file/). Any workflow that lets you move a status field without verifying the underlying state will eventually let you believe something happened that did not. So build the check into the close process, and make the close halt when the proof is missing.
