feat(SAC_LSTM_Bot): mirror-twin sparring partner + readiness check (#54)

- make_twin.sh: generates self-contained SacTwin dir in the sample-bots
  archive (own json/sh identity, own weights dir seeded from a frozen
  sac_best.zip copy, own round_counter) so RunTraining.java resolves it
  like any sample bot; re-running resets the twin to the frozen baseline.
- src/SAC_LSTM_Bot.nim: SACLSTM_BOT_JSON env overrides the baked-in bot
  json (loadBotInfo gives json total precedence, #49) so the same binary
  boots under the twin's name.
- sac_train.sh: chunk loop is a while, not for-over-seq — a crash on the
  FINAL chunk previously fell through ((chunk--);continue on an exhausted
  seq list) and exited 0 with budget incomplete; observed live vs SacTwin.

Readiness dry-run (#54): weighted pool Corners:1,SacTwin:3 picked the twin
in 3/4 chunks; all battles counter-checked; deterministic eval parsed;
main sac_best.zip/counter untouched by twin (twin counter advanced
independently); crash-restart proven end-to-end incl. final-chunk retry.
This commit is contained in:
2026-08-21 23:19:27 +02:00
parent edf26aa45d
commit 6a294ad7ad
3 changed files with 67 additions and 2 deletions
+5 -1
View File
@@ -17,7 +17,11 @@ import SAC_LSTM_Bot/actions
import SAC_LSTM_Bot/rewards
import SAC_LSTM_Bot/integration
const botJsonPath = currentSourcePath().parentDir / "SAC_LSTM_Bot.json"
# Identity json: baked-in src json by default; SACLSTM_BOT_JSON lets a mirror
# twin (#54) boot the same binary under its own name (loadBotInfo gives the
# json total precedence over env, so the twin must point at its own file).
let botJsonPath = getEnv("SACLSTM_BOT_JSON",
currentSourcePath().parentDir / "SAC_LSTM_Bot.json")
# ── Colors (Recurrent Royalty palette) ───────────────────────────────────────