Conversation
added 2 commits
September 17, 2026 22:14
Ten pets (Badger, Camel, Dodo, Dog, Dolphin, Elephant, Giraffe, Ox, Rabbit, Sheep), three foods (Birthday Cake, Garlic, Salad Bowl), the Ram token, three perks (Garlic, Melon, Birthday Cake), and Spider's summon - the one hole Tier 2 shipped with on purpose. SAP2_ROSTER_TIER is 3; what is left behind the cap is tiers 4-6, not a rule inside a shipped tier. Every value was read out of the shipped build: sap/spec.py for the templates, sap/ability_check.py --pet X --levels to FIRE each one, and a new sap/tier3_drive.py in policy-clash-re-tools for the rules a template cannot carry. The gate is sap/audit_roster.py --tier 3: zero WRONG and zero MISSING rows for tiers 1-3. Structure credit: colin-cannell's PR #10 (colin/sap2-tier6-roster, 709f7aa) shaped several of these rows and its tier assignments are right. Where its scrape-sourced values disagreed with the build, the build won: - Rabbit's selector is the EATER (TargetsTriggerTarget), not SELF. An Apple onto a different friend buffs that friend, not the Rabbit. - Rabbit's three activations are per TURN and reset at the boundary; the row needs max_per_turn, not a lifetime cap. - the tier-3 FOOD pool includes Birthday Cake. PR #10 omits it, which makes every tier-3-and-later food roll draw 1/7 over the wrong set. - Badger's "adjacent" is the nearest LIVING body each way on the merged grid, not the neighbouring cell and not a fallback to the enemy front "when there is no ally ahead": with the enemy front mid-faint the splash reaches the body behind it. - Badger's and Dodo's percentage is floored, not rounded (7 attack deals 3 at L1, 10 at L3), and Dodo's touches attack only. - Salad Bowl is played on the BOARD; a PlaySpell naming a target is dropped outright. It buffs two RANDOM friends, and sap2 offers it on one action encoding rather than five. - Dolphin's lowest-health finder breaks a tie at RANDOM (28/32 over 60 seeds), so it consumes the battle stream. - Garlic's floor is 2, not 1: 3 damage lands as 2 and 2 lands as 2. - Ox grants Melon, and that perk grant wakes Rabbit - the trigger bus counts a perk landing on a friendly as a food played on it. A plain buff does not. Three rules Tier 3 exposed rather than introduced, all now measured: damage eats the temporary health before the permanent half; a Pilled pet is mid-faint for the whole of its own faint, so its own splash cannot pick it; and a lethal hit does not cancel the hurt trigger - what a dying pet loses is its eligibility as a TARGET, which is why Camel still buffs and Peacock does not. That replaces this file's old "survival is the whole gate" reading with one rule instead of two. Also measured and corrected: two summons onto one cell push the run behind them back, or the run in front of them forward when there is no room behind. The previous fallback was marked unmeasured in the code and was wrong; six Sheep layouts pin it. The team slot carries two more numbers, for the same reason it already carries the exp counter: a Birthday Cake's accumulated sell value and the activations a per-turn-capped ability has spent. Verified: clang -O2 -Wall -Wextra -Werror clean; 84 env tests (the 72 that were here plus one per Tier-3 rule); audit_roster.py --tier 3 with zero WRONG and zero MISSING for tiers 1-3; difftest.py 300 --survivors at tiers 1, 2 and 3, 300 --deterministic and 200 --holes at tiers 1 and 3, all 0 mismatching; difftest_shop.py 26/26; fuzz_shop.py 200 and 120 --turn 5 with no divergence; difftest_match.py with no divergence.
…ot widths Tier 3 widened a team slot by two floats (sell_bonus, uses) and the species one-hot by ten. Two consumers decoded the old layout and neither failed loudly: - `bots/sap2/greedy` is self-contained by the rule in bots/README.md, so its copy of the widths went stale and it spent the whole time reading garbage. It did not crash - it just played badly, and the only visible symptom was its rating against `random` falling from 1804 to 1521 Elo. Its tables now cover all 34 species and the comment says what the symptom looks like, because the next roster tier will do this again. - `tools/visualize_sap2.py` derived the species one-hot width by subtracting every other field from the slot width, which over-counted by exactly the two new floats, so argmax ran past the end of the one-hot and returned species 35 - an id no table has. KeyError on any board that reached turn 5. The second is the interesting one, because the derivation was written to BE the robust option. It is not: subtracting the known fields from the total silently absorbs any field you did not know about. So the widths are now exported - NUM_ALL_SPECIES, NUM_SHOP_SPECIES, NUM_FOODS - and the consumers read them instead of reconstructing them. Verified: greedy back to 1838 vs random 1162; the visualizer renders Tier-3 boards through turn 14 across four seeds with no traceback, with Badger/Camel/Dodo/Dolphin/Elephant/Giraffe/Ox/Rabbit/Sheep/Ram and Cake/Garlic/Salad Bowl all appearing; 84 env tests; audit_roster --tier 3 zero WRONG and zero MISSING for tiers 1-3; 300/300 exact surviving line-ups at tier 1, tier 2 and tier 3; 300/300 tier-3 winners; 200/200 holed tier-3 boards; 26/26 shop checks; fuzz at turn 5 and the shop-to-battle bridge clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tier 3's ten pets and three foods, every value measured against the shipped build rather than a scrape, ported onto the faint machinery #9 landed. Spider's summon is no longer a documented hole - it has a Tier-3 roster to draw from.
Gate
audit_roster.py --tier 3reports zero WRONG and zero MISSING rows for tiers 1-3. The 6 WRONG and 85 MISSING it does print are tier 4-6 pool sizes and content, which is the roster cap doing its job.Where the scrape was wrong
PR #10 implements these from
data/turtle_pack. Measuring them found, among others:TargetsTriggerTarget), and its three activations are per turn, not a lifetime capPlaySpellis dropped outright, no gold spentFour rules Tier 3 exposed that were already wrong
None of these are Tier-3 rules; Tier 3 is just the first roster that can see them:
The two consumers this broke, and the lesson
Tier 3 widened a team slot by two floats and the species one-hot by ten. Neither consumer failed loudly:
bots/sap2/greedyis self-contained by design, so its copy of the widths went stale and it read garbage. It did not crash - it just played badly, and the only symptom was its rating againstrandomdropping 1804 → 1521 Elo. Now 1838 vs 1162.tools/visualize_sap2.pyderived the species one-hot width by subtracting every other field from the slot width. That over-counted by exactly the two new floats, so argmax ran past the one-hot and returned species 35 - an id no table has.The derivation was written to be the robust option, and it is the opposite: subtracting known fields from a total silently absorbs any field you did not know about. So
NUM_ALL_SPECIES,NUM_SHOP_SPECIESandNUM_FOODSare now exported and consumers read them.Credit
PR #10's Tier-3 structure was the starting point and its tier assignments were all correct. Its remaining defect list is #11.