Split The code is public; the app answers only to the crew.
A bot says what it sees, once: a sighting callout on the message line, to its own side only #168
In flight already — do not start this from scratch. Pull #172 (vesper) carries this half too: callout.ts (+113) with its test, the gate in world.ts and the wiring in bots.ts, on top of the places work that is #167. Its check is green on main at 6b43481, now that the timeout in #166 is fixed — which is the only thing that was ever wrong with the earlier attempt.
If #172 merges, close this and #167 against it. What is left over is the part both this issue and that pull deliberately leave out: the defuse call, the last-magazine call and anything said about a noise. Those are worth one small issue once the gaps have been played with — not a reason to hold the pull.
Done: pull #172 merged at 75febb4. callout.ts holds the rule (sightingText, SIDE_GAP 4s, SPEAKER_GAP 6s, REPEAT_GAP 12s and a Chatter that is cleared on a round restart), bots.ts speaks on contact only, and the check is green on main — 715 pass, types clean. Closing against it.
What both this issue and that pull left out on purpose is still worth one small issue later: the defuse call, the last-magazine call, and anything said about a noise.
Let four silent teammates say where the enemy is, on the message line the HUD already draws, at a rate that makes it information rather than noise.
The second half of #111 (now closed and split in two), narrowed to one kind of call. #103 gave the person a radio; this is the team answering. Every bot already runs
canSeeagainst every enemy every tick to decide whether to shoot, so the information is in hand and nobody says it out loud.Read closed pull #164 before starting: it wrote this (a 135-line
callout.tswith three gaps) and closed on the test timeout in the issue this waits on, not on anything wrong with it.Done looks like
src/client/callout.tsis the rule and holds the numbers: what may be said, the words it is said in, and the gaps that keep the feed readable. Justify each gap in the pull againstMESSAGE_FADE— a side that talks faster than the HUD holds a line overwrites itself unread.placeAtand nowhere else.canSeereturns true for: nothing for a noise, nothing through a wall, and nothing the enemy side's bots know ever reaches the person's message line.scripts/cost.tsmean and p95 before and after, andscripts/measure.tswall clock a match.arena.test.ts's deaf opponent all stay as they are.bun run checkgreen.Files I expect to change:
src/client/callout.tsandcallout.test.ts(new),src/client/world.ts(sayis module-private — export it or keep the gate on that side of the wall),src/client/bots.ts,src/client/bots.test.ts,src/client/world.test.ts,README.md.Left out on purpose, so this fits one run: the defuse call, the last-magazine call and anything said about a noise. They are worth a second issue once these gaps have been played with.
Risks:
bots.tsalso has #46 and #58 queued against it — keep the change narrow and expect to rebase. A callout on every tick a bot can see someone is a wall of text, which is why contact-only and the gaps are acceptance criteria and not niceties.Brief that fits: vesper.