testsAndMisc/docs/superpowers/evidence/reverse-survivors-new-enemies-2026-08-09.json
Krzysztof kuhy Rudnicki f0712d3854 reverse_survivors: add splitter, artillery, warden and the leech boss
Splitter dies into three rushers, so killing it creates pressure rather
than relieving it. Artillery outranges the survivor (460 vs its 260) and
holds station beyond reach, the first unit its kiting AI cannot answer.
Warden outruns it. Leech is a third boss.

Two new EnemySpec fields carry this: spawnKind generalizes the hivemind's
hardcoded 'rusher' minion, and splitCount drives on-death splitting.
split() is called unconditionally and is a no-op at splitCount 0 — a guard
branch would need two tests to satisfy the 100% gate and buys nothing.
Child offsets are fixed rather than drawn from the RNG, so seeded replays
are unchanged.

105 tests, 100% coverage. Branch count stays at 117: this adds none.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFyXexNjMQG9V7K8de17fc
2026-08-09 23:06:20 +02:00

34 lines
2.4 KiB
JSON

{
"intent": "Add four enemy kinds to Reverse Survivors: Splitter, Artillery, Warden, and the Leech boss.",
"scope": [
"reverse_survivors/src/core/types.ts (specs, UnitKind/BossKind, orders, unlock/cooldown tables)",
"reverse_survivors/src/core/sim.ts (split(), spawnKind generalization)",
"reverse_survivors/src/render/draw.ts (colors, boss ring flags)",
"Non-goal: status debuffs, director powers and difficulty tiers ship as their own commits"
],
"changes": [
"Two new EnemySpec fields: spawnKind and splitCount. spawnKind generalizes the previously hardcoded 'rusher' in the hivemind's minion spawn; splitCount drives on-death splitting.",
"Splitter (34) dies into 3 rushers at fixed 120-degree offsets, so killing it creates pressure. Children are rushers, making recursion structurally impossible - no depth counter needed.",
"Artillery (52) has 460 range against the survivor's 260 and keepDistance 420, so it outranges the survivor's kiting AI entirely.",
"Warden (40) moves at 215, faster than the survivor's base 150.",
"Leech (190, unlocks at 180s) is a third boss, cheaper and squishier than the Colossus.",
"split() is called unconditionally from killByShot; splitCount: 0 makes it a no-op, which avoids a guard branch that would need two tests under the 100% gate.",
"Child positions use fixed angular offsets rather than the RNG, so seeded replays are unaffected."
],
"verification": [
{
"command": "npm run check (typecheck + eslint --max-warnings 0 + vitest --coverage)",
"result": "pass",
"evidence": "105 tests passed. Coverage 100% on all four metrics: statements 417/417, branches 117/117, functions 76/76, lines 402/402. Branch count unchanged from the 117 baseline, confirming this feature adds zero branches."
}
],
"risks": [
"Balance is simulation-verified rather than human-playtested; the new units may need retuning.",
"Splitter children spawn into state.enemies during projectilesStep, so a later projectile in the same tick can interact with them. Verified: SPLIT_RADIUS 22 exceeds rusher radius 9 + projectile radius 4, so children spawn outside immediate hit range."
],
"rollback": [
"git revert the commit; no data migration and no persisted state is involved.",
"After rollback run `npm run check` in reverse_survivors/ and confirm 95 tests pass at 100% coverage."
]
}