BotStrikes

Early development No public build yet · 5v5 tactical FPS · PC

Development log

What changed, measured

The public development log. No launch dates and no “soon”: if something did not move, this page says what stopped it.

Development log · latest milestone

Milestone by milestone, with its measurement

One entry per verified milestone: what changed, the number with its scenario, the link to the evidence, and what was tried and dropped, with the measurement that dropped it. What is not measured yet says “pending”, and what is waiting on a person says so too. No phase is declared closed here.

Each entry preserves the versions, measurements and pending work from its date. Check the current status before using a historical figure or instruction. See current status.

· F6 · ADR 0109 An outside AI can now play the whole round

The game is called “humans versus machines” and until yesterday an outside machine could not complete the objective. It could run, aim and shoot; it could not plant the bomb, because where you may plant did not travel in the protocol. The bomb block sent the phase, the site once planted, the fuse, who carries it —only to its own side— and its position; the two site boxes, no. Our own bot received them on the command line, and that was the only datum entering from outside the public channel. Now they travel like everything else. It is not a concession: it is what a person reads off the letter painted over the site's arch the moment they walk in, and the rule governing this says an AI receives no less than a person through the same channel. They are quantised to decimetres —a box is ten metres across and the only question asked of it is “is my foot inside?”— so the two take 26 bytes instead of 50. Verified: ten bots launched without a single coordinate receive both sites and in 200 seconds carry the bomb to a site 14 times.

  • The two site boxes travel in the bomb block, for everyone and in every snapshot
  • The reference bot no longer needs coordinates passed to it at start-up
  • The 5v5 worst case rises from 57,088 to 58,816 B/s against a cap of 64,000: the margin drops from 6,912 to 5,184 and no budget was touched

Why they travel in every snapshot and not once at join The format is read whole and alone: any snapshot decodes with no prior state. Sending them once at join would have saved bytes and left a bot that connects mid-round blind, which is exactly when a person walks in and looks at the arch.

Tried and dropped

  • Having each bot download the map and work the sites outThe map does not travel in the protocol: it would mean asking a third party to parse a game file in order to play.

· F6 · ADR 0108 Everyone else was carrying a different weapon from yours

In first person the game draws the rifle from the purchased pack, sand-coloured. In third person, the weapon a body carries came from the free kit and was painted a single colour, because the shared shader has no spare sampler to spend at twenty metres. They were two weapons. Using the same mesh does not fit: the first-person rifle, without the hands, is 72,885 triangles against the 1,974 a body's weapon costs today, and ten bodies would take the populated scene from 202,218 triangles to more than four times that. What does fit is the silhouette and the paint. The world model is built by remeshing the outer surface of the purchased weapon —the pack models the inside too, because in first person it opens and you see it— and reducing it to the same budget already being spent: 1,974 triangles for the rifle, 3,820 for the pistol, 1,752 for the knife. The colour is not lost: the file's atlas stops being a texture and becomes the colour table of its vertices, one per vertex, which gives back the dark grip and the black barrel for free. The populated scene stays at 202,218 triangles.

  • A bot's body and another player's carry your weapon, with your silhouette and your paint, for the same 1,974 triangles
  • Two new scenes photograph the pistol and the knife in a body's hand for the first time; the regression bank goes to 83 scenes
  • The weapon looks lighter than before, because the purchased one is sand-coloured and the kit's was nearly black: against the map's ochre that is less contrast, and a person has to look at it

The two captures came out identical byte for byte, with the new weapon and without it The first version was taken as good because the visual regression could not see it. The immediate cause was a file name the client was not looking for, but underneath there was a real hole: the bank photographed the weapon in hand only with the rifle, so no scene drew the third-person pistol or knife. A model nothing photographs breaks without any test firing, which is exactly how two different weapons came to exist unnoticed.

Without remeshing before reducing, the barrel vanished entirely The purchased pack does not model a shell: it models the weapon inside too, and its surface measured twice what a rifle measures from outside. Collapsing that directly mixes the inner faces with the outer ones: the receiver came out a hedgehog of crossed triangles and the fifteen centimetres of barrel vanished, with the muzzle flash coming out of nowhere. Rebuilding only the outer surface first leaves the reducer a job it knows how to do.

Tried and dropped

  • Taking the purchased weapon's atlas out into the world, which is what anyone would doOne more sampler in the shared shader cost 2.75 ms with nothing drawn on this card. Per-vertex colour gives nearly the same for zero.

· F6 · ADR 0105 The map's façades were hiding one of the two teams

The two team colours were chosen by measurement, so that neither is easier to spot than the other. That measurement was made against the practice map, and the competitive map was never measured with it: when it was, it gave 27 % imbalance against a cap of 25, and 38 % in the central area. The cause was attributed pixel by pixel and it was not the team colour but the map's: ochre and terracotta façades so saturated that one team's yellow leaned against them and vanished. Darkening them did not work —it is measured, and it also made the façade more ochre—; what works is halving their chroma while keeping the luminance, so the stone stays as bright in the sun and no photograph is touched. The map lands at 14 % overall and 3 % in the central area.

  • The ochre and terracotta of the competitive map's façades drop to half chroma, at equal luminance
  • The side routes remain at 37 % and no palette fixes them: there the culprit is a photograph

The measurement that said it was fine was looking somewhere else The automatic contract measures the two teams against the practice map's background, the only one whose captures are versioned. The competitive map existed only as working captures, so an art decision could worsen fairness there and leave the check green. A comfortable number was also discarded: an earlier clip gave 8 % imbalance, and it turned out to be a framing artefact —it was looking at dark walls up close—. Measured in open ground and sunlight, the same framing gives between 26 and 58 %.

Tried and dropped

  • Darkening the façades by a quarter, which was the first proposalMeasured, it gave 26 % and still failed: it was wrong by a factor of three. And it had the opposite effect to the one sought, because darkening without touching the chroma makes the façade more ochre. The variant that lowers luminance also breaks a rule of the identity document —the surface in sunlight must be the brightest thing on screen— and left the wall below the sky, which is literally the defect that document describes as an overcast day.

· F6 · ADR 0107 Bodies were taking twice the steps they should

The phase of a walk animation has to count the ground covered: if the body moves slowly, the steps are long and few. In September the jog threshold was moved on the assumption that this was so, and it was not: the field carrying the distance had existed since then, with its comment and its fallback, but no match code filled it —only the tests and the measurement benches did—, so the server always fell back to the clock and the cadence did not depend on speed. Walking gave 186 steps per minute at any speed instead of the 90 the animation was captured at, and at 0.40 m/s, where 25 were due, it still gave 186: seven times too many. That reads as a body that barely advances while taking quick little steps. The phase now follows the distance, and the four gaits land on the cadence of their capture.

  • The phase of walk, jog, sprint and crouch follows the ground covered, not the clock
  • Four new scenes photograph the cadence, including one at 0.40 m/s, which is where the error was sevenfold

Why it went three weeks without any test seeing it The tests built their own input and did fill the distance field, so they measured the right cadence and passed green. The only thing that did not fill it was the code that runs in a match. A test that builds its own data checks the formula, not that the program hands it that data. The new scenes photograph the body as a match draws it, which is where the defect was.

Tried and dropped

  • Taking the premise of an earlier decision as given without checking it againSeptember's decision moved a threshold because the phase followed the distance, and wrote it down. The status note repeated it. Neither lied: both rested on a premise nobody measured, and the very defect that decision claims to have solved stayed standing. What closed it was measuring the real cadence of the four gaits, not rereading the document.

· F6 · ADR 0103 The teammate outline was covering the teammate you could already see

Since ADR 0094 the client draws a teammate's outline through the wall, so you know where someone you cannot see is standing. The rule that decided it asked for three things —teammate, alive and not yourself— and did not ask for the fourth: that they were covered. At ten metres it does not show, because the outline's shell stays hidden behind the body itself; at two metres it covered the whole body, with the torso, the arms, the hands and part of the helmet erased by a solid patch that hid the kit and the weapon. What was approved was knowing where a teammate you cannot see is, and one you can see is already seen: painting over them added no legibility, it took legibility away. The outline now requires occlusion —only the body that arrives through the covered-teammate channel carries it— and the contract is written into the legibility test, which walks the whole table of sides twice, covered and in plain view.

  • The outline through the wall is drawn only over a covered teammate; the one in plain view is no longer painted over
  • The new scene “arena-contorno-companero” puts a teammate in plain view at two metres next to a covered one, in the same pose: the visual regression bank goes from 76 to 77 scenes
  • The performance scene of the dressed map measures again what it says it measures: once occlusion was required it had stopped drawing the five outlines of the worst case, so its five bodies now carry the covered mark
  • The founder still has to play it: this is a defect of what you see and a person validates it, not a frame comparison

The regression bank, scene by scene None of the bank's 76 scenes drew that outline, so a regression that compares frames byte by byte had no way of seeing it. The new scene puts a teammate at two metres, in plain view and with nothing covering them, next to a covered one in the same pose: if the condition falls again, the near one is painted whole and the comparison catches it. The bank now stands at 77 scenes.

Tried and dropped

  • Expecting the visual regression bank to find this defectIt did not find it: the recording of a gameplay clip did, looked at frame by frame. The bank compares frames byte by byte, but none of its 76 scenes drew a teammate in plain view, so the wrong condition did not move a single pixel of any reference and passed green. The fix shipped together with the scene that was missing, not from a test that was already written.
  • Leaving the performance scene as it was after the fixThat scene exists to measure the approved worst case, five covered teammates with their outline, and once occlusion was required it drew zero: its ten bodies were behind the synthetic wall, but none of them was marked as covered. The performance gate would have stayed green measuring a worst case that no longer existed, so the five bodies now carry that mark and the scene draws its five outlines again.

· F1–F6 · ADR 0017 The hash matched on Clang because we said so, not because it was checked

The project's pinned-hashes file and the evidence page claim that one million simulation steps produce the same hash on three builds: optimized GCC, GCC with sanitizers and Clang. The full verification compiled two. It now compiles the three and compares the three hashes on every run, and if it does not find Clang it fails instead of skipping the leg. All three give a59ca4f6e2299d88 for the movement corpus and f7d2406fd5b56d4d for the combat one, with 72,863 shots and 3,478 hits. In the same move, the record of the full verification of Sep 24, 2026 was published, which is where the tick, the bandwidth and the render scene the site publishes come from.

Editorial note · : The removed rig constant and the two OpenGL constants were separate cases. The later internal record from September 27 documents that the full tree compiled with Clang after the two OpenGL constants were removed. The original diagnosis is preserved here; this note does not establish a new build of the current tree.

  • Clang 21.1.8, optimized GCC and GCC with sanitizers give the same two pinned hashes, over one million steps each
  • If there is no Clang, the full verification fails: before, the leg was skipped silently and the claim went unchecked
  • The record of that full verification is now published among the raw records, with the seven site figures it backs and with what it does not back
  • The whole tree still does not compile with Clang: two duplicated, unused constants in the OpenGL code break the build with warnings as errors. The two determinism probes do not pull in rendering, so the new leg runs anyway; it is written down instead of hidden

The three legs, one million steps each Movement a59ca4f6e2299d88 and combat f7d2406fd5b56d4d on optimized GCC, GCC with sanitizers and Clang 21.1.8, with 72,863 shots and 3,478 hits on all three. The two hashes are the ones the project's file has pinned and they did not move.

Tried and dropped

  • Degrading the Clang warning with a compiler wrapper so the tree would buildThe wrapper existed only so that an unused constant would stop breaking the build. Measured before deleting it: that constant entered no computation, because the rig's 18 poses come out identical with its value from the tree, with 0 and with 90 degrees, with the same fingerprint in all three cases, and the code section of the compiled object is the same before and after deleting it. It was dead code: it was deleted and no wrapper is needed any more.
  • Treating the populated scene of the dressed map as covered by that recordThe plan said the record covered the first four rows of the budget panel, and it covers three and a half: its render gate is the empty shooting range, 4.1434 ms, and the populated scene, 9.6242 ms against a 8.3333 target, comes from an ADR of the following day. The record says so in its limitations, and the list of figures without a published record still has entries.
  • Publishing the raw verification log next to the recordThe records published so far carry the file and the sha256 of their log, not the log, and that criterion stands: the log is asked for by email and that sha256 is what checks that whatever arrives is the same the figures were measured with. Changing it for one record and not for the other thirteen would make the folder less readable, not more.

· F5 · ADR 0101, 0102 The wall remembers the shot, and the body stands like a soldier

The bullet mark used to be a flat coloured cube of 1.8 cm that expired after 10 s. It is now a textured quad with alpha on the plane of the face that was hit, lit with that same wall's baked light, three material families and four shapes each: 192 alive, for the whole round, cleared when the round changes. In parallel, the gait was fixed where it matters, in the data of both rigs, and not by lowering values in the client.

Editorial note · : The visual reference update recorded in this entry does not constitute human acceptance of checkpoint H3. That validation remains pending. The figures retain their original scenario and date; they are not new measurements.

  • The quad is 6.0 cm and the crater 1.8: the 1.8 was the size of the hole and was being used as the size of the whole mark
  • Acceptance criterion met: thirty shots at 40 cm leave fifteen separate holes, without the smear that had been rejected
  • Ankle to ankle standing 35.5 → 29.0 cm and toe to toe 49.1 → 34.3, baked into both rigs
  • A person still has to play it and accept it: the founder validates the stance and the marks (checkpoint H3)
  • The standing pelvis weight shift stays blocked by a human decision: 0 mm of travel
Frame cost in the worst case, reference card+0.09 ms / 8.3333

Divergence between the drawn body and its hitboxes standing 6.17 → 2.91 cm and toe 9.49 → 2.09: fairness improves with the bake, it does not get worse

Tried and dropped

  • Putting the marks' sampler into the world shaderThe frame went from 1.97 to 4.72 ms without drawing a single mark: that program is tight on registers on the reference card. The decals have their own program, and any lever that adds a sampler to the shared program has to be measured even when it draws nothing.
  • Fixing the stance by lowering three values in the clientIt left the drawn ankle about 5.4 cm inside the one used by the hitboxes, that is, the foot outside its box. Baked into the data, the standing divergence drops from 6.17 to 2.91 cm.

· F6 · ADR 0099, 0100 The wire contract is written down, and the worst case was measuring low

The server was speaking wire protocol 11 and agent API 10, but the wire documentation only reached 10 and declared 8 for the API. It is now written from the code and not from the log: the bomb block with its 18 bytes and its rules about who knows what, the use action, and the full canonical order of the snapshot with the size of every block and who receives each one. Every size was checked by actually encoding: an empty snapshot is 136 bytes.

  • The real worst case downstream for 5v5, a live AI under the motor model, is 795 bytes and 55,552 B/s with headers, not 54,400: that leaves 8,448 B/s of margin against the 64,000 cap
  • There is no budget regression: it was a count that measured low, and the test now pins both families of figures, with an objective and without one
  • What did run out of margin, and gets written down instead of hidden: the format allows up to sixteen seats, and that case would give 65,152 B/s with the bomb block, above the cap. Offering a sixteen-seat match with an objective needs a written decision and a person first
Worst case downstream per client, 5v5 with an objective55,552 B/s / 64,000

Tried and dropped

  • Raising the bandwidth cap so the bomb would fitNothing was raised or lowered: the cap is still 64,000 B/s. What was wrong was the count, which did not add the bomb's 18 bytes even though they travel in every snapshot of a match with an objective.
  • Leaving the version comment and the pending list as they wereThe header comment said 10 with the constant at 11, and the list declared clock adaptation between machines as pending, when it has been implemented and tested since v2. Both divergences were fixed in the same change.

Earlier entries

DateWhat changedNumberPhase
The presentation clock draws where you aimframes below one tick 65.65 % → 20.91 %; frozen 0.93 % → 0.65 %F3b
The genre's radar, without giving away a single enemy13 bytes per living teammate, zero cost in the worst case; spectating 17 bytesF6
Material variety in the map at zero cost, and the sky stops bandingpixels with no local texture 39.8 % → 32.6 % for +180 triangles out of 15,920, at no costF5
The tracer stopped lying, and the command is applied with a single piece of codethe beam missed by 8.94 m running; command disagreements 283 of 300 → 0F3b
“Cinta”: three cover heights and one service entrance per site1,328 brushes, 0 faces in conflict, longest sightline 36.2 m against a 40.0 maximumF5
Camera culling closes part of the gap, and the budget still does not fitaverage 9.6097 → 9.3372 ms against an 8.3333 target: still 12.0 % overF5
Competitive combat band, and stairs that do not jumprifle armour ratio 0.5 → 0.75; eye step per tick 15 → 5 cmF5
Round-based matches with a scoreboard, and the test map stops being an arenafirst to 13, halves of 12, 1:55 round; open floor 35 % → 1 %F6