Thunderous
Devlog

Eighteen bugs no test could see

In one day Astra ran four read-only code reviews of older systems: combat, the run loop and saves, loot, and the backpack. Eighteen of the findings were real bugs, each checked against the code and then fixed with a test watched failing first. The suite had been green through all of them, because it tested the arithmetic and not the order things happen in.

In short: In one day Astra ran four read-only code reviews of older systems: combat, the run loop and saves, loot, and the backpack. Eighteen of the findings were real bugs, each checked against the code and then fixed with a test watched failing first. The suite had been green through all of them, because it tested the arithmetic and not the order things happen in.

Astra, the agent that builds most of my models, also does code review now. The first one, of the camera cradle, found three bugs no test could see, so on 30 September I sent four more at systems that had never had one: combat, the run loop and saves, loot, and the backpack. Each review was read-only, and each finding was classed as broken, a pressure point, or exposed but intentional. Claude checked every "broken" against the code before touching it, and every fix came with a test that was watched going red for its own reason.

The count: combat 8, run loop and saves 5, loot 3, backpack 2. That's eighteen code fixes, plus one doc that described game time as wall-clock time. The suite had passed before and after, apart from three known failures unrelated to any of this.

Combat: the blow's direction was never measured

The biggest one had been there since the flinch was built. A sword's speed is sampled every physics step, and the sample overwrites the tip's previous position. Unity fires trigger contacts after that step, so when the hit code asked how far the tip had just traveled, the answer was nearly always zero. It fell back to the blade's own axis. Every flinch leaned along the blade instead of along the swing. An upright blade moving sideways was worse: its fallback axis was vertical, the hit was refused, and it still spent a crit roll.

The others in combat:

  • Ability hits pushed bodies toward me. Melee and the abilities passed hit directions in opposite conventions, and the receiver negated both the same way.
  • One hand's buzz cut the other's short. An enemy's hit asked both controllers to vibrate, and when that request expired it stopped both hands, including a sword hit that had started after it.
  • A killing Staggering blow stunned the corpse. Death cleared the stun, and then the weapon applied a new one to the dead body, which could carry into that enemy slot's next life.
  • Parries tested one instant of the blade. A fast cut could pass straight through a bolt between two physics steps. Parries are now swept across the step.
  • Teleports and weapon swaps counted as swings. A 0.7 m jump in one 20 ms step reads as 35 m/s.
  • Loading the saved swing history ignored the rule that keeps wiggles out, and cleaned speed and sweep separately. My real history (150 pairs) loads unchanged under the fix.
  • The late-parry test never produced a late parry. It passed without ever reaching the code it was named for.

The run loop and saves

  • What I carried in the hub didn't survive quitting. Come home alive with a sword equipped, quit, and the sword was gone. A new store now keeps the hub carry. Passes 37 and 38 both open with "1 item(s) you were carrying in the hub came back from the last session."
  • Dying during a fade left the old fade's action pending, which could put me back in the arena while the game thought I was home.
  • The snapshot tests wrote their fixtures into the real recovery folder, the one I'd use to restore a lost vault. With my go-ahead, 262 test snapshots were deleted from it, and 113 real ones kept.
  • A dev-panel restart began the new run with the old purse, carry and health.
  • Two snapshots in the same second overwrote each other.

Loot and the backpack

  • Runtime material copies outlived the glints and chest glows that created them.
  • Coins stopped tossing after the first half-second of a session. A coin was handed the session's time as its own age, so every coin after that looked old. Pass 37: they "tossed out and landed."
  • Spending a key while it was lifted on the grid could hand the drag to the next item.
  • Opening the pack could take over a grid panel another interaction owned, then close it.
  • One hand letting go of the pack's pull tab ended the other hand's pull.

Why the suite was green

Every review included an audit of the tests in its area, and the combat, loot and backpack audits said the same thing. Most tests call a pure helper directly: the damage curve, the crit chance, the lean axis. Testing a real helper is valid, but it can't show that the hit code passes the right value, calls the helper at all, or does what it says. Combat's direction bug lived between two correct functions: the sampler was right, the lean was right, and the order in which Unity called them was wrong. A green suite told me the arithmetic was right. It said nothing about the order things happen in, and that's where most of these lived.

The new tests pin each fixed rule, but I won't pretend they all drive the live path. Some still stop at a helper, and one reads the source text to check every place a blade can jump calls the reset. What changed is where I aim a test first: at the seam between two functions that are each correct.

Worn

Pass 36 wore the two fixes you can feel. The flinch along the swing: "it just felt better." Ability hits leaning away: also better. I hadn't flagged either as wrong before the review named them. The loudness of impacts moved onto the same live band as the buzz and lean, and it "sounded good." Pass 37 saw the coins toss. The rest have nothing to feel and are checked by tests only: the haptic deadlines, the corpse stun, the fade, the parry sweep and the saves. Of those, the hub carry is the one that has since shown up working in a real session's log.

Kept on purpose

Some findings stayed as they are, as pressure points: banking isn't a transaction; the settings store is the only saved store without the guard that stops tests writing to it; and the loot's round counter carries across runs, so a forced seed doesn't replay a second run. That last one was found twice, by the run-loop review and the loot review, and it's the same thing Forty-nine percent left open. It's intentional for now.

Combat's review also named something bigger than a bug: the clock every swing speed is measured on. That one needed an instrument before a decision, and it gets its own entry.