---
title: "Hotfix branches need different rules than develop"
canonical: https://dxdev.com/blog/2026-04-22_hotfix-branches-need-different-rules/
datePublished: 2026-04-22
---
On April 22, 2026, I was working on `hotfix/3.346.12`, a release branch pointed straight at production, when I ran `/sync` mid-session and watched the skill prepare to merge `develop` in.

That would have been bad.

`develop` in this codebase is the staging lane. It carries half-finished features, experimental schema changes, and at any given moment, code that is not production-ready. Merging it into a hotfix branch would have pulled all of that toward `master`. One merge commit, and the release becomes a vehicle for everything that was supposed to wait.

The skill didn't know the difference. It saw a branch, it knew there was a `develop` and a `master`, and it ran the standard sync logic.

## what the branch model actually is

HTO is a 25-year-old ASP-classic application. The release topology reflects that age. It works, but it has corners you have to know about.

`develop` is where features land before a release. `master` is production. `ben` is a preview branch David and Aaron use to review work before it goes live. Hotfixes cut directly from `master`, get a version tag like `3.346.12`, and merge back into both `master` and `develop` in a specific order.

That last part matters. When a hotfix lands, the release pipeline carries it forward. `master` gets the fix, then `develop` gets it via the standard hotfix merge. If you run a separate `master` to `develop` sync inside your skill, you're manufacturing a duplicate merge commit, racing the actual release flow, and creating phantom history that confuses future merges.

So there were two bugs in `/sync`, not one. Merging `develop` into a hotfix branch was wrong because it drags unfinished work toward production. Merging `master` into `develop` during sync was wrong because the release flow already handles that, and doing it again creates noise and timing risk.

## what I changed

The fix is not complicated in retrospect. The skill now reads the branch prefix before deciding what to do.

Branches matching `hotfix-*` or `hotfix/*` get a different sync path. No develop merge. No master-to-develop push. Just a targeted sync against the base they actually cut from. `develop` and `master` get their own handling. Everything else falls through to the original logic.

I also updated the workflow docs and the branch validation checks so the agent has the branch semantics written down somewhere it can read them, not just inferred from the codebase topology. The topology is visible. The meaning of the topology is not. Which branches exist is a `git branch -a`. What you are allowed to merge into a hotfix branch is a policy, and policies need to be stated explicitly or they don't exist.

One other thing I fixed at the same time. There was a hardcoded clone path in the sync skill that referenced a specific working directory on my machine. It was fine until I ran the skill from a different clone, at which point it tried to operate on the wrong repo. One line, obvious in hindsight, sitting there untouched because the nominal path always happened to be the one I was using.

## the /item fix alongside it

While I was in the tooling, I also updated `/item`, the skill I use to open an investigation on a JIRA ticket.

The old behavior was to start every investigation with an empty browser tab and wait for me to supply the repro URL. Every session started with me reading the JIRA ticket, finding the Links field, copying the URL, pasting it into the skill. A two-minute tax on every investigation.

The Links field exists in JIRA exactly because repro URLs are part of ticket state. It lives at `customfield_10101`. The skill now reads it on open and navigates there directly. If no link is present, it asks. If one is present, it uses it. Two minutes saved per ticket, one fewer thing to hold in working memory.

Both fixes belong to the same category. The agent was making me supply context that was already written down somewhere accessible. The branch rules were in the workflow docs. The repro URL was in the JIRA ticket. The skill just wasn't reading either.

## the compounding direction

Workflow mistakes move faster than coding mistakes. A bug in a feature affects one feature. A bug in the deployment flow affects every feature that touches it.

Earlier the same day, the `ExpiredRedirect` fix I shipped for ITEM-6643 saturated the IIS worker pool by running a SELECT and UPDATE on every authenticated request. The damage was scoped to one server's thread queue. Recoverable in minutes. If `/sync` had merged `develop` into `hotfix/3.346.12` and I had pushed before catching it, the damage would have been whatever `develop` happened to contain that afternoon, arriving in a production release labeled as a hotfix.

The asymmetry matters. Coding mistakes tend to fail locally and loudly. Workflow mistakes tend to fail silently or at a distance, when the release lands and the wrong code is in it.

That is why the branch rules have to be explicit. Claude is not going to invent the deployment model of your repo from first principles. It will read what you've given it and do the most plausible thing. If you haven't written down that hotfix branches cannot accept develop merges, the most plausible thing is to run the default sync. The default sync will do what it always does.

The leverage isn't in better prompts. It's in better operational rules. The policies your tooling enforces so the agent doesn't have to guess at the shape of your repo.

An AI coding agent is only as safe as the branch rules you bothered to make explicit.
