I closed a database-only ticket the way I closed every ticket. It went into the preview branch first. Then it went on to the mainline. The change was already verified and running in production. The preview step had nothing left to check. I 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 conflicts touched my change. They were the preview branch and the mainline branch having quietly drifted apart from each other’s unrelated work, and my ticket was just the thing that happened to surface it.
The habit I hadn’t examined
The preview branch exists so a human can load a build and look at something before it ships, a person eyeballing a dialog, a color, a layout. That’s the whole job. Somewhere along the way, “ship to preview” had turned into a step I ran on every close, whether or not there was anything in the diff a human needed to see. A stored-procedure reorder has no dialog to look at. There was nothing to preview. I was previewing SQL.
The conflict forced the question I should have asked before running the merge: does this ticket produce anything a human needs to look at? For a database-only change, the answer is no, and the honest close path is a plain merge straight into the mainline branch, no detour through preview at all.
The rule, stated plainly
Route by what the ticket actually touches, not by habit:
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. Skip preview. There is nothing to preview.
The rule held on the next one
Later the same day I 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. No JS behavior change. I merged it straight into the mainline branch, 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. The habit of always running the same step regardless of which one was true is what put thirteen unrelated conflicts on my plate over a ticket that never needed to go near that branch.
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/2026-05-20_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.