Foundry melee roof trap — 9 September 2026
The specified Foundry failure is reproducible: healthy Jump-equipped melee units enter a roof cluster they cannot safely leave, and the AI scores those unreachable approach positions more favorably than a valid ground route. Correcting distance-field direction alone does not fix that decision because missing routes still fall back to geometric distance.
This is a six-game, one-seed diagnostic, not a balance estimate. No engine, data, or frozen study CLI source was edited. Evidence and reproduction scripts retain full events, activation snapshots, candidate scores, map geometry checks and source hashes.
Exact counterexample
Setup: Foundry, seed 300000, armored on A, melee on B, A first, both aggression 0.75, the concrete studyTeams rosters. Baseline and goalpath both choose the following initial ordinary route for B1:
(29,10) → (28,10) → (27,10) → (26,10) → (25,9)
Coordinates throughout are offset column,row. The step from ground (28,10) to roof (27,10) climbs two levels legally with Jump, costing one. Reversing it costs one but is marked fall. Neither ordinary nor Jump safe reachability includes that descent. The bot requests safe movement and never opts into falls.
Before this first B1 move, no candidate in the comparison has current offense, incoming threat or zone occupancy value. The corrected policy nevertheless chooses:
| Candidate | Move cost | Correct remaining cost to enemy / zone center | Geometric fallback | Final position score |
|---|---|---|---|---|
Roof (25,9), level 2 |
4 | No route / no route | 19 / 7 | −9.20 |
Ground (27,6), level 0 |
4 | 20 / 15 | Unused | −11.20 |
For the roof, approach is −0.4×19 −0.2×7 = −9, then movement costs 0.05×4. For ground, approach is −0.4×20 −0.2×15 = −11, with the same movement cost. A position from which the goals are unreachable receives a better score than one with finite routes. Baseline also chooses this roof, scoring it −9.40 versus the same ground −11.20.
By their round-two activations, B1 is at (24,6), B2 (24,7), B3 (25,8), all level 2 and all with 7/7 Legs. The safe, occupancy-free connected roof region has only 14 cells, spanning (24,6) through (28,13). None can safely reach any of the four scoring-zone footprints. This remains true when goals include every footprint hex rather than only centers. Boost adds distance, not a legal exit.
The units then circulate through roof positions. For example, goalpath B2 starts rounds 2–7 at (24,7), (24,7), (26,11), (27,11), (27,10), (25,6) with intact Legs. More movement and correct distance values cannot rescue a policy which discards the meaning of “no route.”
Outcomes and aggression sensitivity
All six games use this same seed/orientation/first side; aggression changes apply equally to both teams. These rows are diagnostic point observations with no population inference.
| Policy | Aggression A/B | Final score A–B | Zone points A–B | Melee exchanges | A Hull fraction remaining |
|---|---|---|---|---|---|
| Baseline | 0.50 / 0.50 | 15–0 | 9–0 | 0 | 100% |
| Baseline | 0.75 / 0.75 | 11–0 | 8–0 | 2 | 100% |
| Baseline | 1.00 / 1.00 | 9–6 | 6–0 | 2 | 42.5% |
| Goalpath | 0.50 / 0.50 | 15–0 | 9–0 | 0 | 100% |
| Goalpath | 0.75 / 0.75 | 12–0 | 9–0 | 0 | 100% |
| Goalpath | 1.00 / 1.00 | 11–0 | 8–0 | 0 | 100% |
Every condition puts all three melee units on level-two roofs by round two, with 7/7 Legs. Every condition gives melee zero objective points. Baseline aggression 1 obtains two later kills when the opposing policy brings enemies into reach, but does not solve exit or scoring access. An aggression grid can therefore change incidental contact without correcting the structural trap.
Vertical melee legality is not what prevents early engagement here. The current engine requires horizontal adjacency and line of sight, without a same-level constraint. In baseline round seven, B3 at (24,6), level 2, starts a legal exchange with Courier A3 at (23,6), level 0. Earlier, no enemy is adjacent to a safely reachable roof cell. The two late baseline 0.75 exchanges produce no damage to A because all three declared B3 blade strikes are parried; that is a separate combat outcome after delayed contact. The full trace must not be summarized as “melee can never reach or attack across height.”
Objective-goal representation is also incomplete
Current Quarry zone 1 center (15,7) and zone 2 center (16,12) are low walls. Both center-seeded goal fields are empty for ordinary and Jump legs. Each complete-footprint field instead reaches 616 cells. A center is a marker, not the only legal scoring position. Simply penalizing missing center routes would incorrectly penalize reachable objectives.
The next optional safeapproach experiment should therefore be explicit about its two corrections:
- Require goal-directed fields. If real goals exist but a candidate has no route, retain that distinction with a finite large board-based penalty; do not replace it with cheaper geometric distance. Preserve the no-goal fallback and existing immediate-target scoring, so a legal ranged firing perch is not rejected merely because it cannot walk to the enemy.
- Seed objective approach with complete passable zone footprints, including zones whose center is blocked. Enemy goals remain a separate design choice: this diagnostic does not silently change them to firing or melee-adjacent cells.
Tests should reproduce this roof/ground ranking, retain a useful ranged perch, handle blocked-center/reachable-footprint goals, preserve omitted/false defaults, and identify opt-in sessions with an explicit capability. Implementation must wait until the active wide study freeze ends. A corrected route representation would still require matched outcome comparisons; these traces do not certify melee balance or a candidate win rate.
Reproduction
The trace hook reads snapshots/fields at melee activation starts without consuming RNG. The scoring probe runs only through the first B1 activation start and copies the current AI module into /tmp, exposing its private position scorer and recording its existing score terms; the repository module remains unchanged. The retained scoring probe was rerun and its output matched exactly.
pnpm exec tsx docs/tuning/evidence/2026-09-09-foundry-roof-trap/trace.ts /tmp/foundry-main.json .75
pnpm exec tsx docs/tuning/evidence/2026-09-09-foundry-roof-trap/trace.ts /tmp/foundry-policy.json .5,1
pnpm exec tsx docs/tuning/evidence/2026-09-09-foundry-roof-trap/score-probe.ts /tmp/foundry-scores.json
pnpm exec tsx docs/tuning/evidence/2026-09-09-foundry-roof-trap/geometry-probe.ts /tmp/foundry-geometry.json
Follow-up after safeapproach was applied
After the wide-study freeze ended, the optional implementation was applied and baseline/goalpath parity repeats passed. A separate four-game mechanism check then ran the same seed/orientation with safeapproach at equal aggression 0.5/0.75/1, plus zonegoals at 0.75. New evidence is retained separately from the original traces, with full cloned catalog/rules, events, snapshots, source fingerprints, summary and reproduction scripts. Ordinary defaults remain unchanged.

The figure shows actual round-one ordinary movement and Boost, at original hex centers. A standalone SVG is also available. It does not depict later combat or hypothetical paths.
Safeapproach enters zero roof tiles in round one in all three runs. B1/B2/B3 finish at ground (24,4) / (25,4) / (26,4) with 7/7 Legs. At their round-two activations, each has safe routes to all four scoring flowers, with nearest costs 10/11/12 respectively. Zonegoals alone still puts all three on the original trapped roofs, with no scoring route. Complete objective footprints alone therefore do not resolve this particular Foundry mechanism.
| Candidate | Aggression A/B | Winner / ending | Score A–B | B zone points | B credited kills | B proactive melee exchanges |
|---|---|---|---|---|---|---|
| Zonegoals | 0.75 / 0.75 | A / round cap, round 7 | 12–0 | 0 | 0 | 0 |
| Safeapproach | 0.50 / 0.50 | B / round cap, round 7 | 10–12 | 6 | 2 | 4 |
| Safeapproach | 0.75 / 0.75 | B / wipe, round 5 | 8–11 | 2 | 3 | 3 |
| Safeapproach | 1.00 / 1.00 | B / wipe, round 7 | 11–10 | 1 | 3 | 5 |
Wipe wins regardless of the score, explaining the final row. Proactive exchanges count only melee_start by the currently active B mech; the aggression-one run also has two other exchanges. Credited kills require a unique A death credited to a B mech. The corrected approach produced actual scoring and proactive combat in these examples, rather than merely different-looking movement. These are still one-seed mechanism traces, not evidence that melee or the overall game is balanced. The full matrix measures outcomes separately.
Importable examples
- Both-bot replay: exact safeapproach 0.75 setup. Current GameSession automatically finishes both-bot games during construction/import; this real zero-command export therefore opens completed at round five, B wins by wipe, score 8–11. Open Replay to watch from the initial board with Play replay or Next activation.
- Fresh manual companion: same rules/rosters/seed, both sides human, round one before any activation. Choose a mech, then use Bot assistance → Auto to let the corrected controller finish that activation; respond to human-controlled melee/reaction prompts as needed. Manual choices can diverge from the both-bot trace.
Use the standalone Play workshop's Import save → Import and resume, rather than the Local Match import. Both files use the real local-prototype-4-safe-approach capability. Export/import checks reproduced the exact setup, events, snapshots and next RNG; the fresh companion has zero activation-start events. There is no fabricated paused both-bot save: that pause is not supported by the current session flow.
Superseded 2026-09-16. The prototype keeps no save compatibility. The engine string is now local-prototype-5, and there are no capability markers. These two files no longer load. They stay here as evidence of the recorded run, not as an import to repeat. See the simulator design.
pnpm exec tsx docs/tuning/evidence/2026-09-09-safeapproach-mechanism/trace.ts /tmp/safeapproach-traces.json .5,.75,1 safeapproach
pnpm exec tsx docs/tuning/evidence/2026-09-09-safeapproach-mechanism/trace.ts /tmp/zonegoals-trace.json .75 zonegoals
python3 docs/tuning/evidence/2026-09-09-safeapproach-mechanism/summarize.py
python3 docs/tuning/evidence/2026-09-09-safeapproach-mechanism/plot-trajectories.py
The plotting script requires matplotlib and reads retained traces. export-demos.ts records the exact demo construction and refuses to overwrite existing demo files. Session round-trip executions are validation runs, not additional independent balance samples.