diff --git a/bridge/sds/Observation.java b/bridge/sds/Observation.java index e38f7bf..0e14b2d 100644 --- a/bridge/sds/Observation.java +++ b/bridge/sds/Observation.java @@ -581,6 +581,12 @@ public final class Observation { * launcher, which is an MML or an ATM, is the damage computed from the * round instead. See {@link #redefinesRanges}. */ + // **Merging with `claude/battle-armor`:** that branch substitutes a swarm + // attack's damage inside this method, and this branch rewrote its tail - + // the two single-packet fallbacks and the nearest-bracket fill below. The + // substitution and the fallbacks are independent and both are needed. A + // resolution that keeps only this version compiles and runs, and drops the + // swarm figure with nothing failing. static double averageDamage(WeaponType wt, AmmoType at, int range, int longRange) { if (range > longRange) { return 0.0; diff --git a/crates/sds-core/src/brackets.rs b/crates/sds-core/src/brackets.rs index 0d3d959..d8026ad 100644 --- a/crates/sds-core/src/brackets.rs +++ b/crates/sds-core/src/brackets.rs @@ -341,6 +341,22 @@ impl Excluded { /// still be holding something this bot cannot price, and that is a fact /// about the bin rather than about the gun - so it is read off the wire, /// where the bridge put it, instead of being guessed at from a name. + /// # Merging this with `claude/battle-armor`: the order is load-bearing + /// + /// That branch moves the same decision off names from the other side. It + /// tests `weapon.anti_mek`, MegaMek's own flag, **before** the name list, + /// because "Swarm Mek" and "Leg Attack" contain none of the strings the + /// list matches and were being summed into volleys as guns that do nothing. + /// This branch adds the round test in front. The merged order is + /// **round, then `anti_mek`, then the name list**, and none of the three is + /// redundant: the round is per-bin, the flag is a property MegaMek states, + /// and the names are the handful of genuine special cases that no property + /// carries - see `docs/PROTOCOL.md` on the AMS. + /// + /// **Taking this function wholesale compiles, passes every test in both + /// branches, and silently restores the anti-Mek bug**, because nothing here + /// mentions `anti_mek` and no test in this branch has a swarm attack in it. + /// A green build is not evidence the other branch's work survived. pub fn for_weapon(weapon: &crate::wire::Weapon) -> Option { if weapon.unmodelled_round.is_some() { return Some(Excluded::UnmodelledRound); diff --git a/crates/sds-core/src/features/firing.rs b/crates/sds-core/src/features/firing.rs index be8c5ab..feba688 100644 --- a/crates/sds-core/src/features/firing.rs +++ b/crates/sds-core/src/features/firing.rs @@ -758,7 +758,15 @@ impl Feature for ValueDestroyed { /// Three things in the plan want it and none can be answered without it. A /// battle armour leg attack does four points, which is nearly noise, and is /// held at no value at all rather than given a plausible constant - its payoff -/// is a through-armour critical. Matches end on criticals rather than on damage +/// is a through-armour critical. +/// +/// **Four is the leg attack's damage, and nothing here is its critical +/// modifier.** That modifier is not a constant and must not be written as one: +/// `hasMyomerBooster()` contributes `squadSize * 2`, which is twelve on a +/// six-suit point against two vibro claws' two, so it runs from 4 to 16 - a +/// factor of four across a real roster. It belongs to the battle armour work, +/// which computes it per squad and spends this column as the currency. Nothing +/// in this file should ever acquire a number for it. Matches end on criticals rather than on damage /// totals, and [`PKill`] is damage-based, so the ammunition explosion that ends /// a match in round three is not in it. And a kick or a punch into an open /// location is the second half of that quotation exactly. diff --git a/plan/exotic-weapons.md b/plan/exotic-weapons.md index 22d3937..f2be372 100644 --- a/plan/exotic-weapons.md +++ b/plan/exotic-weapons.md @@ -88,3 +88,40 @@ bot as "does nothing". The resolver is asked before nothing is reported. exclusion is real (they fire in a phase this bot does not model) and there is no property on the wire that carries it. A `weaponFamily` field, if one is ever added, is where this belongs + +## Merging this branch with `claude/battle-armor` + +Both branches move the same decision off name matching, from opposite sides, and +**neither is right alone**. The merge order has `expected-crits` landing first, +so the resolution falls to `battle-armor` on rebase. What it costs to get wrong +is written here because a wrong resolution does not fail. + +`brackets::Excluded::for_weapon` is the site. + +- **This branch** asks the *round* first: a Narc launcher is a beacon until + somebody loads explosive pods, and `unmodelled_round` drops a gun holding + ammunition the model cannot price. Then it falls through to the name list. +- **`battle-armor`** asks `weapon.anti_mek` - MegaMek's own flag - before the + name list, because "Swarm Mek" and "Leg Attack" contain none of the strings + the list matches and were being summed into volleys as guns that do nothing. + +**The merged order is round, then `anti_mek`, then the name list.** None of the +three is redundant: the round is a fact about the bin, the flag is a property +MegaMek states about the weapon, and the names are the handful of genuine +special cases no property carries - `docs/PROTOCOL.md` records why the AMS is +one of them. + +**The hazard is that taking this branch's `for_weapon` wholesale compiles, +passes every test in both branches, and silently restores the anti-Mek bug.** +Nothing in this branch mentions `anti_mek`, and no test here has a swarm attack +in it, so there is nothing to go red. A green build is not evidence that the +other branch's work survived the merge. + +The same shape sits in `bridge/sds/Observation.java`: `battle-armor` substitutes +a swarm attack's damage inside `averageDamage`, and this branch rewrote that +method's tail - the two single-packet fallbacks and the nearest-bracket fill. +They are independent and both are needed; a resolution that keeps only this +branch's version drops the swarm figure with nothing failing. + +This is the same failure the rest of tonight was about, wearing a merge's +clothes: a signal that reads clean standing in for a question nobody asked.