docs(env): 6-block env reference + .env.example, every claim traceable
Rewrites docs/env_reference.md and ModularBot_garage/.env.example so a reader can act on the file without re-deriving anything, and so every claim in it can be checked. WHAT 177 knobs documented across a 6-block format: WHAT / VALUES / STATUS / GOTCHA / TRY. Values are the built-in defaults, so `.env.example` is behaviourally identical to a clean run. No default value changed anywhere; the only added key is TR_FIRE_LAG=0, which is real (fire_tracker.nim:164). WHY (traceability) Every STATUS line now cites the job or commit behind the claim it makes. A documented default is only useful if you can tell whether it was verified or copied by hand; the citation makes that decidable without re-running the experiment. The presence-gated list was wrong: it claimed 7 knobs, the true number is 10. Three knobs were also wrongly labelled presence-gated; they are value-based and are now documented as such. All 31 `# TRY:` example values were checked against the code that parses them, so no example is rejected when copied. VERIFICATION Round-trip (j172 probe: printEnvReport clean vs .env.example applied through the repo's own env_dotenv loader, reports diffed): 0 mismatches, 0 warnings, 0 dropped keys (177 in file, 177 seen). Re-run after this commit's comment edit, unchanged. test_tfil_commit_env 159 PASS / 0 FAIL test_env_report 25 PASS / 0 FAIL test_tfil_ring_weights 24 PASS / 0 FAIL (earlier in the series) Also drops the stale "snapshot of commit 5e32ec1" pin from .env.example: a pinned hash goes stale the moment the next commit lands, which makes the "regenerate when a default changes" instruction worse than none. The line now just says the values mirror current defaults.
This commit is contained in:
+531
-59
@@ -10,19 +10,184 @@
|
|||||||
# Every value below IS the built-in default, so running the bot with this file
|
# Every value below IS the built-in default, so running the bot with this file
|
||||||
# is identical to a clean run with no file at all. Delete a line (or comment it
|
# is identical to a clean run with no file at all. Delete a line (or comment it
|
||||||
# out with #) and that knob falls back to the built-in default. An inline
|
# out with #) and that knob falls back to the built-in default. An inline
|
||||||
# `# comment` after a value is fine — the loader strips it.
|
# `# comment` after a value is fine — the loader strips it (a `#` that follows
|
||||||
|
# a space starts the comment; a `#` glued to the value, like `x#y`, is data).
|
||||||
#
|
#
|
||||||
# A few switches are PRESENCE-only (`existsEnv`): for those, OFF means the line
|
# These values mirror the current defaults, not a frozen snapshot of one commit.
|
||||||
# is absent, so they are shown commented out. Writing `=0` would still turn them
|
# Regenerate this file whenever a default changes, or it will start lying.
|
||||||
# ON.
|
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 1. ONE EXPERIMENT, END TO END
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
#
|
#
|
||||||
# SNAPSHOT of the code at commit 5e32ec1. Regenerate this file whenever a default
|
# Pick ONE knob. Here the example is TR_TFIL_ARRIVE_TICKS, but the shape is the
|
||||||
# changes, or it will start lying.
|
# same for every knob in this file.
|
||||||
|
#
|
||||||
|
# # 1. write the arm. In ModularBot_garage/.env, change ONE line:
|
||||||
|
# # TR_TFIL_ARRIVE_TICKS=15.0
|
||||||
|
# # A per-run file is better than editing .env, because it is how you
|
||||||
|
# # GUARANTEE the arm: whatever else is in .env or in your shell, this
|
||||||
|
# # file is the one that is applied.
|
||||||
|
# cat > /tmp/arm_arrive15.env <<'EOF'
|
||||||
|
# TR_MOVEMENT=tfil
|
||||||
|
# TR_TFIL_ARRIVE_TICKS=15.0
|
||||||
|
# EOF
|
||||||
|
#
|
||||||
|
# # 2. RESTART THE BOT. Env is read ONCE, at boot (module init). Editing
|
||||||
|
# # .env while the bot runs changes nothing. There is no live reload.
|
||||||
|
# # (Two exceptions read lazily on first use: TR_PATTERN_RAD_* and a few
|
||||||
|
# # TR_TMHORIZON_* — do not rely on either.)
|
||||||
|
# cd ModularBot_garage && ./ModularBot.sh # or restart the GUI
|
||||||
|
#
|
||||||
|
# # 3. CONFIRM IT TOOK EFFECT, before you read a single result line.
|
||||||
|
# # `source: .env` = your file was applied. `source: default` = it was not.
|
||||||
|
# grep '^\[env\]' /tmp/modularbot_stdout.log | grep -E 'env file|ARRIVE_TICKS'
|
||||||
|
# # [env] env file: /tmp/arm_arrive15.env (source: TR_ENV_FILE)
|
||||||
|
# # [env] TR_TFIL_ARRIVE_TICKS = 15.0 (source: .env)
|
||||||
|
# # A value showing `(source: default)` means YOUR FILE NEVER REACHED THE BOT.
|
||||||
|
#
|
||||||
|
# # 4. point at the file instead of copying it into .env:
|
||||||
|
# TR_ENV_FILE=/tmp/arm_arrive15.env ./out/ModularBot
|
||||||
|
# ./out/ModularBot --env-file /tmp/arm_arrive15.env
|
||||||
|
# # This is what an A/B run does: one frozen binary, one env file per arm.
|
||||||
|
# # A file you ASKED for and that does not exist stops the bot with an error
|
||||||
|
# # (it never silently falls back); a missing default .env is silent.
|
||||||
|
#
|
||||||
|
# # 5. the module inventory, when you want to know what is on at all:
|
||||||
|
# grep '^\[modules\]' /tmp/modularbot_stdout.log
|
||||||
|
#
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 2. SAFE TO EXPERIMENT WITH RIGHT NOW
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
#
|
||||||
|
# The honest list is SHORT. After the recent campaign most experimental knobs
|
||||||
|
# are either never live-tested or already measured null/harmful, and this file
|
||||||
|
# says so on every one of them. These four are safe in the sense that they
|
||||||
|
# either cannot change a decision, or are the ones a measurement actually
|
||||||
|
# supports.
|
||||||
|
#
|
||||||
|
# TR_GEO_DEBUG=on Draw-only: the candidate-tile geometry overlay.
|
||||||
|
# Watch: the circle on the two tanks and each
|
||||||
|
# heading line. Good: you can SEE the tile the
|
||||||
|
# picker chose. Cannot change any decision.
|
||||||
|
# TR_VBULLET_DEBUG=1 Draw-only: each admitted gun's virtual bullets.
|
||||||
|
# TR_VBULLET_DEBUG_GUN=all
|
||||||
|
# Watch: travelled path, aim ring, miss vector.
|
||||||
|
# Good: you can see the signal the selector ranks
|
||||||
|
# on. Also draw-only. Needs a gun in the rack.
|
||||||
|
# TR_TFIL_DIAG=on Observability only, on the tfil mover. Fills the
|
||||||
|
# per-pick LOSS HISTOGRAM. Watch: the tfil pick log
|
||||||
|
# line. Good: the sReach/sCool/sSafe/sCand counts
|
||||||
|
# tell you where tiles are lost. Provably does not
|
||||||
|
# move a single command (guard-tested).
|
||||||
|
# TR_MOVEMENT=tfil The long-shipped mover, as an explicit override.
|
||||||
|
# Watch: nothing to compare against — it is the
|
||||||
|
# same engine you had before j119. Good: you are
|
||||||
|
# reproducing an older, documented behaviour. Only
|
||||||
|
# do this together with the tfil knobs below.
|
||||||
|
#
|
||||||
|
# Anything else on this list is a MEASUREMENT, not a free change: read its
|
||||||
|
# STATUS line before you type it.
|
||||||
|
#
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 3. ALREADY REJECTED OR MEASURED NULL — WITH THE NUMBER
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
#
|
||||||
|
# TR_TFIL_GEO_MODE=both-rej REJECTED live, 420 battles, 15-opponent panel.
|
||||||
|
# TR_TFIL_GEO_TAU=60 damage/run -8.83, p(sign-flip) = 0.0061,
|
||||||
|
# Wilcoxon p = 0.011. Round wins null.
|
||||||
|
# Docs: docs/tfil_geo_ab.md. DO NOT re-run it.
|
||||||
|
# TR_RAM_FLOOR_ENERGY=5 CLEAN NULL, 900 battles, 450 runs/arm.
|
||||||
|
# -0.018 wins/run, p(sign-flip) = 0.7676, under
|
||||||
|
# a 0.1420 wins/run MDE. Docs:
|
||||||
|
# docs/ram_floor_exhaustion_ab.md. DO NOT re-run
|
||||||
|
# it — the mechanism fired on 0.04% of ticks, so
|
||||||
|
# more runs buy resolution on an effect that is
|
||||||
|
# not there.
|
||||||
|
# TR_RAM_FLOOR_ENERGY=10/20 MEASURED COSTLY OFFLINE (24.7% of ticks blocked
|
||||||
|
# at 20) and the live zone they guard is almost
|
||||||
|
# empty: only 4.8% of shots are ever taken below
|
||||||
|
# 10 energy. Do not go above 5.
|
||||||
|
# TR_TMHORIZON_WINDOW=150 MEASURED HARMFUL live: 26.5% round wins vs 49.0%
|
||||||
|
# for the shipped rack, p = 0.036. Keep 0.
|
||||||
|
# TR_POWER_POLICY=0 MEASURED HARMFUL live: real hit rate 10.61% ->
|
||||||
|
# 7.88%, p = 0.0012. Keep it on.
|
||||||
|
# TR_TFIL_HEAT_TIME=1 MEASURED HARMFUL live at every tau tried
|
||||||
|
# (3/5/9/15): tau15 alone is -22 damage/run,
|
||||||
|
# p = 0.046. Keep it off.
|
||||||
|
# TR_MOVEMENT=tfil_ring MEASURED: round wins 16/49 -> 6/49, p = 0.012. A
|
||||||
|
# glass cannon — best live hit rate of anything
|
||||||
|
# measured, half the survival. Do not ship.
|
||||||
|
# TR_RACK_* (the full rack) MEASURED NEGATIVE VALUE: Pattern ALONE beats
|
||||||
|
# the full 13-gun rack, p = 0.0012. Adding guns
|
||||||
|
# costs rounds.
|
||||||
|
# TR_TFIL_TURN_BIAS=9 LIVE NULL: +0.15 wins/run, p(sign) = 0.244, under
|
||||||
|
# TR_TFIL_TURN_REF_DEG=0 a 0.30 MDE; 300 battles. Docs:
|
||||||
|
# docs/movement_campaign.md (j145).
|
||||||
|
# TR_RAM_OPPORTUNITY=on MEASURED not to convert: 0/59
|
||||||
|
# opportunity -> contact. The finisher ram is the
|
||||||
|
# only path that converts, and it is always on.
|
||||||
|
#
|
||||||
|
# READ THIS BEFORE YOU TRUST ANY "null" ABOVE. A null only excludes an
|
||||||
|
# effect at or above the MDE that run resolved. The 15-opponent panel at
|
||||||
|
# 14 runs/arm resolves ~0.17 wins/run and ~7.65 damage/run; the j163 run
|
||||||
|
# resolved 0.1420 wins/run. So "clean null" here means "no effect >= that
|
||||||
|
# size", NOT "no effect".
|
||||||
|
#
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 4. PRESENCE-GATED KNOBS — FOR THESE, `NAME=0` TURNS THE FEATURE ON
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
#
|
||||||
|
# grep -rn 'existsEnv' ModularBot_garage/src common_libs | grep -v /tests/
|
||||||
|
#
|
||||||
|
# The knobs below are read with `existsEnv`, not by value. OFF means THE LINE
|
||||||
|
# IS ABSENT. Writing `TR_POWER_LOG=0` does not disable the power log — it
|
||||||
|
# ENABLES it, because 0 is a perfectly good value for a knob nobody reads.
|
||||||
|
# That is why they are all shown COMMENTED OUT in this file: there is no
|
||||||
|
# "off" spelling for them, only absence. To disable one, DELETE its line.
|
||||||
|
#
|
||||||
|
# TR_POWER_LOG one line per power-decision CHANGE
|
||||||
|
# TR_RAM_LOG one line per ram start/stop, with the reason
|
||||||
|
# TR_MOVEMENT_LOG movement band / range-class changes
|
||||||
|
# TR_STRAFE_LOG one line per strafe tile pick
|
||||||
|
# TR_SURF_LOG one line per wave-surfing decision
|
||||||
|
# TR_FIRE_DIAG per-reading fire-detection tick/raw/correction
|
||||||
|
# TR_RECORD_WORLDSTATE dump every observed world state to JSONL
|
||||||
|
# TR_RADAR_SCANLOG log every radar scan tick
|
||||||
|
# TR_RADAR_FORCE_SPIN force the old full-360 spin radar
|
||||||
|
# TR_TRACKER_PROBE dump the enemy-tracker internals
|
||||||
|
#
|
||||||
|
# The VALUE-based switches are the opposite: 0 / false / no / off really
|
||||||
|
# disable them, and anything else enables them. Those are TR_RESULT_LOG,
|
||||||
|
# TR_TMHORIZON_LOG, TR_TMHORIZON_ACCURVE, TR_TMHORIZON_RESET_ON_TARGET,
|
||||||
|
# TR_LEADGAIN_LOG, TR_LEARNED_LOG, TR_LEARNED_GLOBAL, TR_LEARNED_REAL_EVENTS,
|
||||||
|
# TR_POWER_POLICY, TR_POWER_FINISH_KILL, TR_RAM_OPPORTUNITY, TR_RAM_PLAN,
|
||||||
|
# TR_FIRE_FIX, TR_STRAFE_FIRE_FIX, TR_STRAFE_ESCAPE, TR_STRAFE_HEAT_GRID,
|
||||||
|
# TR_TFIL_HEAT_TIME, TR_TFIL_PILLAR_ON, TR_TFIL_DIAG, TR_TFIL_NO_REV,
|
||||||
|
# TR_TFIL_HOLD_WHEN_TRAPPED, TR_TFIL_COMMIT_ARRIVAL,
|
||||||
|
# TR_TFIL_RING_COMMIT_ARRIVAL, GUN_SELECTOR_POOL, GUN_VBULLET_ADMIT_ONLY,
|
||||||
|
# TR_VBULLET_DEBUG, TR_GEO_DEBUG, TR_DEBUG_DRAW, TR_ENV_REPORT.
|
||||||
|
# (TR_TFIL_DIAG / _NO_REV / _HOLD_WHEN_TRAPPED / _COMMIT_ARRIVAL /
|
||||||
|
# _RING_COMMIT_ARRIVAL are read by value in the source; the boot report
|
||||||
|
# labels them by presence, which only affects the "(source: ...)" line, never
|
||||||
|
# the value.)
|
||||||
|
|
||||||
# ── movement ─────────────────────────────────────────────────────────────────
|
# ── movement ─────────────────────────────────────────────────────────────────
|
||||||
# Which dodging engine runs: tfil, tfil_ring, strafe, surf or learned.
|
# Which dodging engine runs. VALUE: strafe (default) | tfil | tfil_ring |
|
||||||
|
# surf | learned. Any unrecognised value silently runs `tfil`, with no warning.
|
||||||
|
# WHAT: the engine that picks the dodge tile every tick.
|
||||||
|
# STATUS: DEFAULT = strafe, the measured champion — 300 fresh battles,
|
||||||
|
# +0.30 wins/run over tfil, 95% CI [+0.02, +0.58], sign-flip p = 0.045
|
||||||
|
# (docs/movement_campaign.md, "Fresh-data confirmation (gate v2)").
|
||||||
|
# tfil_ring is measured harmful (round wins 16/49 -> 6/49, p = 0.012).
|
||||||
|
# surf and learned are wired and measured, and neither beats strafe.
|
||||||
|
# GOTCHA: a typo does not warn. `TR_MOVEMENT=straf` runs tfil.
|
||||||
|
# TRY: TR_MOVEMENT=tfil -> the long-shipped engine; the `[env]` block then
|
||||||
|
# reads `move.effective = tfil`. Pairs with the TR_TFIL_* knobs below.
|
||||||
TR_MOVEMENT=strafe
|
TR_MOVEMENT=strafe
|
||||||
# Whole-engine on/off switches. 0 removes an engine from the TR_MOVEMENT choices.
|
# Whole-engine on/off switches. VALUE: on | 0/false/no/off. 0 removes an engine
|
||||||
|
# from the TR_MOVEMENT choices; the effective engine then falls back to the
|
||||||
|
# first still-enabled one, and tfil if all are off (there is no "no movement").
|
||||||
TR_MODULE_MOVE_TFIL=on # the long-shipped "floor is lava" engine
|
TR_MODULE_MOVE_TFIL=on # the long-shipped "floor is lava" engine
|
||||||
TR_MODULE_MOVE_TFIL_RING=on # the same, re-weighted toward a target range
|
TR_MODULE_MOVE_TFIL_RING=on # the same, re-weighted toward a target range
|
||||||
TR_MODULE_MOVE_STRAFE=on # perpendicular strafe with sign-flip reversals
|
TR_MODULE_MOVE_STRAFE=on # perpendicular strafe with sign-flip reversals
|
||||||
@@ -30,7 +195,17 @@ TR_MODULE_MOVE_SURF=on # wave surfing, steered by the GuessFactor
|
|||||||
TR_MODULE_MOVE_LEARNED=on # learned per-state danger field
|
TR_MODULE_MOVE_LEARNED=on # learned per-state danger field
|
||||||
|
|
||||||
# ── gun rack: which guns the bot may choose (off | 1v1 | melee | both) ───────
|
# ── gun rack: which guns the bot may choose (off | 1v1 | melee | both) ───────
|
||||||
# The shipped rack is Pattern only. Turn a gun on with `both`.
|
# WHAT: which guns the selector is allowed to fire. The shipped rack is
|
||||||
|
# PATTERN only; every other gun is `off`.
|
||||||
|
# VALUES: off | 1v1 | melee | both. Aliases: any/empty->both, single/lock->1v1,
|
||||||
|
# only1v1->1v1, multi/onlymelee->melee, none/disabled/disable->off.
|
||||||
|
# STATUS: MEASURED — the full 13-gun rack is WORSE than Pattern alone,
|
||||||
|
# p = 0.0012. Do not re-enable guns to "improve" the bot.
|
||||||
|
# GOTCHA: an UNRECOGNISED value warns on stderr and falls back to `both`, i.e.
|
||||||
|
# a typo ADDS the gun back into the rack. It never turns one off.
|
||||||
|
# TRY: TR_RACK_PATTERN=off -> nothing admitted in 1v1; the selector falls
|
||||||
|
# back to the full rack, so do not ship this. Real use is a PAIR:
|
||||||
|
# TR_RACK_PATTERN=off + TR_RACK_HEADON=both -> exactly one gun fires.
|
||||||
TR_RACK_PATTERN=both # the only admitted gun; both = usable in 1v1 and melee
|
TR_RACK_PATTERN=both # the only admitted gun; both = usable in 1v1 and melee
|
||||||
TR_RACK_HEADON=off # aim straight at the target, no lead
|
TR_RACK_HEADON=off # aim straight at the target, no lead
|
||||||
TR_RACK_LINEAR=off # constant-angle linear aim
|
TR_RACK_LINEAR=off # constant-angle linear aim
|
||||||
@@ -48,16 +223,24 @@ TR_RACK_TMSELECT=off # Tsetlin machine used as the shot selector
|
|||||||
TR_RACK_TMPATTERN=off # Tsetlin machine used as a pattern matcher
|
TR_RACK_TMPATTERN=off # Tsetlin machine used as a pattern matcher
|
||||||
TR_RACK_TMHORIZON=off # horizon Tsetlin automata gun
|
TR_RACK_TMHORIZON=off # horizon Tsetlin automata gun
|
||||||
TR_RACK_LEADGAIN=off # per-range-band learned lead-gain corrector
|
TR_RACK_LEADGAIN=off # per-range-band learned lead-gain corrector
|
||||||
# Give every admitted gun a fixed share of the turns instead of ranking them,
|
# Give every named gun a fixed share of the turns instead of ranking them.
|
||||||
# e.g. TR_RACK_SHARE=PATTERN:60%,HEADON:40%. Empty = the ranking selector.
|
# e.g. TR_RACK_SHARE=PATTERN:60%,HEADON:40% (GUN:weight, comma separated,
|
||||||
|
# the % sign is optional). Empty = the ranking selector. GOTCHA: every gun you
|
||||||
|
# name must ALSO be admitted by its own TR_RACK_<GUN> line, or the share is
|
||||||
|
# refused with a loud `[gun_harness] ERROR` and the ranking selector is used
|
||||||
|
# instead. In the shipped rack that means PATTERN and nothing else.
|
||||||
TR_RACK_SHARE=
|
TR_RACK_SHARE=
|
||||||
# Drop whole guns by rack id (comma separated, e.g. 16). Empty = keep them all.
|
# Drop whole guns by rack id (comma separated, e.g. 16). Empty = keep them all.
|
||||||
|
# Ids: 0 HEADON 1 LINEAR 2 TSETLIN 3 CIRCULAR 4 GUESSFACTOR 5 PATTERN
|
||||||
|
# 6 WALLBOUNCE 7 ACCEL 8 STOPSHOT 9 DISPLACE 10 AVGLEAD 11 DECAYGF 12 KNN
|
||||||
|
# 13 TMSELECT 14 TMPATTERN 15 TMHORIZON 16 LEADGAIN. A disabled gun never even
|
||||||
|
# spawns a virtual bullet, so its fitness stays empty and it cannot be picked.
|
||||||
GUN_RACK_DISABLE=
|
GUN_RACK_DISABLE=
|
||||||
|
|
||||||
# ── gun selector (which admitted gun fires this tick) ───────────────────────
|
# ── gun selector (which admitted gun fires this tick) ───────────────────────
|
||||||
GUN_VBULLET_METRIC=path # fitness measure: path (time-to-collision) or point
|
GUN_VBULLET_METRIC=path # fitness measure: path (time-to-collision) or point
|
||||||
GUN_SELECTOR_MODE=relative # rank guns against the incumbent (absolute = vs a fixed bar)
|
GUN_SELECTOR_MODE=relative # rank guns against the incumbent (absolute = vs a fixed bar)
|
||||||
GUN_SELECTOR_WINDOW=100 # ticks of virtual-bullet history behind the fitness
|
GUN_SELECTOR_WINDOW=100 # ticks of virtual-bullet history behind the fitness (clamped 1..100)
|
||||||
GUN_SELECTOR_MINOBS=50 # observations a gun needs before it may compete
|
GUN_SELECTOR_MINOBS=50 # observations a gun needs before it may compete
|
||||||
GUN_SELECTOR_TIE=0.2 # relative margin two guns must differ by to count as separated
|
GUN_SELECTOR_TIE=0.2 # relative margin two guns must differ by to count as separated
|
||||||
GUN_SELECTOR_FLOOR=0.25 # fitness fraction of the peak below which a band is unsafe
|
GUN_SELECTOR_FLOOR=0.25 # fitness fraction of the peak below which a band is unsafe
|
||||||
@@ -73,6 +256,8 @@ GUN_SELECTOR_SEED=
|
|||||||
|
|
||||||
# ── power / energy policy ────────────────────────────────────────────────────
|
# ── power / energy policy ────────────────────────────────────────────────────
|
||||||
# Every rule below only ever CAPS power; the gun's own preference is the ceiling.
|
# Every rule below only ever CAPS power; the gun's own preference is the ceiling.
|
||||||
|
# The measured case for keeping it on: TR_POWER_POLICY=0 drops the real hit rate
|
||||||
|
# from 10.61% to 7.88%, p = 0.0012.
|
||||||
TR_POWER_POLICY=on # 0 = no cap at all (the control arm)
|
TR_POWER_POLICY=on # 0 = no cap at all (the control arm)
|
||||||
TR_POWER_FAR_DIST=200.0 # px; past this the enemy is in the bad-chances zone
|
TR_POWER_FAR_DIST=200.0 # px; past this the enemy is in the bad-chances zone
|
||||||
TR_POWER_FAR_CAP=1.0 # cap applied past TR_POWER_FAR_DIST
|
TR_POWER_FAR_CAP=1.0 # cap applied past TR_POWER_FAR_DIST
|
||||||
@@ -85,7 +270,7 @@ TR_POWER_ENERGY_MAX=3.0 # the cap at/above ENERGY_HI; 3.0 means effectively unc
|
|||||||
TR_POWER_FINISH_KILL=on # cap to the smallest bullet that still kills a low-energy enemy
|
TR_POWER_FINISH_KILL=on # cap to the smallest bullet that still kills a low-energy enemy
|
||||||
|
|
||||||
# ── radar ────────────────────────────────────────────────────────────────────
|
# ── radar ────────────────────────────────────────────────────────────────────
|
||||||
#TR_RADAR_FORCE_SPIN=1 # presence-only: force the old full 360 spin instead of 1v1 lock
|
#TR_RADAR_FORCE_SPIN=1 # PRESENCE-only: force the old full 360 spin instead of 1v1 lock
|
||||||
TR_RADAR_SCAN_LOG_PATH=/tmp/radar_scan_log.jsonl # where the per-tick scan log is written
|
TR_RADAR_SCAN_LOG_PATH=/tmp/radar_scan_log.jsonl # where the per-tick scan log is written
|
||||||
|
|
||||||
# ── ram ──────────────────────────────────────────────────────────────────────
|
# ── ram ──────────────────────────────────────────────────────────────────────
|
||||||
@@ -98,42 +283,274 @@ TR_RAM_PLAN=off # the change-of-plan trigger (enemy outguns us while
|
|||||||
TR_RAM_PLAN_DIST=250.0 # px; max range at which the plan trigger may fire
|
TR_RAM_PLAN_DIST=250.0 # px; max range at which the plan trigger may fire
|
||||||
TR_RAM_PLAN_MARGIN=20.0 # energy advantage the plan trigger needs
|
TR_RAM_PLAN_MARGIN=20.0 # energy advantage the plan trigger needs
|
||||||
TR_RAM_PLAN_HITRATE=0.05 # pooled virtual hit rate below which the gun duel counts as failing
|
TR_RAM_PLAN_HITRATE=0.05 # pooled virtual hit rate below which the gun duel counts as failing
|
||||||
TR_RAM_FLOOR_ENERGY=0.0 # j160 firing floor: at/below this self energy stop firing (0 = off)
|
# WHAT: at or below this much SELF energy we start no new shot, keeping a
|
||||||
TR_RAM_ENEMY_ENERGY=0.0 # j160 exhaustion: last-scanned enemy energy <= this -> ram (0 = off)
|
# reserve for the ram. Units: energy points.
|
||||||
|
# VALUES: energy, 0.0 = off (today's behaviour). Any float parses.
|
||||||
|
# STATUS: =5 is a CLEAN NULL and must not be re-run: -0.018 wins/run,
|
||||||
|
# p(sign-flip) = 0.7676, under a 0.1420 wins/run MDE, 900 battles. The
|
||||||
|
# mechanism fired on 0.04% of ticks, ~200x less than the offline ruler
|
||||||
|
# predicted. Docs: docs/ram_floor_exhaustion_ab.md.
|
||||||
|
# GOTCHA: 0.0 genuinely disables it, but any POSITIVE value arms it, and the
|
||||||
|
# higher it goes the more of the low-energy zone it blocks (20 blocked 24.7%
|
||||||
|
# of all ticks offline).
|
||||||
|
# TRY: TR_RAM_FLOOR_ENERGY=5 -> already measured, do not re-run. If you
|
||||||
|
# want to see it at all, that is the only defensible value; anything
|
||||||
|
# higher is worse by the offline ruler and by the live null.
|
||||||
|
TR_RAM_FLOOR_ENERGY=0.0
|
||||||
|
# WHAT: the last-scanned enemy energy at or below this switches the ram decider
|
||||||
|
# into exhaustion mode (they are out of ammo, we are not). Units: energy.
|
||||||
|
# VALUES: energy, 0.0 = off. Any float parses.
|
||||||
|
# STATUS: DEFAULT-OFF, never live-tested. It is the second half of the j160 pair;
|
||||||
|
# the other half (FLOOR_ENERGY) measured null, so the pair is not a win.
|
||||||
|
# GOTCHA: 0.0 is the only safe "off". The always-on finisher (enemy < 20 energy
|
||||||
|
# and we are healthier, within 300 px) already covers most of this; setting
|
||||||
|
# this to 20 makes the two overlap.
|
||||||
|
# TRY: TR_RAM_ENEMY_ENERGY=10 -> ram once a scan shows them at <= 10.
|
||||||
|
# Watch: the `[ram] ON rrExhausted` line. Good: the reason field says
|
||||||
|
# `exhausted` rather than `finisher`. Needs TR_RAM_LOG=1 to see it.
|
||||||
|
TR_RAM_ENEMY_ENERGY=0.0
|
||||||
|
|
||||||
# ── movement internals: tfil (the floor-is-lava field) ──────────────────────
|
# ── movement internals: tfil (the floor-is-lava field) ──────────────────────
|
||||||
TR_TFIL_RANGE_LO=100.0 # px; lower edge of the range band the ring mover prefers
|
TR_TFIL_RANGE_LO=100.0 # px; lower edge of the range band the ring mover prefers
|
||||||
TR_TFIL_RANGE_HI=200.0 # px; upper edge of that band
|
TR_TFIL_RANGE_HI=200.0 # px; upper edge of that band
|
||||||
TR_TFIL_RANGE_TEMP=0.4 # sharpness of the ring mover's weighted random draw
|
TR_TFIL_RANGE_TEMP=0.4 # sharpness of the ring mover's weighted random draw
|
||||||
TR_TFIL_RANGE_K=60.0 # px; how fast the weight falls off outside the band
|
TR_TFIL_RANGE_K=60.0 # px; how fast the weight falls off outside the band
|
||||||
TR_TFIL_RING_COMMIT_ARRIVAL=off # tfil_ring only: on = hold the dodge tile until we are ON it (not a fixed dwell)
|
# WHAT (tfil_ring only): hold the committed dodge tile until we are actually ON
|
||||||
TR_TFIL_RING_NOREV_SPEED=0.0 # tfil_ring only; px/tick; below this, a mid-flight switch may not turn the bot around
|
# it, instead of the fixed dwell. VALUE: on | 0/off.
|
||||||
|
# STATUS: DEFAULT-OFF, never live-tested. Ported to the ring fork in j165; the
|
||||||
|
# tfil original (TR_TFIL_COMMIT_ARRIVAL) has a real but under-powered live
|
||||||
|
# result — see that line. Neither is a proven win.
|
||||||
|
# GOTCHA: the ring mover is NOT the default and is not shippable (round wins
|
||||||
|
# 16/49 -> 6/49, p = 0.012), so this only matters while you are measuring it.
|
||||||
|
# TRY: TR_MOVEMENT=tfil_ring + TR_TFIL_RING_COMMIT_ARRIVAL=1
|
||||||
|
# -> the `[env]` block reads TR_TFIL_RING_COMMIT_ARRIVAL = on.
|
||||||
|
TR_TFIL_RING_COMMIT_ARRIVAL=off
|
||||||
|
# WHAT (tfil_ring only): below this self speed (px/tick), a mid-flight switch
|
||||||
|
# may not turn the bot around. UNITS: px/tick (top speed is 8).
|
||||||
|
# STATUS: DEFAULT-OFF (0.0), never live-tested. The tfil original is in the
|
||||||
|
# j144 recommendation below.
|
||||||
|
# TRY: TR_TFIL_RING_NOREV_SPEED=4 -> 4 px/tick is half of top speed, the
|
||||||
|
# value j144 used on tfil. Accepts any float >= 0.
|
||||||
|
TR_TFIL_RING_NOREV_SPEED=0.0
|
||||||
TR_TFIL_CORRIDOR_HEAT=10.0 # lava painted per corridor-overlapping tile
|
TR_TFIL_CORRIDOR_HEAT=10.0 # lava painted per corridor-overlapping tile
|
||||||
TR_TFIL_CORRIDOR_TICKS=0.0 # corridor length in ticks: 0 = to the wall (shipped); N>0 = min(to wall, bullet speed * N)
|
# WHAT: cap the bullet-danger corridor at `bullet speed x this many ticks`,
|
||||||
|
# instead of running it all the way to the arena wall. UNITS: ticks.
|
||||||
|
# VALUES: ticks, 0.0 = off (corridor reaches the wall, today's behaviour).
|
||||||
|
# Any float parses; negatives are treated as 0.
|
||||||
|
# STATUS: DEFAULT-OFF, never live-tested, and NOT recommended. Commit 5e213df
|
||||||
|
# (j148) shipped it with no measurement at all: no battle, no offline ruler.
|
||||||
|
# The neighbouring j146 field-shape sweep, which is the closest evidence,
|
||||||
|
# says halving the corridor restores a safe tile set offline (filter-broken
|
||||||
|
# 63.5% -> 30.4%) and is a LIVE NULL on outcome.
|
||||||
|
# GOTCHA: value knob - 0.0 genuinely disables it. It is NOT a presence knob.
|
||||||
|
# TRY: TR_TFIL_CORRIDOR_TICKS=20 -> a 20-tick look-ahead. Bullet speed is
|
||||||
|
# 20 - 3*power, so over the shipped power bins 1.0..3.0 that is
|
||||||
|
# 17.0..11.0 px/tick = 340..220 px of corridor, instead of the whole
|
||||||
|
# wall. Watch: in the debug overlay the corridor stops short of the
|
||||||
|
# wall. Only bind it to tfil; strafe has its own knob below.
|
||||||
|
TR_TFIL_CORRIDOR_TICKS=0.0
|
||||||
TR_TFIL_WALL_HOTNESS=15.0 # peak heat painted on tiles next to a wall
|
TR_TFIL_WALL_HOTNESS=15.0 # peak heat painted on tiles next to a wall
|
||||||
TR_TFIL_WALL_RADIANCE=10.0 # how fast wall heat falls off with distance
|
TR_TFIL_WALL_RADIANCE=10.0 # how fast wall heat falls off with distance
|
||||||
TR_TFIL_BULLET_CORE=10.0 # tfil only: lava per bullet-overlapping tile (== PathDangerThreshold, so a bullet is never hot on its own)
|
# WHAT: how hot a bullet paints the tile it is sitting on. UNITS: lava points
|
||||||
TR_TFIL_BULLET_AURA=5.0 # tfil only: lava for the bullet's aura ring tiles
|
# on the picker's heat scale.
|
||||||
TR_TFIL_TILE_REPLAN=self # self | enemy | off: when a dodge commitment is cancelled
|
# VALUES: any float >= 0. 10.0 is exactly the danger threshold, so a bullet is
|
||||||
TR_TFIL_COMMIT_TICKS=15 # ticks to commit to a dodge point before replanning
|
# never dangerous on its own; 20.0 puts one bullet's own tile over it.
|
||||||
TR_TFIL_ARRIVE_TICKS=0.0 # hard bound: never pick a tile farther than this (ticks at 8px/tick); 0 = off = today's draw
|
# STATUS: live-tested ONLY as part of the j146 five-shape batch, 375 battles:
|
||||||
TR_TFIL_HOLD_WHEN_TRAPPED=off # on = when NO safe tile exists, hold position one tick instead of taking the 2 least-hot blocked tiles; off = today's fallback
|
# core 10 -> 20 was a live NULL on both primaries, and the arm that combined
|
||||||
TR_TFIL_HOLD_MAX_TICKS=0 # BOUNDED version of the above: hold at most N ticks per empty-safe-set streak (default 0 = off = today's fallback). The budget is DERIVED from the enemy's rate of fire (2 x 3.0-power shots = 16 ticks); the hold is released the tick a safe tile exists and overridden outright if a tracked bullet reaches us within min(N, 16) ticks
|
# it with no corridor/wall field LOST 13.45 damage/run, p(sign-flip) =
|
||||||
TR_TFIL_DANGER_THRESHOLD=10.0 # hard heat filter on the path; lava is quantised to 5, so the effective steps are 10/15/20 and 10-14 admits exactly what 10 does
|
# 0.0095. The middle shape (corridor 10 / wall 15/5 / core 20 / aura 10) is
|
||||||
TR_TFIL_DIAG=off # on = fill the per-pick picker loss histogram (TfilLoss*); observability only
|
# also a null. Do not retune the shape on one axis.
|
||||||
TR_TFIL_GEO_MODE=off # off | turn | dist | both, each with a `-soft` (default) / `-topk` / `-rej` suffix; shapes the DRAW over the heat-filtered pool
|
# GOTCHA: changing CORE alone with the shipped corridor (10) and wall (15) is
|
||||||
TR_TFIL_GEO_TAU=0.0 # deg; the geometric cost scale. 0 = off = today's uniform draw
|
# the one combination j146 did NOT isolate.
|
||||||
TR_TFIL_NO_REV=off # on = never reverse direction inside a corridor
|
# TRY: TR_TFIL_BULLET_CORE=20 + TR_TFIL_BULLET_AURA=10 -> the j146
|
||||||
|
# "middle" bullet heat. Only meaningful as part of the whole middle
|
||||||
|
# shape; on its own it is a null at best.
|
||||||
|
TR_TFIL_BULLET_CORE=10.0
|
||||||
|
# WHAT: the heat painted on the bullet's AURA ring (the tiles around it), as
|
||||||
|
# opposed to the core tile. UNITS: lava points.
|
||||||
|
# VALUES: any float >= 0; 5.0 is half the core's 10.0.
|
||||||
|
# STATUS: live-tested only inside the j146 batch — null, see BULLET_CORE.
|
||||||
|
# TRY: TR_TFIL_BULLET_AURA=10 -> doubles the aura heat; pairs with
|
||||||
|
# TR_TFIL_BULLET_CORE=20 in the j146 "middle" shape.
|
||||||
|
TR_TFIL_BULLET_AURA=5.0
|
||||||
|
# WHAT: when a dodge commitment is cancelled, replan from whose state?
|
||||||
|
# self = today's behaviour. VALUE: self | enemy | off.
|
||||||
|
# STATUS: `self` is the shipped default; `off` is the pre-j144 behaviour and is
|
||||||
|
# exactly what an earlier A/B (cc11ede arm D) tried and could not measure.
|
||||||
|
# TRY: TR_TFIL_TILE_REPLAN=off -> the tile-crossing cancel stops firing.
|
||||||
|
# Accepts self, enemy, off, none, never, 0, false (case-insensitive);
|
||||||
|
# anything else falls back to self with no warning.
|
||||||
|
TR_TFIL_TILE_REPLAN=self
|
||||||
|
TR_TFIL_COMMIT_TICKS=15 # ticks to commit to a dodge point before replanning (min 1)
|
||||||
|
# WHAT: hold the committed dodge tile until we are actually ON it, instead of
|
||||||
|
# letting our own tile-boundary crossing cancel it. VALUE: on | 0/off.
|
||||||
|
# STATUS: LIVE, 600 battles in two blocks (j144). Mechanism is real and
|
||||||
|
# confirmed: incoming hit rate 18.07% -> 14.92%, sign-flip p = 0.0013, damage
|
||||||
|
# taken -24.57/run. Outcome is NOT distinguishable: +0.28 wins/run,
|
||||||
|
# p(sign) = 0.0574 against a 0.31 MDE. The ledger's answer for your own .env
|
||||||
|
# is YES to this knob, and NO to COMMIT_MARGIN.
|
||||||
|
# GOTCHA: only meaningful with TR_MOVEMENT=tfil; the default strafe mover has
|
||||||
|
# no tfil commitment. With TR_TFIL_COMMIT_ARRIVAL on, COMMIT_TICKS becomes a
|
||||||
|
# MINIMUM dwell, not a maximum.
|
||||||
|
# TRY: TR_MOVEMENT=tfil + TR_TFIL_COMMIT_ARRIVAL=1
|
||||||
|
# -> `[env] TR_TFIL_COMMIT_ARRIVAL = on (source: .env)`.
|
||||||
|
TR_TFIL_COMMIT_ARRIVAL=off
|
||||||
|
# WHAT: leave the committed tile only if the best alternative is at least this
|
||||||
|
# much COOLER on the same pathMaxHeat scale the picker uses. UNITS: lava
|
||||||
|
# points; 10.0 is exactly one PathDangerThreshold level.
|
||||||
|
# VALUES: any float >= 0; 0.0 = off = today's behaviour (any improvement ends
|
||||||
|
# the commitment).
|
||||||
|
# STATUS: LIVE, j144, 600 battles, as the `arrive_hyst` arm. It is the WEAKEST
|
||||||
|
# of the three j144 arms on both primaries (+0.19 wins/run, p = 0.092) and
|
||||||
|
# the ledger's explicit answer is: YES to COMMIT_ARRIVAL, NO to this.
|
||||||
|
# GOTCHA: it is a hysteresis, so it makes the bot commit harder; a large value
|
||||||
|
# with a busy field means it holds a tile that is no longer the best one.
|
||||||
|
# TRY: TR_TFIL_COMMIT_MARGIN=10 -> the j144 value. Already measured, and
|
||||||
|
# the answer was no. Use it only to isolate COMMIT_ARRIVAL, not as an
|
||||||
|
# improvement.
|
||||||
|
TR_TFIL_COMMIT_MARGIN=0.0
|
||||||
|
# WHAT: refuse a candidate tile we cannot REACH inside this many ticks. The
|
||||||
|
# bot's top speed is 8 px/tick, so 1 tick = 8 px. UNITS: ticks.
|
||||||
|
# VALUES: ticks, 0.0 = off = today's uniform draw over every safe tile.
|
||||||
|
# STATUS: DEFAULT-OFF, never live-tested. Found by the j151 offline ruler: 65%
|
||||||
|
# of tfil picks outran the 15-tick commitment and the chosen tile was reached
|
||||||
|
# only 6.5% of the time.
|
||||||
|
# GOTCHA: it is a HARD bound, not a preference. If every safe tile is out of
|
||||||
|
# range the pool empties and the code falls back to today's full pool, so it
|
||||||
|
# can never starve the draw — it can also silently do nothing.
|
||||||
|
# TRY: TR_TFIL_ARRIVE_TICKS=15 -> refuse anything farther than 15*8 = 120
|
||||||
|
# px. That is deliberately the same length as TR_TFIL_COMMIT_TICKS,
|
||||||
|
# i.e. "only pick a tile you can still reach while you hold it".
|
||||||
|
TR_TFIL_ARRIVE_TICKS=0.0
|
||||||
|
# WHAT: when the safe-tile set is EMPTY (no tile under the heat threshold),
|
||||||
|
# hold position for one tick instead of promoting the 2 least-hot blocked
|
||||||
|
# tiles. VALUE: on | 0/off.
|
||||||
|
# STATUS: DEFAULT-OFF, never live-tested. j153 wrote the proposal and the A/B
|
||||||
|
# design; it was NOT run (docs/tfil_hold_when_trapped_ab.md is titled
|
||||||
|
# "NOT RUN"). Four mechanism-positive / outcome-null results preceded it, so
|
||||||
|
# a null was always the likely answer.
|
||||||
|
# GOTCHA: it can never latch — the pick site only runs on a replan tick, so the
|
||||||
|
# next tick re-reads the field from scratch. The gun is untouched: a held
|
||||||
|
# tick still fires exactly like every other tick.
|
||||||
|
# TRY: TR_TFIL_HOLD_WHEN_TRAPPED=on -> the tfil pick log shows `hold`
|
||||||
|
# instead of `promote` on a trapped tick. Needs TR_TFIL_COMMIT_LOG set.
|
||||||
|
TR_TFIL_HOLD_WHEN_TRAPPED=off
|
||||||
|
# WHAT: the BOUNDED version of the knob above: while the safe set stays empty,
|
||||||
|
# hold for at most this many ticks per empty streak. UNITS: ticks (integer).
|
||||||
|
# VALUES: integer >= 0; 0 = off = today's promote-the-2 fallback.
|
||||||
|
# STATUS: DEFAULT-OFF, never live-tested (j154, no battle).
|
||||||
|
# GOTCHA: the budget is DERIVED, not guessed: the enemy fires two 3.0-power
|
||||||
|
# shots 16 ticks apart, so 16 is the first window that admits its second
|
||||||
|
# shot. The hold is released the tick a safe tile exists, the counter resets
|
||||||
|
# when one is taken, and a tracked bullet reaching us within min(N,16) ticks
|
||||||
|
# overrides the hold outright (panic release).
|
||||||
|
# TRY: TR_TFIL_HOLD_MAX_TICKS=16 -> the derived budget. Any integer parses;
|
||||||
|
# a junk value degrades to 0 (off).
|
||||||
|
TR_TFIL_HOLD_MAX_TICKS=0
|
||||||
|
# WHAT: the hard heat filter on a candidate's path. UNITS: lava points.
|
||||||
|
# VALUES: any float >= 0. Lava is QUANTISED to 5, so the only values that
|
||||||
|
# change anything are 10, 15 and 20: 10-14 admits exactly what 10 admits.
|
||||||
|
# STATUS: 10.0 is the shipped const; j150 made it sweepable so the offline
|
||||||
|
# ruler could move it. Never live-tested as a knob.
|
||||||
|
# GOTCHA: raising it does not make the bot braver, it makes the safe set
|
||||||
|
# smaller and more of the picks forced. j146's `nofield` arm is the warning:
|
||||||
|
# -13.45 damage/run, p = 0.0095.
|
||||||
|
# TRY: TR_TFIL_DANGER_THRESHOLD=15 -> one quantisation step stricter. The
|
||||||
|
# picker log then reports fewer safe candidates per pick.
|
||||||
|
TR_TFIL_DANGER_THRESHOLD=10.0
|
||||||
|
# WHAT: fill the per-pick LOSS HISTOGRAM (TfilLoss*): how many tiles die at
|
||||||
|
# each picker stage. VALUE: on | 0/off (read by value, not by presence).
|
||||||
|
# STATUS: DIAGNOSTIC ONLY, j150. Provably does not move a single move command
|
||||||
|
# (byte-for-byte, guard-tested). Never measured on outcome, by design.
|
||||||
|
# GOTCHA: nothing. It is the safest tfil knob in this file.
|
||||||
|
# TRY: TR_TFIL_DIAG=on -> the tfil pick log gains the per-stage counts.
|
||||||
|
TR_TFIL_DIAG=off
|
||||||
|
# WHAT: shape the tile DRAW over the heat-filtered pool by geometry (how far
|
||||||
|
# the tile sits from where we are already going) as well as by heat.
|
||||||
|
# VALUES: off | turn | dist | both, each optionally suffixed -soft (default),
|
||||||
|
# -topk or -rej. `distance`=dist, `rejection`=rej are also accepted.
|
||||||
|
# Anything unrecognised, and `off`, means OFF — today's uniform draw.
|
||||||
|
# The form is NOT printed by the boot report, only the dim.
|
||||||
|
# STATUS: DEFAULT-OFF. THE ONE LIVE-TESTED ARM IS `both-rej` + TAU=60 AND IT
|
||||||
|
# WAS REJECTED: -8.83 damage/run, p(sign-flip) = 0.0061, Wilcoxon p = 0.011,
|
||||||
|
# 420 battles, 15 opponents. Round wins null. Offline it did exactly what was
|
||||||
|
# predicted (arrivals 4.5% -> 29.4%) and that is WHY it is bad: the bot ends
|
||||||
|
# up 26 px further out on 15/15 opponents and deals less. See
|
||||||
|
# docs/tfil_geo_ab.md. DO NOT re-run both-rej.
|
||||||
|
# GOTCHA: this knob ALONE is inert — TR_TFIL_GEO_TAU=0.0 means the weighting is
|
||||||
|
# off whatever the mode says. And it needs TR_MOVEMENT=tfil.
|
||||||
|
# TRY: TR_TFIL_GEO_MODE=both-soft + TR_TFIL_GEO_TAU=45
|
||||||
|
# -> the j152 offline headline (arrivals 4.5% -> 16.9%, top-tile share
|
||||||
|
# only 7.0% -> 8.6%). Still never live-tested, and the family has one
|
||||||
|
# measured loss, so treat it as a hypothesis.
|
||||||
|
TR_TFIL_GEO_MODE=off
|
||||||
|
# WHAT: the geometric cost scale, in degrees. 0.0 = off, i.e. exactly today's
|
||||||
|
# uniform draw. UNITS: degrees. VALUES: any float >= 0.
|
||||||
|
# STATUS: never live-tested with a mode other than off. The one live arm used
|
||||||
|
# TAU=60 and lost (see GEO_MODE).
|
||||||
|
# GOTCHA: TAU is IGNORED unless GEO_MODE is not off. A big TAU with mode=off
|
||||||
|
# looks like it is doing something and is not.
|
||||||
|
# TRY: TR_TFIL_GEO_TAU=45 -> 45 degrees of turn cost. Pairs with
|
||||||
|
# TR_TFIL_GEO_MODE=both-soft; on its own it changes nothing.
|
||||||
|
TR_TFIL_GEO_TAU=0.0
|
||||||
|
# WHAT: inside a corridor, never pick a tile in the reverse direction. VALUE:
|
||||||
|
# on | 0/false/no/off (read by value, so `=off` really disables it).
|
||||||
|
# STATUS: never live-tested as a standalone arm. The j144/j145 arms relied on
|
||||||
|
# the NOREV_SPEED knob instead, which is stricter.
|
||||||
|
# GOTCHA: soft only — every weight is floored, so the pool can never empty; and
|
||||||
|
# it overlaps TR_TFIL_NOREV_SPEED, which is the knob that was actually run.
|
||||||
|
# TRY: TR_TFIL_NO_REV=on -> a 3:1 forward:rearward draw weight inside a
|
||||||
|
# corridor. Accepts on/1/true/yes to enable, 0/false/no/off to disable.
|
||||||
|
TR_TFIL_NO_REV=off
|
||||||
TR_TFIL_COMMIT_LOG= # path for the per-commit log; empty = no log
|
TR_TFIL_COMMIT_LOG= # path for the per-commit log; empty = no log
|
||||||
TR_TFIL_COMMIT_ARRIVAL=off # on = hold the dodge tile until we are ON it (not a fixed dwell)
|
# WHAT: while our own speed is below this, a mid-flight target switch may not
|
||||||
TR_TFIL_COMMIT_MARGIN=0.0 # lava an alternative tile must be cooler by before it wins the tile
|
# take a tile more than 90 degrees off the travel direction. UNITS: px/tick
|
||||||
TR_TFIL_NOREV_SPEED=0.0 # px/tick; below this, a mid-flight switch may not turn the bot around
|
# (top speed 8). VALUES: any float >= 0; 0.0 = off = shipped.
|
||||||
TR_TFIL_TURN_BIAS=0.0 # turn TIEBREAK odds ratio among SAFE tiles; 0 = uniform draw as today
|
# STATUS: LIVE, j144/j145, 600 battles. Mechanism confirmed: slow opposite-way
|
||||||
TR_TFIL_TURN_REF_DEG=45.0 # deg; turn below which the tiebreak applies no penalty
|
# mid-flight switches fell 394 -> 64 offline. Outcome not distinguishable on
|
||||||
|
# its own (+0.12 wins/run, p = 0.39); the ledger recommends 4 in your .env
|
||||||
|
# together with COMMIT_ARRIVAL, not alone.
|
||||||
|
# GOTCHA: the pool can never be emptied — with every candidate behind us it
|
||||||
|
# takes the least-bad turn. 0.0 genuinely disables it.
|
||||||
|
# TRY: TR_TFIL_NOREV_SPEED=4 -> 4 px/tick = half of top speed, the j144
|
||||||
|
# value. Watch: fewer >90 deg switches in the tfil pick log.
|
||||||
|
TR_TFIL_NOREV_SPEED=0.0
|
||||||
|
# WHAT: turn TIEBREAK odds ratio among the SAFE tiles: a straight-ahead safe
|
||||||
|
# tile is drawn `1 + bias` times as often as a 180-degree one.
|
||||||
|
# w = max(1, round(1 + BIAS * (1 - max(0,|turn| - REF)/180)))
|
||||||
|
# UNITS: dimensionless. VALUES: any float >= 0; 0.0 = uniform draw as today.
|
||||||
|
# STATUS: LIVE NULL, j145, 300 battles: +0.15 wins/run, p(sign) = 0.244, under
|
||||||
|
# a 0.30 MDE. Docs: docs/movement_campaign.md. A real but small mechanism
|
||||||
|
# with an under-powered outcome.
|
||||||
|
# GOTCHA: the turn cost is NEVER folded into the heat score — the filter stays
|
||||||
|
# hard, and every weight is floored at 1, so the pool can never empty.
|
||||||
|
# TRY: TR_TFIL_TURN_BIAS=9 + TR_TFIL_TURN_REF_DEG=0
|
||||||
|
# -> the j145 arm value (the knee of the offline bias curve: mean
|
||||||
|
# |turn| -11%, opposite picks -22%). Already measured null.
|
||||||
|
TR_TFIL_TURN_BIAS=0.0
|
||||||
|
# WHAT: the turn below which the tiebreak above applies NO penalty. UNITS:
|
||||||
|
# degrees. VALUES: any float >= 0; 45.0 = today's default.
|
||||||
|
# STATUS: inert unless TR_TFIL_TURN_BIAS > 0. j145 used 0 with bias 9.
|
||||||
|
# GOTCHA: on its own this knob does nothing at all.
|
||||||
|
# TRY: TR_TFIL_TURN_REF_DEG=0 -> penalise every turn, not just the sharp
|
||||||
|
# ones. Pairs with TR_TFIL_TURN_BIAS=9; alone it is a no-op.
|
||||||
|
TR_TFIL_TURN_REF_DEG=45.0
|
||||||
|
# WHAT: paint heat on the virtual centre pillar. VALUE: on | 0/off. The shipped
|
||||||
|
# field has NO pillar: PillarHotness/PillarRadiance are 0.0.
|
||||||
|
# STATUS: live-tested, and the OWNER OVERRULED the recommendation to turn it
|
||||||
|
# back on: `old` (pillar on) was best on damage/run (287) and round wins
|
||||||
|
# (35/70) but the contrast is INSIDE the MDE (33 damage/run, 1.22 wins/run
|
||||||
|
# at n=10) and damage taken was 30.8/run higher with the pillar off
|
||||||
|
# (p = 0.040, not corrected for multiple arms). Decision: pillar stays
|
||||||
|
# removed. Docs: docs/tfil_heat_pillar_ab.md.
|
||||||
|
# GOTCHA: this restores an INVENTED hazard with no physical object behind it.
|
||||||
|
# Reversing that decision needs its own pre-registered A/B.
|
||||||
|
# TRY: TR_TFIL_PILLAR_ON=1 -> the pre-change field (30/10), for a fair
|
||||||
|
# A/B against the shipped one. Needs TR_MOVEMENT=tfil.
|
||||||
|
TR_TFIL_PILLAR_ON=off
|
||||||
TR_TFIL_HEAT_TIME=off # on = index bullet heat by time (flat field when off)
|
TR_TFIL_HEAT_TIME=off # on = index bullet heat by time (flat field when off)
|
||||||
TR_TFIL_HEAT_TAU=9.0 # ticks a tracked bullet's heat lives for
|
TR_TFIL_HEAT_TAU=9.0 # ticks a tracked bullet's heat lives for
|
||||||
TR_TFIL_HEAT_POWER_GAIN=1.0 # scale of the heat a bullet paints, per firepower
|
TR_TFIL_HEAT_POWER_GAIN=1.0 # scale of the heat a bullet paints, per firepower
|
||||||
TR_TFIL_PILLAR_ON=off # on = paint heat on the arena centre, which has no pillar
|
|
||||||
|
|
||||||
# ── movement internals: strafe ───────────────────────────────────────────────
|
# ── movement internals: strafe ───────────────────────────────────────────────
|
||||||
TR_STRAFE_BAND=20.0 # degrees the heading may sit off the perpendicular
|
TR_STRAFE_BAND=20.0 # degrees the heading may sit off the perpendicular
|
||||||
@@ -152,14 +569,42 @@ TR_STRAFE_WALL_BIAS=0.35 # how strongly a tile farther from the wall is preferr
|
|||||||
TR_STRAFE_WALL_SAFE=24.0 # px; a wing point never lands nearer than this to a wall
|
TR_STRAFE_WALL_SAFE=24.0 # px; a wing point never lands nearer than this to a wall
|
||||||
TR_STRAFE_ESCAPE=on # the guaranteed wall escape when every candidate is hot
|
TR_STRAFE_ESCAPE=on # the guaranteed wall escape when every candidate is hot
|
||||||
TR_STRAFE_FIRE_FIX=on # strafe's share of the shared TR_FIRE_FIX switch
|
TR_STRAFE_FIRE_FIX=on # strafe's share of the shared TR_FIRE_FIX switch
|
||||||
TR_FIRE_FIX=on # 0 = the shipped previous-energy bullet detector
|
# WHAT: the shared enemy-fire detector. VALUE: on | 0/off. One switch, read by
|
||||||
#TR_FIRE_DIAG=1 # presence-only: per-reading tick/raw/correction trace
|
# every mover; each mover may AND it with its own (TR_STRAFE_FIRE_FIX).
|
||||||
#TR_FIRE_LAG=0 # ticks to back-date each detected fire at spawn (0=shipped; 1=the measured live detection lag)
|
# STATUS: j134 propagated it to all five movers; the per-mover catch table went
|
||||||
|
# 98.888% -> 100% of enemy fires on a 70-battle corpus.
|
||||||
|
# GOTCHA: TR_STRAFE_FIRE_FIX is an AND, so turning TR_FIRE_FIX off is enough;
|
||||||
|
# turning only TR_STRAFE_FIRE_FIX off does not disable strafe's detector.
|
||||||
|
# TRY: TR_FIRE_FIX=0 -> the shipped previous-energy detector everywhere
|
||||||
|
# (the control arm for any fire-detector A/B).
|
||||||
|
TR_FIRE_FIX=on
|
||||||
|
#TR_FIRE_DIAG=1 # PRESENCE-only: per-reading tick/raw/correction trace
|
||||||
|
# WHAT: back-date every detected enemy fire by this many ticks when the ghost
|
||||||
|
# is spawned. UNITS: ticks (integer, clamped at 0). 0 = shipped.
|
||||||
|
# STATUS: LIVE, j147, 180 battles. The 1-tick detection lag is OURS and was
|
||||||
|
# measured on 1777 matched ghost spawns (displacement 19.1 px mean on tfil,
|
||||||
|
# 16.1 on strafe; the arrival deadline the mover reads was 0.99 / 0.77 ticks
|
||||||
|
# late). With =1 it falls to 5.4 / 9.0 px and 0.06 ticks. The live OUTCOME is
|
||||||
|
# null on both movers (+2.08 / +3.77 damage/run, every p > 0.6), so it stays 0.
|
||||||
|
# GOTCHA: a junk or negative value degrades to 0, never a negative back-date.
|
||||||
|
# TRY: TR_FIRE_LAG=1 -> one bullet step at power 1.0 is 17 px; the ghost is
|
||||||
|
# born that far downrange. Watch the tfil/strafe pick log's arrival
|
||||||
|
# deadline, which is what the knob actually corrects.
|
||||||
|
TR_FIRE_LAG=0
|
||||||
TR_STRAFE_HEAT_GRID=on # draw the whole heat grid; 0 leaves only the chosen tile
|
TR_STRAFE_HEAT_GRID=on # draw the whole heat grid; 0 leaves only the chosen tile
|
||||||
TR_STRAFE_BULLET_CORE=20.0 # strafe's own retune: lava per bullet-overlapping tile
|
TR_STRAFE_BULLET_CORE=20.0 # strafe's own retune: lava per bullet-overlapping tile
|
||||||
TR_STRAFE_BULLET_AURA=10.0 # strafe's own retune: lava for the bullet aura ring
|
TR_STRAFE_BULLET_AURA=10.0 # strafe's own retune: lava for the bullet aura ring
|
||||||
TR_STRAFE_CORRIDOR_HEAT=10.0 # strafe's own retune: lava per corridor tile
|
TR_STRAFE_CORRIDOR_HEAT=10.0 # strafe's own retune: lava per corridor tile
|
||||||
TR_STRAFE_CORRIDOR_TICKS=0.0 # same length bound for strafe: 0 = to the wall (shipped)
|
# WHAT: the same corridor LENGTH bound as TR_TFIL_CORRIDOR_TICKS, for the
|
||||||
|
# strafe mover. UNITS: ticks. VALUES: ticks, 0.0 = to the wall (shipped).
|
||||||
|
# STATUS: DEFAULT-OFF, never live-tested (commit 5e213df, j148). Same standing
|
||||||
|
# as the tfil one: no battle, no offline ruler, not recommended.
|
||||||
|
# GOTCHA: this is the DEFAULT engine's knob. Setting only the tfil one does
|
||||||
|
# nothing at all, because the shipped movement is strafe.
|
||||||
|
# TRY: TR_STRAFE_CORRIDOR_TICKS=20 -> 20-tick look-ahead, 220..340 px over
|
||||||
|
# the shipped power bins, instead of the whole wall. Watch: the strafe
|
||||||
|
# heat grid's corridor stops before the wall.
|
||||||
|
TR_STRAFE_CORRIDOR_TICKS=0.0
|
||||||
TR_STRAFE_WALL_HOTNESS=15.0 # strafe's own retune: peak wall heat
|
TR_STRAFE_WALL_HOTNESS=15.0 # strafe's own retune: peak wall heat
|
||||||
TR_STRAFE_WALL_RADIANCE=5.0 # strafe's own retune: wall heat falloff
|
TR_STRAFE_WALL_RADIANCE=5.0 # strafe's own retune: wall heat falloff
|
||||||
|
|
||||||
@@ -168,7 +613,7 @@ TR_SURF_PREF_DIST=400.0 # px; the wave distance the mover tries to sit at
|
|||||||
TR_SURF_DIST_BAND=50.0 # px dead band around it
|
TR_SURF_DIST_BAND=50.0 # px dead band around it
|
||||||
TR_SURF_WALL_MARGIN=48.0 # px kept from the wall when picking a wave point
|
TR_SURF_WALL_MARGIN=48.0 # px kept from the wall when picking a wave point
|
||||||
TR_SURF_RADIAL_FRAC=0.35 # how much of the remaining weight goes to the radial blend
|
TR_SURF_RADIAL_FRAC=0.35 # how much of the remaining weight goes to the radial blend
|
||||||
#TR_SURF_LOG=1 # presence-only: one line per wave-surfing decision
|
#TR_SURF_LOG=1 # PRESENCE-only: one line per wave-surfing decision
|
||||||
|
|
||||||
# ── movement internals: learned (per-state learned danger) ──────────────────
|
# ── movement internals: learned (per-state learned danger) ──────────────────
|
||||||
TR_LEARNED_DECAY_EVERY=128 # learns between forgetting passes; 0 never forgets
|
TR_LEARNED_DECAY_EVERY=128 # learns between forgetting passes; 0 never forgets
|
||||||
@@ -183,18 +628,20 @@ TR_LEARNED_WALL_MARGIN=48.0 # px kept from the wall
|
|||||||
TR_LEARNED_GLOBAL=off # on = ignore the learned state (ablation arm)
|
TR_LEARNED_GLOBAL=off # on = ignore the learned state (ablation arm)
|
||||||
TR_LEARNED_LABEL=histogram # histogram (default) or outcome: what a wave is labelled with
|
TR_LEARNED_LABEL=histogram # histogram (default) or outcome: what a wave is labelled with
|
||||||
TR_LEARNED_REAL_EVENTS=off # on = resolve a wave on the real bullet event, not on energy
|
TR_LEARNED_REAL_EVENTS=off # on = resolve a wave on the real bullet event, not on energy
|
||||||
#TR_LEARNED_LOG=1 # presence-only: one line per learned decision
|
#TR_LEARNED_LOG=1 # VALUE-based (1/on/yes to enable, 0/off to disable)
|
||||||
|
|
||||||
# ── guns ─────────────────────────────────────────────────────────────────────
|
# ── guns ─────────────────────────────────────────────────────────────────────
|
||||||
# Virtual bullets: the prediction the whole gun selector is built on.
|
# Virtual bullets: the prediction the whole gun selector is built on.
|
||||||
TR_MODULE_VBULLETS=on # 0 = no gun predicts or spawns; the selector falls back to its floor gun
|
TR_MODULE_VBULLETS=on # 0 = no gun predicts or spawns; the selector falls back to its floor gun
|
||||||
|
|
||||||
# TMH — the horizon Tsetlin automata gun.
|
# TMH — the horizon Tsetlin automata gun. Inert unless TR_RACK_TMHORIZON=both.
|
||||||
TR_TMHORIZON_SHIFT=2.0 # degrees added to the aim; 0 disables the correction arm
|
TR_TMHORIZON_SHIFT=2.0 # degrees added to the aim; 0 disables the correction arm
|
||||||
TR_TMHORIZON_BIG_MULT=1.5 # extra scale applied when the error magnitude is big
|
TR_TMHORIZON_BIG_MULT=1.5 # extra scale applied when the error magnitude is big
|
||||||
TR_TMHORIZON_RESET_ON_TARGET=on # wipe the automata when the target changes
|
TR_TMHORIZON_RESET_ON_TARGET=on # wipe the automata when the target changes
|
||||||
TR_TMHORIZON_NSTATES=64 # automata state count (the inertia it can hold)
|
TR_TMHORIZON_NSTATES=64 # automata state count (the inertia it can hold)
|
||||||
TR_TMHORIZON_WINDOW=0 # samples kept in the sliding window; 0 keeps everything
|
TR_TMHORIZON_WINDOW=0 # samples kept in the sliding window; 0 keeps everything
|
||||||
|
# e.g. TR_TMHORIZON_WINDOW=30 -> retrain on the 30 most recent samples only.
|
||||||
|
# MEASURED HARMFUL LIVE at 150: 26.5% round wins vs 49.0%, p = 0.036. Keep 0.
|
||||||
TR_TMHORIZON_RESET_DROP=0.0 # rolling accuracy drop, in points, that forces a retrain
|
TR_TMHORIZON_RESET_DROP=0.0 # rolling accuracy drop, in points, that forces a retrain
|
||||||
TR_TMHORIZON_ACCURVE=off # log the accuracy curve even without the thinking log
|
TR_TMHORIZON_ACCURVE=off # log the accuracy curve even without the thinking log
|
||||||
TR_TMHORIZON_RETRAIN_EVERY=50 # samples between full retrains in sliding mode
|
TR_TMHORIZON_RETRAIN_EVERY=50 # samples between full retrains in sliding mode
|
||||||
@@ -207,7 +654,7 @@ TR_LEADGAIN_MIN_OBS=8 # samples a band needs before its gain is trusted
|
|||||||
TR_LEADGAIN_DECAY=250 # samples between count-decay passes
|
TR_LEADGAIN_DECAY=250 # samples between count-decay passes
|
||||||
TR_LEADGAIN_DECAY_FRAC=0.02 # fraction each decay pass takes off every count
|
TR_LEADGAIN_DECAY_FRAC=0.02 # fraction each decay pass takes off every count
|
||||||
TR_LEADGAIN_RESET_ON_TARGET=on # wipe the learned gains when the target changes
|
TR_LEADGAIN_RESET_ON_TARGET=on # wipe the learned gains when the target changes
|
||||||
TR_LEADGAIN_LOG=off # on = one line per gain change
|
TR_LEADGAIN_LOG=off # on = one line per gain change (value-based: 0 disables)
|
||||||
# Kept only so a pre-rename .env does not warn. The gun does not read them.
|
# Kept only so a pre-rename .env does not warn. The gun does not read them.
|
||||||
TR_LEADGAIN_N=32 # NO-OP: the old SBC geometry, no longer used
|
TR_LEADGAIN_N=32 # NO-OP: the old SBC geometry, no longer used
|
||||||
TR_LEADGAIN_NADE=256 # NO-OP: the old ADE count, no longer used
|
TR_LEADGAIN_NADE=256 # NO-OP: the old ADE count, no longer used
|
||||||
@@ -221,6 +668,10 @@ TR_LEADGAIN_SEED=20240921 # NO-OP: the old seed, no longer used
|
|||||||
TR_PATTERN_LEN=10 # ticks of movement history used as the search key
|
TR_PATTERN_LEN=10 # ticks of movement history used as the search key
|
||||||
TR_PATTERN_DEPTH=500 # how far back the history scan may reach
|
TR_PATTERN_DEPTH=500 # how far back the history scan may reach
|
||||||
TR_PATTERN_RAD_OFFSET=0.0 # px added to the aim distance; negative aims short
|
TR_PATTERN_RAD_OFFSET=0.0 # px added to the aim distance; negative aims short
|
||||||
|
# Both RAD_* knobs are read LAZILY, inside predict() — the one place a
|
||||||
|
# mid-run change can matter, and it still does not. The live aim is bearing
|
||||||
|
# only, so a purely radial offset is structurally invisible: MEASURED
|
||||||
|
# byte-identical on bmPath. Docs: docs/env_reference.md §7.
|
||||||
TR_PATTERN_RAD_SCALE=1.0 # multiplier on the whole aim distance
|
TR_PATTERN_RAD_SCALE=1.0 # multiplier on the whole aim distance
|
||||||
|
|
||||||
# The SBC library (common_libs/bitbrain), not a gun knob. Registered so a config
|
# The SBC library (common_libs/bitbrain), not a gun knob. Registered so a config
|
||||||
@@ -250,32 +701,53 @@ TR_BITBRAIN_DECAY_SHIFT=1 # forgetting strength, counted mode only; 0 disa
|
|||||||
#TR_BITBRAIN_RESET_ON_TARGET=on # LEGACY: old name of TR_LEADGAIN_RESET_ON_TARGET
|
#TR_BITBRAIN_RESET_ON_TARGET=on # LEGACY: old name of TR_LEADGAIN_RESET_ON_TARGET
|
||||||
|
|
||||||
# ── debug overlays (all on top of the gun; they never change a decision) ─────
|
# ── debug overlays (all on top of the gun; they never change a decision) ─────
|
||||||
TR_DEBUG_DRAW=on # master switch for every mover's debugGraphics
|
# WHAT: master switch for every mover's debugGraphics. VALUE: on | 0/off.
|
||||||
TR_GEO_DEBUG=off # draw the shared candidate-tile geometry overlay
|
TR_DEBUG_DRAW=on
|
||||||
TR_VBULLET_DEBUG=off # draw each admitted gun's virtual-bullet paths
|
# WHAT: draw the shared candidate-tile geometry overlay. VALUE: on | 0/off.
|
||||||
TR_VBULLET_DEBUG_GUN= # which gun the overlay draws: empty = the selected one
|
# DRAW ONLY — it cannot change a decision, so it is the safest knob here.
|
||||||
TR_VBULLET_DEBUG_MAX=32 # max virtual bullets drawn per gun
|
# GOTCHA: independent of TR_DEBUG_DRAW: the overlay is drawn either way, and
|
||||||
|
# TR_DEBUG_DRAW=0 is what suppresses the movers' own graphics.
|
||||||
|
# TRY: TR_GEO_DEBUG=on -> the geometry circles appear over the arena.
|
||||||
|
TR_GEO_DEBUG=off
|
||||||
|
# WHAT: draw each admitted gun's virtual-bullet paths. VALUE: 1/on/yes to
|
||||||
|
# enable, 0/off/no/false to disable, unset = off. DRAW ONLY.
|
||||||
|
# GOTCHA: needs a gun in the rack to be legible; the shipped rack admits
|
||||||
|
# Pattern only, so set TR_VBULLET_DEBUG_GUN too.
|
||||||
|
# TRY: TR_VBULLET_DEBUG=1 + TR_VBULLET_DEBUG_GUN=all
|
||||||
|
# -> travelled path, aim ring and miss vector for every admitted gun.
|
||||||
|
TR_VBULLET_DEBUG=off
|
||||||
|
# WHICH gun the overlay draws. VALUES: empty = the currently selected gun;
|
||||||
|
# `all` or `*` = every gun; otherwise a gun name, e.g. `Pattern`.
|
||||||
|
# TRY: TR_VBULLET_DEBUG_GUN=all -> every admitted gun at once.
|
||||||
|
TR_VBULLET_DEBUG_GUN=
|
||||||
|
TR_VBULLET_DEBUG_MAX=32 # max virtual bullets drawn per gun (clamped to >= 1)
|
||||||
TR_VBULLET_ADMIT_ONLY=on # on = a gun the rack does not admit is not even predicted
|
TR_VBULLET_ADMIT_ONLY=on # on = a gun the rack does not admit is not even predicted
|
||||||
|
|
||||||
# ── logs (set the value to 1; presence alone turns some of them on) ──────────
|
# ── logs (set the value to 1; PRESENCE alone turns these on) ─────────────────
|
||||||
TR_RESULT_LOG=on # one line per round result
|
# WHAT: one line per round result. VALUE-based (unlike the block below): 0/off
|
||||||
#TR_POWER_LOG=1 # presence-only: one line per power decision
|
# really disables it, which is why this one is written out uncommented.
|
||||||
#TR_RAM_LOG=1 # presence-only: one line per ram start/stop and why
|
# TRY: TR_RESULT_LOG=off -> no [result] lines at all.
|
||||||
#TR_MOVEMENT_LOG=1 # presence-only: movement band/class changes
|
TR_RESULT_LOG=on
|
||||||
#TR_STRAFE_LOG=1 # presence-only: one line per strafe tile pick
|
#TR_POWER_LOG=1 # PRESENCE-only: one line per power decision (0 would ENABLE it)
|
||||||
#TR_TMHORIZON_LOG=1 # presence-only: the per-shot thinking of the TM horizon gun
|
#TR_RAM_LOG=1 # PRESENCE-only: one line per ram start/stop and why
|
||||||
|
#TR_MOVEMENT_LOG=1 # PRESENCE-only: movement band/class changes
|
||||||
|
#TR_STRAFE_LOG=1 # PRESENCE-only: one line per strafe tile pick
|
||||||
|
#TR_TMHORIZON_LOG=1 # VALUE-based: the per-shot thinking of the TM horizon gun
|
||||||
GUN_STATS_PATH=/tmp/gun_stats.jsonl # where the per-round gun stats are written
|
GUN_STATS_PATH=/tmp/gun_stats.jsonl # where the per-round gun stats are written
|
||||||
GUN_SHOTLOG_PATH=/tmp/shot_log.jsonl # where the per-shot log is written
|
GUN_SHOTLOG_PATH=/tmp/shot_log.jsonl # where the per-shot log is written
|
||||||
|
|
||||||
# ── measurement helpers (leave off unless you are measuring) ─────────────────
|
# ── measurement helpers (leave off unless you are measuring) ─────────────────
|
||||||
#TR_RECORD_WORLDSTATE=1 # presence-only: dump every observed world state
|
#TR_RECORD_WORLDSTATE=1 # PRESENCE-only: dump every observed world state
|
||||||
#TR_RADAR_SCANLOG=1 # presence-only: log every radar scan tick
|
#TR_RADAR_SCANLOG=1 # PRESENCE-only: log every radar scan tick
|
||||||
#TR_TRACKER_PROBE=1 # presence-only: dump the enemy-tracker's internal state
|
#TR_TRACKER_PROBE=1 # PRESENCE-only: dump the enemy-tracker's internal state
|
||||||
TR_TRACKER_PROBE_PATH=/tmp/tracker_probe.jsonl # where that dump is written
|
TR_TRACKER_PROBE_PATH=/tmp/tracker_probe.jsonl # where that dump is written
|
||||||
|
|
||||||
# ── dotenv / boot report ─────────────────────────────────────────────────────
|
# ── dotenv / boot report ─────────────────────────────────────────────────────
|
||||||
# Name of the env file to load. Must be set in the REAL environment, not in the
|
# Name of the env file to load. Must be set in the REAL environment, not in the
|
||||||
# file it points at. Empty = use ./.env, else .env next to the binary.
|
# file it points at. Empty = use ./.env, else .env next to the binary.
|
||||||
|
# GOTCHA: the line below sets it to the EMPTY string, which is the correct
|
||||||
|
# "use the default" spelling; putting a real path here would make this file
|
||||||
|
# load itself, recursively, at every start.
|
||||||
TR_ENV_FILE=
|
TR_ENV_FILE=
|
||||||
# 1 = print the [env] report on startup (default). 0 = do not print it.
|
# 1 = print the [env] report on startup (default). 0 = do not print it.
|
||||||
TR_ENV_REPORT=1
|
TR_ENV_REPORT=1
|
||||||
|
|||||||
+115
-5
@@ -47,13 +47,123 @@ misled people:**
|
|||||||
warning at all**.
|
warning at all**.
|
||||||
2. **Some flags are presence-based, not value-based.** They are read with
|
2. **Some flags are presence-based, not value-based.** They are read with
|
||||||
`existsEnv`, so **`TR_POWER_LOG=0` turns the log ON** (any value does).
|
`existsEnv`, so **`TR_POWER_LOG=0` turns the log ON** (any value does).
|
||||||
Presence-based: `TR_POWER_LOG`, `TR_RAM_LOG`, `TR_MOVEMENT_LOG`,
|
Value-based (`0`/`false`/`off` really disable): `TR_ENV_REPORT`,
|
||||||
`TR_RECORD_WORLDSTATE`, `TR_RADAR_FORCE_SPIN`, `TR_RADAR_SCANLOG`,
|
`TR_TMHORIZON_LOG`, `TR_TMHORIZON_ACCURVE`,
|
||||||
`TR_TRACKER_PROBE`. Value-based (`0`/`false`/`off` really disable):
|
|
||||||
`TR_ENV_REPORT`, `TR_TMHORIZON_LOG`, `TR_TMHORIZON_ACCURVE`,
|
|
||||||
`TR_TMHORIZON_RESET_ON_TARGET`, `TR_POWER_POLICY`, `TR_POWER_FINISH_KILL`,
|
`TR_TMHORIZON_RESET_ON_TARGET`, `TR_POWER_POLICY`, `TR_POWER_FINISH_KILL`,
|
||||||
`TR_RAM_OPPORTUNITY`, `TR_RAM_PLAN`, `GUN_SELECTOR_POOL`,
|
`TR_RAM_OPPORTUNITY`, `TR_RAM_PLAN`, `GUN_SELECTOR_POOL`,
|
||||||
`TR_VBULLET_ADMIT_ONLY`.
|
`TR_VBULLET_ADMIT_ONLY`, `TR_LEADGAIN_LOG`, `TR_LEARNED_LOG`,
|
||||||
|
`TR_LEARNED_GLOBAL`, `TR_LEARNED_REAL_EVENTS`, `TR_FIRE_FIX`,
|
||||||
|
`TR_STRAFE_FIRE_FIX`, `TR_STRAFE_ESCAPE`, `TR_STRAFE_HEAT_GRID`,
|
||||||
|
`TR_TFIL_HEAT_TIME`, `TR_TFIL_PILLAR_ON`, `TR_TFIL_DIAG`, `TR_TFIL_NO_REV`,
|
||||||
|
`TR_TFIL_HOLD_WHEN_TRAPPED`, `TR_TFIL_COMMIT_ARRIVAL`,
|
||||||
|
`TR_TFIL_RING_COMMIT_ARRIVAL`, `TR_VBULLET_DEBUG`, `TR_GEO_DEBUG`,
|
||||||
|
`TR_DEBUG_DRAW`, `TR_RESULT_LOG`.
|
||||||
|
|
||||||
|
### THE FULL PRESENCE-GATED LIST (j172, from `grep -rn existsEnv`)
|
||||||
|
|
||||||
|
The list above was **incomplete**: it was missing four knobs. The complete set,
|
||||||
|
from `grep -rn 'existsEnv' ModularBot_garage/src common_libs | grep -v /tests/`,
|
||||||
|
is:
|
||||||
|
|
||||||
|
| knob | read at | what it logs / does |
|
||||||
|
|---|---|---|
|
||||||
|
| `TR_POWER_LOG` | `ModularBot.nim:145` | one line per power-decision CHANGE |
|
||||||
|
| `TR_RAM_LOG` | `ram_decision.nim:119` | one line per ram start/stop + reason |
|
||||||
|
| `TR_MOVEMENT_LOG` | `the_floor_is_lava_ring.nim:192` | movement band / range-class changes |
|
||||||
|
| `TR_STRAFE_LOG` | `strafe.nim:402` | one line per strafe tile pick |
|
||||||
|
| `TR_SURF_LOG` | `wave_surfer.nim:102` | one line per wave-surfing decision |
|
||||||
|
| `TR_FIRE_DIAG` | `ModularBot.nim:137`, `the_floor_is_lava.nim:299`, `strafe.nim:415` | per-reading fire-detection tick/raw/correction |
|
||||||
|
| `TR_RECORD_WORLDSTATE` | `ModularBot.nim:70` | dump every observed world state |
|
||||||
|
| `TR_RADAR_SCANLOG` | `ModularBot.nim:80` | log every radar scan tick |
|
||||||
|
| `TR_RADAR_FORCE_SPIN` | `ModularBot.nim:79` | force the old full-360 spin radar |
|
||||||
|
| `TR_TRACKER_PROBE` | `ModularBot.nim:86` | dump the enemy-tracker internals |
|
||||||
|
|
||||||
|
**For these ten, `NAME=0` turns the feature ON.** OFF means the line is ABSENT.
|
||||||
|
That is why `.env.example` shows every one of them commented out: there is no
|
||||||
|
"off" spelling, only absence. To disable one, delete its line.
|
||||||
|
|
||||||
|
Two more are read with `existsEnv` but are *not* features — `TR_ENV_FILE` (an
|
||||||
|
empty value is the correct "use the default" spelling) and the loader's own
|
||||||
|
`existsEnv(e.key)` conflict check.
|
||||||
|
|
||||||
|
**And one label is misleading:** `env_report.nim` prints `TR_TFIL_DIAG`,
|
||||||
|
`TR_TFIL_HOLD_WHEN_TRAPPED`, `TR_TFIL_COMMIT_ARRIVAL` and
|
||||||
|
`TR_TFIL_RING_COMMIT_ARRIVAL` through `sourceOfPresence`, but all four are read
|
||||||
|
**by value** (`getEnvBool`) in the source. The value is always right; only the
|
||||||
|
`(source: ...)` label is affected. Do not read that label as "presence-gated".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ONE EXPERIMENT, END TO END (mirrored from `.env.example`)
|
||||||
|
|
||||||
|
Pick ONE knob. Here it is `TR_TFIL_ARRIVE_TICKS`; the shape is the same for
|
||||||
|
every knob.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. write the arm as its own file — that is how you GUARANTEE the arm, because
|
||||||
|
# nothing else can be applied on top of it
|
||||||
|
cat > /tmp/arm_arrive15.env <<'EOF'
|
||||||
|
TR_MOVEMENT=tfil
|
||||||
|
TR_TFIL_ARRIVE_TICKS=15.0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 2. RESTART THE BOT. Env is read ONCE, at boot (module init). Editing .env
|
||||||
|
# while the bot runs changes nothing; there is no live reload.
|
||||||
|
cd ModularBot_garage && ./ModularBot.sh # or restart the GUI
|
||||||
|
|
||||||
|
# 3. CONFIRM IT TOOK EFFECT, before reading a single result line.
|
||||||
|
# `source: .env` = your file was applied. `source: default` = it was not.
|
||||||
|
grep '^\[env\]' /tmp/modularbot_stdout.log | grep -E 'env file|ARRIVE_TICKS'
|
||||||
|
# [env] env file: /tmp/arm_arrive15.env (source: TR_ENV_FILE)
|
||||||
|
# [env] TR_TFIL_ARRIVE_TICKS = 15.0 (source: .env)
|
||||||
|
|
||||||
|
# 4. point at the file instead of copying it into .env:
|
||||||
|
TR_ENV_FILE=/tmp/arm_arrive15.env ./out/ModularBot
|
||||||
|
./out/ModularBot --env-file /tmp/arm_arrive15.env
|
||||||
|
# A file you ASKED for and that does not exist stops the bot with an error; a
|
||||||
|
# missing default .env is silent. This is what an A/B run does: one frozen
|
||||||
|
# binary, one env file per arm.
|
||||||
|
|
||||||
|
# 5. what is switched on at all:
|
||||||
|
grep '^\[modules\]' /tmp/modularbot_stdout.log
|
||||||
|
```
|
||||||
|
|
||||||
|
## SAFE TO EXPERIMENT WITH RIGHT NOW
|
||||||
|
|
||||||
|
The honest list is SHORT: after the recent campaign most experimental knobs are
|
||||||
|
either never live-tested or already measured null/harmful, and `.env.example`
|
||||||
|
says so on every one of them. These four are safe in the sense that they either
|
||||||
|
cannot change a decision, or are the ones a measurement actually supports.
|
||||||
|
|
||||||
|
| knob | what changes | what to watch | a good result |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `TR_GEO_DEBUG=on` | draw-only geometry overlay | the circles on the two tanks, each heading line | you can SEE the tile the picker chose; it cannot change a decision |
|
||||||
|
| `TR_VBULLET_DEBUG=1` + `TR_VBULLET_DEBUG_GUN=all` | draw-only: each admitted gun's virtual bullets | travelled path, aim ring, miss vector | you can see the signal the selector ranks on; also draw-only |
|
||||||
|
| `TR_TFIL_DIAG=on` | fills the per-pick loss histogram (tfil only) | the tfil pick log line | `sReach/sCool/sSafe/sCand` tell you where tiles are lost; provably moves no command |
|
||||||
|
| `TR_MOVEMENT=tfil` | runs the long-shipped mover | nothing to compare against | you are reproducing an older, documented behaviour; only do it together with the `TR_TFIL_*` knobs |
|
||||||
|
|
||||||
|
## ALREADY REJECTED OR MEASURED NULL — WITH THE NUMBER
|
||||||
|
|
||||||
|
Do not re-run these by accident.
|
||||||
|
|
||||||
|
| knob / arm | result | where |
|
||||||
|
|---|---|---|
|
||||||
|
| `TR_TFIL_GEO_MODE=both-rej` + `TR_TFIL_GEO_TAU=60` | **REJECTED** live, 420 battles, 15 opponents: damage/run **-8.83**, p(sign-flip) **0.0061**, Wilcoxon p 0.011. Round wins null. Offline it did what was predicted (arrivals 4.5% -> 29.4%) and that is why it is bad: +26 px distance on 15/15, less damage. | `docs/tfil_geo_ab.md` |
|
||||||
|
| `TR_RAM_FLOOR_ENERGY=5` | **CLEAN NULL**: **-0.018 wins/run**, p(sign-flip) **0.7676**, under a **0.1420 wins/run** MDE, 900 battles. Mechanism fired on 0.04% of ticks (~200x less than the offline ruler said). Do not re-test: more runs buy resolution on an effect that is not there. | `docs/ram_floor_exhaustion_ab.md` |
|
||||||
|
| `TR_RAM_FLOOR_ENERGY=10/20` | measured COSTLY offline (20 blocked 24.7% of all ticks) and the zone it guards is nearly empty: only 4.8% of shots are taken below 10 energy. | same |
|
||||||
|
| `TR_TMHORIZON_WINDOW=150` | **MEASURED HARMFUL** live: 26.5% round wins vs 49.0% for the shipped rack, p = 0.036. Keep 0. | env_reference "Measured verdicts" |
|
||||||
|
| `TR_POWER_POLICY=0` | **MEASURED HARMFUL** live: real hit rate 10.61% -> 7.88%, p = 0.0012. | same |
|
||||||
|
| `TR_TFIL_HEAT_TIME=1` | **MEASURED HARMFUL** live at every tau tried (3/5/9/15); tau15 alone is -22 damage/run, p = 0.046. | `docs/tfil_heat_pillar_ab.md` |
|
||||||
|
| `TR_MOVEMENT=tfil_ring` | **MEASURED**: round wins 16/49 -> 6/49, p = 0.012. Best live hit rate of anything measured, half the survival. | same / env_reference |
|
||||||
|
| the full `TR_RACK_*` rack | **MEASURED NEGATIVE VALUE**: Pattern ALONE beats the full 13-gun rack, p = 0.0012. Adding guns costs rounds. | `docs/gun_rack_analysis.md` |
|
||||||
|
| `TR_TFIL_TURN_BIAS=9` + `_TURN_REF_DEG=0` | **LIVE NULL**: +0.15 wins/run, p(sign) 0.244, under a 0.30 MDE, 300 battles. | `docs/movement_campaign.md` (j145) |
|
||||||
|
| `TR_RAM_OPPORTUNITY=on` | **MEASURED not to convert**: 0/59 opportunity -> contact. The finisher ram is the only path that converts, and it is always on. | env_reference |
|
||||||
|
| `TR_TFIL_PILLAR_ON=1` | live-tested, and the recommendation to revert to pillar-on was **OVERRULED by the owner**: the contrast is inside the MDE (33 damage/run, 1.22 wins/run at n=10). Pillar stays removed. | `docs/tfil_heat_pillar_ab.md` |
|
||||||
|
|
||||||
|
> **A null is only a null at the resolution that run reached.** The frozen
|
||||||
|
> 15-opponent panel at 14 runs/arm resolves ~0.17 wins/run and ~7.65 damage/run;
|
||||||
|
> the j163 run resolved 0.1420 wins/run. "Clean null" here means *no effect at or
|
||||||
|
> above that size* — not *no effect*.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user