Xenocide Uprising

A rule stated twice

This one shipped, so it gets written down.

The small tokens that stand in for cards, on other players’ lanes and beside the payment options, are supposed to follow whichever skin you are wearing. Dark ink on parchment in Woodcut. Bone on black in Original.

For about a day they were pale red on a dark box in every skin, including the two built on cream paper.

How

The defeat screen is fixed red no matter what skin you are wearing, because death should not be a matter of taste. Its tokens therefore cannot inherit the skin’s ink or they vanish against it, so there is one rule, deliberately outside the theme system, giving them fixed colours.

That rule got cut in half.

These stylesheets get edited by search and replace, and one such edit matched an anchor that appears twice in the file, so it pasted a block of seventeen rules twice. The second copy landed inside the defeat screen’s selector, between the part naming the defeat screen and the part naming the token. The tail was left behind as a rule that named the token and nothing else. Which made it global.

Why nothing caught it

This is the part worth keeping.

The project has a check that finds stylesheet rules nothing can reach. It could not see this, because both copies were perfectly reachable. That is the whole difficulty with duplication: it is invisible to anything reasoning about one rule at a time.

It has another check that validates every skin against its token contract. That found nothing wrong either, and it was right. Nothing was wrong with the skins. Every token held the correct value. A rule outside the theme system was overriding them, which is a question no theme check asks.

And I had already been bitten by the same paste earlier the same day without recognising it: a spacing change measured as having no effect, because a duplicate copy further down the file was quietly winning. Half an hour went into re-deriving arithmetic that had been right the first time.

What now catches it

A new check, run before every deploy, that looks for two things:

The same rule stated twice, identically, in one file. That is the fault at the moment it is made, while both copies still match.

And three or more consecutive rules whose names reappear in order elsewhere in the same file. That is the one that matters, because the moment somebody edits one of the two copies the bodies stop matching, and a rule that differs is indistinguishable from a deliberate later override. Order preserving adjacency is what tells a pasted block from an intentional one, because a person writing an override writes one rule, not a faithful replay of nine in sequence.

Re-stating a single rule later to override it is ordinary and correct, and this project does it twenty one times. Those are not flagged. A check that cries wolf gets ignored, which is exactly how the original fault survived.

I tested it by putting all three versions of the bug back and confirming each one failed the check, then by adding a legitimate override and confirming it did not. A check that cannot fail is worse than no check, and the only way to know which one you have written is to break something on purpose.