Wreckhold started this sprint with 731 tests and ended it with over 2,500. That is not a typo. Over twenty-three commits, the QA harness expanded from a reasonable safety net into a systematic audit of every module the game touches. This devlog covers what changed, why it changed, and the three bugs the expansion caught before players would have.
The QA Expansion
The original test suite was solid for its size. It covered the core session lifecycle — boot, day loop, night loop, dawn, defeat — and validated that nothing crashed. But it did not ask hard questions about individual systems. The turret firing model had no coverage. The barricade collision resolver had one test. The raid forecast had never been validated against actual config values.
Twenty-three commits fixed that.
The Method
Each commit targeted a specific module or family of modules and added a dedicated test block. The naming convention tells you exactly what happened: TURRET EXTENDED III, BARRICADES EXTENDED II, CONFIG COHERENCE VI. Every block starts with a clean module state, exercises the public API, and asserts specific numeric outcomes. No randomness. No timing dependencies. If the test passes today, it passes tomorrow.
Here is what the expansion covered, module by module:
Defense systems — Turrets got 17 new assertions covering firing mechanics, resist/vulnerability calculations, and repair. Barricades got two rounds: placement, HP multipliers, repair clamping, collision resolution via findNearest, and a final count validation. Traps picked up 12 assertions (placement, recharge, removal, cap enforcement). The fortress itself — four independent wall faces — got 17 assertions spanning damage, repair, allBreached, total damage tracking, and the braceWall mechanic.
Economy and resources — The economy cycle tests now verify fuel consumption, component flow, and dismantle refund accuracy across 13 assertions. Salvage got a full pass: init, deposit, carry-full rejection, drop mechanics, and yield multiplier application. Finds (the loot pool) added coherence checks on pool weights and effect multipliers.
Combat and raids — Raid tests expanded to cover wave forecasting, type scaling per night, and event roll validation. Player tests deepened to include shoot cooldown, bullet direction, dash mechanics, and spawn state. Scouts (the dusk-phase recon units) added spawn, alive-check, flee-all, and day-scaling assertions. Flares got reset, throw-decrement, active-state, expiry, and slow-zone validation.
Configuration invariants — CONFIG COHERENCE V and VI together added 39 assertions that the game’s balance tables are internally consistent. Wall costs match wall HP scaling. Event probability sums equal one. Screen dimensions and radius constants are sane. Timing values do not produce divide-by-zero at any difficulty tier. These are the tests that catch config drift — someone changes a number in one table and a different system quietly breaks.
Difficulty and progression — Difficulty tests now verify per-tier ordering invariants across all difficulty levels, plus derived values like day duration, raider count, and player max HP. Scores got tier-table validation and leaderboard insert mechanics.
Visual checks — Alongside the assertion expansion, the harness maintains 86 visual checks: automated screenshots of boot, gameplay, pause, night, dawn, shop, hall of records, and HUD states. These are not just “does it render” checks. They capture specific UI configurations so layout regressions show up as pixel differences between runs.
What the Numbers Mean
Before the expansion: 640 assertions + 91 visual checks = 731 tests.
After: 2,500+ assertions + 86 visual checks.
The visual count dropped slightly because five redundant captures were consolidated. The assertion count more than tripled. Every module that touches gameplay now has dedicated coverage. The test suite runs deterministically — same seed, same inputs, same outputs — so a failure means something actually broke, not that the random number generator was unkind.
This is what the transition from “building” to “building with confidence” looks like. The game is still in active development. New systems are still being added. But now, every addition runs against a harness that knows what the existing systems promise.
Night Wave Ambient Hum
Wreckhold’s night phase already had the mechanical tension of the DAWN IN countdown, wall integrity warnings, and raider spawns. What it did not have was atmosphere. The screen communicated pressure. The audio did not.
The fix is a 40Hz sine wave blended with LFO-modulated noise, synthesized at runtime into a three-second seamless loop.
How It Works
The fundamental tone is a 40Hz sine wave — low enough to feel more than hear on most speakers. It sits in the subsonic rumble range where your chest registers it before your ears do. On top of that, a 0.4Hz low-frequency oscillator modulates a noise layer, creating an undulating texture that shifts slowly (one full cycle every 2.5 seconds). The mix is 70% sine, 30% modulated noise.
The loop is three seconds long, generated sample-by-sample at 44,100Hz. A 50-millisecond fade-in and fade-out at the loop boundary prevents the click artifact that plagues naive looping. The result is a seamless drone that sounds continuous regardless of how long the night lasts.
When It Plays
The ambient manager starts the hum at wave 1 with a volume of 0.1 and a two-second ramp-in. By wave 3, the volume adjusts to 0.2 with a 1.5-second ramp. The increase is subtle — you are unlikely to notice the moment it changes — but by the third wave the audio bed is noticeably heavier. At dawn break and on defeat, the hum stops cleanly.
The intent is not a jump scare or a dramatic music cue. It is a persistent low-frequency pressure that makes the night feel different from the day even when nothing is actively attacking. The raids provide the spikes. The hum provides the floor.
The Keybind Fix
This one is embarrassing in hindsight. The dismantle action — removing a structure for a partial scrap refund — was bound to the D key. D is also “move right” in WASD. The movement system polls the key state continuously in the update loop. The dismantle system listens for discrete keypressed events. Both fire on the same key.
The result: every time you pressed D to move right near a structure, you also triggered a dismantle. Walk past your own barricade line and watch it evaporate. Not great for a game about building defenses.
The fix rebinds dismantle to X — an unused key far enough from the movement cluster that accidental activation is not physically possible. Six files updated: the day state handler, the build module, the how-to-play screen, the main menu controls display, the pause screen desk reference, and the HUD contextual prompt. Every place in the game that mentions or responds to the dismantle key now says X.
Simple fix. Should have been caught earlier. Now it is covered by the test suite so it cannot regress.
Three Bugs the Expansion Found
Expanding a test suite does not just add coverage. It finds the bugs that were already there, hiding in the corners where nobody looked.
Camera Decay
The camera shake system tracks a shakeTimer that counts down each frame. When the timer expires, the shake offsets should zero out cleanly. Instead, when dt exceeded the remaining timer inside the decay calculation, the timer went negative. The intensity formula — shakeAmount * (shakeTimer / shakeDuration) — produced a negative value. Negative intensity meant inverted shake direction and unpredictable magnitude. On short frames (high FPS), the effect was barely visible. On long frames (stutter or background tab), the camera would jerk violently in the wrong direction for one frame.
The fix restructures the update to check shakeTimer <= 0 first and zero offsets before any intensity calculation. Shake is now smooth through the entire decay curve regardless of frame timing.
Forecast N1
A test for night-1 raid composition asserted that only “normal” raiders would spawn in the first wave. The game’s config, however, sets RUNNER_MIN_NIGHT = 1, meaning runners are eligible from night 1 onward. The test was wrong — the game was right. The assertion was corrected to expect both normal and runner types in the first wave forecast.
This is the kind of bug that hides in plain sight. The test was green when it was written because the config was different. The config changed. The test did not. The QA expansion caught the drift.
Barricade Resolve
The barricade collision resolution test used position (100, 100) for both the barricade center and the test point. Same position. Zero distance. The pushout calculation divides by distance to normalize the pushout vector. Distance zero means either division by zero or a no-op, depending on the guard clause. Either way, no actual collision resolution was being tested.
The fix moves the test point to (100, 95) — five pixels of offset, enough to produce a nonzero distance and a valid pushout vector. The test now exercises the actual math that keeps entities from clipping through barricades.
Where This Leaves Wreckhold
Wreckhold is still building. New systems are still arriving. But the relationship between the code and its tests has fundamentally changed. Before this sprint, the test suite was a smoke detector — it told you if something was on fire. Now it is a structural inspection — it tells you if something is going to be on fire.
The ambient audio gives the night phase a physical weight it was missing. The keybind fix removes a frustration that would have made the first five minutes of every session annoying. The bug fixes close gaps that were invisible at low test counts and inevitable at high ones.
Next: the test count is still climbing. As of the latest commit, the harness sits at nearly 3,900 assertions plus 82 visual checks. Every new system gets its own test block before it ships. That is the standard now.