From c64cda6e44fa500d5ae00da1dccc7d4f8b422bbf Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Mon, 20 Jul 2026 21:28:34 -0700 Subject: [PATCH] Docs: 07-20 tuning bench session log (profiles / audit / probe workflow) Co-Authored-By: Claude Fable 5 --- .../2026/2026-07-20_Tuning_Bench_C.md | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Docs/Vault/07_Sessions/2026/2026-07-20_Tuning_Bench_C.md diff --git a/Docs/Vault/07_Sessions/2026/2026-07-20_Tuning_Bench_C.md b/Docs/Vault/07_Sessions/2026/2026-07-20_Tuning_Bench_C.md new file mode 100644 index 000000000..0101efb7d --- /dev/null +++ b/Docs/Vault/07_Sessions/2026/2026-07-20_Tuning_Bench_C.md @@ -0,0 +1,41 @@ +# 2026-07-20 (C) — Data-driven tuning bench (profiles + audit + probe) + +**Operator:** "the knobs are a lot & not very intuitive — is there any way for you to do data-driven tuning?" +The answer: raw scalars are bad for both of us — the operator can't intuit ticks/radians, and I can't feel the +game. What I CAN do precisely is **derive and measure**. Three tools: + +## 1. Feel profiles — whole gestalts as data +`Assets/_Project/Tuning/Profiles/*.json` — one file = sim knobs (TuningKnob names) + FeelConfig fields, PARTIAL +(only listed keys apply). `FeelProfileService` (Client/Debug, editor-only) applies via the existing authoritative +SetTuning path + FeelConfig reflection; **"Save current"** captures a hand-dialed state back to a profile. +DebugOverlay grew a Profiles section (one-click A/B) + the probe button. Starter set: `baseline-0720` (the shipped +defaults / reset), `heavy-committed` (MonHun-lean), `snappier` (Hades-lean) — all DPS-held (~60) via dmg = recover. +**Rule: code defaults stay the single shipped truth; profiles are experiments — a winner gets folded into +`TuningConfig.Defaults()` / `FeelConfig.ResetDefaults()` and the profile archived.** + +## 2. TuningAuditTools — the derived truth (edit-time, no eyes needed) +`ProjectM/Tuning/Audit Melee Timing + Reach`: derives per-step contact from the ACTUAL clip WindUp takes ÷ wired +state speeds and compares against `MeleeTiming` + the knob (drift detector — kills the hand-copied-constant class +of bug); checks the un-clamped coupling invariants the design review flagged (contact < lock, ≤ CastFacingTicks); +computes cadence/DPS; measures the reach-honesty ratio off the BAKED weapon mesh. First run: **zero drift** +(16/10/20 == clip truth), DPS 60.0 flat, and **reach ratio ×0.93 base / ×1.16 finisher** — the "swings don't line +up" complaint is now a measured number inside the ≤1.25 budget (was >2×). + +## 3. CombatProbe — measured play numbers +`CombatProbe.Run(n)` (Client/Debug, editor-only; overlay button): spawns a 100k-HP dummy in the cone, mash-drives +a real injected attack chain, samples the SERVER per frame → per-swing start/scheduled-contact/damage-tick/amount, +measured cadence + DPS + buffer usage. Demo run at defaults: gaps 30/30/45 exactly, contacts +16/+10/+20 exactly, +damage 36/36/54 (class seed × finisher). Then **the full loop**: applied `snappier` → measured 24/24/36 gaps and ++12/+8/+15 contacts immediately. Tuning = author JSON → apply → measure → compare. Probe fix during the demo: wait +for the FINAL swing's contact before finishing (first run cut off swing 6). + +## The workflow now +- **Me (precise):** edit/author a profile → `Apply` → `CombatProbe` → read measured numbers vs targets → iterate. +- **Operator (intuitive):** tap profile buttons in the overlay to A/B whole feels → nudge individual rows if + desired → **Save current** → I fold the winner into code defaults. + +Validation: console clean; audit + probe both demonstrated live; profile apply verified against measured sim +output. No netcode surface (profiles ride the existing SetTuning RPC; probe is read-only diagnostics). + +**Next:** operator A/Bs the three starter profiles in DevSandbox (DEV overlay → Feel Profiles); tell me which +direction wins (or Save-current a custom) and I fold it into defaults + build the next profile iteration.