Phase 3b (sweep): nick-floor + supply-burn sweep, T5 supply unlock

Wired SurpriseNickFloorOverride and SupplyBurnRatePctOverride into the
harness day-loop via two new parameterized helpers (surpriseRoundNickF,
applyDailyBurnP). Live callers go through the existing constants;
sweep test sits on top of the Phase 3-A best cell (e=23, d=1).

TestExpeditionBalance_Phase3B_NickSupplySweep walks 3×3 (floor ∈ {0, 1,
tier=live}) × (burn% ∈ {50, 75, 100=live}) × 10 zones × 200 trials.

Strong partial T5 positive; nick-floor lever inert.

  - Supply burn is the T5 unlock: dragons_lair 0% → ~55% at burn=50.
    Fighter survives elites; burn=75 isn't enough margin.
  - T4 peaks at burn=75 (~12% underdark/feywild); burn=50 dips T4
    slightly (more elites survived into).
  - Nick-floor inert across tiers (≤3pp swing); wounded-clamp already
    eats the chip-damage budget. Recommend dropping from live-tuning
    candidates.
  - T2-T3 wall persists: forest_shadows, manor_blackspire,
    abyss_portal stuck at ~0% across every combo — outliers, not
    addressable by global levers.

Global levers wrung out. Plan-doc Phase 3-B section + memory pointers
updated; next is Phase 4 (per-zone outlier pass). -short shows the
same two pre-existing failures (TestAdv2Scenario_ZoneRunGoblinWarrens,
TestMageSpellbookLineInRender).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-15 11:10:21 -07:00
parent 235122f2a1
commit 2d44c990f3
5 changed files with 262 additions and 3 deletions

View File

@@ -203,11 +203,24 @@ func (p *AdventurePlugin) runHarvestInterrupt(
// surpriseRoundNick computes a small HP nick representing the enemy's
// free first swing. Roughly attack-bonus + 1d4, with a tier-based floor.
func surpriseRoundNick(m DnDMonsterTemplate, tier int) int {
return surpriseRoundNickF(m, tier, -1)
}
// surpriseRoundNickF is the floor-parameterized form used by the Phase
// 3-B sim harness lever sweep. floorOverride < 0 means "use live"
// (floor = tier); floorOverride >= 0 substitutes that absolute value
// as the floor (0 disables the floor entirely). Live callers always go
// through surpriseRoundNick. See gogobee_expedition_difficulty.md
// Phase 3-B.
func surpriseRoundNickF(m DnDMonsterTemplate, tier, floorOverride int) int {
if tier < 1 {
tier = 1
}
dmg := 1 + rand.IntN(4) + m.AttackBonus/2
floor := tier
if floorOverride >= 0 {
floor = floorOverride
}
if dmg < floor {
dmg = floor
}