We closed a database-only ticket the way we closed every ticket. It went into the preview branch first, then on to the mainline. The change was already verified and running in production, so the preview step had nothing left to check. We ran it anyway, out of habit, and hit thirteen merge conflicts against unrelated work that had piled up on that branch.
None of the thirteen touched our change. They came from the preview branch and the mainline branch drifting apart over other people’s work, and our ticket just happened to surface it.
The preview branch exists so a human can load a build and look at something before it ships: a dialog, a color, a layout. That is the whole job. Somewhere along the way, “ship to preview” had become a step we ran on every close, whether or not the diff held anything a human needed to see. A stored-procedure reorder has no dialog to look at. We were previewing SQL.
The conflicts forced the question we should have asked before running the merge: does this ticket produce anything a person needs to look at? For a database-only change the answer is no. The right close path is a plain merge straight into the mainline branch, with no detour through preview.
Routing by what the ticket touches
Previewable (UI, JS, CSS, anything a human needs to see rendered): ship to the preview branch first so someone can look at it, then merge on.
Not previewable (database-only, server config, backend logic with no visual surface): merge straight into the mainline branch and skip preview. There is nothing to preview.
The next ticket that day
Later the same day we shipped a change to the web server’s caching headers, so a set of already-versioned static files would tell browsers to cache them for a year instead of re-fetching every time. No UI, and no JS behavior change. We merged it straight into the mainline branch with no preview step, and it went out clean.
If the diff is the entire review surface, the preview branch is ceremony. If a human needs to look at something rendered, the preview branch is the review. Before you close a change, check which of those two it is. Database-only, server config and backend logic with no visual surface go straight to the mainline. Anything a person needs to see rendered goes through preview first.
AI Skills
Use this lesson with the AI assistant you already use
A preview branch exists so a human can look at something before it ships. Running that step out of habit on a change with nothing to look at is how an unrelated database close picked up thirteen merge conflicts that had nothing to do with it.
Paste the prompt, share only the context needed to answer it, and treat the result as a draft for your review. Do not include confidential information or let an AI assistant make changes without your approval.
Optional: for a visual report and saved memory, run /dxdev first.
Don’t have it? Get it at dxdev.com/skills/dxdev. The prompt works without it.
dxdev LESSON · paste into your AI coding agent
LESSON: Route a Close by What the Ticket Touches, Not by the Step You Always Run
SOURCE: dxdev.com/blog/branch-rule-follow-the-change
WHAT HAPPENED: A database-only ticket was closed the same way every ticket was closed, merged into a preview branch first, then on to the mainline, even though the change had already been verified and there was nothing in it for a human to look at. The preview branch had quietly drifted from the mainline through unrelated work, and the merge surfaced thirteen conflicts, none of which touched the actual change. The same day, a caching-header change with no UI or JS behavior was merged straight into the mainline with no preview step, and it shipped clean.
THE RULE: The preview step exists to let a human look at something rendered before it ships. Whether a given change needs that step depends on what the change touches, not on what the last ten closes did. A change with a visual or behavioral surface (UI, JS, CSS) goes through preview so someone can look at it. A change with no visual surface (database-only, server config, backend logic with no rendered output) should merge straight to the mainline, because there is nothing to preview and running the step anyway only exposes the change to whatever unrelated drift has piled up on that branch.
CHECK MY CODE, then report PASS or FAIL with file:line for each:
1. Any documented or scripted close/release process that routes every change through the same intermediate branch or environment regardless of whether that change has a human-reviewable surface.
2. Any recent merge conflict or drift incident where the conflicting commits had nothing to do with the change being merged, suggesting the intermediate branch was carrying unrelated state.
3. Any rule distinguishing "needs human preview" from "does not" that exists only as tribal knowledge, with no check in the tooling that actually routes by it.
THEN PRINT: a table (check, PASS/FAIL, evidence, fix) + a verdict (applies / partially / OUT_OF_SCOPE / no) + the single most important next action.