SirStone aed579b3af TM horizon: retain learning ACROSS ROUNDS, reset only when the ENEMY changes
The user's requirement: "every battle i means from round 1 to round end-battle, so
retain all learning until the enemy change." What was built wiped the Tsetlin
machines EVERY ROUND, in two places (`onRoundStarted` and the gun's own
tick-regression self-reset), so in a 7-round battle each round started cold,
trained ~360 samples and threw them away - discarding most of its one chance to
do what was asked: overfit the current enemy over the whole battle.

THE FIX - two kinds of state, two triggers:
- **`resetRoundState` (per ROUND)**: the observation ring, pending/deferred
  labels, the bullet proxy, motion history, per-tick caches, `roundStartTrained`.
  These MUST clear every round, because bots teleport back to the starting corners
  between rounds - an old position would build a garbage label. (That exact class
  of bug shipped 36-58% wrong labels in the old gun.)
- **`resetLearning` (per BATTLE / per ENEMY)**: both Tsetlin machines, `trained`,
  `sideCorrect/sideTotal`, all histograms, the magnitude median, `pendingDropped`,
  `observedTargetId`. These now SURVIVE round boundaries.
Triggers for the machine wipe: `onGameStarted` (primary) plus a redundant
`roundNumber <= 1` fallback in `onRoundStarted`; and a TARGET CHANGE
(`targetChanged`, knob `TR_TMHORIZON_RESET_ON_TARGET` default on - a no-op in 1v1,
fires on melee target switches; first acquisition never wipes). The
tick-regression self-reset now clears ONLY per-round state.
Still NO cross-battle persistence: grep for file I/O in the gun finds none.

PROOF IT WORKS (live 2-round battle, `TR_RACK_PATTERN=off TR_RACK_TMHORIZON=both`):
  [tmh-reset] reason=game_start trained_was=0
  [tmh-reset] reason=round1     trained_was=0
  ...exactly TWO reset lines in the whole battle, both at battle start, and NONE
  at the round-2 boundary. And the per-round summaries:
  [tmh-round] trained=1249 thisRound=1249 ... sideAcc=711/1177  (60.4%)
  [tmh-round] trained=2226 thisRound=977  ... sideAcc=1361/2154 (63.2%)
`trained` CLIMBED 1249 -> 2226 across the boundary, and side accuracy rose
60.4% -> 63.2% in round 2 (one battle - suggestive, not proof).

Unit tests: `test_tm_horizon` 79 (was 54), including "trained SURVIVES the
boundary", "clause states SURVIVE", "trained climbs round1->round2", "game-start
wipes and all clauses end Exclude", "different enemy wipes / same enemy does not /
knob-off does not", and crucially "a label CANNOT be built across a round
boundary" (ringValidCount==0, ringHas(oldTick)==false, pendingCount==0) - the
single most dangerous interaction of this change.

Guards: test_tm_horizon 79, test_rack_membership 48, test_gun_harness 39,
test_vbullet_metric 11, test_power_selection 3, test_adaptive_radar 41,
test_tfil_ring_weights 24, test_power_policy 26, test_ram_decision 40,
test_selector_tiebreak 19, test_tm_pattern_registration 20,
test_vbullet_admit_gate 12, test_tm_diag 48, test_tm_automata_diag 55,
test_tm_clause_shape 66. acceptance_offline_vs_online 12/12 VERDICT PASS.
Shipped rack unchanged: DefaultRackMembership is still Pattern-only, TMHORIZON off.

Residual (pre-existing, out of scope, stated): the internal base
`PatternMatcherGun` has a rolling move-history buffer that is NOT cleared at round
boundaries - it never was, and the SHIPPED Pattern gun carries history across
rounds too. It cannot affect label correctness (labels come from `g.ring`), only
base-prediction quality in a round's first ticks.
2026-09-22 23:24:11 +02:00
S
Description
No description provided
104 MiB
Languages
Nim 73.7%
Python 18%
Shell 3.7%
Java 3.5%
HTML 1%
Other 0.1%