Blog
Deep diveJuly 9, 2026

Observe before you patch

An audit diagnosed an arithmetic error in Limon's prayer loop. I almost fixed it. The code said the opposite: the mechanism was sound. The code tells no story.

The verdict that makes you want to fix

An automated audit flagged a bug in Limon. An arithmetic error, it said, in the prayer loop. The kind of verdict that makes you want to open the file and fix it right away. I almost did. Then I read the code. The bug did not exist.

What a prayer does

In Limon, you play a god who watches peoples without steering them. When a camp suffers, it implores you: a prayer rises. Answer in time, with the right power on the right camp, and it is granted: the people gain fervor, you gain faith. Let the countdown run out, and the prayer turns to doubt.

A small mechanism, but it carries the whole relationship between the player and his people. Broken, the heart of the game is cold.

A small mechanism, but it carries the whole relationship between the player and his people. Broken, the heart of the game is cold.

The diagnosis that rang true

An audit, here, is a pass of analysis: I hand my code to an agent, whose job is to find what is wrong. This one returned a precise verdict. The grace window, the delay during which a god's action can still be credited to a prayer, was supposedly too short. The announced consequence: prayers would expire before being recognized. An arithmetic error, two numbers badly tuned against each other.

It made obvious sense. A window too short, prayers never granted, a player frustrated without knowing why. The diagnosis told a coherent story. That is exactly what made it dangerous.

The diagnosis told a coherent story. That is exactly what made it dangerous.

What the code actually said

I opened the configuration file. Two values.

The lifetime of a prayer: 420 simulation steps. The grace window: 500. Five hundred is larger than four hundred and twenty. The window is not too short, it is longer than the entire life of a prayer. A prayer dies of old age at 420, well before the window of 500 ever closes. The ratio in the diagnosis was inverted.

Worse for the diagnosis: reading the loop, I saw that crediting is not even driven by that countdown. When the god acts on a praying camp, with the right type of power, a simple flag is raised on that camp (a boolean, a yes or no in memory). The moment the need resolves, if the flag is up, the prayer is granted. Timing is not the gate. The action is. The whole story of the window being too short rested on a mechanism that was not the one in the code.

Timing is not the gate. The action is.

The tripwire I built

I was not going to settle for reading. Reading is already better than patching blind, but I wanted to see the real behavior.

I wrote a diagnostic, a read-only script that asserts nothing and modifies no file: it runs the simulation and prints numbers. Two worlds compared on the same seed. In the first, a god that answers: for every prayer, it casts the right power on the right camp. In the second, a passive god that never does anything, my control, my baseline. Faith forced high on the answering god's side, to isolate the single prayer-to-resolution mechanism and set aside the economy of faith. Eight thousand simulation steps, three different seeds.

The verdict of observation contradicted the verdict of the audit. The god that answers grants prayers; the passive god does not. The gap between the two is the signature of a mechanism that works. There was no arithmetic error to fix. If a problem remained, it was elsewhere: in readability, in the fact that the player does not always realize he has just answered a prayer. A problem of feel, not of arithmetic. A completely different job.

The gap between the two is the signature of a mechanism that works.

The temptation to patch

Here is what I kept from the episode. An audit, human or machine, is excellent at raising a flag: something smells wrong, here. It is far less reliable when it explains why. The agent had produced a plausible cause, numbered, tellable. It was false.

The trap is not the tool, it is the temptation. A well-phrased diagnosis gives the illusion of having understood, and a patch ready to write does the rest. I could have swapped two numbers, broken a healthy balance, and created the real bug while believing I was fixing a fake one.

My rule since: never patch on the faith of a diagnosis. Go read the code, or better, run it and watch what it actually does. Detecting is spotting a symptom. Understanding is something else, and it cannot be delegated. The code tells no story. It runs its own, and that is the only one that counts.

The code tells no story. It runs its own, and that is the only one that counts.