chore(training): promote stage-4 retry2 to medium and open stage 5

20260816-2126-gen5-s4-handling-retry2 exhausted its three attempts and
missed only the 0.80 training goal-rate floor, at 0.7731. Every
evaluation gate passed: 65-22-13 versus promoted/easy.json, 87% non-draw
against an 80% floor, 12.6% physical-side imbalance against a 20%
ceiling, and both handling telemetry floors clear. The round improved the
goal rate monotonically across attempts (0.537 -> 0.683 -> 0.773) and the
checkpoint plays well by hand, so close Stage 4 by human override.

Promote it to Game/bots/promoted/medium.json. Medium and Hard both point
at the new policy: Hard stays a label-only duplicate until a stronger one
earns hard.json, which keeps the tiers monotonic rather than leaving Hard
weaker than Medium.

generation5_state.json flips that log entry to "pass" with a
decision_override block preserving the original verdict and reasoning,
and advances to Stage 5 attempt 1. This is what passing_entry() needs to
resolve Stage 5's resume checkpoint and evaluation reference, and what
league_pool() will need at Stage 6; --skip-to-next-stage would advance
the stage without marking anything as passing and die immediately.

generation5.sh now pulls before launching. Each stage ends in
commit_progress()'s push, which fails and kills the run hours in if the
box is behind origin.
This commit is contained in:
Josh Creek
2026-08-17 07:49:21 +01:00
parent 62ff85e75c
commit 0b6679e84b
5 changed files with 65 additions and 15 deletions
+35 -5
View File
@@ -164,7 +164,14 @@ flat files there, never touching subdirectories.
actually referenced by the shipped game — currently `easy.json` (promoted
2026-08-08 from generation 4's `20260806-1939-curric-s3-gauntlet`; this is
the 320M-step MultiDiscrete policy and the foundation for the planned
generation-5 curriculum below) and `reference-grounded.json` (added for
generation-5 curriculum below), `medium.json` (promoted 2026-08-17 from
generation 5's `20260816-2126-gen5-s4-handling-retry2` — Stage 4 attempt 3,
which the pipeline recorded as a *fail* on the 80% training-goal-rate gate at
0.7731, but which beats `easy.json` 65-22-13 in the 100-episode paired
evaluation, 87% non-draw and 12.6% physical-side imbalance, both inside the
Stage-4 bars; promoted by hand on gameplay feel, so its recorded
`decision: "fail"` in `generation5_state.json` is expected and not a
bookkeeping error) and `reference-grounded.json` (added for
generation 4 — a copy of generation 3's `curric-s5-aggression`, made before
the flat `Game/bots/` dump was scrapped for the redesign, kept as the
strongest grounded-era artifact and the fixed yardstick generations 1-3 were
@@ -174,10 +181,12 @@ promoted file is never touched by training scripts, never overwritten by a
same-named future export, and never disturbed by pruning old experiment
files from the flat dump.
Until distinct `medium.json` and `hard.json` policies earn promotion, the
three menu tiers all run this same `easy.json` policy at its full trained
cadence (`reaction_ticks=8`, `action_noise=0`). The tiers are labels only;
the game does not manufacture difficulty gaps by handicapping this model.
Easy and Medium are now genuinely different policies. Hard still points at
`medium.json` and remains a label-only duplicate until a stronger policy earns
`hard.json`. Every tier runs at full trained cadence (`reaction_ticks=8`,
`action_noise=0`) — the game does not manufacture difficulty gaps by
handicapping a model. When promoting, keep the tiers monotonic: a lower tier
must never point at a policy that beats the tier above it.
To promote a new bot into a tier: copy the chosen `Game/bots/<experiment>.json`
to `Game/bots/promoted/<tier>.json` (overwriting the old one), and note the
@@ -609,6 +618,27 @@ that fades to zero by 3m altitude. Its scoring gates deliberately run before
Stage 5: becoming upright is not progress if the resulting policy stops
finishing goals. Stage 5 adds moving high-ball intercept
starts aimed toward real goals rather than a standalone air-touch reward.
**Stage 4 was closed by human override on 2026-08-17**, not by the automatic
gate. `20260816-2126-gen5-s4-handling-retry2` exhausted all three attempts and
the pipeline recorded `decision: "fail"`, on the training goal-rate floor alone
(0.7731 vs 0.80). Every other gate passed — 65-22-13 versus
`promoted/easy.json`, 87% non-draw against the 80% floor, 12.6% physical-side
imbalance against the 20% ceiling, and both handling telemetry floors clear
(`upright_fraction` 0.772 vs 0.45, `forward_motion_fraction` 0.315 vs 0.25) —
and the round's three attempts improved the training goal rate monotonically
(0.537 → 0.683 → 0.773). The same checkpoint also plays well enough by hand to
have been promoted to `medium.json`. `generation5_state.json` therefore has
that log entry's `decision` flipped to `"pass"` with a `decision_override`
block recording the original verdict and reasoning, and `stage_index`/
`attempt`/`status` advanced to Stage 5 attempt 1 — which is what
`passing_entry()` needs to resolve Stage 5's resume checkpoint and evaluation
reference, and what `league_pool()` will later need at Stage 6. Prefer this
edit over `--skip-to-next-stage`: that flag advances `stage_index` without
marking anything as passing, so the run dies immediately with `RuntimeError:
No passing generation-5 stage index 0`. Note that retry2 already clears Stage
5's own 0.75 goal-rate floor; the 0.80 Stage-4 figure was always the stricter
of the two.
Stage 6's `league` opponent mode samples a historical exported policy at each
episode reset. Each later stage preserves the preceding shaping and adds one
new difficulty.