Three defects the owner hit as "no heat tiles anymore" under TR_MOVEMENT=strafe.
1. The strafe overlay drew ONLY the tiles on its strafe line, so the computed
heat field was essentially invisible. It now draws the WHOLE field exactly as
TFIL does (every non-zero tile, yellow->orange->red ramp by field max, integer
value label) behind the same debugGraphics flag, with TR_STRAFE_HEAT_GRID=0 to
hide it. The strafe overlays draw on top, unchanged.
2. STRAFE carried the SHIPPED bullet constants (core 10 / aura 5), so a bullet's
own heat sat exactly ON PathDangerThreshold (10.0) and a bullet was never
dangerous on its own in this mover; it only ever bit through its corridor.
Defaults are now the retune's 20/10, exposed as TR_STRAFE_BULLET_CORE /
TR_STRAFE_BULLET_AURA.
3. The ring mover's header documented CorridorHeat 5.0 / WallHotness 10.0 while
the code has always been 10.0 / 15.0. A job read the comment and handed out
sub-threshold heat values, which emptied the field. The comment now states the
real values and their actual behaviour; no code values changed.
Also sets strafe's heat defaults to the retune shape (bullet 20/10, corridor 10,
wall 15/5, pillar 0), documented with the reason.
Gate A re-run (j110, offline DrussGT fixture, measure_strafe_gates.nim):
corrected DEFAULT : 24.6% of picks with ZERO safe tile, mean 11.17 safe
j108 shipped field: 63.4% / 3.70 (reproduced exactly)
j108 ring retune : 8.1% / 18.41 (reproduced exactly)
bullet isolated : 11.4% / 17.07
The corrected default beats the shipped field but is WORSE than j108's retune
row: the bullet retune alone costs 8.1 -> 11.4, the corridor/wall retune accounts
for the rest. That is the deliberate price of making a bullet dangerous.
Guards green: test_env_report 24 PASS, test_tfil_commit_env 30 PASS (shipped TFIL
default untouched, byte-for-byte), test_tfil_ring_weights 24 PASS. The three new
knobs are registered in the boot env report so the tree-scan guard stays clean.
New engine movements/strafe.nim, selected by TR_MOVEMENT=strafe (default stays
tfil, byte-identical — test_tfil_commit_env.nim's 30 checks still pass).
Design (the owner's):
- AXIS = incoming bullet's direction when a bullet is in flight, else the
perpendicular of the enemy bearing. The body heading is kept inside a band
(TR_STRAFE_BAND, default 20 deg) around the perpendicular LINE; it turns only
when outside the band, and never turns to face a movement target.
- Candidate tiles on the perpendicular line through our position, both forward
and backward, within TR_STRAFE_REACH px, with a perpendicular jitter of
+/- TR_STRAFE_SPREAD tiles. A tile is acceptable when its path max heat is
<= PathDangerThreshold, the SAME safety rule TFIL uses.
- Move by SIGN only: setForward(+/-MaxSpeed>). Dwell is re-picked after a random
number of ticks in [TR_STRAFE_DWELL_MIN, TR_STRAFE_DWELL_MAX], on arrival, or
on a serious threat spike.
- Heat machinery is REUSED from the shipped mover, not re-implemented: the
exported heatDecay()/bulletMagScale() (j105 time-indexed model) and the
PillarHotness/PillarRadiance globals (j106 pillar-free default). The heat
shape is overridable via TR_STRAFE_CORRIDOR_HEAT/WALL_HOTNESS/WALL_RADIANCE
(defaults = the shipped TFIL field).
- GUI overlay: strafe line, threat axis, candidate tiles (safe/unsafe), chosen
target, sign-coloured movement ray, and the heading band.
Gates (offline, recorded DrussGT fixture, 20026 ticks):
- A TILE AVAILABILITY: shipped heat field -> a safe tile exists on only 36.6%
of picks (63.4% fall back to the least-hot tile); the ring retune
(corridor 5, wall 10/5) raises it to 91.9%.
- B PREDICTABILITY: reversal-interval entropy 5.84 bits vs TFIL 5.09; direction
entropy 1.00 both; long-lag autocorrelation ~0 for both (no periodic
component). Fewer reversals (710 vs 1453) and more full-speed ticks.
measurements: common_libs/tests/measure_strafe_gates.nim
Also registers TR_STRAFE_* in the boot env report (ModularBot_garage/src/
env_report.nim) and wires the engine into ModularBot.nim (hold -> strafe,
ram trigger -> rammer).