Pokémon TCG AI Battle — Temporal BC Overhaul, 2026-07-29
Historical implementation record for recurrent TBPTT, FP16 MLX training, Muon/AdamW routing, progress accounting and self-contained PyTorch inference; current runtime is reconciled separately.
Pokémon TCG AI Battle — Temporal BC Overhaul, 2026-07-29
Evidence boundary
This record describes commit 2a57659 in ~/workdir/pokemon-tcg.
The implementation was validated only with real competition replays through
configs/smoke.json. No long training run is part of this workflow.
It is a historical July 29 implementation record. The later source snapshot
enforces strict FP32 for training and PyTorch conversion; see
pokemon_tcg_current_state_reconciliation and
pokemon_tcg_training_pipeline before treating the runtime table below as
current.
The preserved baseline checkpoint contains 14 epochs: zero-based epoch=13,
gstep=93,386, and validation accuracy 0.7419737. The user reports that an
earlier seven-epoch submission reached roughly 900–930 ladder rating. This
ladder result is user-reported, not a causal comparison.
Runtime and artifact contract
dataset construction -> Python game engine and encoder
training -> MLX on Apple Silicon
arena inference -> PyTorch FP16
configs/train_config.json and configs/smoke.json are transient session
sheets. Neither is included in the submission archive or read by arena
inference. A checkpoint carries:
- resolved training provenance;
- architecture and token-schema versions;
- exact inference settings, including would-KO;
- static card-feature table and card CSV hash;
- model, optimizer, scheduler, epoch, global step, and phase identity;
- dataset manifest and build fingerprint.
The portable PyTorch artifact contains the same runtime contract and a strict
FP16 state dictionary. Old checkpoints without inference metadata
conservatively use would_ko=false.
Temporal unit
The recurrent unit is an engine decision, not an emitted row. A multi-select decision can expand into several autoregressive labels:
[ \pi(a_1\mid s),\quad \pi(a_2\mid s,a_1),\quad \pi(\mathrm{SUBMIT}\mid s,a_{<k}). ]
Every row from one decision reads the same incoming recurrent memory. Only the
last substep commits memory to the next engine decision. Memory is isolated by
(episode_id, side).
TBPTT chunks are measured in decisions. Independent episode-side lanes can be packed up to the configured physical row limit. The limit is dynamic: 128 is the current smoke value, not an architectural maximum. Validation uses the same temporal and multi-select semantics and reconstructs logits in original row order.
Optimization and precision
| Parameter class | Optimizer |
|---|---|
| hidden two-dimensional Transformer matrices | Muon |
| embeddings, heads, vectors, biases, and remaining parameters | AdamW |
Parameters and forward activations are FP16. Cross entropy, reductions, accumulated gradients, Muon velocity, and AdamW moments use FP32. Loss is summed per microbatch and divided exactly once by the real accumulated example count. Clipping and scheduling advance once per optimizer update.
Optimizer and scheduler state are explicit. reset starts a new optimization
phase while retaining model weights; resume continues a compatible,
interrupted phase. Daily phases carry a fingerprint of the dataset and session
sheet, and rolling checkpoints carry the same phase identity.
Progress semantics
The progress plan is derived from the exact temporal batches before an epoch. It reports real microbatches, optimizer updates after accumulation, scheduler position, and phase-specific ETA. Training, validation, metrics, checkpoint, and epoch completion are separate phases. A training bar at 100% therefore does not claim that validation or checkpointing has finished.
Real smoke evidence
configs/smoke.json built two real episodes from the 2026-07-28 competition
archive:
rows=322
attack_rows=78
would-KO computed options=78
valid zero would-KO options=44
failed would-KO options=0
masked labels=0
Two smoke epochs used:
batch_size=128
val_batch_size=128
accum_steps=2
tbptt_chunk=32
microbatches/epoch=3
optimizer_steps/epoch=2
Observed peak unified memory was 0.65 GiB. Global step reached 4. The portable
submission loaded would_ko=true from its checkpoint without a JSON file and
returned the 60-card deck in an isolated extracted environment.
Operational boundary
Only smoke runs are authorized during implementation. Increasing smoke epochs
is permitted through configs/smoke.json; starting a long/full-corpus training
run is not.