End the mission and say how it went #42

Merged
icub3d merged 1 commit from 12-victory-and-defeat into main 2026-09-13 23:03:26 +00:00
Owner

M1 is "played to victory or defeat". Until now a mission had no ending: a wiped squad kept
being handed turns it had nobody left to spend, and the only way out was Escape.

The objective lives outside the HUD

src/game/ holds it — for now, one objective: the mission ends when a side has nobody
standing. It is there rather than in the UI because a mission that ends only when
somebody is looking at it cannot be played headlessly
, and #13 has to watch one run to
completion with no renderer. Every test here does exactly that.

Losing everybody at once is a defeat. A cell that is gone has not won, whatever happened to
the opposition, and saying so explicitly beats letting the order of two checks decide it.

MissionReport counts turns handed out and the fallen on both sides. It outlives the
mission it describes — the screen that reports it is a different state from the one that
produced it — and is removed on leaving the results so a second run starts from nothing.

Acceptance criteria

  • The victory check is part of resolution, not a UI system — src/game/, and every
    test observes it with no renderer present.
  • Mission entities fully torn down — a test fights a mission out, returns to the
    menu, and asserts no Unit entities and no mission resources survive.
  • A second mission works and is unaffected by the first — a test fights the same
    mission twice, asserts everybody arrives whole the second time, and asserts both runs
    come out the same way. That is ADR 0007 and 0008's determinism observed end to end.
  • Built from widget builders and theme tokens — verdict in words as well as
    colour, tally, and the way back. Every string ASCII, because assets/fonts/ is empty
    (#27).

Escape stops being a placeholder and becomes what it is: abandoning a mission. It goes to
the menu rather than the results, because walking out is not an outcome.

Verification

cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test —
196 passing, up from 188. Seven of the new ones are whole missions fought headlessly.

The results screen has not been seen on the device. The app runs and does not panic,
but I passed 70 turns through the HUD's Wait control without reaching an ending, and I
did not work out why — headlessly the same mission ends in 44 frames once turns are passed.
A probe confirmed a single press travels the whole path correctly (press → Confirmed →
accepted → Resolving → Animating), so the mechanism works; something about driving it
by adb taps does not. I would rather flag that than claim a screen I have not looked at.

Closes #12

🤖 Generated with Claude Code

https://claude.ai/code/session_01TA4hJHkRSU3XBxZYtMKXdh

M1 is "played to victory or defeat". Until now a mission had no ending: a wiped squad kept being handed turns it had nobody left to spend, and the only way out was Escape. ## The objective lives outside the HUD `src/game/` holds it — for now, one objective: the mission ends when a side has nobody standing. It is there rather than in the UI because **a mission that ends only when somebody is looking at it cannot be played headlessly**, and #13 has to watch one run to completion with no renderer. Every test here does exactly that. Losing everybody at once is a defeat. A cell that is gone has not won, whatever happened to the opposition, and saying so explicitly beats letting the order of two checks decide it. `MissionReport` counts turns handed out and the fallen on both sides. It outlives the mission it describes — the screen that reports it is a different state from the one that produced it — and is removed on leaving the results so a second run starts from nothing. ## Acceptance criteria - [x] **The victory check is part of resolution, not a UI system** — `src/game/`, and every test observes it with no renderer present. - [x] **Mission entities fully torn down** — a test fights a mission out, returns to the menu, and asserts no `Unit` entities and no mission resources survive. - [x] **A second mission works and is unaffected by the first** — a test fights the same mission twice, asserts everybody arrives whole the second time, and asserts both runs come out the same way. That is ADR 0007 and 0008's determinism observed end to end. - [x] **Built from `widget` builders and `theme` tokens** — verdict in words as well as colour, tally, and the way back. Every string ASCII, because `assets/fonts/` is empty (#27). Escape stops being a placeholder and becomes what it is: abandoning a mission. It goes to the menu rather than the results, because walking out is not an outcome. ## Verification `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo test` — **196 passing**, up from 188. Seven of the new ones are whole missions fought headlessly. **The results screen has not been seen on the device.** The app runs and does not panic, but I passed 70 turns through the HUD's `Wait` control without reaching an ending, and I did not work out why — headlessly the same mission ends in 44 frames once turns are passed. A probe confirmed a single press travels the whole path correctly (press → `Confirmed` → accepted → `Resolving` → `Animating`), so the mechanism works; something about driving it by `adb` taps does not. I would rather flag that than claim a screen I have not looked at. Closes #12 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01TA4hJHkRSU3XBxZYtMKXdh
M1 is "played to victory or defeat". Until now a mission had no ending: a wiped
squad kept being handed turns it had nobody left to spend, and the only way out
was Escape.

`src/game/` holds the objective — for now, one: the mission ends when a side has
nobody standing. It lives there rather than in the HUD because a mission that
ends only when somebody is looking at it cannot be played headlessly, and #13
has to watch one run to completion with no renderer. Every test here does
exactly that.

Losing everybody at once is a defeat. A cell that is gone has not won, whatever
happened to the opposition, and saying so explicitly is better than letting the
order of two checks decide it.

`MissionReport` counts turns handed out and the fallen on both sides. It
outlives the mission it describes, because the screen that reports it is a
different state from the one that produced it, and is removed on leaving the
results so a second run starts from nothing. A test fights the same mission
twice and asserts everybody arrives whole the second time and it comes out the
same way — the determinism ADR 0007 and 0008 are for, observed end to end.

The results screen is `widget` builders and `theme` tokens like every other
screen: the verdict in words as well as colour, the tally, and the way back.
Every string is ASCII, because `assets/fonts/` is empty (#27).

Escape stops being a placeholder and becomes what it actually is — abandoning a
mission. It goes to the menu rather than the results, because walking out is not
an outcome and should not be reported as one.

Closes #12

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TA4hJHkRSU3XBxZYtMKXdh
icub3d merged commit 54664cdea3 into main 2026-09-13 23:03:26 +00:00
icub3d deleted branch 12-victory-and-defeat 2026-09-13 23:03:26 +00:00
Sign in to join this conversation.
No description provided.