mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 16:42:41 +00:00
89edc768294571d27d8b793894ecb60a31bbae51
9 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5ef10e35dc |
Phase 5b: player power floor + Phase-3 winners shipped to live
Closes the 'fairly breezy with some death' target the user picked
for Phase 5. Five-piece ship; Phase 1 matrix lands T1 88%, T2 74%,
T4 72%, T5 ~57% in or above band. T3 remains the design hump at
~45% (manor 39, underforge 47) — Wraith promotion to elite was
already done in Phase 4-B, the remaining standard-pool deaths are
the irreducible part of T3.
Pieces:
1. computeMaxHP × 1.5 (phase5BHPMult in dnd.go). Uniform across
class/level so the class-balance harness's in-tier parity
assertion stays green. Bootstrap (bootstrap_phase5b_hp.go)
refreshes hp_max for existing characters at startup;
idempotent via db.JobCompleted. hp_current is bumped by the
same delta so a full-HP character stays at full.
2. applyPhase5BPlayerFloor (dnd_combat.go): +3 AC, +3 AttackBonus,
+3 weapon.MagicBonus (damage). Applied at the END of
applyDnDEquipmentLayer (after computeArmorAC's AC override)
and inside buildHarnessPlayer so live and harness measurement
match.
3. Elite bracket 19 → 23 (resolveCombatInterrupt). Case order
puts Elite (≥23) before Patrol (≥22) so a 23+ total prefers
the single dangerous fight. Elite is now effectively a
high-threat event reachable only via the +1-per-20-threat-
above-40 mod — Phase 4-B's elite-pool monsters still appear,
just less often.
4. dailyThreatDrift base 3 → 1. Slows the threat clock so
players have the days they need before threat tips zones
into the new 23+ elite band.
5. applyDailyBurn default → 50% (phase5BDailyBurnRatePct). Also
applied in the temporal-override branch in
dnd_expedition_cycle.go so tidal / unraveling days scale by
the same 0.5× — otherwise those days would be
disproportionately harsh against the new baseline.
The harness's expedition_balance.go reads phase5BDailyBurnRatePct
as the default-burn fallback when the override knob is zero, so
Phase 1 matrix measurements now reflect what live players
experience.
Test debt: 13 pinned-numbers unit tests across combat_stats_test,
dnd_test, dnd_xp_test, dnd_equipment_profiles_test,
dnd_expedition_supplies_test, dnd_expedition_cycle_test,
dnd_expedition_extract_test, dnd_expedition_region_cmd_test,
dnd_expedition_combat_test, dnd_expedition_threat_test,
dnd_expedition_temporal_test, expedition_balance_test were
pinning pre-Phase-5-B baselines; updated with comments noting
the cause. Class-balance suite stayed green (uniform buff
preserves spread).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
dcd9e4158f |
Phase 4a (diag): per-zone outlier attribution
The Phase 3-B sweep wrung out the global lever surface and named four
zones that read ~0% completion under every (elite-threshold, drift,
nick-floor, supply-burn) combo: crypt_valdris T1, forest_shadows T2,
manor_blackspire T3, abyss_portal T5. Each has a healthy sibling at
the same tier (goblin_warrens 44%, sunken_temple 13.5%, underforge
2.5%, dragons_lair 57.5%) so the gap is per-zone, not tier-wide.
Adds a structured per-fight trace hook (traceFightStruct + the
harnessFightTrace struct that mirrors the existing string trace) so
diagnostics can aggregate without parsing the formatted log line.
Mirror-format with traceFight; if a field is added, update both
paths.
TestExpeditionBalance_Phase4A_OutlierDiagnostic walks the four
outlier-vs-sibling pairs at 200 trials each on the Phase 3-A/3-B best
cell (e=23 d=1 burn=50) and reports per-monster appearances /
win-rate / avg HP loss / kill attribution + day-of-end histogram +
elite-vs-standard fight mix.
Findings:
- crypt_valdris: dual-killer elite pool (Wight 99 kills, Flameskull
68). Phase 2c left this zone untouched ("already dual-elite") but
both elites are over-tier for T1.
- forest_shadows: standard pool too lethal — Displacer Beast (53
kills, 38% win standard) + Bandit Captain (48 kills, 57% win).
- manor_blackspire: Wraith on the standard slot is dragging the
floor (85 kills, 45hp loss per win). Vampire Spawn + Revenant
elite pair is also rough.
- abyss_portal: Nalfeshnee mis-classified standard (86 kills, 2.8%
win at L17). Vrock at 79% win is borderline.
Phase 4-B applies per-zone roster tweaks (IsElite re-flag, drop a
deadly entry, soften a SpawnWeight) — no monster stat-block changes.
T3 may need a follow-up tier-wide pass since the sibling underforge
also sits at 2.5%; out of scope here.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
2d44c990f3 |
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>
|
||
|
|
235122f2a1 |
Phase 3a (sweep): elite-bracket + drift sweep, strong partial positive
Wired two harness lever overrides — EliteInterruptThresholdOverride
(live=19) and ThreatDriftBaseOverride (live=3) — into the day-loop in
expedition_balance.go. Live runHarvestInterrupt / dailyThreatDrift are
untouched; the harness re-buckets Standard↔Elite after the live call.
TestExpeditionBalance_Phase3_GlobalLeverSweep walks a 3×3 grid
(elite ∈ {17,19,23} × drift ∈ {1,3,5}) over the Phase 1 matrix at
200 trials/cell. -short skips.
Elite-bracket threshold is the dominant lever for T1–T3. At
e=23/d=1: T1 mean 24.0% (goblin_warrens 40.5%), T2 7.2%
(sunken_temple 14.5%), T3 1.8%. Still well below target bands
(T1 70-90%, T2 62-82%) — the lever moves the needle in the right
direction but cannot land any tier on-band alone.
T4/T5 fingerprint changed but didn't lift. At e=23 dragons_lair
death drops 60% → 24% but starvation climbs to 75% — the fighter
now survives elites long enough to run out of supplies. T4 cells
shift the same way. Indicates a second lever is needed for the
higher tiers (standard-fight survivability or supply margin), to
be swept in Phase 3-B.
Plan doc updated. Renumbered the trailing "per-zone outlier pass"
to Phase 4 and "MAD / second-order" to Phase 5 so the test names
align with phase numbers going forward.
-short suite: same 2 pre-existing failures
(TestAdv2Scenario_ZoneRunGoblinWarrens, TestMageSpellbookLineInRender).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
8cdd64b383 |
Phase 2 (sweep): lever-tuning sweep, negative result
Sweep the two knobs surfaced by Phases 2a/2b — retreatThreatBump
and clampSurpriseNick's wounded-entrant divisor — across a full
3×4 grid (bump ∈ {2, 5, 10} × divisor ∈ {3, 5, 8, 12}) at 200
trials/cell across every matrix zone.
Wiring is harness-only: clampSurpriseNick keeps its live shape and
delegates to a new clampSurpriseNickD(divisor) variant; the harness
profile gains RetreatThreatBumpOverride/SurpriseNickDivisorOverride
fields threaded onto expeditionHarness; resolvedRetreatBump and
resolvedNickDivisor pick override-or-live. Zero on either field
falls back to the shipped value so live runHarvestInterrupt is
untouched.
Sweep test: TestExpeditionBalance_Phase2_LeverSweep, -short skipped,
mirrors Phase2_CadenceCalibration's per-tier digest shape.
Outcome: across 24,000 trial-cells (12 lever combos × 10 zones
× 200 trials), every cell reports 0.0% completion / ~100% death.
The knobs are inert on the headline metric — even (b=2, d=12)
can't lift any tier off the floor. Confirms the post-2b
tier-lethality trace: remaining deaths are fresh-entry elite
one-shots (Warchief, Hag, Roper, Young Red Dragon), not chained-
interrupt cascades. Justifies Phase 2c (roster dilution) rather
than further tuning of these two levers.
Plan doc updated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
159daf8fc8 |
Phase 2b (lever): wounded-entrant surprise-nick clamp
The post-2a tier-lethality trace showed the remaining 0% completion was driven by chained surprise-round nicks on already-wounded fighters, not by the elites themselves. Pattern from the trace: fight day=5 Hobgoblin Warchief: hp_pre=24 → hp_post=14 WON fight day=5 Goblin Archer: nick=6, hp_pre=8 → hp_post=0 LOST The Warchief left the fighter at HP 14; the Goblin Archer's surprise nick (6 HP) dropped them to 8 before combat resolved — and a standard goblin then finished a fighter who should have survived. Same shape at T2 (Dire Wolf nick 4 on hp=3), T3 (Fire Elemental nick 4 on hp=5), T4-T5. The nick was acting as a hidden cascade multiplier, pre-empting the combat engine on wounded entries. clampSurpriseNick caps the nick at max(1, hpCurrent/5) when the fighter enters wounded (HPCurrent < HPMax); at full HP the raw nick stands. The existing 'nick < HPCurrent' KO-guard is preserved as a backstop. /5 is the wounded-fighter lethality knob; tighter (/10) is gentler, looser (/3) re-opens the cascade. Live caller (runHarvestInterrupt) and harness (runHarnessFight) both route through the new helper so the sim measures the same lever the live caller applies. Matrix delta is mild (encs +0.1-0.2 per cell, completion% still 0%) but the tier-lethality trace stretches substantively: T1 trial 0 ran 5→8 encs / 5→7 days, T3 trial 1 saw a fighter survive multiple chained interrupts at low HP that pre-2b would have ended on nick alone. The remaining deaths are now legible as elite-one-shot fights on fresh entries (Warchief, Green Hag, Roper, Young Red Dragon) — that's the Phase 2c roster-gate signal. Push-back on the original lever-order: the Phase 2a recap put roster gate first, but the trace fingerprint named the wounded-entry nick as the dominant cause-of-death in 4 of 5 tier traces. Doing nick-cap first keeps Phase 2c's diagnostic clean and avoids re-tuning rosters after another lever changes the shape under us. Pre-existing failures unrelated to this change: - TestAdv2Scenario_ZoneRunGoblinWarrens (advance regression, prior) - TestMageSpellbookLineInRender (render assertion, prior) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
04aa887d18 |
Phase 2a (lever): expedition retreat semantics split
Phase 2 diagnostics named the InterruptElite bracket as the likely
first lever; tier-walking the lethality probe at the matrix cadence
told a different story. Phase 1's uniform-0% baseline isn't an
elite-bracket calibration issue at all — every tier reads 0% because
the engine's TimedOut contract was being ignored by every expedition
caller.
combat_engine.go:451 says: "Timeout = retreat, not lethal blow.
Caller treats a timeout loss as 'fight ended, no character death'".
But runHarvestInterrupt / tryPatrolEncounter / resolveCombatRoom all
called abandonZoneRun + retireAllRegionRuns on any !PlayerWon —
ending the expedition outright on a retreat. The retreat flavor line
("X outlasts you. You retreat from the expedition, wounded but alive")
was already in the code, just stapled to an actual run-abort.
Splits the policy by caller:
• runHarvestInterrupt — autopilot daytime interrupt. TimedOut →
retreat: threat +5, HP carries over, run continues, harvest slot
forfeit (no kill / loot). HP<=0 still ends the run + marks dead.
• tryPatrolEncounter — !advance pre-room patrol roll. Same
retreat policy: patrols don't gate progress, so retreating from
one and walking into the next room is the right shape.
• resolveCombatRoom — !advance room/elite combat. Unchanged —
this path gates room progression; a retreat has nowhere to go, so
any loss still ends the run. (Manual zone runs were always
intended to end here.)
Harness mirrored: daytime interrupt timeout → carry HP + threat bump
+ continue day; night-encounter loss → terminate (mirrors
resolveCombatRoom, since live night encounters defer to !advance).
retreatThreatBump = 5 is the per-retreat threat penalty. Low enough
not to compound brutally with chained retreats, high enough that 3–4
retreats noticeably walks the threat clock toward Stirring. Easy to
dial in Phase 3 if zones go off-band.
Phase 1 matrix after the change still reads 0% completion at every
cell — but the encounter counts and survival shape are dramatically
different (T4 underdark 3.6→7.5 encs; T3 underforge trial saw 18
encounters across 10 days where the pre-change run died on day 2/3).
Adds TestExpeditionBalance_Phase2_TierLethality, a tier-walking
companion to the T1/rolls=1 probe, that traces every fight at the
matrix cadence across one zone per tier — the actual Phase 2b lever
work picks from this data, not the old T1-only probe.
The remaining 0% is now legibly driven by tier-disproportionate elite
rosters (Hobgoblin Warchief at T1, Green Hag at T2, Roper/Helmed
Horror higher up) that one-shot or two-shot tier-appropriate
fighters. Phase 2b's lever shortlist:
1. Roster gate / SpawnWeight tuning to dilute over-tier elites.
2. Surprise-nick floor reduction on chained interrupts (carryover
HP + nick is the death-spiral fingerprint at T1 specifically).
3. Per-day cadence reduction if 1+2 don't carry T1 to band.
Pre-existing test failures (TestAdv2Scenario_ZoneRunGoblinWarrens,
TestMageSpellbookLineInRender) verified to fail identically on HEAD;
no new test regressions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
0f09a421bc |
Phase 2 (diag): cadence sweep, gear-tier fix, lethality probe
Three Phase 2 diagnostic artifacts. No tuning knob has moved on
production code yet — these tests calibrate the harness and surface
the real first lever for next session.
1) Cadence calibration sweep
TestExpeditionBalance_Phase2_CadenceCalibration sweeps
HarvestRollsPerDay ∈ {1,2,3,4} across the full Phase 1 matrix and
logs per-cell + per-tier completion. Required a new
HarvestRollsPerDay field on expeditionBalanceProfile so cells can
override the package-default constant. Finding: cadence is NOT the
dominant lever — at rolls=1 the T1 cell only reaches 2%, with
bimodal hp_left (100% survivors / 0% deaths). Killed the cadence
hypothesis from Phase 1's commit message.
2) Gear-tier centerline fix
phase1TierCenterline bumped for T3/T4/T5 (8→9, 11→13, 15→17). The
shared gearTier ladder (5/9/13/17 boundaries) was placing T3/T4/T5
centerlines one gear bracket *below* the zone's tier, so those
cells fought with under-spec'd weapons/armor. New centerlines are
the lowest level in each tier's design-doc range where gearTier ==
tier. All centerlines still inside their design-doc ranges. Effect
in the sweep at rolls=1: underforge T3 1.0% → 10.5% comp, underdark
T4 flipped from pure combat-death to 14% starve (i.e. fighter now
survives combat, runs out of food). Real bug, but small — the
structural lethality problem remains.
3) Lethality probe + traceFight hook
TestExpeditionBalance_Phase2_LethalityProbe runs 5 trials at the
cleanest cell (T1 goblin_warrens L3 fighter, rolls=1) with a new
optional traceFight hook on expeditionHarness that logs
monster/AC/atk/HP-pre/HP-post/outcome per fight. Hook is nil in
production runs, zero cost when unused. Finding: at T1, the
InterruptElite branch keeps drawing Hobgoblin Warchief (AC 18,
atk +5) from goblin_warrens' elite roster, and an L3 fighter has
~coin-flip odds against a CR-6-ish elite. One bad draw = dead;
that's the bimodal hp_left fingerprint from the sweep. Non-elite
draws (Worg, AC 13) play out as normal multi-round combats and
are winnable.
Next-session lever choices, in order of suspected impact:
- Roster gate: Hobgoblin Warchief out of (or weighted down in)
the T1 elite pool — it's tier-disproportionate for goblin_warrens.
- InterruptElite threshold: rarer elite-bracket draws at low threat
so a single d20 swing doesn't equal expedition end.
- Tier-floor cap on already-over-tier bestiary entries.
Plan doc: gogobee_expedition_difficulty.md §Phase 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
53d1608490 |
Phase 0: expedition-difficulty sim harness spike
New file internal/plugin/expedition_balance.go — sibling to dnd_class_balance.go, no dnd_ prefix per feedback_avoid_dnd_naming. Plan doc: gogobee_expedition_difficulty.md. Critical de-risk settled: clock-injection seam. The harness does not run the wall-clock tickers (expeditionBriefingTicker @ 06:00, expeditionRecapTicker @ 21:00, expedition_ambient @ 3h) and does not inject a virtual time.Now. Instead, advanceExpeditionOneDay reimplements the morning→day→night pipeline by calling the math-pure helpers directly: applyDailyBurn, dailyThreatDrift, resolveCombatInterrupt, resolveWanderingCheck, simulateCombatWithRNG. No DB, no goroutines, no clock. Phase 0 trade-offs (documented in the file header): - Boss completion deferred; survive-N-days is the proxy. - Per-region zones, loot/XP, pardon/Sovereign, babysit, temporal stack effects all skipped — Phase 1+ scope. - Encounter cadence (harnessHarvestRollsPerDay=4) is a placeholder to be calibrated against live traces in Phase 1. Tests: - TestExpeditionBalance_Phase0_Spike — T2 Crypt Valdris × L5 Fighter, 100 trials, asserts only degenerate sentinels (no 0%/100%, days>0, days<=cap). Runs in <3s. - TestExpeditionBalance_Phase0_SeedSpread — confirms the RNG seam is actually wired by showing two distinct seeds produce different trials. Full byte-for-byte reproducibility under same seed is not asserted at Phase 0; surpriseRoundNick + pickWanderingMonster draw from package-global rand (same caveat as class balance). Spike numbers (calibration baseline, NOT a target): 1% completion, 99% deaths, median 4 days, ~6 encounters. The headline death rate is loud but expected — Phase 1's full matrix will diagnose whether it's HP-carryover punishment, bestiary-vs-abstract-monster delta, or kit ladder mismatch. Phase 2 is where the centerline gets tuned. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |