The cap worked, and was the wrong instrument
Early raids had a dogpile problem: every bot on the map converged on the player and the fight was unsurvivable. So I capped how many could commit to one target.
The report after that was bots present but doing nothing. Nine visible at once, zero damage taken in thirty seconds.
The cap was working exactly as built. It was the wrong instrument.
Limiting who may fight does not remove anyone from the scene
Measured across five seeds, five to eight bots could see the player while the number allowed to fight stayed pinned at three.
So the surplus stood in view, forbidden to act. Which reads worse than the dogpile it replaced. A crowd of inert bodies is not a difficulty setting, it is visibly broken.
The mistake is a specific and repeatable one: I limited the symptom rather than the cause. Too many bots shooting was the symptom. Too many bots knowing where the player was is the cause. Capping the first leaves everyone standing there with the knowledge and no permission.
The research said so at the time
The prior art I had read on this does not cap attackers. It makes knowledge scarce.
I knew that, and built a hard cap anyway because it was the smaller change. Which is a reasonable instinct that was wrong here, and worth being honest about: the smaller change was smaller because it addressed something easier than the actual problem.
A bot that has not seen you and has not been told anything stays on patrol somewhere else entirely. It is not standing in your field of view being inert. It is not in your field of view at all. The behaviour you want isn't "don't shoot", it's "don't be here".
How knowledge spreads now
Sightings propagate between bots unreliably: a 4% chance per tick, within 35 metres, aged out after eight seconds.
Unreliable is the point. Perfect information sharing is the dogpile again with extra steps. A slow, lossy, range-limited channel produces bots that arrive in ones and twos over several seconds, which is what a squad reacting to a contact actually looks like.
Being told beats hearing a noise, because it is a specific report rather than a guess at a direction. It feeds the existing investigate path rather than adding a parallel one.
peak bots seeing the player 5-8 -> 3-4 peak committed 3 -> 3-4
The commitment number now tracks what can see you, instead of leaving spectators. The ceiling went back up to five, because a lot of bots genuinely seeing you at once is a real situation. It just should not be an execution.
The burst chain
An earlier attempt that day added suppression and dropped the cap to three. Both worked as intended. Neither fixed the thing they were built for, and two tests regressed, so it went on a branch rather than into the trunk.
The trace explained why. Peak committed was two, peak firing was two, armour was working, with hits landing for 2, 4 and 9 rather than 14, and the player still died in eleven seconds.
The kill was not a grind. It was a burst chain. Nothing landed, then hits arrived seven ticks apart where the burst pause specifies sixty-six.
Two bots were interleaving their bursts. The pause existed per bot and never reached the player as a gap.
Which is the same category of error as the cap, one level down: the pause was measured on the thing that was easy to measure, one bot's weapon, rather than on the thing that matters, which is what the player receives. Every individual bot was well-behaved. The composition of them was not.
Suppression cannot help a player who does not shoot
Worth recording because it looked like a fix and structurally could not be one.
Suppression accumulates from near misses and makes a pinned bot break contact. The test player never fires. So nothing accumulates, and suppression has no effect on that measurement whatsoever.
It only rewards a player who shoots back. That is correct behaviour and it means it is not an answer to "the player dies too fast while standing still".
Two regressions, and one real hole behind them
Both regressions came from the cap drop rather than suppression, verified by putting the cap back with suppression still in, and watching both pass.
Turning more of the raid away from the fight sent those bots back to patrolling straight past the player, which broke a test asserting bots hold a preferred engagement range.
Chasing it found a genuine bug: the function that pulls a bot off a crowded target returned nothing for a bot already inside the standoff ring. Correctly refusing to send it to the ring, wrongly leaving it walking through.
The rest of the day was structural: the main bot decision function went from 1,428 lines to 396 across three commits, with the simulation's output pinned first so the refactor had something to be checked against.