mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
The post-J1 sweep had the casters clustered at 19–22% L12 clear, vs martials at 70–80%. A per-round trace across 240 boss-room fights showed why: autoResolveCombat dispatched !attack only — zero spell_casts, zero mid-fight consumable uses across every caster class. The entire "caster cliff" was the sim measuring a strawman where casters couldn't cast. J2a teaches the sim's autoResolveCombat to mirror a competent prod player: heal at low HP if an inventory consumable is available, otherwise cast the highest-EV damage spell (slot or cantrip), otherwise swing. BuildCharacter now seeds the known-spell list via ensureSpellsForCharacter so the synthetic spellbook is populated. A -trace flag on the cmd attaches the raw CombatEvent stream to the last combat of each run for post-hoc diagnostics. A first re-baseline (n=100, all 10 classes) showed Ranger regressed -35.8pp — the picker was burning L3 slots on lightning_arrow when Ranger's weapon chassis (Hunter's Mark + Extra Attack) was the better play. Added simMartialFirstClass to gate the picker off for Ranger and Paladin (whose default kit is also weapon-first / no damage spells). J2c experimented with widening the picker to control + heal spells; heal-spell preempt cost druid 10pp (slot heals are 10HP vs 40HP consumables) and control-spell scoring at 22 cost warlock 6.6pp. Both reverted. Corpora retained under baseline_j2c*.jsonl for the post-mortem in sim_results/j2b_findings.md. Post-J2 L12 leaderboard (baseline_j2a_v2_all10.jsonl, n=100): fighter 80.0, ranger 80.0, paladin 78.4, rogue 76.8, druid 61.6, mage 53.4, sorcerer 50.6, warlock 48.2, bard 40.4, cleric 39.0. The caster cluster is dissolved; martials are within ±5pp of J1 (sweep noise). Bard/cleric still trail, but it's no longer a sim artifact — their defaultKnownSpells damage rosters cap at L2 and the picker can't pick spells they don't have. That's a prod-level fix, deferred. J3 trace (sim_results/j3_findings.md): T5 dragons_lair walls every solo class at 0% (Infernax 546 HP vs solo player HP 110–175; ~25% boss HP eaten before TPK across all classes). Per the J3 plan menu, this is party-shaped content the engine doesn't yet have parties for. Surface a TwinBee-voiced heads-up in handleDnDExpeditionCmd's start path and a matching tag in !expedition list — players see "raid-shaped — solo runs not yet survivable" before they spend outfitting coin. No combat or class balance changes. Files: cmd/expedition-sim/main.go +trace flag; expedition_sim.go picker + SimCombatSummary.Events + spellbook seed; dnd_expedition_cmd.go raidContentWarning + list tag. All baselines + traces + findings checked in under sim_results/.
82 lines
8.2 KiB
Markdown
82 lines
8.2 KiB
Markdown
# J2b — Post-J2a all-classes baseline (n=100)
|
||
|
||
**Date:** 2026-05-17
|
||
**Corpus:** `sim_results/baseline_j2a_v2_all10.jsonl` (15,000 rows = 10 classes × 3 levels × 5 zones × n=100). Per-cell tabular summary in `sim_results/j2b_all10_summary.txt`.
|
||
**Replaces:** `sim_results/baseline_j1_all10.jsonl` as the post-sim-fix canonical corpus. The J1 numbers measured a strawman where casters never cast (see [j2_findings.md](j2_findings.md)).
|
||
|
||
## L12 leaderboard (mean %clr across all 5 zones)
|
||
|
||
| Class | J1 baseline | J2b | Δ | J1 boss% | J2b boss% | Per-zone J2b %clr (T1 / T2 / T3 / T4 / T5) |
|
||
|----------|-------------|-------|--------|----------|-----------|--------------------------------------------|
|
||
| fighter | 79.6 | 80.0 | **+0.4** | 100.0 | 100.0 | 100 / 100 / 100 / 100 / 0 |
|
||
| ranger | 78.6 | 80.0 | **+1.4** | 100.0 | 100.0 | 100 / 100 / 100 / 100 / 0 |
|
||
| paladin | 72.2 | 78.4 | **+6.2** | 99.6 | 99.2 | 100 / 100 / 96 / 96 / 0 |
|
||
| rogue | 70.6 | 76.8 | **+6.2** | 99.0 | 99.0 | 100 / 100 / 90 / 94 / 0 |
|
||
| druid | 38.6 | 61.6 | **+23.0** | 88.4 | 88.0 | 100 / 100 / 74 / 34 / 0 |
|
||
| mage | 20.0 | 53.4 | **+33.4** | 77.2 | 77.6 | 100 / 99 / 49 / 19 / 0 |
|
||
| sorcerer | 20.0 | 50.6 | **+30.6** | 70.4 | 70.0 | 100 / 98 / 47 / 8 / 0 |
|
||
| warlock | 21.4 | 48.2 | **+26.8** | 82.2 | 81.6 | 100 / 100 / 34 / 7 / 0 |
|
||
| bard | 21.6 | 40.4 | **+18.8** | 82.0 | 84.4 | 100 / 100 / 2 / 0 / 0 |
|
||
| cleric | 18.6 | 39.0 | **+20.4** | 61.6 | 62.4 | 96 / 90 / 9 / 0 / 0 |
|
||
|
||
## Headline
|
||
|
||
1. **No martial regression.** Fighter/Ranger/Paladin/Rogue all moved within +0.4 to +6.2pp, indistinguishable from sweep variance. The `simMartialFirstClass` gate added after the v1 sweep saved Ranger (which had regressed -35.8pp when the picker burned L3 slots on `lightning_arrow` instead of letting the weapon-attack + Hunter's Mark + Extra Attack chassis swing).
|
||
2. **Caster cliff is dissolved.** The pre-fix 19–22% cluster spread out to 39–62%. The picker alone — no balance changes — converted the trailers to mid-band classes.
|
||
3. **Druid is now top-of-band-2 at 61.6%.** Wild Resilience's ThornLash on weapon swings plus the new cast path stacks cleanly. Druid is still defensive-first by design; the cast layer turns boss rooms from "swing-and-bleed" into "burn-and-finish".
|
||
4. **T5 dragons_lair still walls everyone (0% clear across all 10 classes).** That's the J3 problem; J2 wasn't on the hook for it, and the sim-artifact half of J3's hypothesis 1 (`autoResolveCombat` never casting/consuming) is now closed by J2a.
|
||
|
||
## What's still trailing — bard and cleric
|
||
|
||
Bard L12 manor 2%, cleric L12 manor 9% — both reach the boss (~50–84%) and die there. **Not a sim artifact**; this is the spell pool. The v1 picker only scores damage-effect spells, and these two classes have thin damage rosters in `defaultKnownSpells`:
|
||
|
||
- **Bard** damage options: `vicious_mockery` (cantrip), `shatter` L2. Everything else in the bard kit is control / heal / buff, which the picker skips.
|
||
- **Cleric** damage options: `sacred_flame` (cantrip), `guiding_bolt` L1, `spiritual_weapon` L2, `spirit_guardians` L3, `flame_strike` L5. The non-damage options (`bless`, `healing_word`, `mass_cure_wounds`, etc.) are skipped too.
|
||
|
||
Both classes' identity spells are control (`hold_person`, `hypnotic_pattern`, `command`) and heal (`cure_wounds`, `healing_word`, `mass_cure_wounds`). The picker treats those as zero-value.
|
||
|
||
Note on cleric underdark: 87% of L12 underdark runs end as `tpk` with stop `ended` — that's expedition-side starvation, not boss-fight TPK (only 13% reach boss/elite). Cleric's exploration loop is brittle for unrelated reasons (low STR/CON build, supply burn). Out of J2 scope.
|
||
|
||
## J2 DoD check
|
||
|
||
Reframed DoD (`gogobee_harvest_charges_plan.md` §6.J2, updated 2026-05-17):
|
||
|
||
- **J2a — ≥80% of boss fights produce a cast or consumable.** **MET** (100% cast rate in the verification sweep, [j2a_findings.md](j2a_findings.md)).
|
||
- **J2b — caster L12 manor mean clear ≥ druid's pre-J2a 39%.** Mage 49 ✓, sorcerer 47 ✓, warlock 34 ✗ (close), bard 2 ✗, cleric 9 ✗. **3 of 5 pass.**
|
||
- **No martial leader regresses >10pp.** **MET** (all +0.4 to +6.2pp).
|
||
|
||
Two trailers still under the floor (bard, cleric). They're now bottlenecked on **spell-pool richness for the v1 damage-only picker**, not on the sim itself. The cleanest next move:
|
||
|
||
## J2c — tried, reverted (2026-05-17)
|
||
|
||
Implemented two widening levers, ran two n=100 sweeps, and reverted both:
|
||
|
||
1. **Heal-spell preempt** (cure_wounds / healing_word / mass_cure_wounds preferred over heal consumable at low HP). Regressed **druid -10pp**: slot heals at L12 heal ~10HP vs 40HP from a tier-4 Spirit Tonic, and the picker burned slots druid needed for damage spells.
|
||
2. **Control-spell scoring at 22** (denied-enemy-turn proxy). Regressed **warlock -6.6pp** — vampiric_touch L3 (10.5 expected over multiple rounds + heal) was outscored by hypnotic_pattern L3 (single denied turn). Dropping the score to 5 brought net deltas back to ±2pp but didn't lift bard or cleric, because the level-first sort prevents low-score control spells from ever winning over a higher-level damage option (which the trailer classes don't have at higher slots).
|
||
|
||
Corpora retained for reference: `sim_results/baseline_j2c_all10.jsonl` (heal-preempt + control@22) and `sim_results/baseline_j2c_v2_all10.jsonl` (control@5 only). The picker reverted to the J2b shape (damage-effect only, level-first sort, no heal-spell preempt).
|
||
|
||
**Real lever for bard/cleric trailing.** Their `defaultKnownSpells` damage rosters cap at L2 (bard: shatter; cleric: spiritual_weapon's 1d8). The picker can't pick higher-damage spells they don't have. Lifting these classes is therefore a **prod-level change to `defaultKnownSpells`** (add a damage option at L3+ for bard, a damage option at L4+ for cleric) — not a sim-picker change. Out of scope for J2; revisit alongside class identity / Open5e integration work.
|
||
|
||
## (original) Recommended J2c (now superseded by the section above)
|
||
|
||
**Widen the picker to score control + heal spells.**
|
||
|
||
- `EffectControl` (e.g. `hold_person`, `hypnotic_pattern`, `hideous_laughter`, `command`) should score as the *enemy damage it prevents over its expected effect duration* — i.e. each prevented enemy turn ≈ one round's worth of incoming damage. For a stunner that lands and lasts 1 round on a 30-dmg/round boss, that's a 30-equivalent. Better than most damage spells.
|
||
- `EffectSpellHeal` should compete with the consume-on-low-HP branch — if the cleric has `mass_cure_wounds` ready, it should fire at the low-HP threshold instead of a `Spirit Tonic`.
|
||
- `EffectBuffSelf` (e.g. `bless`, `shield_of_faith`) lifts to-hit chance / AC. Score in opening round of a fight only; subsequent rounds it's a waste.
|
||
|
||
This is one focused change in `simPickSpell` + `simPickCombatAction`. Expected impact: bard pulls into the 30–40% manor band (control spells are the bard identity); cleric pulls similarly. Martial leaders unchanged. Whether it's needed depends on operator: J2's reframed DoD allows shipping J2 with bard/cleric trailing if the prod target is "five classes mid-band, two below". Per [feedback_difficulty_target](.claude/memory/feedback_difficulty_target.md), the explicit ask is to lift trailers — that argues for landing J2c.
|
||
|
||
## Files touched this phase
|
||
|
||
- `internal/plugin/expedition_sim.go`:
|
||
- `SimCombatSummary.Events`, `simIncludeTrace` + `SetSimIncludeTrace` (J2 diagnostic).
|
||
- `simPickCombatAction`, `simPickSpell`, `simMartialFirstClass`, `simHealHPThresholdPct` (J2a picker + post-baseline fix).
|
||
- `BuildCharacter` now seeds `ensureSpellsForCharacter`.
|
||
- `autoResolveCombat` dispatches via the picker.
|
||
- `cmd/expedition-sim/main.go`: `-trace` flag.
|
||
- Docs: `sim_results/j2_findings.md`, `sim_results/j2a_findings.md`, `sim_results/j2b_findings.md`, `sim_results/j2b_all10_summary.txt`, plan §6.J2.
|
||
|
||
No prod combat / class / spell paths changed. Everything is in the sim harness.
|