11-combat.md · 288 requirements

11 — Combat

This document is the normative specification of combat resolution in Every Last City: the Clash — a single exchange between two forces that produces losses and, independently, a decision about whether the ground changes hands — together with bombardment, reactive fire, disengagement, retreat and rout, encirclement, the persistent strength and disorder a unit carries between turns, post-combat recovery, and the pre-commitment odds readout. It owns every number that decides who loses what and who gives ground. It does not own the map, terrain vocabulary, movement, stacking capacity, fog, or the unit roster; it states precisely what it requires of each.

Status: Draft v0.2 · Owner: unassigned · Depends on: docs/design/00-direction.md, docs/design/01-decision-turn-model.md, docs/design/combat.md, 01-game-rules.md (map, terrain, fog, adjacency, stacking, city ownership), 02-units-and-industry.md (unit combat stats, roles, engagement domains, air-defence tiers, bombard parameters, retreat class), 10-turn-model.md (Initiative, activation order, Stance, reaction capacity, creation sequence), 12-economy.md (supply state, depots), 13-command.md (Postures, Sanctions, the win-probability contract CM-150/CM-160), 03-architecture.md (determinism, integer arithmetic, seeded PRNG, canonical hashing), 04-ui-ux.md (presentation).

Naming note, binding on this document. Stance always means the per-turn tactical setting owned by 10-turn-model.md with values March, Advance, Hold, Entrench. Posture always means the standing job owned by 13-command.md (CM-330). The source design proposal used the word posture for the tactical setting and named a fourth value Withdraw; that value is expressed here as the Disengagement procedure of §12, driven by the Withdraw Reflex of CM-1400, and is not a Stance.


1. Scope, vocabulary, and what this document owns

CB-010 A Clash MUST be the only mechanism by which one unit reduces another unit's strength as a direct consequence of an attack, a bombardment, or a reactive engagement. Strength loss from supply attrition, scuttling, or scripted scenario effects is owned by the specification that inflicts it and MUST NOT reuse the Clash procedure.

CB-020 A Clash MUST resolve as a single exchange. The engine MUST NOT loop, iterate rounds, sample repeatedly, or run any procedure whose step count depends on the units involved.

Rationale: this is the load-bearing decision of the whole document. A single exchange is what makes the outcome distribution closed-form, which is what makes the pre-commitment readout exact, which is what makes committing orders before seeing them resolve (docs/design/01-decision-turn-model.md) a skill rather than a gamble. It is also what makes worst-case turn time flat regardless of army size.

CB-030 A Clash MUST produce two independent results: a loss result (integer strength removed from each side) and a break result (whether either side loses its nerve). The two MUST be computed from different inputs — losses from the odds ratio, breaks from shock against resolve — and MUST be permitted to disagree.

Rationale: separating "how much did it cost" from "did the line move" is what gives combat texture without adding dice. You can bleed an enemy badly without shifting them, and shift them without killing them, and those are different plans requiring different forces. A system where damage and displacement are the same number is a system where the only question is "do I have more?".

CB-040 Combat MUST NOT be fight-to-the-death. Most Clashes MUST be capable of ending with both units alive. Destruction MUST occur only when (a) a unit's strength reaches 0, or (b) a unit breaks and has no legal retreat destination.

Rationale: retreat is what creates a front — a line that can be pushed, bent and broken through, where taking ground and destroying an enemy are different achievements. If every engagement ends with a corpse the map is a sequence of duels and positioning collapses into arithmetic.

CB-050 Encirclement MUST NOT be a special case. It MUST emerge entirely from the conjunction of CB-040(b) and the retreat-destination rules of §6, with no rule that names "surrounded", "pocket", or "cut off" as a trigger for a distinct code path.

Rationale: two individually trivial rules — "a broken unit retreats" and "a unit that cannot retreat is destroyed" — produce fronts, pockets, breakthroughs, and the entire operational layer for free. The player achieves encirclement by taking away the roads, not by rolling well, and the engine needs no surrounded-unit logic at all.

CB-060 Every quantity in this document MUST be an integer. Fractional quantities MUST be expressed per-mille. Floating-point arithmetic MUST NOT appear anywhere in combat resolution or combat prediction. Q16.16 fixed point MUST NOT be used by this subsystem.

Rationale: the accumulate-wide-divide-once discipline of §5 means every named quantity is produced by exactly one division, so there is no compounding rounding to reason about and no fixed-point representation is needed at all. Using Q16.16 here would add a representation without adding precision and would give a second way to be wrong.

CB-070 Every division in this document MUST be floor division toward negative infinity. Truncation toward zero MUST NOT be used. Implementations in languages whose integer division truncates toward zero MUST implement an explicit floor division helper and use it everywhere.

Rationale: this is not a style preference. The volatility swing s is negative for draws below 500, and floor(−102.9) = −103 while trunc(−102.9) = −102. That one-unit difference changes break probabilities by whole per-mille and would make two conforming implementations disagree, which CB-2500 forbids. It is the single most likely source of a cross-platform desync in this subsystem.

CB-080 This document MUST own: the Clash procedure and all its constants; the terrain combat profile schema and its default values; the effect of Stance, grade, supply, works and dig-in on combat; retreat destination selection; recovery of strength and disorder; and the prediction function of §16. It MUST NOT define terrain types, movement costs, stacking capacity, fog rules, supply propagation, unit roster values, or city ownership transfer.

CB-090 The terms below are defined once and used throughout with exactly these meanings.

Term Meaning
Clash One resolution of the procedure in §5, of one of the kinds in §3
Lead attacker The unit whose order initiated the Clash; the only attacker that may advance
Supporter A friendly unit adjacent to the target tile that contributes reduced power
Attacking force Lead attacker plus supporters
Defender The single unit of the target stack that contributes defensive power
Defending stack Every unit on the target tile, defender included
Flankers Friendly units of the attacking side adjacent to the target tile, excluding the lead attacker
Break A side's shock reaching its resolve; for the defender this means giving ground
Falter An attacker break; the attack is thrown back
Rout A break with no legal retreat destination, which destroys the broken stack
Shock The pressure applied to a side's nerve: losses taken plus positional terms
Resolve The integer a side's shock must reach for it to break
Draw The single integer r ∈ [0, 1000) that is the only random input to a Clash

2. What a unit carries

CB-100 Every unit capable of combat MUST carry the following mutable per-unit combat state, which MUST persist across turns and MUST be part of authoritative game state.

Field Type Range Initial Meaning
strength integer 0–100 100 Proportion of the unit remaining; scales its power linearly
disorder integer 0–100 0 Accumulated shock; subtracts point-for-point from resolve
xp integer 0–999 0 Drives grade (CB-1600)
shaken integer 0–2 0 Turns remaining of the post-break penalty of CB-1130

It MUST additionally read the entrenchment counter defined by 10-turn-model.md (TM-700), an integer in [0, 4]. This document MUST NOT define that counter, its range, or the conditions that increment or reset it, and MUST NOT keep a counter of its own beside it (CB-1560).

Rationale for reading rather than owning: entrenchment is a record of what a unit did during the Cascade — where it stood and what Stance it held — which is turn-model business, and 10-turn-model.md also consumes it for reaction capacity (TM-1530). Two documents each keeping a dig-in counter with a different range and a different increment condition is precisely the defect this document exists to be free of. What is left here is the only part that is combat: what the value does once a Clash begins.

CB-110 strength MUST be expressed on the same 0–100 scale for every unit type, so that "this unit is at 60" means the same thing for every unit in the game.

Rationale: a normalised scale is what lets one bar in the UI mean one thing, lets tough express "hard to grind down" independently of "hard to hurt", and lets a player compare a rifle company and an armoured battalion without a lookup. It costs the roster designer the ability to express unit size as hit points; 02-units-and-industry.md gets tough instead, which does that job better.

CB-120 A unit's power contribution MUST scale linearly with strength (CB-470). A unit's resolve MUST fall by floor((100 − strength) / 2) (CB-710). No other automatic effect of strength on combat MAY be added without a combatLogicVersion bump (CB-2530).

Rationale: the two condition penalties compound deliberately. A unit at 60 strength with 30 disorder has lost 50 resolve before anything else is counted, so worn units break sooner and attrition snowballs locally. That is what makes a front wear out, what makes rotation a genuine decision, and what makes bombardment worth doing.

CB-130 strength MUST be clamped to [0, 100] and disorder to [0, 100] after every modification. A unit whose strength reaches 0 as a result of a Clash MUST be destroyed and removed immediately, before the next unit activates.

CB-140 This document MUST NOT define a separate "suppressed" or "pinned" state. disorder is the sole representation of a unit having been shaken, and every effect that a suppression flag would have carried MUST be expressed through disorder.

Rationale: one number instead of two states, with a continuous gradient instead of a cliff, and it recovers on a schedule the player can plan around. A boolean suppression flag would additionally need its own clear condition, its own display, and its own interaction with every other modifier.

CB-150 The static per-class combat stats this document consumes MUST be exactly: atk, def, tough, role, retreatClass, engages, flak, bombardRange, bombardShots. Their values are owned by 02-units-and-industry.md (CB-2760).

atk, def and tough MUST be non-negative integers on one common scale, on which tough = 100 is the reference value and against which atk and def are read. This document MUST NOT fix an upper bound on any of the three. 02-units-and-industry.md owns the shipped range and MUST state it; the only binding constraint on their magnitude is the exactness bound of CB-2510, which CI MUST assert against the shipped roster (CB-2685).

Stat Type Meaning
atk integer ≥ 0 Offensive base on the common scale; 0 means the class may never initiate a Clash
def integer ≥ 0 Defensive base on the common scale
tough integer ≥ 20 Divides incoming losses; 100 is the reference
role enum Foot | Armor | Gun | Recon | Naval | Air
retreatClass enum Ground | Detached (CB-1330)
engages set of {land, sea, air} The defender domains this class may initiate against (CB-235)
flak integer 0–4 Air-defence tier; adds attacker shock against an Air lead (CB-965)
bombardRange integer 0–4 0 means the class may not bombard
bombardShots integer 0–4 Bombardments permitted per turn

Rationale for engages and flak, which are new to this list and are the two fields that carry what a per-domain attack vector used to carry. A single atk cannot say "this class may not touch that class", and a low atk is not the same statement — it says "may touch it badly", which is a different game, one in which a submarine will be ordered to shell a hilltop at ten per cent effectiveness. engages is therefore a legality set, checked before a Clash is constructed rather than inside it. flak is the other half: anti-aircraft fire is not principally damage, it is the reason a pilot breaks off, so it belongs in the break check and not in the power calculation. Both are single fields with one effect each, and neither adds a step to §5.

Rationale for a common scale with no ceiling: what §5 needs from these three stats is a relationship, not a range. atk and def enter Step 1 as base (CB-480), and the losses they produce are divided by tough in CB-870, so the only thing that must hold is that all three are read against the same reference — tough = 100, fixed by CB-940's calibration that an even fight at that value costs 30 strength. A roster on 0–40 and a roster on 0–1000 both satisfy that, and the second can express distinctions the first rounds away, which matters in a document that works in per-mille everywhere else (CB-060). The ceiling of 255 that previously stood here expressed no such relationship: it is the unsigned-8-bit maximum, and nothing in §5, in CB-060's integer discipline, or in 03-architecture.md's integer discipline has ever required a stat to fit in a byte. It also conflicted with its own owner, which states a narrower range for def and never mentions 255. Magnitude does constrain these stats, but through CB-2510, and that is a bound on a four-factor product rather than on any one stat, so it belongs where it is stated and must be checked against the roster that actually ships.

Rationale for the floor of 20 on tough, which is load-bearing and therefore stays: tough is a divisor in CB-870 and again in CB-1860, so 0 is arithmetically illegal and the floor must sit somewhere above it. 20 is where the arithmetic stops describing a unit at all. At tough = 20 an even Assault removes floor(60 × 500 × 100 / (1000 × 20)) = 150 strength against a maximum of 100, so the class dies in the first of the three even fights CB-940 calibrates it to survive, and its parting loss under CB-1860 is floor(1000 / 20) = 50 — half the unit for breaking contact once. Below 20 the roster is not expressing a fragile unit; it is expressing one that cannot take the field.

CB-160 tough MUST divide incoming losses and MUST NOT affect power, resolve, or volatility.

Rationale: it is the roster's lever for "hard to grind down" as distinct from "hard to hurt". A scout troop and an armoured battalion should not both lose 30 points in an even fight, and expressing that through def would also make the scout harder to displace, which is wrong.

CB-170 A unit's Grade MUST be derived from xp by CB-1600 and MUST NOT be stored independently.

CB-180 strength, disorder, xp and shaken MUST contribute to the canonical state hash defined by 03-architecture.md. entrenchment contributes to it under TM-700.

CB-190 The client MUST be able to render strength and disorder as a single composite condition badge (04-ui-ux.md owns the visual). This specification's requirement is that the two numbers are always available together and always mean the same thing; a UI that exposes them as two raw spreadsheet columns MUST be treated as failing CB-2410.

Rationale: two persistent numbers per unit is real bookkeeping, and at three hundred units it is the thing most likely to make this design worse than what it replaces. The composite badge is a promise the interface has to keep for the mechanical design to be worth its cost.


3. Kinds of engagement

CB-200 The engine MUST recognise exactly four kinds of engagement, and every strength loss caused by combat MUST arise from one of them.

Kind Initiated by Intensity out / back Break checks Advance possible
Assault An Attack order or a sanctioned automated attack 60 / 60 both sides yes
Bombardment A Bombard order, at range 22 / 0 neither side no
Reaction The turn model's reaction rule, out of activation 34 / 14 both sides no
Disengagement An attack landing on a unit under a Withdraw Reflex none — no draw none yes, unopposed

CB-210 Assault, Bombardment and Reaction MUST all resolve through the identical procedure of §5, differing only in the constants named in CB-200 and in the specific requirements of §10 and §11. A separate resolution path for any of them MUST NOT exist.

Rationale: one procedure means one place to be wrong, one function to prove monotone, one preview to verify, and no possibility of a bombardment preview disagreeing with a bombardment.

CB-220 Disengagement MUST be resolved before any exchange and MUST consume no draw (§12).

CB-230 A unit whose class has atk = 0 MUST NOT initiate an Assault or a Reaction. It MAY still be a supporter only if its atk > 0; a class with atk = 0 MUST NOT support.

CB-235 A unit MUST NOT initiate an Assault or a Reaction against, or support a Clash against, a defender whose domain is not in the initiating class's engages set. The check MUST be made when the order is validated and again at activation, and a failure MUST be reported as an unachievable order under CB-340, never resolved as a weak attack.

Rationale: this is a legality rule and not a modifier, deliberately. Expressing "an aircraft cannot be reached by a rifle company" as a very large negative per-mille term would put a number in the clamp, would appear in the preview as a line item the player is invited to overcome, and would leave a nonzero probability that the impossible happens — which CB-640 otherwise guarantees can never be displayed as zero. A set membership test has none of those properties and greys the order out with a sentence, which is what 02-units-and-industry.md US-370 requires of every build and order gate.

CB-240 Initiating an Assault MUST cost the lead attacker one movement point. A unit with no movement point remaining MUST NOT initiate an Assault. Supporting MUST cost no movement.

Rationale: movement is the natural bound on attacks per turn and needs no separate per-turn attack cap. A unit with four movement points can make four attacks and arrive nowhere, which is a real and legitimate choice, and one the falter and disorder rules already price.

CB-250 A unit that has faltered this turn (CB-1150) MUST NOT initiate a further Assault or Bombardment this turn.

CB-260 A unit that has supported this turn MUST NOT bombard this turn, and a unit that has bombarded this turn MUST NOT support this turn. A unit MUST NOT support more than one Clash per turn.

Rationale: both are firing actions and a gun should not be able to do both. Without this a battery supports the assault it is adjacent to and then shells a second target, which doubles the value of every gun and collapses the positioning decision the support rule exists to create.

CB-270 All state changes produced by a Clash MUST be applied immediately and completely before the next unit activates, so that a later attacker in the same Cascade sees the reduced strength and raised disorder its predecessors caused.

Rationale: this is what makes the siege vector of CB-2040 work, what makes bombard-then-assault a plan rather than a coincidence, and what makes conditional orders evaluated at activation see a true board.


4. The Clash Specification

CB-280 The engine MUST construct a Clash Specification — a value containing every input the procedure of §5 reads — before evaluating any part of that procedure. The procedure MUST read nothing outside the Specification.

Rationale: this is what makes the prediction guarantee of §16 mechanically enforceable rather than aspirational. Resolution and prediction call the same function on the same value; a preview can disagree with a resolution only if the Specification differs, which is a data problem with an inspectable diff, not a logic problem hidden in two copies of the arithmetic.

CB-290 The Clash Specification MUST contain exactly the following fields and no others.

Field Type Source
kind enum (CB-200) The initiating order
terrain terrain combat profile (§7) The defender's tile, or the mover's halt tile for a Reaction
lead combatant record The lead attacker
supporters 0–2 combatant records CB-370
defender combatant record CB-400
stackExtra integer 0–3 CB-1930
flankers integer ≥ 0 CB-980
defenderInOwnCity boolean 01-game-rules.md
defenderEncircled boolean CB-1400
attackerEdgeMods integer per-mille CB-590
ambush boolean CB-885
defenderExtraMods integer per-mille CB-620
hashKey (seed, turn, initiatorSeq, attackOrdinal) CB-800

Rationale for stating no upper bound on flankers: its true ceiling is a map property this document does not own — the eight tiles of the Chebyshev-1 neighbourhood of CB-980, times the per-layer occupancy limits of 01-game-rules.md GR-720 and GR-730 — and restating it here would put a second, silently staling answer in a document that cannot see when the first one changes. Nothing downstream needs the ceiling in any case: CB-970 clamps the count to 4 before it is used, so the field carries no additional shock above that value and the panel enumerates the units themselves (CB-2410) rather than reading the total. The bound this field carried previously was 255, which is neither the geometric limit nor the clamp, and stated nothing about the game.

CB-300 A combatant record MUST contain exactly: atk, def, tough, role, flak, strength, disorder, grade, supplyTier, stance, entrenchment, works, shaken, creationSequence.

CB-310 Every field of the Clash Specification MUST be an integer, an enumeration value, or a boolean. It MUST NOT contain object references, entity handles, or map coordinates.

Rationale: a Specification that cannot reach back into the world is a Specification that can be serialised into a test vector, replayed, diffed against a golden master, and shipped to the client for a preview without shipping the world.

CB-320 The Clash Specification MUST be serialisable to a canonical byte form and MUST appear in the combat event emitted for every resolution (CB-2440).

CB-330 A Clash Specification MUST be constructed from the true world state when resolving, and from a player's knowledge view when predicting (§17). The construction function MUST be the same in both cases, parameterised only by the view it reads.

CB-340 A Specification whose lead.strength is 0, whose defender.strength is 0, or whose defender is absent MUST be rejected before resolution; the initiating order MUST be treated as unachievable at activation rather than as an error, per the turn model's handling of stale orders.

CB-350 The engine MUST expose buildClashSpec(view, order) → ClashSpec | null as a pure function of its arguments.

CB-360 Two Clash Specifications that are byte-equal MUST produce byte-equal outcomes on every conforming implementation.


5. The resolution procedure

Every step below is normative in the order given. An implementation that reorders steps, or that combines two divisions into one, will produce different integers and is non-conforming.

5.1 Step 0 — Assemble the force

CB-370 Up to two supporters MAY join an Assault. A supporter MUST satisfy all of:

  1. it belongs to the attacking player or a player allied to them;
  2. it is adjacent (Chebyshev 1) to the target tile;
  3. it has not yet been activated this turn;
  4. it has not supported or bombarded this turn;
  5. it is not embarked in a transport;
  6. its class atk is greater than 0 and its strength is at least 1;
  7. its order stack does not have a Withdraw Reflex active (CM-1400).

Rationale for "not yet activated": a unit that has taken its activation has spent its turn. The consequence is that support flows from later-activating units to earlier-activating ones, so a gun that is standing still — low Initiative, late activation — is the one available to support. That is exactly backwards from what it first looks like and exactly right: the battery that displaced forward this turn cannot also fire in support of the assault, and the one that sat in position can.

CB-380 Support MUST be opt-in on the Attack order, with a supportPolicy of Auto (the default) or an explicit list of unit ids.

CB-390 Under supportPolicy: Auto the engine MUST select supporters by repeating twice over the eligible candidates: prefer a candidate whose role is not already present in the attacking force; among those, prefer the highest Step-1 contribution; ties break by lowest creationSequence. The same selection MUST be used by the preview.

Rationale: role diversity first because the combined-arms bonus (CB-560) is usually worth more than the marginal power of a second unit of the same role, and because the preview must be able to explain the choice in one clause.

CB-400 The defender MUST be the unit of the defending stack with the greatest Step-1 defensive contribution; ties break by lowest creationSequence. Every other unit of the stack MUST contribute only through stackExtra (CB-1930) and MUST NOT contribute power of its own.

CB-410 Supporting MUST cost the supporter its support for the turn and +10 disorder, and MUST NOT cost it movement or its activation.

CB-420 Support MUST key off physical adjacency and eligibility only. Formation or Group membership, shared Posting, or shared orders MUST NOT affect whether a unit may support, how much it contributes, or whether it is selected. (Satisfies CM-2160.)

CB-430 Supporters MUST take losses (CB-900) and MUST NOT advance under any circumstance.

CB-440 A Bombardment MUST have no supporters. Concentration of artillery MUST be expressed by firing several batteries at the same target in the same turn, not by one bombardment aggregating several guns.

Rationale: several independent bombardments against a target whose disorder is rising between them is a strictly more interesting thing than one aggregated shot, because each subsequent shot faces a weaker defence and the player can stop when the resolve threshold is crossed. It also makes the artillery concentration threshold of CB-1750 emerge from arithmetic rather than from a stacking rule.

CB-450 A Reaction MUST have no supporters.

CB-460 The attacking force MUST be frozen at the instant the lead attacker's order is evaluated. A supporter destroyed later in the Cascade MUST NOT retroactively alter a resolved Clash.

5.2 Step 1 — Each unit's raw contribution

CB-470 Each unit's contribution MUST be computed as exactly one expression with exactly one division:

contribution = floor( base × strength × (1000 + gradePower + supplyPower + roleTerrain) × factor
                      / 100 000 000 )

CB-480 base MUST be the class atk for every member of the attacking force and the class def for the defender.

CB-490 factor MUST be 1000 for the lead attacker and for the defender, and 400 for a supporter.

Rationale: 400 makes a supporter worth about four-tenths of itself, which is enough that a second role is worth bringing and not enough that massing three of the same thing beats bringing two kinds. It is the number that makes the combined-arms bonus the reason to add a supporter rather than the supporter's raw power being the reason.

CB-500 gradePower MUST come from CB-1610 and supplyPower from CB-1650.

CB-510 roleTerrain MUST be looked up by the contributing unit's role against the Specification's terrain, per CB-1450. Both sides MUST use the same terrain: there is exactly one battlefield and it is the defender's tile.

CB-520 A_raw MUST be the sum of the contributions of the lead attacker and all supporters. D_raw MUST be the defender's contribution alone.

CB-530 Each contribution MUST be floored independently before summation. The engine MUST NOT accumulate un-floored terms and divide once at the end of Step 1.

Rationale: the accumulate-wide-divide-once discipline applies within a single named quantity, not across units. Flooring per unit is what makes a supporter's line item in the readout (CB-2400) equal to the number that actually entered the sum, which is what lets a player learn the rules by reading the panel.

5.3 Step 2 — Force-level modifiers

CB-540 Force-level modifiers MUST be additive in per-mille, never multiplicative.

attackerMods = clamp( Σ attacker terms, −700, +1800 )
defenderMods = clamp( Σ defender terms, −700, +1800 )
A = max(1, floor( A_raw × (1000 + attackerMods) / 1000 ))
D = max(1, floor( D_raw × (1000 + defenderMods) / 1000 ))

Rationale: multiplicative stacking is more "realistic" and produces unassailable turtles — forest × dug-in × works × stack is four to five times defence, and each further bonus is worth more the more you already have. Additive stacking makes every bonus worth the same wherever you find it, which makes the one you are missing worth pursuing, and it makes the arithmetic something a player can do in their head while looking at a map.

CB-550 The attacker's terms MUST be exactly:

Term Value Condition
Stance CB-1520 The lead attacker's Stance; Assault only
Prepared fire +200 Reaction only, replacing the Stance term (CB-1790)
Combined arms CB-560 Assault only
River crossing −180 The lead attacker's tile and the target tile are separated by a river edge
Uphill −100 The target tile's elevation exceeds the lead attacker's
Amphibious −250 The lead attacker is attacking from aboard a transport
Siege CB-555 Bombardment only, against a defender in a city or works

CB-555 Where 02-units-and-industry.md gives a class a siege capability, that capability MUST be expressed as a +250 attackerEdgeMods term applying to a Bombardment whose defender occupies a city or a works of level ≥ 1, and MUST have no other effect on this procedure (CB-1740).

Rationale for +250 and for putting it here rather than leaving it to the roster to invent: it is the same size as the largest thing a player can buy with a Stance, which is the right weight for the one capability whose entire purpose is reducing fortifications, and it is small enough that it cannot reach the clamp — a Bombardment takes neither the Stance term nor the combined-arms term, so +250 is the whole of a siege bombardment's attacker total.

CB-560 The combined-arms term MUST be determined by the count of distinct roles present in the attacking force:

Distinct roles Term
1 0
2 +120
3 +260

Rationale: +120 is roughly the value of a Trained grade, so bringing a second kind of unit is worth about as much as a level of experience — significant, learnable, not decisive. The jump to +260 for three is deliberately super-linear because a full combined-arms force is the thing the design most wants players to build, and because reaching three roles costs both supporter slots and a real positioning problem.

CB-570 A river-crossing or uphill term MUST apply only to the lead attacker's approach, and MUST NOT be recomputed per supporter.

Rationale: a supporter is firing across the same battlefield from wherever it stands; making each supporter's approach a separate modifier would multiply the panel's line items without changing any decision a player makes.

CB-580 River-crossing and elevation are map properties. 01-game-rules.md MUST supply the predicates crossesRiverEdge(from, to) and elevation(tile); where it defines neither, both terms MUST be 0 and the readout MUST NOT display them.

CB-590 attackerEdgeMods in the Specification MUST be the pre-summed total of the river, elevation and amphibious terms, computed by buildClashSpec.

CB-600 The defender's terms MUST be exactly:

Term Value Condition
Terrain cover CB-1460 Always
Stance CB-1520 The defender's Stance
Position +100 × max(entrenchment, works) CB-1550
Stack support +100 × min(3, stackExtra) CB-1930
Caught −200 Disengagement failed for want of a retreat tile (CB-1880)

CB-610 A fortification of works level W MUST NOT contribute a defence modifier of its own. It MUST instead set the occupant's dig-in floor to W (CB-600 Position term), add +6 × W resolve (CB-710), add min(16, 8 × W) attacker shock (CB-1000), and forbid retreat (CB-1330).

Rationale: keeping works out of the additive defence stack is what stops a fortified city defender pinning at the modifier cap, and it reframes fortification as time saved and stubbornness rather than as a fourth multiplier. A player who builds works gets the dug-in position instantly instead of waiting four turns, and gets a garrison that will not run — which is what a fortification is for.

CB-620 defenderExtraMods MUST carry only the Caught term. No other source MAY write to it without a combatLogicVersion bump.

CB-630 The maximum reachable defender additive total MUST be +1600 (Mountain cover 600 + Stance Entrench 300 + position 400 from a level-4 works + stack 300) and the maximum reachable attacker total MUST be +510 (Stance Advance 250 + combined arms 260; the siege term of CB-555 applies only to a Bombardment, which takes neither of those, and reaches only +250). The attacker's reachable minimum MUST be −680 (Stance Entrench −400 + river −180 + uphill −100) and MUST also be asserted, since CB-540's floor clamps at −700 and a reachable minimum below it would be a dead zone on the low side. CI MUST assert all three bounds against the shipped tables (CB-2680).

Note on the minimum, which was previously unasserted: the amphibious term of −250 is not reachable together with the Entrench term, because a unit attacking from aboard a transport changed tile to board it and therefore holds entrenchment 0 and cannot be in a prepared position; nor with the river term, because an assault launched from a hull does not additionally cross a river edge. The worst land approach — dug in, across a river, uphill — is therefore the binding case at −680, twenty inside the clamp. That is a thin margin and it is the reason the assertion exists.

Rationale: the clamps at ±1800 and −700 are a safety rail, not an operating range. If a new terrain type or Stance value pushes the reachable maximum into the clamp, players discover a dead zone where their next bonus is worth nothing, and that feels like being cheated. The assertion is what keeps that a build failure rather than a bug report.

CB-640 The max(1, …) floors on A and D MUST be applied. A force MUST NOT have zero power.

Rationale: nothing is ever mathematically impossible. A player told "0 per-mille" who then wins, or told "certain" who then loses, stops trusting the readout, and the readout is the whole product.

CB-650 The engine MUST export A and D as integers. The odds ratio MUST be presented by the client from those two integers; the core MUST NOT compute or store a decimal ratio.

5.4 Step 3 — Volatility

CB-660 Volatility MUST be computed as:

volX       = gradeVolatility[grade] + supplyVolatility[supplyTier]
volatility = clamp( floor((volLead + volDefender) / 2) + terrainChaos, volatilityFloor, 1500 )

where volLead uses the lead attacker's grade and supply and volDefender the defender's.

CB-670 volatilityFloor MUST be 250 by default and MUST be settable at setup to 600 by the rules option of CB-2630.

CB-680 Supporters MUST NOT affect volatility.

Rationale: volatility is how well the two commanders in contact can predict the fight. A supporting battery two tiles of frontage away does not make the assault more or less legible to either of them, and letting it do so would give supporters a second, invisible effect the panel could not explain.

CB-690 Terrain MUST contribute both cover (CB-600) and chaos (CB-660), and these MUST be independent columns of the terrain profile.

Rationale: this is the cheapest high-value idea in the design. Terrain does not only change the odds, it changes how much you can trust them. Open ground is predictable; forest, marsh and above all city fighting are gambles. One extra column per terrain buys a whole strategic dimension and gives experience and reconnaissance a job that is not merely "bigger number".

CB-700 The reliability figure shown to the player MUST be floor(volatility / 4) in per-mille, and MUST be displayed as a first-class number alongside the odds, never folded into them.

5.5 Step 4 — Resolve

CB-710 Resolve MUST be computed for both sides as:

Resolve = clamp( 40 + gradeResolve + stanceResolve + 6 × works + supplyResolve
                    + (inOwnCity ? 10 : 0)
                    − disorder
                    − floor((100 − strength) / 2)
                    − (encircled ? 20 : 0)
                    − (shaken > 0 ? 20 : 0),
                 5, 95 )

CB-720 The attacker's resolve MUST be computed for the lead attacker only. Supporters MUST NOT contribute to or receive a resolve value.

CB-730 inOwnCity MUST be true only for the defender, and only when the defender's tile holds a city owned by the defender's player.

CB-740 encircled MUST be true only for the defender, and MUST be computed by CB-1400.

CB-750 The base of 40 MUST be common to every unit in the game. Class-specific resolve MUST NOT exist; resolve differences MUST come only from grade, Stance, works, supply, city, and condition.

Rationale: making resolve a property of the situation rather than of the unit type is what makes condition legible. A player who learns that "dug in and fresh is about 60, worn and shaken is about 15" has learned it for every unit in the game at once. A per-class morale stat would make that knowledge non-transferable and would give the roster a second axis to be unbalanced on.

CB-760 The clamp bounds 5 and 95 MUST both be reachable, and the engine MUST NOT assume resolve lies strictly inside them.

CB-770 Resolve MUST be recomputed for every Clash from current state. It MUST NOT be cached across activations.

CB-780 The resolve of the two sides MUST be computed by the same function with the same terms, differing only in which side supplies each input.

CB-790 The engine MUST expose both resolve values in the combat event and in the preview.

Rationale: resolve is the number that decides whether the tile changes hands, and it is not visible anywhere on the map. If the panel does not name it, the two-track structure of CB-030 is invisible and players will read the odds ratio as the whole story — which is precisely the misconception the system exists to replace.

5.6 Step 5 — The draw

CB-800 Exactly one random number MUST be drawn per Clash:

h = coreHash(seed, turn, initiatorSequenceNumber, attackOrdinal)     // 64-bit
u = h & 0xFFFFFFFF                                                  // low 32 bits, unsigned
r = floor( u × 1000 / 4294967296 )                                  // uniform in [0, 1000)

CB-810 The hash MUST be positionally addressed — a counter-based function of the identity of the engagement — and MUST NOT be drawn from a stream cursor, a global PRNG sequence, or any state that depends on how many other combats have already resolved.

Rationale: this is not a nicety, it is what makes the value for a given attack independent of everything else in the turn. It means a preview computed during the Orders phase and the resolution computed during the Cascade address the same cell; it means a replay that skips an unrelated combat still reproduces this one; and it means the AI can evaluate a hundred thousand candidate attacks without perturbing a single draw.

CB-820 initiatorSequenceNumber MUST be the creation sequence number of the unit that initiated the engagement — the lead attacker for an Assault or Bombardment, the reacting unit for a Reaction.

CB-830 attackOrdinal MUST be the count of Clashes of any kind that the initiating unit has already resolved this turn, starting at 0, and MUST be incremented after each. A Disengagement MUST NOT increment it.

Rationale: the pair (initiator, ordinal) is unique within a turn by construction, so the four hash inputs address a unique cell with no domain-separation tag needed. Making the ordinal shared across kinds is what guarantees a unit that reacts and then attacks does not reuse a draw.

CB-840 Deriving r by multiply-shift as in CB-800 MUST be used. u mod 1000 MUST NOT be used.

Rationale: mod 1000 over a 32-bit range is biased — 1000 does not divide 2³², so 296 of the residues are very slightly more likely. The bias is about 2.3 × 10⁻⁷ and would never be noticed, and that is exactly why it should not be shipped: it is a free correctness win that costs one multiply, and a system whose entire selling point is an exact readout should not contain a known-biased draw.

CB-850 u × 1000 MUST be computed in at least 42 bits of integer precision. In an IEEE-754-double implementation this is exact, since u × 1000 < 2⁴² < 2⁵³.

CB-860 The draw MUST NOT be consumed for a Clash that is rejected under CB-340, and MUST NOT be consumed by any preview.

5.7 Step 6 — The exchange

CB-870 The exchange MUST be computed as exactly:

s      = floor( (r − 500) × volatility / 2000 )        // per-mille swing, ±volatility/4
A_eff  = max(1, floor( A × (1000 + s) / 1000 ))
D_eff  = max(1, floor( D × (1000 − s) / 1000 ))
shareA = floor( A_eff × 1000 / (A_eff + D_eff) )
shareD = 1000 − shareA
Ld     = min( defenderStrength, floor( intensityOut  × shareA × 100 / (1000 × toughDefender) ) )
La     = min( leadStrength,     floor( intensityBack × shareD × 100 / (1000 × toughAttacker) ) )

CB-880 intensityOut and intensityBack MUST be taken from CB-200 by kind.

CB-885 Where the Clash Specification's ambush flag is set, intensityBack MUST be 0 for that Clash, so the defender returns no losses. ambush MUST be set only for an Assault, only when 02-units-and-industry.md gives the lead attacker's class the corresponding capability, and only when the defender's player holds no observation of the lead attacker at the moment of resolution. It MUST NOT alter intensityOut, the break checks, or any other quantity.

Rationale: a first strike from concealment is exactly the case in which the defender does not fire back, and this document already has a constant for "the target cannot reach you" — it is the intensityBack = 0 that makes a Bombardment safe (CB-200). Reusing it means an ambush needs no new step, no new modifier, and no addition to the monotonicity obligation of CB-2150, because setting intensityBack to 0 makes La identically zero, which is trivially non-increasing in r.

CB-890 The single draw MUST push the odds both ways at once — A up and D down by the same s. Two independent draws MUST NOT be used.

Rationale: pushing both ways keeps the total heat of the battle roughly constant and moves only the split, so a good draw is a better trade rather than a bigger battle. It is also what makes every downstream quantity monotone in r, which is what makes the preview exact (CB-2150). The honest cost is that outcomes within one Clash are perfectly correlated: you cannot have "unlucky casualties but they broke anyway". Some players will find that flat. The exactness is worth more.

CB-900 For an Assault, La MUST be distributed across the attacking force: the lead attacker loses La, and each supporter loses floor(La × 400 / 1000).

Rationale: a supporter contributes at 400 per-mille and bleeds at 400 per-mille. Anything else makes support either free (and therefore always correct) or ruinous (and therefore never taken).

CB-910 For a Bombardment La MUST be 0 by CB-200's intensityBack = 0, and no special case MUST be written.

CB-920 Ld MUST be allocated to the defending stack by carry-over: the defender absorbs up to its current strength; any excess passes to the next unit of the stack in descending Step-1 defensive contribution (ties by lowest creationSequence); any excess beyond the last unit is discarded.

Rationale: this settles the source design's open question on casualty distribution. Putting all losses on the top defender makes stacking cheap right up to the moment the whole stack dies at once, which is a violent and unreadable cliff. Carry-over is one line of deterministic arithmetic, removes the cliff, preserves the exactness of the preview (the preview reports Ld and the allocation is a pure function of it), and makes a stack genuinely absorb more total strength than one unit — which is what justifies the modest +100-per-unit defence term rather than a larger one.

CB-930 The saturating shape of A/(A+D) MUST NOT be linearised or replaced. Overwhelming odds MUST have diminishing returns on damage and sharply increasing returns on safety.

Rationale: at 4:1 the defender loses 48 and the attacker 12; at 10:1 the defender loses 54 and the attacker 5. The payoff for overwhelming force is that your own losses collapse and the break becomes certain, not that the hammer gets bigger. That is deliberate anti-doom-stack design: massing buys safety, not throughput, so a second army somewhere else is usually worth more than a bigger one here.

CB-940 At even odds each side MUST lose 30 strength at tough = 100, so that a unit survives approximately three even fights. intensityOut = 60 for an Assault is calibrated to this and MUST NOT be changed without re-deriving the recovery table of §15.

Rationale: three even fights is long enough that a unit is a persistent asset with a history worth protecting, and short enough that a contested tile resolves in two or three turns rather than ten.

CB-950 Reference values at tough = 100, for CI and for the tuning record:

shareA Approx. odds Ld La (tough 100) La (tough 130)
500 1.00 : 1 30 30 23
600 1.50 : 1 36 24 18
700 2.33 : 1 42 18 13
800 4.00 : 1 48 12 9
909 10.0 : 1 54 5 4
950 19.0 : 1 57 3 2

5.8 Step 7 — The break checks

CB-960 The break checks MUST be computed as exactly:

shockDefender = Ld + flankShock + stanceShockToDefender
shockAttacker = La + stanceShockToAttacker + min(16, 8 × defenderWorks) + flakShock

defenderBreaks = shockDefender ≥ resolveDefender
attackerFalters = shockAttacker ≥ resolveAttacker  AND NOT defenderBreaks

CB-965 flakShock MUST be 6 × defenderFlak when the lead attacker's role is Air and the kind is Assault or Reaction, and 0 otherwise. It MUST NOT apply to a Bombardment, MUST NOT apply when the air unit is the defender, and MUST NOT contribute power, resolve or volatility.

Rationale, and this is where an entire mechanic from the roster's previous combat model landed. That model had the defender fire back at an air attacker in a separate round before the strike; there are no rounds here, and CB-870's exchange already returns losses to the attacker generically, so a second exchange would double-count the damage half of anti-aircraft fire. What it would not carry is the half that matters: flak mostly does not down the aeroplane, it makes the pilot break off the run. That is shock, not damage, and this document already has an attacker break check for exactly that shape of statement. At the top tier the term is +24 against a typical attacker resolve of 30, so a dedicated air-defence class turns away a bomber it has no prospect of destroying — which is what an air-defence unit is for, and what a damage-shaped rule never quite delivered. Six per tier rather than eight keeps the maximum below the +25 disorder a falter costs (CB-1150), so being driven off remains more expensive to the attacker than the shock that drove it off.

CB-970 flankShock MUST be 8 × min(4, flankers) for an Assault, 12 (a fixed ambush term) for a Reaction, and MUST NOT apply to a Bombardment.

CB-980 flankers MUST be the count of units belonging to the attacking player or a player allied to them that are adjacent (Chebyshev 1) to the target tile at the moment of resolution, excluding the lead attacker, with strength ≥ 1. Supporters MUST be counted.

Rationale: a unit standing next to the defended tile is exerting pressure whether or not it fired. Excluding supporters would mean adding a supporter reduces the flanking bonus, which is incoherent and would make the panel impossible to explain. Note that the illustrative summary tables in the source design proposal were generated with supporters excluded and consequently disagree with the proposal's own worked example; the worked example and the prose are correct and this requirement follows them.

CB-990 Flanking MUST contribute shock only, and MUST NOT contribute power.

Rationale: this is the single most important structural constraint in §5. Surrounding a unit does not make your shells hit harder; it makes the unit decide it cannot stay. Keeping flanking out of the power calculation is what stops "adjacency bonus" from degenerating into "bring more units", and it is what makes positioning worth more than force — the design's central claim.

CB-1000 stanceShockToDefender and stanceShockToAttacker MUST come from CB-1520. For a Reaction both MUST be 0, replaced by the fixed ambush term of CB-970.

CB-1010 A defender break MUST suppress an attacker falter.

Rationale: you are not thrown back from a position you have just taken. Without the suppression the same Clash could both take the ground and refuse it, which has no coherent consequence.

CB-1020 Neither break check MUST apply to a Bombardment.

Rationale: guns unstick, they do not take ground. A bombardment that could rout a defender would let artillery capture tiles at zero risk from beyond retaliation range, which is the single most degenerate outcome available in this design space.

CB-1030 Break MUST be a threshold comparison, never a probability roll. All uncertainty in the break outcome MUST enter through Ld/La and therefore through the single draw.

Rationale: a second roll would double the entropy, halve the legibility, and destroy the exactness of the readout for nothing. The break is already uncertain, because the losses that drive it are.

5.9 Step 8 — Consequences

CB-1040 The outcomes MUST be exactly these five, evaluated in this order.

# Condition Consequence
1 Defender's stack reduced to 0 strength throughout Every reduced-to-zero unit destroyed; survivors remain; attacker MAY advance if the tile is empty
2 defenderBreaks and a legal retreat destination exists The whole defending stack vacates to that tile with +10 disorder each and 0 movement remaining; the lead attacker MAY advance
3 defenderBreaks and the defender's retreat class forbids retreat (CB-1330) Not destroyed. shaken set to 2. The tile does not change hands
4 defenderBreaks and no legal retreat destination exists Rout: the whole defending stack is destroyed
5 attackerFalters Losses stand; the attacker does not advance, gains +25 disorder, and may not attack again this turn (CB-250)

CB-1050 When none of conditions 1–5 hold, losses MUST be applied and nothing MUST move. The lead attacker MAY initiate a further Assault if it has movement remaining.

CB-1060 The lead attacker MAY advance only when the target tile is empty of enemy units after the consequence step, its Stance is Advance or Hold, it has at least one movement point remaining, and the tile is legal for it to occupy under stacking and passability rules.

CB-1070 Advancing MUST cost one movement point.

CB-1080 Stance Entrench and Stance March MUST NOT advance.

Rationale: an entrenched unit that leaves its position to occupy the ground it has just cleared has thrown away the position it spent turns preparing; the player who wants the tile sets Advance. A marching column is not fighting for ground at all.

CB-1090 Supporters MUST NOT advance (CB-430). A Reaction MUST NOT produce an advance (CB-200).

CB-1100 A retreating stack MUST arrive with its movement allowance for the turn spent, MUST NOT act again that turn, and MUST retain its Posture and order stack intact per CM-220.

CB-1110 Retreat MUST move the entire defending stack to the same destination tile. Splitting a retreating stack across destinations MUST NOT occur.

CB-1120 A retreat destination MUST have stacking room for the entire retreating stack. Where no candidate does, the retreat MUST be treated as having no legal destination and outcome 4 applies.

Rationale: this makes crowding behind a line into a real vulnerability, which is the correct consequence of the design's stacking economics. It is also the sharpest edge in the document and the first thing to soften if playtest shows rout losses above the CB-2710 band.

CB-1130 shaken = 2 MUST subtract 20 from resolve while non-zero and MUST be decremented by 1 at the end of each turn, so a garrison that breaks in place fights the remainder of this turn and the whole of the next at reduced resolve.

Rationale: cities fall to strength loss, not to rout. A defender that cannot run has to be killed, and the shaken penalty is what makes the second and third assault of a siege progressively cheaper without ever letting a fortification be taken by morale alone.

CB-1140 A stack destroyed by rout MUST emit one combat event listing every destroyed unit and MUST raise a Routed Attention Event for the losing player naming the tile and the unit count.

CB-1150 A faltered attacker MUST gain +25 disorder and MUST be barred from initiating further Assaults or Bombardments that turn.

CB-1160 After a sanctioned automated capture resulting from an advance, the capture obligations of CM-730 apply. This document MUST NOT duplicate them.

CB-1170 A unit that advances MUST be treated as having changed tile for the purposes of TM-700, so its entrenchment is reset to 0.

CB-1180 All consequences MUST be applied before the Clash's combat event is emitted, and the event MUST contain the resulting state of every unit it touched.

5.10 Step 9 — Bookkeeping

CB-1190 Disorder MUST be applied after consequences, in exactly these amounts, and MUST be clamped to [0, 100] after summation:

Event Disorder change
Initiated an Assault lead attacker +6 + floor(La / 2)
Was assaulted defender +floor(Ld / 2)
Was bombarded defender +3 × Ld + 5
Was engaged by a Reaction mover +floor(Ld / 2) + 4
Reacted reactor +8
Broke and retreated broken unit +10 (whole stack)
Broke in place (outcome 3) defender +10
Attack faltered lead attacker +25
Supported an attack supporter +10
Disengaged disengaging unit +15

CB-1200 The bombardment coefficient of 3 × MUST be the mechanism by which artillery removes resolve. It MUST NOT be applied to any other kind.

Rationale: this one row is the entire combined-arms argument for a third role. A bombardment that takes 7 strength and adds 26 disorder has removed 26 resolve, and resolve is what decides whether the tile changes hands. Guns do not kill; guns unstick. That is a mechanically distinct job no amount of extra armour can do, and it is expressed entirely through the two-track structure of CB-030 rather than by giving artillery a bigger number.

CB-1210 Experience MUST be awarded as:

xpGain = 2 + floor(damageDealt / 4) + (opposingSideBroke ? 10 : 0)

for the lead attacker and for the defender, and floor(xpGain / 2) for each supporter, where damageDealt is Ld for the attacking side and La for the defender.

CB-1220 Total xp gained by a unit MUST be capped at 25 per turn from all sources.

Rationale: the cap is what stops a unit being farmed on a helpless target. Twenty-five per turn means the fastest possible path from Green to Elite is 28 turns of continuous heavy fighting, which no unit survives — so Elite is genuinely rare and is a story about a formation rather than a grind.

CB-1230 xp MUST be capped at 999 and MUST NOT decrease.

CB-1240 No xp MUST be awarded from a Disengagement, to either side.

Rationale: nobody learns anything from a contact broken before the exchange, and awarding it would make a screening force an experience farm.

CB-1250 This document MUST NOT increment, reset, or otherwise write entrenchment. TM-700 owns the counter, its range of [0, 3], and both conditions: it increments during the Reckoning of a turn in which the unit's committed Stance was Entrench and the unit did not change tile, and it is set to 0 whenever the unit changes tile for any reason or holds any other Stance at a Reckoning.

Rationale, and the two documents genuinely disagreed rather than merely differing in wording. This document previously incremented a counter of its own on "began and ended the turn on the same tile", which credits an out-and-back move, and withheld the increment from a unit that initiated a Clash, which TM-700 does not. TM's reading wins on both, and on the merits rather than on ownership alone. "Reset on any move" is what the source design paper specifies and is the sentence a player can hold, whereas "began and ended on the same tile" rewards a unit for driving out and back, which is the opposite of what digging in is. Dropping the "did not initiate a Clash" clause costs less than it looks like, because an entrenched attacker already pays −400 attack (CB-1520) and may never advance (CB-1080); a second penalty for firing from a prepared position was punishing the one thing a prepared position is for.

CB-1260 A unit that retreats, disengages, is transported, or advances MUST have its entrenchment reset by TM-700's own rule, which fires on the tile change. CB-1170 restates that consequence for an advancing attacker only because the advance is this document's action.

CB-1270 A unit is considered to have fought this turn if it initiated, defended, supported, reacted to, was bombarded by, or disengaged from any engagement this turn. This flag MUST be cleared at the start of each turn.

CB-1280 The bookkeeping of §5.10 MUST be applied to every participant of every Clash, including participants that were destroyed, before the destroyed units are removed, so that the combat event reports final values.

CB-1290 Every quantity in §5.10 MUST be emitted in the combat event with its source named.

CB-1300 The engine MUST NOT apply any disorder, experience, or dig-in change not enumerated in §5.10.


6. Retreat, rout, and encirclement

CB-1310 A retreat destination MUST be selected deterministically from the tiles adjacent (Chebyshev 1) to the defender's tile that satisfy all of:

  1. passable to every unit of the retreating stack under its movement class;
  2. contains no unit hostile to the retreating player;
  3. is not the lead attacker's tile;
  4. has stacking room for the entire retreating stack;
  5. is legal for the retreating units' domain (a land unit may not retreat into open water).

CB-1320 Among the candidates the engine MUST select the lowest score under:

score = 4000 × (count of units hostile to the retreating player adjacent to the candidate)
      − terrainCover(candidate)
      − (a friendly unit is present on the candidate ? 500 : 0)
      − (candidate is strictly closer to the nearest friendly city than the current tile ? 2000 : 0)

with ties broken by lowest tile index (row-major), consistent with 03-architecture.md's canonical tile ordering.

Rationale for the weights: avoiding further contact dominates everything, so 4000 per adjacent enemy sits an order of magnitude above the rest. Falling back toward home (2000) outranks falling back into cover (at most 600) because a unit that retreats deeper into a pocket to sit in a forest has made its situation worse; company (500) is the smallest term because it is a preference, not a survival requirement. Every weight is separated from the next by more than the maximum of the terms below it, so the ordering is a strict lexicographic preference expressed as one integer — which is what makes it explainable in the readout as a ranked list of reasons.

CB-1330 Every unit MUST have a retreatClass:

Class Behaviour on break
Ground Retreats per CB-1310; destroyed if no candidate exists (rout)
Detached Disengages immediately to its nearest reachable friendly basing site; destroyed if none is reachable within its remaining endurance

CB-1340 A unit occupying a city or a works of level ≥ 1 MUST NOT retreat regardless of its retreatClass, and MUST take outcome 3 of CB-1040 instead.

CB-1350 The retreat destination MUST be computed against the world as it stands at the instant of resolution, using true state.

CB-1360 The preview MUST compute the retreat destination from the viewing player's knowledge view, and MUST mark it provisional whenever any input to CB-1310 or CB-1320 is unobserved.

Rationale: the exactness guarantee of §16 is a guarantee about the resolution function given its inputs, not a claim that a player can see the whole board. Showing a retreat tile computed from partial knowledge without saying so would be the one lie the readout must never tell.

CB-1370 The predicted retreat destination MUST be displayed on the map in the attack preview before the player commits.

Rationale: this is what turns "cut their line of retreat" from a thing that happens to you into a thing you plan. The mechanic of CB-050 is worthless if the player cannot see the roads they need to take away.

CB-1380 A retreating stack MUST NOT pass through or over any intervening tile. Retreat is a single step to an adjacent tile.

CB-1390 Zone-of-control rules, where 01-game-rules.md defines them, MUST be applied as an additional exclusion in CB-1310 and MUST NOT alter the scoring of CB-1320.

CB-1400 A defender MUST be considered encircled for the purposes of the resolve term in CB-710 when the candidate set of CB-1310 is empty at the moment resolve is computed.

Rationale: encirclement is not a state to track, a flag to set, or a subsystem to write. It is the name of a condition the retreat rule already computes, and reusing that computation is what makes CB-050 true rather than merely claimed. The −20 resolve means a cut-off unit breaks sooner, and breaking with nowhere to go destroys it — so the same geometry both causes and punishes the break.

CB-1410 Encirclement MUST be visible before it is fatal: the client MUST mark any unit whose candidate set is empty, for both owners, whenever the marked unit is visible to the viewing player.

CB-1420 Rout destruction MUST NOT be reduced, split, or partially applied. If the stack cannot retreat, all of it is destroyed.

Rationale: this is the mechanic the source design was least sure of, and it is also the one that makes the whole manoeuvre game worthwhile. Four units vanishing in one Clash is enormous swing, and softening it pre-emptively would remove the reason to encircle anything. CB-2710 puts a measured band on it so that a tuning failure is a failing number rather than an argument.

CB-1430 A unit destroyed by rout MUST count as a combat loss for scoring and victory purposes on the same terms as any other destruction; 14-victory.md owns the terms.


7. Terrain

CB-1440 Every terrain type defined by 01-game-rules.md MUST carry a combat profile consisting of: cover (per-mille), chaos (per-mille), and one roleTerrain per-mille value for each of the six roles.

CB-1450 The roleTerrain table MUST be:

Terrain family Foot Armor Gun Recon Naval Air
Open 0 +150 0 +100 0
Hills +100 −150 +100 0 0
Forest +150 −300 −150 −100 −100
Marsh 0 −400 −250 −150 0
Mountain +200 −500 −200 −150 −150
Urban +200 −250 −100 −200 −150
Water 0 0

Rationale: this one table is the whole combined-arms argument. Armour is 150 per-mille better than foot in the open and 700 worse in mountains. There is no terrain where a single role is correct, so a force that is all one thing has a map full of tiles it cannot profitably touch — and that is a structural incentive to mix rather than a bonus bolted on to reward mixing.

CB-1460 The cover and chaos table MUST be:

Terrain family Cover (defender force mod) Chaos (volatility)
Open 0 −150
Marsh +250 +250
Hills +300 +50
Forest +400 +200
Urban +500 +350
Mountain +600 +150
Water 0 0

Rationale: marsh is the deliberate oddity — only moderate cover, but the highest chaos short of a city. It is a bad place to be and a worse place to plan, which gives the map a terrain type whose danger is informational rather than numerical. Urban has both the second-highest cover and the highest chaos because city fighting should be the thing a careful player is most reluctant to gamble on, and that is a different feeling from "hard".

CB-1470 01-game-rules.md MUST assign every terrain type it defines to one of these families, or supply an explicit profile of its own. A terrain type with neither MUST use the Open profile, and CI MUST fail the content build with a named error rather than defaulting silently.

CB-1480 A terrain profile MUST NOT vary by attacker, by turn, by weather, or by any dynamic state. Where a scenario needs seasonal or weather effects, they MUST be expressed as a separate additive term in CB-550/CB-600 with its own requirement, not by mutating the profile.

Rationale: a static profile is what makes the terrain overlay of CB-2470 honest and what lets a player learn the map once. A mutating profile turns every learned fact into a maybe.

CB-1490 The engine MUST export defensiveValue(unitClass, terrain) = cover(terrain) + roleTerrain(role(unitClass), terrain) as an integer per-mille, higher being better. (Satisfies CM-1410.)

CB-1500 The terrain overlay in the client MUST be computed from the same profile data the core resolves with. A separate presentation table MUST NOT exist.


8. Stance, dig-in, and works

CB-1510 Combat MUST read the unit's Stance as defined by 10-turn-model.md, with values March, Advance, Hold, Entrench. Combat MUST NOT define its own tactical posture vocabulary and MUST NOT modify a unit's Stance.

CB-1520 The Stance combat table MUST be:

Stance Attack force mod Defence force mod Resolve Shock to defender Shock to attacker May advance
Advance +250 −200 −10 +6 0 yes
Hold 0 0 0 0 0 yes
Entrench −400 +300 +15 0 +10 no
March −250 −300 −5 0 0 no

Rationale for the March row, which the source design did not have: the turn model grants Initiative and forfeits reaction capacity for March, and something has to make that a trade rather than a free win. A column caught on the road is bad at fighting and much worse at being fought, which is what makes reactive fire (§11) and screening forces mechanically real. The resolve penalty is only −5 because a unit that is merely moving has not lost its nerve; the punishment is positional, not moral.

CB-1530 A unit in Stance March MUST NOT initiate an Assault or a Bombardment. It MAY be the defender of one, and MAY be the mover in a Reaction.

CB-1540 The Advance resolve penalty of −10 MUST be retained in combination with the strength penalty of CB-120.

Rationale: together they produce a specific and intended behaviour — a unit below about 60 strength falters out of any marginal attack, while a good attack still goes in. The rule is therefore "worn units cannot make bad attacks", not "worn units cannot attack", and it is intentional culmination rather than an accident of two penalties meeting. It will nonetheless be felt as "my units stopped working" before it is understood as "rotate your line", so CB-2400 requires the falter risk to be named explicitly in the preview.

CB-1550 The defender's position term MUST be +100 × max(entrenchment, works), so that works sets a floor on dug-in position rather than adding to it.

CB-1560 entrenchment MUST be the counter 10-turn-model.md defines (TM-700), an integer in [0, 4] giving a position term of at most +400. This document MUST NOT define a counter, a range, or an accrual rule of its own (CB-1250).

Rationale for reconciling to 4 rather than to the 3 the counter's owner originally carried, which is 10-turn-model.md's decision and this document accepts it. The position term is max(entrenchment, works) and works runs 0-4 (CB-1570), so a ceiling of 3 on digging would leave the comparison dead over the top fifth of its own scale: a unit could never dig itself to the position a finished fortification confers, and a unit standing in a finished fortification could never improve its position by digging at all. The counter-argument -- that a fortification ought to be strictly better than a spade -- is answered without narrowing the range, because CB-610 gives works two effects digging does not: +6 x W resolve and no retreat. A finished fort and four turns of digging reach the same defence modifier and are still not the same position, which is the correct distinction and a more interesting one than a numerical ceiling.

CB-1570 works MUST be an integer 0–4 supplied per tile by 01-game-rules.md. A city MUST supply its own works level.

CB-1580 Stance MUST be derivable from Posture by the rules of 13-command.md §4 and MUST be overridable per turn by the player (CM-560). Combat MUST accept whatever value it is given.

CB-1590 The preview MUST name the Stance of both sides and the numeric contribution of each.


9. Grade and supply

CB-1600 Grade MUST be derived from xp by these thresholds and MUST NOT be stored separately:

Grade xp threshold
Green 0
Trained 100
Veteran 300
Elite 700

CB-1610 The grade table MUST be:

Grade Power Resolve Volatility
Green +0 +0 1000
Trained +80 +5 850
Veteran +180 +12 700
Elite +300 +20 550

Rationale: Elite is +30% power, not +200%. Veterans should be reliably better, not individually decisive — an Elite unit that beat four Green ones would make combat a race to a few super-units and would make every loss catastrophic. The volatility drop from 1000 to 550 is arguably the larger effect and is certainly the one that matters to a planner: an Elite formation's outcomes cluster, so you can build an operation around it.

CB-1620 Combat MUST read a supply tier with four values: Cut, Strained, Adequate, Full.

CB-1630 The supply tier MUST be derived from the supply state owned by 12-economy.md by exactly:

Economy supply state Additional condition Combat supply tier
Isolated Cut
Extended Strained
Supplied unit is not on a supply source tile Adequate
Supplied unit occupies a supply source tile (a supplying city or an emplaced depot) Full

Rationale: the economy owns the geography of supply and this document owns what supply does in a fight, so the mapping belongs here and the inputs belong there. The fourth tier is derived rather than requested because "standing on the depot" is a fact the economy already computes for its own purposes, and giving a unit a combat edge for fighting on top of its own supply head is both true to life and a real reason to place depots where the fighting will be.

CB-1640 12-economy.md MUST NOT define combat power multipliers for supply. The values below are the normative ones.

CB-1650 The supply table MUST be:

Supply tier Power Resolve Volatility
Cut −400 −15 +300
Strained −150 −5 +100
Adequate 0 0 0
Full +50 0 −100

Rationale: −150 for Strained is within 25‰ of the ×7/8 — that is, −125‰ — that the economy proposal reached independently, so the two designs agree about extension to within a fortieth. Cut is deliberately harsher than the economy's ×3/4, at −400 plus −15 resolve plus +300 volatility, because cutting a road is meant to be the strongest thing in the game, and the supply table of §23 shows it working: against a defender that no assault can shift, severing supply produces certain break. That is the operational game this system exists to create, and it should not be a marginal effect.

CB-1660 Supply MUST affect only power, resolve and volatility. It MUST NOT affect losses, break thresholds, or retreat directly.

CB-1670 The supply tier of both sides MUST be shown in the preview.


10. Bombardment

CB-1680 A Bombardment MUST be legal only when: the firing unit's class has bombardRange ≥ 1; the target tile is within bombardRange (Chebyshev) of the firing unit; the firing unit has not moved this turn; the firing unit has fired fewer than bombardShots times this turn; and the firing unit has not supported this turn.

CB-1690 A Bombardment MUST forfeit all of the firing unit's remaining movement for the turn.

Rationale: guns either displace or fire. This is what makes the position of a battery a decision a turn in advance rather than a thing that resolves itself, and it is what stops artillery from being able to both keep pace with an advance and support it.

CB-1700 A Bombardment MUST use intensityOut = 22 and intensityBack = 0, and MUST perform no break check for either side (CB-1020).

CB-1710 A Bombardment MUST NOT reduce a unit's strength below 1.

Rationale: artillery softens; it never takes ground and it never takes the last point. Without this floor a gun line kills at zero risk from beyond retaliation range, which is both degenerate and thematically wrong. It also means the last strength point of every defender must be paid for by somebody who walked into contact.

CB-1720 A Bombardment MUST apply +3 × Ld + 5 disorder to the target (CB-1190) and MUST NOT apply disorder to the firing unit.

CB-1730 A Bombardment MUST target the defending stack's top defender under CB-400, and its Ld MUST be allocated by carry-over under CB-920 subject to the floor of CB-1710 applying to each unit individually.

CB-1740 Bombardment against a city or works MUST use the same procedure. The siege capability of 02-units-and-industry.md MUST take effect solely through the attackerEdgeMods term of CB-555 and MUST NOT alter this procedure.

CB-1750 The equilibrium between bombardment and recovery MUST be treated as a designed quantity. One bombardment against a defender in a city produces roughly +23 disorder. That defender has fought this turn by CB-1270 — being bombarded counts — so its city recovery of −45 is halved by CB-2080 to −22. One shot therefore nets +1 and accomplishes nothing at all; two net +24; three net +47. 02-units-and-industry.md MUST set bombardShots against this threshold — a class whose bombardShots alone exceeds two is a gun line in one unit and can reduce a fortification single-handed, and a class with bombardShots 1 requires a gun line of three.

Rationale: artillery only works concentrated, and this is the arithmetic that makes it so. A gun line is a thing you build, move and protect as a unit rather than a per-unit habit, and the threshold falls directly out of the recovery table without any rule that mentions concentration. The reason the threshold is stated in shots rather than in batteries is that bombardShots is the roster's dial: whether concentration is required is decided there, and this requirement is what makes that decision visible to whoever turns the dial. The halving is the part that was previously got wrong here: stated against the unhalved −45 the break-even sits at two shots, and against the true −22 a single gun is not marginal, it is useless. The conclusion is the same and the margin is much sharper, which matters because it is the margin a roster designer sets bombardShots against.


11. Reactions

CB-1760 10-turn-model.md owns when a reaction occurs and who gets it: reaction capacity, eligibility, and the interruption of the mover. This document owns only what the reaction does.

CB-1770 A Reaction MUST resolve as a Clash with the reacting unit as the attacking side and the moving unit as the defender, on the mover's halt tile, with intensityOut = 34 and intensityBack = 14.

Rationale for the asymmetry: a reaction is a firefight begun by a unit that is in position against one that is deployed for movement. The reactor deals a real blow and takes a glancing one. Symmetric intensity would make overwatch a losing trade against any tougher unit — a dug-in rifle company would deal 13 and take 16 to an armoured battalion — and a mechanic that costs you more than it costs your enemy will simply never be used, which would waste the reaction rule the turn model paid for.

CB-1780 The mover MUST halt regardless of the Clash outcome; the halt is the turn model's, not this document's. The break check determines only whether the mover is additionally thrown back.

CB-1790 In a Reaction the reactor's Stance attack modifier MUST NOT apply. A flat +200 prepared fire modifier MUST apply in its place, and the combined-arms term MUST NOT apply.

Rationale: Entrench gives −400 attack, and a reaction is precisely the reward for having entrenched. Applying the assault modifier to prepared fire would make the best-positioned unit the worst reactor, which inverts the mechanic.

CB-1800 In a Reaction the mover's own Stance defence modifier MUST apply, so that March (−300) is punished and Advance (−200) is punished less.

CB-1810 In a Reaction flankShock MUST be the fixed ambush term of 12 and the works and Stance shock terms MUST be 0 (CB-1000).

CB-1820 A mover that breaks MUST retreat from its halt tile under §6, and MUST be destroyed if no candidate exists.

Rationale: overwatch on a chokepoint is lethal, and it is lethal by the same rule that makes encirclement lethal. No new rule is needed for "ambushed in a defile".

CB-1830 A reactor that falters MUST gain +25 disorder and MUST forfeit its remaining reaction capacity for the remainder of the Cascade. It MUST NOT move or retreat.

CB-1840 A Reaction MUST NOT be predictable in the attack preview, because reaction capacity is not observable. The preview MUST instead state, as a warning without a probability, when the target tile or the planned route is adjacent to a visible enemy that could hold reaction capacity.

Rationale: an honest "you may be intercepted here" is worth more than a fabricated percentage. This is the one place the readout deliberately declines to give a number, and saying why is part of the contract.


12. Disengagement

CB-1850 When an Assault would resolve against a unit whose order stack has an active Withdraw Reflex (CM-1400), and that unit has not already disengaged this turn, the engine MUST resolve a Disengagement instead of a Clash.

CB-1860 A Disengagement MUST consume no draw, MUST perform no break check, and MUST resolve as:

  1. select a retreat destination by §6;
  2. if one exists, the disengaging unit loses floor(1000 / tough) strength, gains +15 disorder, vacates the tile, and its movement for the turn is spent;
  3. the attacker takes no losses and MAY advance under CB-1060;
  4. if no destination exists, the unit is Caught and a normal Assault resolves with a −200 defender force modifier (CB-600).

CB-1870 Parting losses follow directly: 33 at tough 20, 16 at 60, 14 at 70, 10 at the reference 100, 7 at 130, 6 at 150, 5 at 190 and 4 at 240 — every one of which is exercised by a shipped class (02-units-and-industry.md §8).

Rationale for deriving the parting loss from tough rather than fixing it: breaking contact costs a formation a fixed absolute number of people and vehicles, so it costs a small unit proportionally far more than a large one. A scout troop pays a sixth of itself to break away and a capital hull pays a twenty-fifth, which is what makes screening a job for something cheap rather than for whatever is nearest.

CB-1880 The Caught modifier of −200 MUST apply only to the Clash that follows a failed disengagement, and MUST NOT persist.

CB-1890 A unit MUST disengage at most once per turn. A second attack on a unit that has already disengaged this turn MUST resolve as a normal Clash.

Rationale, and this settles the source design's open question on infinite screening: a screening unit trades strength and disorder for tempo, and both meters run against it. Disengaging counts as having fought (CB-1270), so the unit recovers no strength at end of turn and only half its disorder — +15 gained against −10 recovered is a net +5 disorder per turn, while strength falls by the parting loss with no recovery at all. A scout troop screening every turn is dead in about six turns. The once-per-turn cap closes the other half of the hole, which is one unit absorbing an unbounded number of attacks in a single turn by walking backwards.

CB-1900 A disengaging unit MUST NOT gain or grant experience (CB-1240).

CB-1910 The attacker's preview MUST show, when the target is under a Withdraw Reflex and that fact is observable, that the attack will yield the tile without an exchange, together with the parting loss the defender will take.

CB-1920 A Detached unit MUST NOT disengage under this section; CB-1330 governs it.


13. Stacks

CB-1930 stackExtra MUST be the count of units on the defending tile other than the defender, with strength ≥ 1, and MUST contribute +100 × min(3, stackExtra) to the defender's force modifier.

CB-1940 01-game-rules.md owns stacking capacity. The cap of 3 in CB-1930 MUST be independent of that capacity, so that raising the stacking limit does not raise the defensive ceiling.

Rationale: the reachable-maximum assertion of CB-630 must survive a stacking-rule change made by another document. Decoupling the two is what makes that possible without a cross-document renegotiation.

CB-1950 Only the defender MUST contribute defensive power (CB-400). Other stack members MUST NOT contribute power, resolve, volatility, or break terms.

CB-1960 Losses MUST be allocated to the stack by carry-over (CB-920).

CB-1970 A break MUST move or destroy the whole stack (CB-1110, CB-1420).

CB-1980 The attacking side MUST NOT stack: an Assault is one lead attacker plus at most two supporters, each on its own tile.


14. Cities, works, and sieges

CB-1990 A defender in a city or works MUST NOT retreat (CB-1340) and MUST take the shaken consequence of CB-1130 instead.

CB-2000 A city MUST therefore fall to strength loss, never to rout.

Rationale: cities are sieges, not skirmishes. They are where the game's big decisions land and they are the one place where fight-to-the-death is the rule — which is only tolerable because CB-040 makes it the exception everywhere else.

CB-2010 The +10 own-city resolve term (CB-710) and the +6 × works term MUST both apply, and MUST stack additively with the Stance and grade terms.

CB-2020 A player MUST be able to order a garrison to abandon its place during the Orders phase. An abandoning unit MUST move out under normal movement at its activation, and the place MUST be left undefended.

Rationale, and this settles the source design's open question on city retreat: the pathology it worried about is a player feeding units into a hole they cannot leave, and the fix is to let them leave — deliberately, in advance, as a decision. Making it an automatic break-triggered behaviour instead would take the decision away and would let a fortification be lost to a morale check, which CB-2000 forbids. As an order it is legible, it is the player's, and it costs them the city they chose to give up.

CB-2030 Abandonment MUST NOT be reachable through any Sanction and MUST require an explicit player order, consistent with CM-410.

CB-2040 The following siege sequence MUST be reproduced exactly by any conforming implementation and MUST be a golden-master test vector. Every unit in it is a class of the shipped roster and every stat is that class's shipped value (02-units-and-industry.md §8), so the vector is reproducible from the content that ships rather than from an illustrative cast.

The garrison. One Infantry (atk 30, def 44, tough 100, role Foot), Trained, Adequate, Stance Entrench, alone in its own works-3 city on Urban terrain, starting at strength 100 and disorder 0.

The gun line. Three Field Guns (atk 48, def 18, tough 70, role Gun, bombardShots 1), Trained, Adequate, strength 100, each firing once per turn at the median draw r = 500. No siege term applies: the Field Gun does not carry the capability.

The assault force. One Armour (atk 62, def 38, tough 130, role Armor), Veteran, Full, Stance Advance, strength 100, with three flankers.

Turn 1 — the gun line fires three times.

Shot A D Strength taken Disorder added Defender after
1 47 117 6 23 str 94, dis 23
2 47 109 6 23 str 88, dis 46
3 47 102 6 23 str 82, dis 69

At end of turn the defender fought this turn (CB-1270: it was bombarded), so it recovers no strength and its city disorder recovery of −45 is halved to −22 (CB-2080). It begins turn 2 at strength 82, disorder 47.

Turn 2 — three more shots, then two assaults. The three shots run A 47 against D 96, 88 and 79, taking 7, 7 and 8 strength and adding 26, 26 and 29 disorder, leaving the defender at strength 60, disorder 100 (clamped by CB-130).

The assault table, at each state the defender passes through:

Defender state A D Resolve They lose (min/med/max) You lose Break
str 100, dis 0 (turn 1, before the guns) 75 117 88 16 / 23 / 31 21 / 28 / 33 0‰; attacker falters 1000‰
str 82, dis 47 (turn 2, before the guns) 75 96 32 18 / 26 / 34 19 / 25 / 31 1000‰
str 60, dis 100 (turn 2, after the guns) 75 69 5 22 / 31 / 39 15 / 22 / 28 1000‰
str 29, dis 100, shaken 2 (after the first assault) 75 33 5 29 / 29 / 29 9 / 14 / 19 1000‰, destroyed

The first assault of turn 2 takes a median 31 and the defender breaks; it is in a city, so CB-1040 outcome 3 applies — it is not destroyed, it does not retreat, and shaken is set to 2. The second assault removes its remaining 29 and the city falls.

Note the first row, which is the whole argument for a gun line in one line of a table: the identical assault against the intact garrison cannot break it at any draw and falters at every draw, costing the attacker more than it costs the defender. Nothing about the attacking force changed between that row and the third. What changed was 100 points of disorder, and disorder is resolve.

CB-2050 The intended shape is two turns of a three-Field-Gun line plus two Armour assaults to take one entrenched Infantry out of a level-3 fortification, which is what CB-2040 reproduces exactly. CB-2710 measures deviation from it.

CB-2060 Combat MUST NOT transfer city ownership. It vacates or destroys the defenders; the advance of CB-1060 into an empty city is what 01-game-rules.md acts on.


15. Recovery

CB-2070 At the end of every turn, after all combat and before production, each unit MUST recover according to the base row that matches its situation:

Situation Disorder Strength
In the field −20 +4
Stance Entrench, in the field −35 +4
In a friendly city −45 +12
In a friendly city with a depot −45 +20

CB-2080 The base row MUST then be modified, in this order:

  1. if supply tier is Strained, halve both values by floor division and set strength recovery to 0;
  2. if supply tier is Cut, set both to 0;
  3. if the unit fought this turn (CB-1270), set strength recovery to 0 and halve the disorder recovery by floor division.

CB-2090 The order of operations in CB-2080 MUST be exactly as given. Halving twice MUST produce floor(floor(x/2)/2).

CB-2100 Strength MUST be capped at 100 and disorder floored at 0 after recovery.

CB-2110 The recovery asymmetry MUST be preserved: a unit at 40 strength is 5 turns from full in a city, 3 in a city with a depot, and 15 in the field.

Rationale: rotation is a real decision with a real cost, and this is where it lives. Fifteen turns in the field is long enough that leaving a worn unit forward is a genuine sacrifice; five in a city is short enough that pulling it back is a plan rather than a write-off. It also gives cities a purpose beyond production — they are where armies are repaired — which is a second reason to want them and a second thing to lose when one falls.

CB-2120 Recovery MUST NOT be applied to a unit destroyed during the turn.

CB-2130 Attrition damage from being out of supply is owned by 12-economy.md and MUST be applied after this section's recovery, so that a Cut unit neither recovers nor is double-counted.


16. The prediction contract

This section is the reason the rest of the document is shaped the way it is. Under Orders and the Cascade a player commits before seeing, so a prediction that can disagree with the resolution is worse than no prediction at all.

CB-2140 The engine MUST expose exactly one resolution function

resolveExchange(spec: ClashSpec, r: int) → Outcome

and the prediction function MUST be implemented by calling it. A second implementation of the arithmetic, in any form — an estimator, an approximation, a client-side copy, an AI-specific evaluator — MUST NOT exist.

Rationale: this is the requirement the whole subsystem is built to make satisfiable. Single-exchange resolution (CB-020), a self-contained Specification (CB-280) and monotonicity (CB-2150) exist so that an exact preview is a handful of calls to the real function rather than a model of it. The class of bug where the AI plays a different game from the player, or where the preview is right in the common case and wrong at the edges, is not mitigated here — it is made unrepresentable.

CB-2150 Every downstream quantity MUST be monotone in r, specifically: s, A_eff, shareA, Ld and shockDefender are non-decreasing; D_eff, shareD, La and shockAttacker are non-increasing.

Rationale, stated as a proof obligation rather than an observation: s is non-decreasing in r by construction; A_eff is non-decreasing and D_eff non-increasing in s; shareA = floor(1000 · A_eff / (A_eff + D_eff)) is increasing in A_eff and decreasing in D_eff, so it is non-decreasing; Ld and La are monotone transforms of shareA and shareD; min with a constant preserves monotonicity, as does the max(1, …) floor. The property therefore holds for every intensity pair and every clamp setting, not merely for the shipped constants — but CB-2670 requires the sweep anyway, because a future non-monotone modifier would silently make every preview a lie.

CB-2160 The loss bands MUST be computed by evaluating resolveExchange at r = 0, r = 500 and r = 999, and taking minimum, median and maximum by value rather than by position.

CB-2170 The break threshold rDef MUST be the least r ∈ [0, 1000) for which defenderBreaks holds, or 1000 if none does, found by binary search over the closed range. P(defender breaks) MUST be reported as 1000 − rDef per-mille.

CB-2180 The falter threshold rAtt MUST be the least r ∈ [0, 1000) for which shockAttacker < resolveAttacker, or 1000 if none does. P(attacker falters) MUST be reported as min(rAtt, rDef) per-mille.

Rationale: the attacker breaks for r < rAtt because its shock is non-increasing, and CB-1010 suppresses the falter whenever the defender breaks, which happens for r ≥ rDef. The intersection is exactly r < min(rAtt, rDef), so the answer is one subtraction and no further search.

CB-2190 The survival threshold rSurv MUST be the least r for which La < leadStrength. P(attacker destroyed) MUST be rSurv per-mille.

CB-2200 winPermille MUST be defined as 1000 − max(rDef, rSurv), floored at 0: the count of draws for which the defender breaks and the lead attacker survives.

CB-2210 capturePermille MUST be winPermille when CB-1060's positional preconditions hold for the attacker, and 0 otherwise. (Satisfies the capture-probability requirement of CM-1370.)

CB-2220 The binary search MUST use exactly the bracket [0, 1000) and MUST terminate in at most 10 probes.

CB-2230 A full preview MUST cost at most 33 evaluations of resolveExchange: 3 for the bands, 10 each for rDef, rAtt and rSurv.

CB-2240 Every reported probability MUST be an exact count of favourable draws out of 1000, expressed in per-mille. Monte Carlo sampling, expected-value approximation, and curve fitting MUST NOT appear anywhere in prediction.

Rationale: "roughly 60%" is the specific lie that makes players distrust odds displays. 597‰, and it is right, is a different kind of object.

CB-2250 The command layer's win-probability predictor (CM-150) MUST be winPermille from this function, evaluated over the knowledge view.

CB-2260 The predictor MUST set estimated = true whenever the knowledge view lacks a current observation of the target's strength, and in that case MUST return 400‰, per CM-160. 01-game-rules.md GR-1370 fixes when that is: estimated is false if and only if the relevant Contact holds current fidelity 3 at age 0. This document MUST NOT state a second condition for the same flag.

Rationale: this document owes the command layer a conservative single number under uncertainty, and owes the player a band and a pivot for the same situation (§17). Those are two projections of the same computation, not two predictors, and the difference is what the caller can act on: automation needs a threshold test, a person needs to know which unknown is doing the damage.

CB-2270 The actual outcome of a resolution MUST always lie within the displayed loss bands, by construction. A violation MUST be a build-failing CI assertion, not a playtest observation (CB-2660).

CB-2280 The preview MUST be a pure function of the Clash Specification. It MUST NOT consume the PRNG, mutate state, emit events, or depend on how many previews have already been computed.

CB-2290 The AI MUST use this preview function and MUST NOT be given a cheaper approximation.

Rationale: at the cost bounds of §20 there is no efficiency argument for a separate estimator, so the only thing a separate estimator could buy is a divergence between what the AI believes and what the game does. That divergence is a whole class of bug and it is being designed out.


17. Prediction under fog

CB-2300 Combat prediction MUST be computed over the viewing player's knowledge view and MUST NOT read true state for anything the viewing player has not observed, consistent with CM-130.

CB-2310 Combat prediction MUST read the observation fidelity ladder 01-game-rules.md already defines (GR-1260), which has four values, not the three this document previously asked for. This document MUST NOT define a ladder of its own. What it requires is that the following combat inputs be available at the stated fidelity and at no lower one:

Fidelity GR name Combat inputs this document may read
0 Trace The subject's domain only. No Clash Specification can be built; the preview MUST report that there is nothing to predict rather than predicting from a default.
1 Sighting Position, owner, domain, and a count band. stackExtra MUST be estimated from the band and reported provisional.
2 Identification The above, plus exact stack count and the class of every unit present — and therefore atk, def, tough, role, retreatClass, engages and flak, which are class constants rather than observations. works is a tile property available from the Terrain Record at whatever fidelity the tile itself was observed at.
3 Assessment The above, plus each unit's strength, its Stance, and the condition fields disorder, entrenchment and shaken, which GR-1260 admits as "condition flags 11-combat.md exposes".

Rationale, and the previous three-level ladder was this document inventing a subsystem it does not own. 01-game-rules.md owns fog and had already designed a four-value scale with decay, projection and exclusion behind it; restating it here as L1/L2/L3 produced a second vocabulary for one mechanism and, worse, no home at all for Trace — the level at which a player knows something is out there and nothing else, which is the most common state on a large map and the one a preview most needs to refuse politely. The mapping above is the whole of what combat needs from fog, and it is stated as a demand on a scale GR owns rather than as a scale of this document's own. It also lands the way the design intends: the class constants arrive at Identification, so a player who knows what they are attacking can compute their own losses exactly, while strength arrives only at Assessment, so what they cannot compute is whether the attack will work. That is precisely the asymmetry CB-2370 requires the panel to make explicit, and it is now a consequence of GR's ladder rather than a coincidence between two.

Two of GR's caps bear directly on this document and MUST be honoured rather than worked around: an observer whose domain is air is capped at Identification (GR-1280), so aerial reconnaissance never supplies strength; and a subject on a tile carrying a Fort is capped at Sighting from outside that tile, so a fortified garrison is a known unknown. Both are the reason the pivot analysis of CB-2340 exists, and neither may be relaxed by this document.

CB-2320 Any unit that fought a given enemy during the previous Cascade MUST hold Assessment on it until the end of the current turn, regardless of distance and regardless of GR-1300's decay, except where GR-1280's caps apply -- a subject inside a Fort, an air observer, and a submerged subject detected only by adjacency are capped there, and this document MUST NOT lift a cap that document sets.

This document MUST NOT state a reconnaissance rule of its own. 01-game-rules.md already grants Assessment to any adjacent observer (GR-1270, base = 3 at d <= 1) and gives the recon class a further +1 that offsets a concealing terrain, so the clause this requirement previously carried -- that a Recon-role unit adjacent to an enemy grants the top level -- was redundant where it was true and wrong wherever GR-1280 caps it.

Rationale: reconnaissance's job in this system is not to add a bonus, it is to collapse a band into a number, and 01-game-rules.md had already built exactly that. What this document has to add is the one case that document could not know about — that having just fought something tells you what it is — because otherwise a preview computed the turn after a Clash would be worse informed than the Clash it follows, and a player would watch their own knowledge evaporate between committing and resolving.

Rationale: reconnaissance's job in this system is not to add a bonus, it is to collapse a band into a number. The table in CB-2360 shows a prediction that spans the entire 0–1000‰ range at Sighting and resolves to a single value at Assessment, so scouting is the difference between knowing and not knowing rather than a few percentage points of edge.

CB-2330 When an input is unobserved, the preview MUST evaluate over the full domain of that input and report the resulting range of each output, together with a provisional flag naming every unobserved field.

CB-2340 The preview MUST perform pivot analysis over each unobserved field with an enumerable domain (grade 4 values, stance 4, supplyTier 4, entrenchment 5, works 5). For each such field it MUST determine whether the break verdict is constant across the domain; where it is not, it MUST report the threshold value at which the verdict changes. Where strength itself is unobserved — the ordinary case at fidelity 2 and below — the preview MUST report the range of each output over the full 1–100 domain rather than a pivot, and MUST name strength as the dominant unknown.

CB-2350 The preview MUST display at most two pivots, ordered by the span of breakPermille each induces, largest first.

Rationale: a readout that says "0 to 1000 per-mille" is useless. A readout that says "they break unless they are Veteran or better — grade unobserved, a Recon unit adjacent would tell you" names the risk, names the threshold, and names the fix, and it is a sentence a player can act on. It costs four more preview calls over the unobserved dimension, which at the bounds of §20 is free.

CB-2360 The following pivot table MUST be reproduced exactly and MUST be a golden-master test vector, and like CB-2040 it uses only shipped classes at their shipped values. Attack: an Armour (atk 62, tough 130, role Armor; Veteran, Full, strength 92, Stance Advance) with a Field Gun supporting (atk 48, tough 70, role Gun; Trained, Full, strength 100), against an Infantry (def 44, tough 100, role Foot) at strength 78, disorder 15, Stance Entrench, entrenchment 2, Adequate, in Forest, one flanker. A = 97 throughout. The unobserved field is grade, which is exactly what GR-1260 withholds below fidelity 3.

Defender grade D Resolve They break They lose
Green 74 29 1000‰ 26 / 34 / 41
Trained 79 34 1000‰ 25 / 33 / 39
Veteran 85 41 885‰ 25 / 31 / 38
Elite 93 49 125‰ 24 / 30 / 36

CB-2370 The preview MUST make explicit that the attacker's own losses are well-known even when the outcome is not, because La depends on the defender's power and not on its resolve.

Rationale: the cost of attacking is roughly knowable from a distance while the result is not, and that is exactly the right asymmetry for a game about committing forces. The panel should say so rather than leaving the player to infer it from two bands of different widths.

CB-2380 A preview MUST NOT be cached across turns and MUST be recomputed whenever the knowledge view changes.


18. The readout

CB-2390 The attack preview MUST present its content in this order, and 04-ui-ux.md MUST implement that ordering:

  1. The verdict, in plain language, first — "They break — certain."
  2. Both loss bands as min ── median ── max, with the resulting strength values.
  3. Odds and reliability as two separate figures.
  4. Every contributing line item, with its source named.
  5. The consequence: where they will retreat to, whether they are cut off, whether you take the tile.
  6. The alternative: a one-click preview of the same attack without each supporter.

CB-2400 A single expected value MUST NOT be shown in place of a band, and the falter probability MUST always be shown even when it is 0‰.

Rationale: a single expected value is the specific lie that makes players distrust odds displays, and a falter risk that appears only when non-zero is a risk players never learn exists until it happens to them. CB-1540's culmination behaviour is only fair if the panel names it every time.

CB-2410 Because support and flanking are automatic, the panel MUST enumerate every unit it counted and every modifier it applied.

Rationale: automatic contributions that are not itemised are indistinguishable from magic. The panel is where a player learns the rules, and a rule that fires without appearing on it will be learned as superstition or not at all.

CB-2420 The panel MUST name the retreat destination and MUST state explicitly when the defender has none.

CB-2430 A hostile-tile overlay MUST be available, colouring each enemy-occupied tile adjacent to the player's units by the breakPermille of the best available attack, computed with the same function.

CB-2440 After every resolution the client MUST show a reconciliation line stating the prediction and the actual result — "predicted 26–41, actual 35".

Rationale: this builds trust in the readout faster than any tutorial, because it is evidence rather than a claim, and it makes CB-2270's invariant visible to the person it protects.

CB-2450 The core MUST emit a combat event for every resolution containing: the Clash Specification, r, every intermediate quantity of §5, the outcome, and the resulting state of every participant.

CB-2460 The combat event MUST be sufficient to reconstruct the resolution without access to the world state at the time of resolution.

CB-2470 The client MUST NOT compute any combat number itself. Every figure it displays MUST come from a core export.

CB-2480 Every per-mille figure shown to a player MUST be shown in per-mille or as a rounded percentage derived from it, and MUST NOT be re-derived from a percentage.


19. Determinism and arithmetic

CB-2490 Combat MUST be the only subsystem that consumes randomness, consistent with CM-110.

CB-2500 Two conforming implementations given the same Clash Specification and the same r MUST produce byte-identical outcomes on every platform.

CB-2510 Every intermediate product MUST fit within a signed 64-bit integer, and every intermediate in §5 MUST be below 2⁴⁷ in magnitude, so that an IEEE-754-double implementation is exact. This bound, and not any stat ceiling, is the binding constraint on the magnitude of atk, def and tough (CB-150).

Rationale, derived rather than asserted: two intermediates compete for the largest. The draw of CB-800 computes u × 1000, fixed below 2⁴² by CB-850 and independent of the roster. The Step-1 contribution numerator of CB-470 is base × strength × (1000 + gradePower + supplyPower + roleTerrain) × factor, and every factor but base is bounded by a table this document owns: strength ≤ 100 (CB-100); the per-mille term at 1550 (Elite +300 by CB-1610, Full +50 by CB-1650, Foot in Mountain or Urban +200 by CB-1450); and factor ≤ 1000 (CB-490). That leaves base × 1.55 × 10⁸, and setting it below 2⁴⁷ gives base ≤ 907,983 — so any roster whose atk and def stay under 900,000 is exact on a double, which is the sentence CB-150 relies on when it declines to state a ceiling. The shipped roster peaks at base 132 (02-units-and-industry.md US-230), putting the largest §5 intermediate reachable today at about 2³⁵ and leaving four orders of magnitude of headroom. Stating it this way makes the headroom a figure CI recomputes from the shipped content when the roster moves (CB-2685), rather than a claim about a stat cap nobody argued for, and it is what makes "a TypeScript number is fine here" a checked claim rather than a hope.

CB-2520 Iteration over stacks, adjacency, supporters and flankers MUST be in a canonical order: tiles by lowest tile index, units by lowest creationSequence, consistent with CM-170.

CB-2530 A combatLogicVersion MUST be recorded in the game record. Any change to a constant, a table, a formula, or an ordering in this document MUST bump it.

CB-2540 Combat MUST NOT read wall-clock time, entity allocation order, hash-map iteration order, or object identity.

CB-2550 A Clash MUST NOT depend on the number of Clashes previously resolved this turn other than through attackOrdinal (CB-830) and through the state changes of CB-270.

CB-2560 The seeded hash function MUST be the one 03-architecture.md defines, used in its counter-based form.


20. Performance

CB-2570 One resolution MUST be O(1) in the number of units in the game and MUST perform no allocation on the hot path.

CB-2580 A full exact preview MUST cost at most 33 resolutions (CB-2230); a preview with pivot analysis over one unobserved enumerable field MUST cost at most 33 × 5 = 165.

CB-2590 The engine MUST sustain at least 500 resolutions per Cascade and 100,000 previews per second on the reference hardware of 03-architecture.md, with no Monte Carlo anywhere and no loop whose length depends on the units involved.

Rationale: the second figure is what makes CB-2290 affordable. An AI that can evaluate a hundred thousand candidate attacks in well under a second can use the player's exact preview rather than an approximation, and the hostile-tile overlay of CB-2430 can be repainted every frame.

CB-2600 Worst-case Cascade combat time MUST be flat with respect to force composition, terrain, and odds.

CB-2610 Preview computation MUST be safe to run concurrently and off the simulation thread, being a pure function (CB-2280).


21. Rules options

CB-2620 Combat rules options MUST be fixed at setup, MUST be part of the game record, and MUST contribute to combatLogicVersion resolution.

CB-2630 The option volatilityFloor MUST offer exactly two values: Measured (250, the default) and Chaotic (600).

Rationale, and this addresses the source design's open question on whether one draw is enough drama: the design's position is that the surprise should come from not knowing what you are attacking rather than from the resolution, and §17 is the argument for it. But it is a taste question that only playing answers, and raising the floor is a one-constant experiment that changes nothing structural — the preview stays exact, the bands simply get wider. Shipping both and measuring which is preferred is cheaper than arguing about it.

CB-2640 No rules option MAY alter the shape of the procedure, only the value of a named constant.

CB-2650 The client MUST display the active options in the attack preview header whenever any is not at its default.


22. CI invariants and playtest metrics

CB-2660 CI MUST assert, over the golden-master corpus, that every resolved outcome lies within the loss band the preview displayed for it. A violation MUST be a build failure.

CB-2670 CI MUST re-run the monotonicity sweep of CB-2150 whenever any constant in this document changes. The reference sweep covers every terrain, grade, supply tier, Stance, three strength levels, two disorder levels, two entrenchment levels and all pairings of the shipped roster’s six role values, over all 1000 draws: 86,016,000 evaluations, zero violations at the constants specified here.

CB-2680 CI MUST assert, against the shipped tables (CB-630), that the maximum reachable additive defender total is at most +1600, the maximum reachable attacker total at most +510, and the minimum reachable attacker total no lower than −680. All three MUST be computed from the tables rather than asserted as constants, so that adding a terrain family, a Stance value or an edge term fails the build rather than silently opening a dead zone at a clamp.

CB-2685 CI MUST assert, against the shipped roster of 02-units-and-industry.md, that the largest §5 intermediate reachable from that roster's atk, def and tough values under the tables of this document is below 2⁴⁷ (CB-2510). The assertion MUST be computed from the roster's actual maximum base, and MUST NOT be satisfied by any stat ceiling declared here, because CB-150 declares none.

Rationale: releasing the byte-width stat ceiling moves the exactness guarantee from a constant in this document to a property of the content that ships against it, so the check must move with it. It is one multiplication over the roster's maximum, and it fails the build on the day a content pack raises a stat past the point where a double stops being exact — which is the only failure the old ceiling actually prevented, and it prevented it four orders of magnitude early, at the cost of forbidding every finer stat scale in between.

CB-2690 CI MUST verify the binary-search prediction against a brute-force oracle over all 1000 draws for a spanning corpus of Specifications. The reference corpus is 5,376 cases: zero mismatches.

CB-2700 CI MUST assert that no combat code path calls a floating-point operation, consistent with the determinism lint rules of 03-architecture.md.

CB-2710 The automated playtest harness MUST measure the following, with the stated targets, so that a balance regression is a failing number rather than an opinion.

Risk Metric Target Response if it fails
Encirclement swing dominates Share of total unit losses from rout 20–35% Reduce CB-1420 to the top two units of the stack
Fronts freeze under entrenchment Share of turns on a contested front with no tile changing hands < 40% Reduce the Entrench defence term or raise the bombardment coefficient
Artillery dominance Ratio of Bombardments to Assaults ≤ 2:1 Lower intensityOut for Bombardment or raise the recovery floor
Artillery uselessness Same ratio ≥ 0.5:1 Raise the bombardment disorder coefficient from 3×
Disorder death spiral Share of unit-turns above 70 disorder < 10% Raise field disorder recovery from −20
Combat too grindy Mean turns to resolve a contested tile 2–4 Raise intensityOut for Assault from 60
A role is never worth building Build share by role No role below 15% Retune CB-1450
Fog band unusable Share of previews where pivot analysis names a single dominant unknown > 70% Show two pivots (already permitted by CB-2350)
Screening is free Mean turns a screening unit survives continuous disengagement 5–8 Raise the disengagement disorder from +15

CB-2720 Preview trust MUST NOT appear in the playtest table as a tuning metric. It is an invariant asserted by CB-2660.

CB-2730 The reference worked example of §23 MUST be a golden-master test vector.

CB-2740 Every table in this document MUST be generated from the same constant definitions the engine compiles, and CI MUST assert that the document's tables match the shipped constants.

Rationale: hand-edited numbers in a specification drift from the code within one release, and this document's entire value is that its numbers are the real ones.


23. Worked example, normative as a test vector

Every unit named below is a formation of a class in the shipped roster, at that class’s shipped stats (02-units-and-industry.md §8): the 3rd Rifles are an Infantry (atk 30, def 44, tough 100, role Foot), the 2nd Armoured an Armour (atk 62, def 38, tough 130, role Armor), and the 1st Field Battery a Field Gun (atk 48, def 18, tough 70, role Gun). The example is therefore reproducible from the content that ships, which is what makes it usable as a golden master (CB-2730).

The situation. Belvoir Wood, a Forest tile. The 3rd Rifles hold it: Green, strength 78, disorder 15, Stance Entrench, entrenchment 2, supply Adequate, alone on the tile. Attacking are the 2nd Armoured Battalion (Veteran, strength 92, supply Full, Stance Advance) from the west, and the 1st Field Battery (Trained, strength 100, supply Full) adjacent to the north, joining as a supporter. Both attackers are adjacent to the target, so flankers = 1.

Step 1 — contributions.

Working Result
2nd Armoured 62 × 92 × (1000 + 180 + 50 − 300) × 1000 / 10⁸ 53
1st Field Battery (supporter, factor 400) 48 × 100 × (1000 + 80 + 50 − 150) × 400 / 10⁸ 18
A_raw 71
3rd Rifles 44 × 78 × (1000 + 0 + 0 + 150) × 1000 / 10⁸ 39

Step 2 — force modifiers. Attacker: Advance +250, combined arms (Armor + Gun) +120 → +370; A = floor(71 × 1370 / 1000) = 97. Defender: Forest cover +400, Entrench +300, position +200 → +900; D = floor(39 × 1900 / 1000) = 74. Odds 97 : 74.

Step 3 — volatility. Attacker 700 − 100 = 600; defender 1000 + 0 = 1000; mean 800; Forest chaos +200 → 1000. Reliability ±250‰.

Step 4 — resolve. Defender 40 + 0 + 15 − 15 − floor(22/2) = 29. Attacker 40 + 12 − 10 − floor(8/2) = 38.

Step 5 — the draw. r = 617.

Step 6 — the exchange. s = floor(117 × 1000 / 2000) = 58; A_eff = 102; D_eff = 69; shareA = floor(102000 / 171) = 596; shareD = 404; Ld = floor(60 × 596 × 100 / 100000) = 35; La = floor(60 × 404 × 100 / 130000) = 18.

Step 7 — the break checks. Defender shock 35 + 8 + 6 = 49 ≥ 29the 3rd Rifles break. Attacker shock 18 + 10 = 28 < 38, and suppressed regardless by CB-1010.

Step 8 — consequences. 3rd Rifles: 78 → 43 strength, disorder 15 → 42, retreat to the lowest-scoring adjacent tile. 2nd Armoured: 92 → 74, disorder +15, advances into Belvoir Wood if it has a movement point. 1st Field Battery: disorder +10, support spent.

What the player was shown before committing — every figure below is the exact output of the preview function, and the actual result above falls inside every band:

┌─ ASSAULT ─ 2nd Armoured Battalion → Belvoir Wood (Forest) ──────────────────┐
│  YOUR FORCE                                        attack power     97      │
│    2nd Armoured    Advance    92   Veteran          53   base 62            │
│                    +180 veteran  +50 full supply  −300 armour in forest     │
│    1st Field Bty   support   100   Trained          18   base 48 × 400‰     │
│                    +80 trained   +50 full supply  −150 guns in forest       │
│    force           +250 advance  +120 combined arms (armour + guns)         │
│                                                                             │
│  THEIR FORCE                                       defence power    74      │
│    3rd Rifles      Entrench    78   Green           39   base 44            │
│                    +150 foot in forest                                      │
│    position        +400 forest cover  +300 entrench  +200 entrenchment 2    │
│                                                                             │
│  ODDS 97 : 74                   RELIABILITY  ±250‰  (broken ground, green)  │
│                                                                             │
│  THEY LOSE     26 ── 34 ── 41   →  78 drops to 37–52                        │
│  YOU LOSE      14 ── 19 ── 25   →  92 drops to 67–78                        │
│                                                                             │
│  ▸ THEY BREAK — certain (1000‰).  Resolve 29 against shock 40–55.           │
│    They fall back to Ford Seven. They are not cut off.                      │
│  ▸ Your attack falters: never (0‰).                                         │
│  ▸ You take Belvoir Wood if you have a movement point left.  You do.        │
│                                                                             │
│  [ Attack ]   [ Attack without 1st Field Battery ]   [ Cancel ]             │
└─────────────────────────────────────────────────────────────────────────────┘

The same attack against a fresh defender — strength 100, disorder 0, everything else identical:

Worn (78 / 15) Fresh (100 / 0)
Defence power 74 95
They lose 26 / 34 / 41 22 / 30 / 37
You lose 14 / 19 / 25 17 / 22 / 28
Their resolve 29 55
They break 1000‰ 0‰

The identical attack is decisive against one and pointless against the other. What changed was not the odds — 1.31:1 against 1.02:1, a modest shift — but the resolve, and resolve is driven by condition. So change the condition first. The battery bombards instead of supporting: A 47 against D 95, taking 4 / 7 / 10 strength and adding 17 / 26 / 35 disorder. Seven strength is almost nothing; 26 disorder is 26 points of resolve. The armour then assaults alone at A 66 against D 89 — worse odds than the attack that achieved nothing — and the defender, now at resolve 26, breaks 882‰ of the time. The armour pays a median 26 strength to do it, more than the 22 it would have lost failing. Winning is more expensive than losing. Good.

Three terrains and two Stances, a lone Veteran Armour in Advance at full strength and Full supply against a Trained Infantry at full strength and Adequate supply, no supporters, no flankers:

Terrain Their Stance A D Reliability They lose You lose Resolve They break You falter
Open Hold 106 47 ±143‰ 37/41/45 11/14/17 45 858‰ 0‰
Open Entrench 106 61 ±143‰ 33/38/41 13/16/20 60 0‰ 0‰
Forest Hold 71 75 ±231‰ 22/29/36 18/23/29 45 0‰ 0‰
Forest Entrench 71 91 ±231‰ 19/26/33 20/25/31 60 0‰ 0‰
Mountain Hold 56 89 ±218‰ 17/23/29 23/28/33 45 0‰ 0‰
Mountain Entrench 56 106 ±218‰ 15/20/27 25/30/34 60 0‰ 297‰

A lone tank breaks infantry caught in the open 858 times in a thousand. It cannot break infantry that has dug in anywhere, including in the open. In mountains it has a 297‰ chance of being thrown back with nothing to show for 30 strength. The same six cases with a Field Gun supporting and two more units adjacent (flankers = 3):

Terrain Their Stance A D They lose You lose They break
Open Hold 145 47 42/45/48 9/11/13 1000‰
Open Entrench 145 61 38/42/45 11/13/16 1000‰
Forest Hold 102 75 27/34/41 14/19/25 1000‰
Forest Entrench 102 91 24/31/38 16/21/27 625‰
Mountain Hold 84 89 22/29/35 18/23/28 1000‰
Mountain Entrench 84 106 20/26/33 20/25/30 239‰

A battery and two adjacent units turn 0‰ into certainty in three of the six cases, and 0‰ into a real chance in the other two, while barely moving the odds — Forest Entrench goes from 71:75 to 102:91, a shift of a third of a point of odds, and from never to 625‰. Positioning is worth more than force. The hard cell remains entrenched infantry in mountains at 239‰ — a bad bet with the whole apparatus applied. That cell is not a bug; it is the answer to "how do you take a mountain?", and the answer is that you do not assault it. Same defender at entrenchment 2, same supported attack, varying only supply:

Their supply D They lose Their resolve They break
Full 121 18/24/30 60 66‰
Adequate 117 18/25/31 60 127‰
Strained 102 20/27/34 55 653‰
Cut, and encircled 79 23/30/38 25 1000‰

Cutting the road does more than three extra battalions, and it emerges from the interaction of supply, resolve and the break check rather than from any rule that mentions "siege".


24. Contracts on other documents

Obligations this specification places on subsystems it does not own, recorded so that a change on either side is detectable.

CB-2750 01-game-rules.md MUST provide: a terrain combat profile for every terrain type (CB-1440, CB-1470); Chebyshev adjacency and a canonical row-major tile index; stacking capacity per tile; passability per movement class; city ownership and works level per tile; the observation fidelity ladder and its decay, whose combat use is fixed by CB-2310, together with the estimated condition of GR-1370 that CB-2260 reads; and, optionally, crossesRiverEdge and elevation (CB-580). It MUST NOT define combat resolution, terrain defence multipliers, or retreat behaviour.

CB-2760 02-units-and-industry.md MUST provide, per class: atk, def, tough, role, retreatClass, engages, flak, bombardRange, bombardShots (CB-150), and the siege and ambush capabilities that CB-555 and CB-885 read. It MUST additionally state the shipped range of atk, def and tough on the common scale of CB-150, since this document declares no upper bound for them; the range it states MUST satisfy CB-2510, and CB-2685 asserts it. It MUST NOT define a combat resolution model of its own, MUST NOT express unit durability as hit points (CB-110 makes strength normalised and tough the durability lever), MUST NOT define per-domain attack values, a round or strike-run limit, or terrain, entrenchment or suppression multipliers — CB-140 replaces suppression with disorder, CB-020 removes rounds, and CB-235 replaces per-domain attack values with an engages legality set.

Recorded because it was the largest defect this specification carried: that document previously defined hits, atkLand, atkSea, atkAir, flak as a strength and strikeRun, which is a per-round attrition model with hit points and per-domain effectiveness, and is a different game from the one specified here. It supplies this document’s fields now, and the obligations it placed on this document that this document forbids — a per-round procedure, a Suppressed condition, a flak exchange — are withdrawn on its side (US-2140).

CB-2770 10-turn-model.md MUST provide: a Stance per unit with the four values of CB-1510; a totally-ordered creation sequence number; a stable per-unit per-turn attack ordinal keyed positionally rather than by stream cursor (CB-810 depends on this, and it is a hard requirement, not a preference); reaction eligibility and capacity, and the halt of a moving unit when a reaction fires (CB-1780); the entrenchment counter of TM-700, its range of [0, 3], and both the condition that increments it and the condition that resets it, which this document reads and MUST NOT redefine (CB-1250, CB-1560); and the guarantee that combat state changes are visible to units activating later in the same Cascade (CB-270). It MUST read the veterancy grade this document derives from xp (CB-170) rather than a stored grade, which no document keeps.

CB-2780 12-economy.md MUST provide: a per-unit supply state in its three-value vocabulary and a per-unit flag for occupying a supply source, from which CB-1630 derives the combat supply tier; depot locations for the recovery table of CB-2070; and out-of-supply attrition applied after recovery (CB-2130). It MUST NOT define combat power multipliers for supply (CB-1640) and MUST NOT define an independent repair rate — strength recovery is CB-2070.

CB-2790 13-command.md's CM-150, CM-160, CM-1370 and CM-1410 are satisfied by CB-2250, CB-2260, CB-2210 and CB-1490 respectively. CM-2160's requirement that co-ordinated attacks key off adjacency and timing rather than Formation membership is satisfied by CB-420.

CB-2800 13-command.md MUST provide the Withdraw Reflex state that §12 reads, and the Risk Sanction that pushes it. This document MUST NOT decide when a unit chooses to disengage.

CB-2810 14-victory.md MUST own how combat losses, city captures and rout destruction score.

CB-2820 03-architecture.md MUST provide the counter-based coreHash of CB-800, the canonical state hash that CB-180 contributes to, the determinism lint rules that CB-2700 asserts against, and the golden-master corpus infrastructure that CB-2660, CB-2690 and CB-2730 use.

CB-2830 04-ui-ux.md MUST own the presentation of the attack preview (CB-2390), the condition badge (CB-190), the hostile-tile overlay (CB-2430), the encirclement marking (CB-1410) and the reconciliation line (CB-2440), implementing the content requirements this document states.


Open questions

  1. Is the whole-stack rout the right severity? CB-1420 destroys every unit on a tile that breaks with nowhere to go, which can remove three units in one Clash. It is the mechanic that makes the entire manoeuvre game worthwhile and it is also the largest single swing in the design. CB-2710 bands it at 20–35% of total losses; if the measured share sits above that, the named response is to destroy only the top two defenders and let the rest survive at heavy loss. What is not settled is whether that response would leave encirclement worth attempting at all.

  2. Should a stack that cannot fit its retreat destination be destroyed? CB-1120 says yes, which makes crowding behind a thin line a genuine vulnerability and is the sharpest edge in the document. The alternative — the units that fit retreat and the remainder are destroyed — is more forgiving and much harder to preview honestly, because the preview would have to name which units die. The current rule is chosen partly because it is explainable.

  3. Is two supporters the right number? CB-370 allows two, which makes a three-role combined-arms force reachable and therefore makes the +260 term of CB-560 attainable. One supporter would make three roles impossible and would turn combined arms into a two-role decision, which is simpler and possibly better. There is no data either way; the metric that would settle it is the build share by role in CB-2710.

  4. Does the "not yet activated" support rule read as arbitrary? CB-370's rationale argues that it correctly rewards a battery that stayed put, because staying put lowers Initiative and lowers Initiative means activating later and activating later means being available to support. That is an elegant chain and it is also four inferential steps long. If players experience it as "my gun sometimes cannot support and I cannot tell why", the rule is wrong however good the reasoning is, and the fix is to make support available regardless of activation at the cost of a larger disorder charge.

  5. Air and naval combat are only partially specified here. CB-1330's Detached retreat class and the Naval/Air rows of CB-1450 make the procedure applicable to them, but interception, basing, endurance, submerged concealment and shore bombardment are not designed in this document and the intensity constants have not been calibrated for them. The assault intensity of 60 is almost certainly wrong for an air strike, which should be sharper and shorter.

  6. tough is now both, and the seam may be in the wrong place. CB-160 keeps its meaning here as a pure combat divisor, while 02-units-and-industry.md US-1715 derives its values from a unit size ladder that is also meant to inform transport slots and supply draw. That is a reasonable division and it is not the one either document started from, so it has not been tested against a content pack. If a modder finds that changing tough to make a unit harder to grind down silently changes what can carry it, the field is doing two jobs and should be split.

  7. Does the once-per-turn disengagement cap create a new exploit? CB-1890 stops one unit absorbing unlimited attacks in a turn, but it also means a screening unit's second attacker gets a Caught Clash at −200 defence, which is usually fatal. A player who screens with a single unit against two attackers therefore loses it outright, which may make screening a two-unit minimum in practice. That might be correct; it was not designed.

  8. Should reactive fire be previewable at all? CB-1840 declines to give a probability because reaction capacity is unobservable, and shows a warning instead. The opposing case is that a player who knows an enemy is in Stance Hold can infer reaction capacity perfectly well, so the warning is coy rather than honest, and the preview should show the reaction as a conditional outcome. The counter-argument is that inferring capacity requires knowing the enemy's Stance, which is only available at observation fidelity 3 (GR-1260).

  9. Is engages a set, or should it have been a rule over role? CB-235 gives every class an explicit set of defender domains it may attack. Most of the shipped roster's sets are predictable from its roleNaval engages sea, Foot engages land — and a rule would be one fewer field to author and to get wrong. It is a set because the exceptions are real and load-bearing: a Bomber and a Fighter share the role Air and engage disjoint domains, and an Air Defence Battery shares the role Gun with a Field Gun and engages the opposite one. Whether four exceptions justify a field on every class is a judgement, not a proof.

  10. The flak shock coefficient of 6 per tier was set against one number. CB-965 is calibrated so that the top tier's +24 turns away a bomber against a typical attacker resolve of 30, and against nothing else. It is the newest constant in this document and the only one with no sweep behind it. The metric that would settle it is the ratio of air attacks that falter to air attacks that break a defender, which is not currently in CB-2710.


Built from source 7f764a6c1ff9 · VERSION.json