Minus One Pound a Month

A price change and its matching discount were tracked as independent stories. Deploy the first without the second and every subscriber gets a net charge of minus one pound a month.

Two stories. Both listed as independent. Both the kind of change everyone calls simple config.

The first drops the price of a subscription add-on from £5 to £4. The second drops the matching discount on the same add-on from £5 to £4.

Deploy the first without the second and every customer on that add-on has a net monthly charge of minus one pound.

The Arithmetic Nobody Ran

The add-on was priced at £5 and carried a £5 discount. Five minus five is zero, which is what the customer was meant to see.

Change one side of that pair and the offset stops offsetting. A £4 price against a £5 discount is minus one pound a month, recurring, for every active subscriber — not a display glitch, a monthly recurring charge with a sign in front of it that should not be there.

Neither story is wrong. Each one, read on its own, does exactly what it says and does it correctly. The defect exists only in the space between them, and no acceptance criterion has a space between two stories in scope.

Where the Dependency Was Hiding

Nowhere. That is the finding.

Not in the story descriptions, which describe the change to the price and the change to the discount respectively. Not in the acceptance criteria, which are satisfied by their own stories. Not in any linked issue, because linking them would have required somebody to already know.

It surfaced during analysis, and only because the question being asked was different from the usual one. The usual question is "what does this story do?" The question that found it was "what happens if this story ships and the other one does not?"

Those look like the same question. They are not, and the second one is the only one that can see a pair.

Why a Pair Splits So Easily

Because everything in a release process is happy to split them.

They are separate records, so they get separately estimated, separately assigned and separately picked up. One can be blocked by a review while the other is ready. One can sit behind a component that is not deploying this week. One can be descoped at the last minute by someone protecting a date, and the descoping conversation will consider it entirely on its own merits — which, on its own merits, look like almost no risk at all.

The phrase "simple config change" is doing real damage here. It sets the expected blast radius near zero before anyone has calculated anything, and it makes both stories feel like the sort of thing you can move around freely.

The Other Population

There is a second thing this pair taught me, and it has nothing to do with deployment order.

The price change applies only to new orders. Existing active subscriptions keep the old price. No retroactive data fix was planned — it was recorded as an open item to confirm.

So the test scope is "a new order shows £4.00". That is what the story asks for and it is a legitimate scope. Meanwhile there is a live population of customers still paying £5.00, and nothing in the story, the acceptance criteria or the test cases says a word about them.

That population is not a defect. It might be entirely intended. But it is a decision somebody has to make deliberately, and until they do, the story has one tested slice and one unresolved question sitting next to it wearing no label at all.

Two Rules Out of One Pair of Stories

Calculate the net business effect of a partial release, not just the effect of each story. For any change that adjusts one side of a calculation, find the other side and ask what a release containing only one of them produces. If the answer is a number that would embarrass someone, the two records are one release, and they need to be linked in a way the release process actually reads.

Know which of a price change's two populations you are covering. Every price change has a new-behaviour scope and an existing-data scope. You will usually be asked about the first. Flag the second explicitly as out of scope with the reason, because "nobody mentioned the existing customers" is not a state anyone chose — it is a state everyone assumed somebody else had chosen.

What stayed with me is that nobody had to be wrong for this to go badly. Two correct stories, one release train, one ordinary week in which one of them slips.

Take the smallest config change in your current sprint. What is the net effect if it ships and the story next to it does not?