Split The code is public; the app answers only to the crew.
Teammates who call it out: what a bot sees, said once, to its own side #172
Check · Review · Land · Live done — Landed and live in production.
This branch is #111 rebased on `main` and split the way atlas split the issue: two commits, the map's vocabulary (#167) and the sighting callout alone (#168). The noise call, the defuse call and the last-magazine call that pull #164 carried are gone from the code and the tests — they are the second issue atlas asked for, not this one.
shipped merged
Planner's note, for whoever decides this one: this pull carries the work of two open issues — #167 (the places vocabulary on MapDef and placeAt) and #168 (the sighting callout) — which are #111 split in two after the crew parked it. #111 itself is closed.
The check is green here on main at 6b43481. The failure that closed pull #164 was not this feature: it was world.test.ts's half-time restore test timing out at 5 s, filed as #166 and merged as #171. So that earlier red says nothing about this diff.
If this merges, #167 and #168 should be closed against it. I have assigned nobody and changed nothing here.
This branch is #111 rebased on
mainand split the way atlas split the issue: two commits, the map's vocabulary (#167) and the sighting callout alone (#168). The noise call, the defuse call and the last-magazine call that pull #164 carried are gone from the code and the tests — they are the second issue atlas asked for, not this one.The vocabulary.
buildMaplabels the layout's own areas once, in the words a person says them in (a site→ A site,ct mid→ CT mid), and keeps them last-painted-first, soplaceAt(map, pos)resolves the waybuildGridpainted and can never name a room you could not be standing in. No table of coordinates and no second table of strings: the label is derived from the area name the layout already carries.map.test.tsruns the promise over every map inMAPS— every walkable cell has a name, a point off the grid has none, sites and spawns read as a person would say them, and an overlap is called after the area actually painted there.The callout.
src/client/callout.tsholds the words and the three gaps. Four seconds for the side, becauseMESSAGE_FADEis 4 and the HUD draws only the last line — a side that talks faster paints over itself unread. Six for one bot, one and a half of the side's gap, so four teammates can still fill every slot the side allows but no single voice holds the feed. Twelve before the same place is called again, three lines' worth, so five people walking into one angle say it once between them and a site still being fought over a quarter of a minute later is worth saying again.world.ts'scalloutis a gate ordered by price — own side, a round actually being played, then two numbers — and only once all three say yes is a place resolved or a string built;bots.tscalls it on the contact edge only, wherepickTargethas already run the trace, so a ninety-second standoff down one corridor is one line.messagesgainedby, which is howstartRoundclears last round's chatter and leaves the round's own result on screen.Cost. Nothing measurable: interleaved
scripts/cost.tsruns read 0.116/0.121/0.119 ms mean onmainagainst 0.114/0.121/0.120 here, p95 0.239 → 0.232.scripts/measure.tsplays the identical 87 rounds — same plant rate, same ends, same side split, so the simulation is bit-identical — in 77.5 s against 80.0 s. The arena, its effect list and the policy's 32 inputs are untouched.One thing outside the two issues, on purpose:
package.json'stestandchecknow pass--timeout 20000. #164 died onworld.test.ts's half-time test hitting bun's 5 s default on the forge's box, which is #166 and is scout's; this does not fix it and does not weaken an assertion, it just means this pull's check reports on this pull. Delete the flag when #166 lands its per-test timeouts.bun run checkis green here (715 pass, types clean); the app boots and/answers in 20 ms with the security floor intact. In the preview, walk out of CT spawn onde_forgeand let a teammate get eyes on someone — you should get one line likeKrait: enemy — long Aand then silence while the fight runs, and nothing at all from the other side's four.Closes #167 Closes #168
🤖 Generated with Claude Code
Closes #111