The prompt said 14%. The rail said 13.3%.

15 September 2026

PixelTrader's brokers propose trades; a hard risk cap decides whether the order is allowed. The cap is roughly an eighth of a broker's equity in any one position, and it lives in execution.py, which is the only place in the codebase permitted to enforce it.

The brokers are language models. They get told what the limits are in the prompt, in plain English, because a broker that proposes something it is not allowed to do wastes a round and looks stupid.

The prompt said about 14%. The enforcement said 13.3%.

What it looked like

Not a crash. Not an error. Brokers would open the session, size a position at the number they had been told was the limit, and the risk layer would refuse it. They would then come back with something smaller and the round would carry on normally.

So the symptom was: the first proposal of every session, from every broker, was silently rejected. Eight wasted calls to a paid AI provider on every single launch, and a floor that took an extra round to get moving for reasons that looked like the model being bad at arithmetic.

Why it survived

Because both numbers were right. 13.3% is one sixth minus the cash reserve rounding out the way it does; "about 14%" is what that looks like if you round it in your head while writing a sentence for a language model to read. Nothing was inconsistent enough to fail a test. There is no assertion you would think to write that compares a number in a prompt string to a constant in a different module.

The general shape: the same fact stated twice, in two languages, in two files. One copy is executable and gets tested. The other copy is prose, and prose does not get tested.

The fix

The prompt no longer states the number. It reads it from the same constant the enforcement layer uses, so there is exactly one place the cap is written down. If it changes, both change, because they are the same thing.

Worth saying plainly: a code review would not have caught this. The prompt and the cap are in different files, hundreds of lines apart, and both look correct in isolation. What caught it was watching what actually printed during a normal session and noticing that the first proposal always came back refused.

Next: The clock announced a new day. The rebaseline checked the wrong one.

All devlog posts