Our local preview branch was 304 commits behind origin/preview, and the /sync skill had no idea.

The ticket was a clean hotfix. The CAD exchange rate was hardcoded at 1.4 and had been overcharging Canadian customers without anyone noticing. Changing it to 1.31 touched four files across checkout, packages, and receipt mailers. Short diff, clear business impact. We ran /sync, the skill fetched origin, found the ticket branch clean and ready, and was about to merge.

What it did not do was fast-forward preview first.

A skip rule that made sense and was wrong

/sync treats personal branches carefully. Our preview branch carries custom state: commits from teammates, and preview-only changes that are not ready for develop. Merging into it without understanding that state could clobber work. So the skill skipped personal branches entirely, every session, and the drift piled up without ever being surfaced.

Those commits held a lot of upstream work our local clone did not have. When we started the merge, git began reconciling the two histories, and it would have replayed 71,000-plus insertions already present in the remote branch. It would not have failed loudly. It would have produced a merge commit that looked internally consistent and was mostly noise.

We caught it because the diff preview was enormous. The tooling did not stop us.

Fast-forward first, halt on divergence

The fix was one change to /sync. Personal branches no longer get skipped. They get fast-forwarded first. If the local branch cannot fast-forward cleanly because the histories have diverged, the skill halts and surfaces the conflict. That means no merge commits created where nobody sees them, no silent replays, and no diff that looks complete while carrying 71,000 lines that were never meant to be in this changeset.

We also updated the written branch rules. The order is now fetch, fast-forward, then merge. The handoff for review branches is explicit: confirm local is current with origin/preview before anything touches it. These rules existed before in a loose way. They live in a file now, and the skill enforces them.

Speed removes the pauses

The platform’s workflow runs across multiple repo clones. When Claude is doing the file edits and /sync is handling the merge path, the cycle time for a ticket compresses a lot. That is the point, since it lets us close more tickets and keep the queue moving. It also means we move through sessions without the natural pauses where we used to catch things like branch currency.

Slow manual work has informal safety checks baked into its slowness. You read the branch name twice because you typed it twice. You notice the diff is strange because you waited for it to generate. We do not want the slowness back. But the habits we built were calibrated to that pace, and running the same habits at a faster pace means they stop catching things.

The gap did not open recently. The skip logic was not a bug from the last sprint. It was a reasonable default that quit being appropriate without announcing it.

The branch model was not enforcing itself

The model is preview for the preview tip, develop for the release tip, master for prod. The team understands it. But a branch model is a set of intentions, and intentions do not enforce themselves at merge time. /sync does. If the skill’s behavior does not match the model’s invariants, the model is just documentation.

Changing one behavior made that gap concrete. A skip that let stale state accumulate invisibly became a halt that surfaces the drift and demands a decision. A near-miss like the 71,000-line preview merge cannot recur silently now, because the skill will not let it stay quiet.

If your merge tooling skips the check that a branch is current before merging into it, go look. Ours let a local branch fall 304 commits behind, and only an oversized diff preview exposed it. Faster merge workflows need that check enforced in the tooling, because habit will not hold at that speed.