← All Solo, Not Alone posts

ai-coding process

Two Clean Looks at a Bug That Was There

A bug report said the hand in The Lien looked ragged. I checked twice and saw nothing wrong. Both looks were accurate, and both were useless, because the tool I checked with could not show the bug.

In August I filed a bug report against The Lien. The cards in the player's hand did not share a top edge, so the hand looked ragged. My report also guessed at why, and the guess was wrong.

The card was Final Verse+. Its description reads "Deal 0 damage. Scales with all Resonance, spent." with no Resonance banked, and that wraps to four lines. Once Resonance builds up in a fight the number grows, and "Deal 45 damage." wraps to five, because the extra digit pushes "damage." onto a new line. A Godot Label with autowrap takes its minimum height from its wrapped height. One more line made one taller card, and the hand went ragged.

How I verified it, twice

The game has a debug scenario flag that launches straight into a battle with a chosen hand. I used it to put Final Verse+ in my hand and looked. On one launch my verdict was "final verse is correct now." On another, "final verse looked fine too." The smoke ledger, the file where I track claims that only a person looking at a screen can settle, recorded the item as "did not reproduce, twice."

Both readings were accurate. The card did look fine. A scenario hand starts every fight at zero Resonance, so it renders "Deal 0 damage," which is the one value that cannot trigger the bug. I had checked the defect twice with an instrument that could only ever show the case where the defect is absent.

My original guess made things worse. A queued card is deliberately raised 30 pixels, and my report had put the offset at roughly 35 pixels. The numbers were close enough that the lift got proposed as the likely explanation. My own earlier screenshot refuted it in one line. The card was not queued, and it read "Deal 45 damage."

There was a third check with the same blind spot, and it was automated. The test that guards card text fit formatted every card with no battle context, so every number sat at its authored value. The fix commit notes that it was green for about two weeks on text the game never renders.

What the fix recorded

The fix shrinks a description's font one point at a time, down to a floor, when it would otherwise wrap too tall. The test now measures every card with three digits substituted into every number, and says outright that three digits is a floor on the slack, not a proof of a ceiling. Measured that way, five cards had the same exposure. I had happened to be holding one.

The lesson went into the ledger in this form: "A scenario reproduces the SCENE, not the RUN." Anything whose display depends on accumulated run state, such as Resonance, stacks, stats or gold, renders at its floor in a scenario, and a clean look at the floor says nothing about the range. The practical rule that came with it is small. When a ledger item is about a value that moves, write down what value the scenario put on screen. The old entry said "correct now" and never recorded that the card read 0.

This case is one precedent the design cites. The design for a per-fight transcript, a debug log a battle writes about itself, quotes these two readings as "accurate about the instrument and wrong about the defect."

The part that applies beyond this game

I did not look carelessly, and the test did not assert nothing. Each check measured something true. What none of them could do was reach the state where the bug lived, and nothing in their output said so. A passing result from a check that cannot fail looks exactly like a passing result from one that can.

Working solo, there is no second person to ask how I tested something. So the question has to be part of the check itself. Before I trust a clean result I ask whether this setup could have shown me the failure at all, and I write the answer next to the verdict.

The game is at /games/the-lien, and the series lives at /notes.

← All Solo, Not Alone posts