feat(@projects/@magic-civilization): ✨ add freepeople tribe founding presentation layer
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
ff4b053ca0
commit
f4845479cb
5 changed files with 40 additions and 18 deletions
|
|
@ -179,3 +179,4 @@ The specific bullets citing canopy fields + weather_event records in `turn_stats
|
|||
[ref: p0-30, p0-31, p0-32, p0-35, p0-36]
|
||||
|
||||
2026-04-18 00:05 p0-35 + p0-36 telemetry instrumentation landed: canopy `{mean, delta}` block added to turn_stats.jsonl per-turn record, `weather_event` / `climate_effect` records added to events.jsonl, aggregate gains `weather_events_count` + `total_weather_events`. Rust: new `GdEcologyPhysics::canopy_summary(grid) -> Dictionary` bridge tracking `last_canopy_mean` internally (NaN sentinel for first call → delta=0); `cargo test -p mc-climate --lib` 28/28 pass. GDScript: `climate.gd` now actually runs `GdEcologyPhysics.process_step(_grid, 1.0)` after `GdClimatePhysics.process_step` so the Rust ecology tick advances flora succession (was dormant — p0-31 wired the climate call but ecology never ticked). `event_bus.gd` adds `weather_event_applied(kind, tile, severity)` + `climate_effect_applied(unit_id, cause, hp_loss)` signals; `weather.gd` emits one per derived event; `climate_effects.gd` emits one per damaged unit; `auto_play.gd` subscribes both, per-turn counter resets on flush. Schema updates: `turn-stats-line.json` aggregate gets two counters + optional top-level `ecology` block; `events-line.json` enum extended (+ backfilled pre-existing `improvement_started`/`loot_dropped`/etc.). `tools/autoplay-report.py` adds `print_canopy_summary` + `print_weather_summary`. Apricot smoke batch 20260417_233821_p035 (10 seeds T300) confirms: every seed has non-zero flora_canopy_mean (0.00052–0.00508) AND non-zero flora_canopy_delta (positive on all 10 seeds), and every seed has `total_weather_events` ≥ 97 (max 406). 5/10 seeds victory (seeds 1,5,6,8,10), 5/10 in_progress at T300 cap, 0 invariant violations. `climate_effect` counts are 0 — storm radii didn't intersect units in this batch; emit path wired but nothing to trigger it. Tuning deferred to p1-05. Files changed: 9 (2 Rust, 4 GDScript, 2 schemas, 1 Python). **Promotes** p0-30 → done (bullet 4 canopy evolution cited), p0-31 → done (bullets 5+6 batch + p0-30 re-promotion cited), p0-32 → done (bullets 3+4 weather events cited), p0-35 + p0-36 → done. [ref: p0-35, p0-36, p0-30, p0-31, p0-32]
|
||||
2026-04-18 01:30 p0-34 Freepeople tribe-founding presentation layer landed end-to-end: Rust `GdPrologue` GDExtension bridge + GDScript integration wire the existing `mc-turn::prologue` simulation (already green from task #9) into the live game's turn -1/0/1 cold-open. Rust: new `GdPrologue` class in `api-gdext/src/lib.rs` (~300 lines) owns `PrologueTurn` + per-player `Wanderer`/`DwarfTribe` + `Chronicle`; exposes `state()`, `display_turn()`, `is_prologue()`, `register_player()` (calls `place_spawn_box` against a `GdGridState` mirror), `wanderers_for()`, `centroid()`, `advance()` (runs roll/step/converge per edge, returns `{new_state, new_turn, chronicle_events}`), `dwarf_tribe()`, `found_capital()`, `all_chronicle_events()`. GDScript: new `PrologueDriver` wrapper (`src/game/engine/src/modules/management/prologue_driver.gd`, ClassDB.instantiate pattern) + new `PrologueOverlayRenderer` (draw-first circle+W glyph per wanderer, circle+T for tribe) + new `city.gd::found_with_population` hop to `GdCity::found_with_population` (tribe-dev's Rust side, task #9). `TurnManager.prologue: RefCounted` field + `end_turn()` branch skips per-player rotation and drives `prologue.advance()` during prologue phases; `EventBus` gains `prologue_state_changed`, `tribe_converged`, `capital_founded` signals. `world_map.gd`: `_bootstrap_prologue` branches on `setup.json:start_turn == -1`, populates a minimal `GdGridState` biome mirror, registers each `GameState.players` entry via `GdPrologue::register_player`; `_handle_hex_click` short-circuits via `_is_prologue_active()`; `_on_prologue_tribe_converged` spawns a GDScript `Unit("dwarf_tribe", pid, centroid)` with `movement_remaining=1` so the Found City button unlocks; `_on_found_city_pressed` branches on `type_id == "dwarf_tribe"` and calls `prologue.found_capital(pid)` → `city.found_with_population(...)` with the mode-derived override pop. `world_map_hud.gd::set_prologue_banner(state)` shows a centered "Your wanderers gather..." / "The tribe converges on common ground..." banner + hides the unit panel during turns -1/0. `auto_play.gd` subscribes both new EventBus signals and writes `tribe_converged` + `capital_founded` records into events.jsonl; `_append_turn_stats` prefers `prologue.display_turn()` over `_turn_count` while prologue is active so turn_stats.jsonl first line reads `"turn":-1`. New GUT `test_prologue_driver.gd` covers stub fallback + full state sequence + EventBus dispatch. Three debugging iterations needed to land end-to-end: (1) initial code landed, apricot smoke-1 showed prologue never fired → found `DataLoader.get_data("setup")` vs `get_setup_entry("start_turn")` API mismatch (setup.json is top-level-keys); added typed helpers `_read_start_turn_from_setup`/`_read_prologue_mode_from_setup`/`_read_spawn_box_radius_from_setup` reading `DataLoader._raw.get("setup", {})`. (2) smoke-2 reached prologue but turn_stats + events had no prologue records → added auto_play's prologue override + two new listeners. (3) smoke-3 green end-to-end: E2E 10/10, `head -1 turn_stats.jsonl` shows `"turn":-1`, every seed has ≥1 `tribe_converged` (turn 0) + ≥1 `capital_founded` (turn 1) per player (2/2 in 2-player runs). Files changed: 11 (1 Rust + 10 GDScript + 1 vocabulary.json banner strings + 1 new GUT test). Batch evidence: `.local/iter/apricot-20260417_235740/20260417_235740/smoke/`. Determinism byte-identical bullet left to p1-09 scope per team-lead 2026-04-18; cosmetic `_turn_count` discontinuity (`-1, 0, 1, 4, 5…`) after prologue is a known non-blocker. **Promotes** p0-34 → done. [ref: p0-34]
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@
|
|||
|
||||
| Priority | ✅ | 🟡 | 🔴 | ❌ | ⚫ | Total |
|
||||
|---|---|---|---|---|---|---|
|
||||
| **P0** | 26 | 6 | 3 | 0 | 0 | 35 |
|
||||
| **P0** | 27 | 5 | 3 | 0 | 0 | 35 |
|
||||
| **P1** | 13 | 3 | 2 | 0 | 1 | 19 |
|
||||
| **P2** | 9 | 6 | 0 | 9 | 0 | 24 |
|
||||
| **P3 (oos)** | 0 | 0 | 0 | 0 | 17 | 17 |
|
||||
| **total** | **48** | **15** | **5** | **9** | **18** | **95** |
|
||||
| **total** | **49** | **14** | **5** | **9** | **18** | **95** |
|
||||
|
||||
</td><td valign='top' style='padding-left:2em'>
|
||||
|
||||
|
|
@ -29,8 +29,8 @@
|
|||
| [asset-sprite](../team-leads/asset-sprite.md) | 7 |
|
||||
| [warcouncil](../team-leads/warcouncil.md) | 6 |
|
||||
| [wireguard](../team-leads/wireguard.md) | 4 |
|
||||
| [shipwright](../team-leads/shipwright.md) | 3 |
|
||||
| [tourguide](../team-leads/tourguide.md) | 3 |
|
||||
| [shipwright](../team-leads/shipwright.md) | 2 |
|
||||
| [testwright](../team-leads/testwright.md) | 2 |
|
||||
| [asset-audio](../team-leads/asset-audio.md) | 1 |
|
||||
|
||||
|
|
@ -73,7 +73,7 @@
|
|||
| [p0-31](p0-31-climate-rust-path-restore.md) | ✅ done | Restore Rust ecology path — fix ClimateScript bugs + re-enable per-turn tick | [shipwright](../team-leads/shipwright.md) | 2026-04-18 |
|
||||
| [p0-32](p0-32-weather-climate-effects-restore.md) | ✅ done | Restore WeatherScript + ClimateEffectsScript — per-turn weather and climate-effects | [shipwright](../team-leads/shipwright.md) | 2026-04-18 |
|
||||
| [p0-33](p0-33-world-map-input-and-panel-wiring.md) | 🟡 partial | World-map input wiring — unit selection panel, city click, ESC/F10 menu, panel close | [wireguard](../team-leads/wireguard.md) | 2026-04-17 |
|
||||
| [p0-34](p0-34-freepeople-tribe-founding.md) | 🟡 partial | Freepeople tribe-founding cinematic — turn -1 / 0 / 1 start sequence and Dwarf Tribe founder unit | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
|
||||
| [p0-34](p0-34-freepeople-tribe-founding.md) | ✅ done | Freepeople tribe-founding cinematic — turn -1 / 0 / 1 start sequence and Dwarf Tribe founder unit | [shipwright](../team-leads/shipwright.md) | 2026-04-18 |
|
||||
| [p0-35](p0-35-movement-mode-ux.md) | 🔴 stub | Movement mode UX — Move button, path preview, right-click confirm, fog-aware pathing | [wireguard](../team-leads/wireguard.md) | 2026-04-17 |
|
||||
|
||||
## P1 — Ship-readiness
|
||||
|
|
|
|||
|
|
@ -4,16 +4,25 @@ title: Freepeople tribe-founding cinematic — turn -1 / 0 / 1 start sequence an
|
|||
priority: p0
|
||||
scope: game1
|
||||
owner: shipwright
|
||||
status: partial
|
||||
updated_at: 2026-04-17
|
||||
status: done
|
||||
updated_at: 2026-04-18
|
||||
evidence:
|
||||
- public/resources/villages/freepeople.json
|
||||
- public/resources/ai/freepeople/freepeople.json
|
||||
- src/simulator/crates/mc-turn/
|
||||
- src/simulator/crates/mc-core/
|
||||
- src/simulator/api-gdext/src/lib.rs
|
||||
- src/game/engine/scenes/world_map/world_map.gd
|
||||
- src/game/engine/src/autoloads/turn_manager.gd
|
||||
- src/game/engine/src/autoloads/event_bus.gd
|
||||
- src/game/engine/src/modules/management/prologue_driver.gd
|
||||
- src/game/engine/src/rendering/prologue_overlay_renderer.gd
|
||||
- src/game/engine/scenes/hud/world_map_hud.gd
|
||||
- src/game/engine/scenes/tests/auto_play.gd
|
||||
- src/game/engine/tests/unit/test_prologue_driver.gd
|
||||
- public/games/age-of-dwarves/data/units/
|
||||
- public/games/age-of-dwarves/data/setup.json
|
||||
- .local/iter/apricot-20260417_235740/20260417_235740/smoke/
|
||||
---
|
||||
|
||||
## Context
|
||||
|
|
@ -64,11 +73,11 @@ Keeping them separate means the variance only exists at game-start, not inside t
|
|||
## Acceptance
|
||||
|
||||
- ✓ New game starts on **turn -1**, not turn 1. Turn counter visibly reads `-1`. _Rust-core: `mc-turn/src/prologue.rs::PrologueTurn::new_game() → { turn: -1, state: TurnMinusOne }`, test `mc_turn::prologue::tests::new_game_starts_at_turn_minus_one`. GDScript HUD label wiring to this value is still pending (presentation layer)._
|
||||
- ✗ On turn -1, each player's spawn box contains `N` (3–12) ordinary free-dwarf wanderer sprites. **None** carry a `player_ancestor` flag — allegiance is emergent from their turn-0 roll. _Rust contract: `mc_turn::prologue::Wanderer { owner, position, rolled_direction, merged_into_tribe }` — `owner` is provenance only; tests `non_converging_wanderers_persist` + `convergence_never_fails` verify emergence from roll. Sprite render / world-map placement — presentation layer pending._
|
||||
- ✗ On turn -1, **End Turn** (button + Enter key) is the only enabled input. No unit is selectable. City / tech / menu overlays remain reachable per p0-33. _Rust gate: `mc_turn::prologue::allowed_player_actions(PrologueState::TurnMinusOne) == ["end_turn"]`, test `player_input_locked_on_prologue_turns`. GDScript `world_map.gd` input-lock wiring pending._
|
||||
- ✓ On turn -1, each player's spawn box contains `N` (3–12) ordinary free-dwarf wanderer sprites. **None** carry a `player_ancestor` flag — allegiance is emergent from their turn-0 roll. _Rust contract: `mc_turn::prologue::Wanderer { owner, position, rolled_direction, merged_into_tribe }`; tests `non_converging_wanderers_persist` + `convergence_never_fails` verify emergence from roll. GDScript presentation: `GdPrologue::register_player` calls `mc_mapgen::place_spawn_box` which seeds `N` wanderers per mode; `PrologueOverlayRenderer` (`src/game/engine/src/rendering/prologue_overlay_renderer.gd:1-74`) draws circle + 'W' glyph per wanderer from `GdPrologue::wanderers_for(pid)` — draw-first baseline per p0-23. Mounted on `$OverlayLayer` by `world_map.gd::_setup_renderers`, redraws on `prologue_state_changed`. Apricot smoke-3 seed1 stdout: `[p0-34] _bootstrap_prologue: mode=tournament radius=3 players=2` (batch `.local/iter/apricot-20260417_235740/20260417_235740/smoke/`)._
|
||||
- ✓ On turn -1, **End Turn** (button + Enter key) is the only enabled input. No unit is selectable. City / tech / menu overlays remain reachable per p0-33. _Rust gate: `mc_turn::prologue::allowed_player_actions(PrologueState::TurnMinusOne) == ["end_turn"]`, test `player_input_locked_on_prologue_turns`. GDScript: `world_map.gd::_handle_hex_click` short-circuits via `_is_prologue_active()` helper (reads `TurnManager.prologue.is_prologue()`) so hex clicks, unit selection, and bombard targeting all no-op during the prologue; the End Turn button and ESC/F10/T/C hotkeys (tech/chronicle panels) stay live so players can still explore overlays per spec. Apricot smoke-3 E2E 10/10 green._
|
||||
- ✓ Per-wanderer direction rolls use the seeded PRNG and respect the tournament/lucky bias rules above. Guaranteed-inward count ≥ 3 by construction; convergence cannot fail. _Rust-core: `mc-turn/src/prologue.rs::{roll_wanderer_directions, PrologueRng}`; tests `same_seed_same_directions`, `tournament_mode_pins_exactly_3_unbiased_rest` (100 seeds, analytical-mean check), `lucky_mode_at_least_3_inward` (200 seeds), `convergence_never_fails` (2×1000 seeds across both modes, d=3 mapgen-perimeter ring fixture). End-to-end pipeline sweep: `mc-mapgen/src/spawn_box.rs::tests::spawn_box_feeds_prologue_convergence_1000_seeds` (2×1000 seeds, real `place_spawn_box` output → prologue pipeline → `converge_tribe`, asserts `ancestors_merged ≥ MIN_WANDERERS_TO_FORM_TRIBE` every seed). Convergence radius tuning: `TRIBE_CONVERGENCE_RADIUS = 2` (was `1`), approved as p0-34 Option 1 after mapgen-dev's sweep exposed the single-step d=3→d=2 geometric dead-end._
|
||||
- ✓ Turn counter advances -1 → 0. Wanderers step along their rolled directions (one hex, deterministic). _Rust-core: `PrologueTurn::advance` + `step_wanderers`; tests `turn_sequence_minus_one_zero_one`, `byte_identical_across_runs`._
|
||||
- ✗ On turn 0, **End Turn** is again the only enabled input. _Rust gate green (same `allowed_player_actions` test). GDScript presentation wiring pending._
|
||||
- ✓ On turn 0, **End Turn** is again the only enabled input. _Rust gate green (same `allowed_player_actions` test). GDScript: `_is_prologue_active()` also returns true on `PrologueState::TurnZero` (state id 1), reusing the same `_handle_hex_click` short-circuit; `_bootstrap_prologue`'s banner text flips from "Your wanderers gather..." to "The tribe converges on common ground..." via `set_prologue_banner(state)` driven by `EventBus.prologue_state_changed`. Apricot smoke-3 turn_stats.jsonl line 2 confirms `"turn":0 "outcome":"in_progress"`._
|
||||
- ✓ At end-of-turn-0, wanderers within `tribe_convergence_radius` of the box centroid merge into one **Dwarf Tribe** unit with `founding_pop_override` computed per mode. Non-converging wanderers are **left on the map** as ordinary freepeople NPCs — not deleted, not flagged. _Rust-core: `mc-turn/src/prologue.rs::converge_tribe`; tests `non_converging_wanderers_persist`, `tournament_mode_always_pop_1`, `lucky_mode_third_per_extra`._
|
||||
- ✓ Subsequent freepeople convergence (any 3+ freepeople within radius of each other at end-of-turn) forms a `nomadic_band` camp per `freepeople.json` rules — the same mechanic that formed the player's tribe, now available to the general freepeople population for the rest of the game. _Evidence: `mc-ecology::freepeople_camps::scan_and_form_camps` (`src/simulator/crates/mc-ecology/src/freepeople_camps.rs`); tests `any_three_freepeople_in_radius_form_camp` (TDD step 14) and `leftover_wanderers_can_form_camps` (TDD step 15) both green. Shared constants `MIN_WANDERERS_TO_FORM_TRIBE` / `TRIBE_CONVERGENCE_RADIUS` re-exported from `mc-turn::prologue` so ecology + prologue reference the same source of truth._
|
||||
- ✓ Turn counter advances 0 → 1 (explicitly skipping any "turn 0.x"). Dwarf Tribe unit is selectable and player-controlled. _Rust-core: `PrologueTurn.turn: i32` integer-only; test `turn_sequence_minus_one_zero_one` asserts exact `[-1, 0, 1, 2]` progression with zero fractional steps. Selectability (Godot side) pending._
|
||||
|
|
@ -76,8 +85,8 @@ Keeping them separate means the variance only exists at game-start, not inside t
|
|||
- ✓ Founding the capital creates a city with `population = founding_pop_override`. Dwarf Tribe unit is consumed. _Rust-core: `mc_city::City::found(..., override_population: Some(pop))` + `mc_turn::prologue::found_capital` clears `PlayerPrologue` and emits `capital_founded`. Tests `mc_city::city::tests::found_capital_uses_founding_pop_override`, `mc_turn::prologue::tests::found_capital_uses_founding_pop_override`, `mc_turn::prologue::tests::chronicle_emits_converged_then_founded`. GDExtension entry point: `GdCity::found_with_population` (`api-gdext/src/lib.rs`)._
|
||||
- ✓ On turn 2+, settlers built by cities produce pop-1 cities (ordinary Founder behavior). _Rust-core regression guards: `mc_city::city::tests::normal_founder_always_pop_1`, `mc_city::city::tests::found_clamps_zero_override_to_one`; the ordinary `GdCity::found(...)` path passes `None`, which the implementation unwraps to pop=1._
|
||||
- ✓ `setup.json` exposes `start_mode: "tournament" | "lucky"` and `lucky_max_bonus_pop: int`. Autoplay batches default to `tournament`. [evidence: `public/games/age-of-dwarves/data/setup.json:304-318` adds top-level `start_turn`, `tribe_convergence_radius`, `start_mode:"tournament"`, `lucky_max_bonus_pop:3`, `min_wanderers_to_form_tribe:3`, `spawn_box_size`, `spawn_box_wanderer_count:{tournament:3, lucky:[6,12]}`, `lucky_inward_bias_prob:0.33`; `prologue` group mirror at lines 290-303; validator green (python3 tools/validate-game-data.py → 190 pass / 0 fail, +2 from baseline 188)]. Rust-side consumption: `mc_turn::prologue::{StartMode, DEFAULT_LUCKY_INWARD_BIAS_PROB, LUCKY_MAX_BONUS_POP}`.
|
||||
- ✗ A deterministic seed produces byte-identical turn -1 → 0 → 1 state across runs (p1-09 determinism gate covers this once wired). _Rust-core unit gate: `mc_turn::prologue::tests::byte_identical_across_runs` (4-seed parity on roll+step+converge). Full 10-seed autoplay Chronicle byte-equality requires apricot SSH (same blocker as p0-31) — tracked in CHANGELOG open items._
|
||||
- ✗ Same sequence runs for each AI player (AI clans also start with Dwarf Tribes that converge on turn 0 and found on turn 1). Off-camera for AI — no cinematic delay. _Rust primitives are player-agnostic: `converge_tribe(..., player_id: u8, ...)` and `PlayerPrologue` are per-player. AI orchestration (mc-sim turn loop / GDScript driver) — pending._
|
||||
- ⚠ A deterministic seed produces byte-identical turn -1 → 0 → 1 state across runs (p1-09 determinism gate covers this once wired). _Rust-core unit gate: `mc_turn::prologue::tests::byte_identical_across_runs` (4-seed parity on roll+step+converge) green. Apricot smoke-3 10-seed batch green E2E 10/10 with consistent `tribe_converged` / `capital_founded` counts per seed; full byte-equality Chronicle diff left to the p1-09 determinism gate scope by design. Not blocking p0-34 closure per team-lead 2026-04-18._
|
||||
- ✓ Same sequence runs for each AI player (AI clans also start with Dwarf Tribes that converge on turn 0 and found on turn 1). Off-camera for AI — no cinematic delay. _Rust primitives are player-agnostic: `converge_tribe(..., player_id: u8, ...)` and `PlayerPrologue` are per-player. GDScript: `world_map.gd::_bootstrap_prologue` iterates every `GameState.players` entry (human + AI clans) and calls `GdPrologue::register_player(pid, start_q, start_r, mode, radius, grid)` once each; `TurnManager.end_turn()` prologue branch runs a single `advance()` per end-turn that rolls/steps/converges for ALL registered players in one pass (per-player loop inside Rust). Apricot smoke-3 seed1 events.jsonl: **2** `tribe_converged` + **2** `capital_founded` entries — one per player in a 2-player game, confirming both AI and human clans run the sequence._
|
||||
- ✓ Chronicle log records: `tribe_converged` on turn 0, `capital_founded` on turn 1. _Rust-core: `mc-turn/src/chronicle.rs::ChronicleEntry::{TribeConverged, CapitalFounded}` emitted by `converge_tribe` (turn=0) and `found_capital` (turn=1). Tests `chronicle_emits_converged_then_founded`, `tribe_converged_roundtrips_as_snake_case_json`, `capital_founded_roundtrips_as_snake_case_json`._
|
||||
|
||||
## Files to touch / create
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -160,7 +160,13 @@ case "${MODE}" in
|
|||
SEEDS="${1:-10}"; TURNS="${2:-300}"
|
||||
# Default: use the GPU when available (MCTS rollouts through WGSL kernel).
|
||||
# gpu-walltime mode overrides this explicitly to true/false per iteration.
|
||||
GPU_ENV="AI_GPU_ROLLOUT=${AI_GPU_ROLLOUT:-true}"
|
||||
# Default AI_GPU_ROLLOUT=false for smoke/clan. The GPU integration
|
||||
# (p0-20 task #10) is parity-verified on isolated rollouts, but
|
||||
# enabling it in a 2-player smoke produced a deterministic
|
||||
# "P0 always wins at T11-T18, P1 never founds" regression on
|
||||
# 2026-04-18. Opt-in via env override; gpu-walltime flips
|
||||
# per-iteration as its explicit comparison.
|
||||
GPU_ENV="AI_GPU_ROLLOUT=${AI_GPU_ROLLOUT:-false}"
|
||||
echo "[$(date +%H:%M:%S)] smoke batch: ${SEEDS} seeds T${TURNS} PARALLEL=${PARALLEL} ${GPU_ENV}"
|
||||
ssh "${APRICOT}" "set -euo pipefail; cd '${SCRATCH_ABS}' && \
|
||||
AI_USE_MCTS=true ${GPU_ENV} PARALLEL=${PARALLEL} \
|
||||
|
|
@ -169,7 +175,13 @@ case "${MODE}" in
|
|||
clan)
|
||||
CLAN="${1:?usage: apricot-run.sh clan <clan_id> [seeds] [turns]}"
|
||||
SEEDS="${2:-10}"; TURNS="${3:-300}"
|
||||
GPU_ENV="AI_GPU_ROLLOUT=${AI_GPU_ROLLOUT:-true}"
|
||||
# Default AI_GPU_ROLLOUT=false for smoke/clan. The GPU integration
|
||||
# (p0-20 task #10) is parity-verified on isolated rollouts, but
|
||||
# enabling it in a 2-player smoke produced a deterministic
|
||||
# "P0 always wins at T11-T18, P1 never founds" regression on
|
||||
# 2026-04-18. Opt-in via env override; gpu-walltime flips
|
||||
# per-iteration as its explicit comparison.
|
||||
GPU_ENV="AI_GPU_ROLLOUT=${AI_GPU_ROLLOUT:-false}"
|
||||
echo "[$(date +%H:%M:%S)] clan=${CLAN} batch: ${SEEDS} seeds T${TURNS} PARALLEL=${PARALLEL} ${GPU_ENV}"
|
||||
ssh "${APRICOT}" "set -euo pipefail; cd '${SCRATCH_ABS}' && \
|
||||
AI_USE_MCTS=true AI_PIN_PERSONALITY='${CLAN}' ${GPU_ENV} PARALLEL=${PARALLEL} \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue