Slice 3: Expedition Combat Spine — epoch-seeded zone waves (DR-040)

Reactivate the dormant Expedition region as a procedural combat venue.
v1 loop: walk the gate -> fight an epoch-seeded enemy wave in the
expedition -> clear -> return -> flat Ore reward (once per epoch) ->
escalated retaliation base siege.

- New sim types: ZoneEnemyTag, ZoneEnemyDirector (+ ZoneEnemyPrefab
  buffer), ZoneEnemyState, ZoneEnemyMath (grunt->charger composition
  by epoch). ZoneEnemyDirectorSystem (server, Burst): drip-spawns the
  wave at a deterministic ring under a MaxAlive cap while a player is
  out and the base is Calm; marks ClearedThisEpoch on a real clear.
  [UpdateAfter(ExpeditionFieldSystem)] only (avoids a sort cycle).
- BLOCKER 1: EnemyAISystem region-filters target selection (player +
  structure snapshots gain parallel region lists; no base structures /
  no Core fallback for expedition husks).
- BLOCKER 3: WaveSystem, ThreatDirectorSystem timeout cull, and
  CyclePhaseSystem DefendCleared + Core-breach cull all count/cull
  RegionTag{Base} husks only (the breach cull was caught region-blind
  by the post-impl review: a base breach wiped the live expedition
  wave and spuriously paid the reward).
- BLOCKER 4: reward de-duped via CycleRuntime.LastRewardedEpoch +
  ClearedThisEpoch; ExpeditionGateSystem deposits RewardOre once/epoch.
- ExpeditionFieldSystem teardown also culls zone enemies + region-
  guards the clutter loop. Subscene wired with the director + roster.

368/368 EditMode green + clean netcode Play smoke. Docs: DR-040 ->
built, session log, CLAUDE.md cross-region tag-reaudit rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-21 22:58:26 -07:00
parent cf45ec82ae
commit 3109b86d71
33 changed files with 1044 additions and 161 deletions
@@ -1,7 +1,7 @@
---
id: DR-040
title: Slice 3 — Expedition Combat Spine (v1 plan, reviewed + locked)
status: accepted
title: Slice 3 — Expedition Combat Spine (v1 plan, reviewed + locked → built)
status: built
date: 2026-06-18
tags:
- decision
@@ -52,4 +52,18 @@ Netcode: **PROCEED WITH BLOCKERS RESOLVED** (the chassis is sound + heavily reus
- **EditMode tests (planned):** region-filter target correctness; deterministic epoch scatter (same epoch → identical spawns); WaveSystem cleared-check ignores expedition enemies; zone-clear reward deposits once per epoch. **Play-validation:** zone enemies spawn `RegionTag{Expedition}` (visible to expedition player, NOT a base-only connection); kill them, return, retaliation siege arms; expedition player gets no base-Husk aggro; server==client; relevancy cost sane.
- **Deferred to v2 (logged):** arena-layout pool + authoring; zone-theme/depth byte + pre-gate HUD ("DEPTH 5 — BOSS"); the felt-beat replicated reward + `TimedModifier` buff; SaveData v6 (persist epoch); mini-boss; layout×encounter decoupling; sequential zones; RegionRelevancy incremental caching.
- **Open (operator):** the OPTIONAL-vs-REQUIRED sortie fork (default OPTIONAL); the Slice 3 fun-gate; the still-open Slice 1 + 2 fun-gates.
- **Status:** reviewed + locked, **NOT built** — the build is the immediate next unit (start with the new components + the three surgical server-count fixes, then the `EnemyAISystem` region-filter (the riskiest, test it), then `ZoneEnemySpawnSystem` + authoring + the reward, then tests + Play-validate, then commit). Full review (verdicts/blockers/forks/sources) in the run transcript `wf_b8033e26-1f5`.
- **Status:** **BUILT + verified 2026-06-21** (see build record below). Full pre-build review (verdicts/blockers/forks/sources) in the run transcript `wf_b8033e26-1f5`.
## Build record (2026-06-21)
Built per the locked plan; all four blockers landed. **368/368 EditMode green + a clean netcode Play smoke** (ServerWorld/ClientWorld boot with no sort-cycle, the subscene re-baked the `ZoneEnemyDirector` singleton + 2-prefab roster, real prefabs instantiate `RegionTag{Expedition}`+`ZoneEnemyTag` with baked Scale preserved, zero runtime errors).
**Deviations from the locked text (all deliberate, caught at grounding):**
- **System renamed `ZoneEnemyDirectorSystem`** (was `ZoneEnemySpawnSystem` in the plan).
- **Ordering is `[UpdateAfter(ExpeditionFieldSystem)]` ONLY** — the plan's extra `[UpdateBefore(CyclePhaseSystem)]` would close a `CyclePhase→Field→Zone→CyclePhase` sort cycle that throws at Play world-creation and is invisible to EditMode (ExpeditionFieldSystem is itself `UpdateAfter(CyclePhaseSystem)`). Grounding catch.
- `ZoneEnemyState.SeededEpoch` is **`int`** (not `uint`) to match `int CycleRuntime.ExpeditionEpoch`; `CycleRuntime` gained **both** `LastRewardedEpoch` (int) **and** `ClearedThisEpoch` (byte) — the director sets `ClearedThisEpoch=1` on a real clear, the gate pays `RewardOre` once per epoch on return.
**Post-impl adversarial review (run `wf_7b45e3c0-b81`, 3 lenses + synth) — 1 HIGH found + fixed:**
- **Region-blind Core-breach cull (a THIRD cull path beyond BLOCKER 3's two).** `CyclePhaseSystem`'s overrun/soft-loss branch despawned **all** `EnemyTag` entities — pre-slice that was safe (all enemies were base), but Slice 3 makes expedition enemies share `EnemyTag`, so a **base** Core breach wiped a live **expedition** wave AND spuriously tripped the zone director's `aliveZone==0` clear/reward edge. **Fix:** Base-only region filter matching the BLOCKER-3 siblings (`ThreatDirectorSystem` timeout + `DefendCleared`); dead `m_AliveHusks` field removed. Locked with regression test `CyclePhaseSystemTests.Base_Overrun_Disperses_Base_Husks_But_Spares_Expedition_Husks`. (Lesson: a cull/query that was region-safe before a region split must be re-audited the moment a second region shares its tag — same class the post-impl review caught in DR-031.)
**Still open (operator):** the OPTIONAL-vs-REQUIRED sortie fork (default OPTIONAL); the Slice 3 fun-gate (needs a hands-on playtest of the full walk-gate→fight→return→reward→siege loop — logic is unit-covered, feel is not).