Track commander damage at combat-damage time by checking `is_commander`
on each attacking creature. Damage from commander creatures is now
recorded in both a per-seat aggregate (`commander_damage_received`) and
a per-card breakdown (`commander_damage_by_card`), enabling correct
21-damage lethal checks for partner/multi-commander games.
Changes:
- engine._resolve_combat: identify commander attackers, accumulate their
damage (including trample overflow and double strike), write to both
tracking dicts, and check commander-damage elimination after combat.
- models.Player: add commander_damage_received, commander_damage_by_card,
and is_dead_to_commander_damage() so the headless engine can track
commander damage without the full CommanderGameState wrapper.
- game_state.CommanderPlayer: replace the separate
commander_damage_received field with a property delegating to
base.Player to avoid split-brain state between engine and wrapper.
- game_state.CommanderGameState.deal_commander_damage: accept optional
commander_name for per-card tracking.
- 22 new regression tests covering unblocked, blocked, trample, double
strike, lifelink, partner, cumulative, and lethal scenarios.
Partial fix for Issue #86 item 2.
Co-authored-by: Claude <noreply@anthropic.com>
Implements the three approved Phase 5 architecture decisions:
1. Zone embedding boundary: add explicit documentation in StateDimensions
and StateEncoder._encode_zones making the 6144-dim zero-padded zone
contract visible to future maintainers.
2. SQLite WAL online learning store: new OnlineLearningStore class backed
by WAL-mode SQLite for concurrent read/write on single-machine baseline.
New /api/policy/decide endpoint collects decisions during inference.
Stats endpoint at /api/policy/decide/stats.
3. Forge-only default weights: change ppo_weight default from 0.5 to 0.0
across scope.py, DistillationConfig, DatasetConfig, and CLI defaults.
Add MIXED_MODE_PRESETS dict with forge_only, forge_90_10, forge_80_20
presets. Distill/start endpoint now accepts a "preset" parameter.
27 new tests covering all three decisions (all passing).
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Replace SELECT * + Python-side color loop in _get_collection_for_colors()
with projected SELECT + NOT EXISTS json_each() sub-query
- Apply same pattern to _build_collection_summary(), removing card_fits_identity()
- Add partial index idx_ce_quantity on collection_entries(quantity) WHERE qty > 0
- Handle NULL and empty-string color_identity via CASE guard
- Fix colorless commander bug: old code skipped color check entirely for []
- Add scripts/bench_deckgen.py benchmark (3-5x speedup on filtered queries)
- Add tests/test_deckgen_color_filter.py with 7 regression tests