From c8896d50c934ffa33ede86f053c03032626cb143 Mon Sep 17 00:00:00 2001 From: Natalie Date: Thu, 25 Jun 2026 00:43:21 -0400 Subject: [PATCH] =?UTF-8?q?fix(@projects/@magic-civilization):=20?= =?UTF-8?q?=F0=9F=A7=B9=20is=5Fat=5Fwar=20defaults=20absent=20relation=20t?= =?UTF-8?q?o=20PEACE=20(p3-16=20cleanup)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit movement.rs::is_at_war defaulted a missing relation slot to `true` (at war) — the legacy p1-01 "missing → war" model that courier-diplomacy (p3-16) supersedes: every pair starts at PEACE, war begins only on a war-dec envelope. An absent slot now defaults to peace (`map_or(false, …)`), so the AI never treats a not-yet-projected pair as a phantom war. project_tactical_relations fills the vec from real courier state, so genuine wars are unaffected. mc-ai+mc-player-api 556/0. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../crates/mc-ai/src/tactical/movement.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/simulator/crates/mc-ai/src/tactical/movement.rs b/src/simulator/crates/mc-ai/src/tactical/movement.rs index cd5a0704..3a4fa58a 100644 --- a/src/simulator/crates/mc-ai/src/tactical/movement.rs +++ b/src/simulator/crates/mc-ai/src/tactical/movement.rs @@ -381,20 +381,20 @@ fn is_military(unit: &TacticalUnit) -> bool { // ── Enemy / diplomacy enumeration ──────────────────────────────────────── pub(super) fn is_at_war(me: &TacticalPlayerState, opponent_index: u8) -> bool { - // Canonical model is courier-diplomacy: pairs start at PEACE and war - // begins when a player dispatches a war-dec envelope (COMMUNICATIONS.md - // §"War declaration semantics"; p1-01's "missing → war" is superseded, - // see p3-16). `project_tactical_relations` fills the relations vec, so a - // slot is normally present; the `map_or(true, …)` fallback only fires for - // a genuinely absent slot and is left open so a not-yet-projected pair - // never silently blocks retaliation. + // Canonical model is courier-diplomacy: every pair starts at PEACE and war + // begins only when a player dispatches a war-dec envelope (COMMUNICATIONS.md + // §"War declaration semantics"). p1-01's legacy "missing relation → war" is + // SUPERSEDED (p3-16): an absent slot now defaults to PEACE, so the AI never + // treats a not-yet-projected pair as a phantom war. `project_tactical_relations` + // fills the vec from the courier relation state, so real wars are present; + // `< 0` is the at-war marker. if (opponent_index as usize) == (me.index as usize) { return false; } me.relations .get(opponent_index as usize) .copied() - .map_or(true, |r| r < 0) + .map_or(false, |r| r < 0) } fn collect_enemy_units<'a>(