Docs: DR-030 MC-4 combo melee (primary verb) + session log; Path_to_Fun MC-1 passed / MC-4

MC-1 fun-gate PASSED (kill-switch cleared); MC-4 built as the combo-chain melee primary-verb variant, both adversarial reviews folded in. Roadmap MC-1/MC-4 status updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-10 17:23:10 -07:00
parent d77649fe16
commit 5b0af63a3b
3 changed files with 93 additions and 0 deletions
@@ -0,0 +1,39 @@
---
id: DR-030
title: MC-4 = a combo-chain melee as the PRIMARY verb (ranged demoted); predicted-replicated combo state
status: accepted
date: 2026-06-10
tags:
- decision
- design
- combat
- netcode
- mc-4
permalink: gamevault/07-sessions/decisions/dr-030-mc4-combo-melee-primary-verb
---
# DR-030 — MC-4: Combo-Chain Melee as the Primary Verb
## Context
[[2026-06-10_MC4_Combo_Melee]] · direction [[Path_to_Fun]] (MC-4) · forks ritual [[DR-029_Path_A_Fork_Locks]] · combat thesis [[DR-028_Combat_Primary_Verb_Depth_First]] / [[combat-first-depth-before-breadth]].
**MC-1 PASSED its fun-gate** (operator, 2026-06-10: *"It's fun — the dash feels fine"*). The project kill-switch is cleared and the combat thesis is validated — so depth continues. The operator then chose to address the flattest-feeling thing: the default offense (`AbilityFireSystem`'s auto-aim hold-to-fire projectile — the *only* offense verb). Of the four MC-4 shapes presented (single cleave / Attack+Special pair / combo-chain / full weapon-kit), the operator picked **combo-chain Attack**, and on the role/binding fork picked **melee as the PRIMARY verb** (ranged demoted to a secondary poke). Hades-like.
The slice is netcode-heavy (predicted combo state under rollback), so per the standing rule it went through the **mandatory pre-code adversarial review** (3 lenses → 21 findings → 8 confirmed) before any code, and a **post-build review** (3 lenses → 18 findings → 4 confirmed, all fixed).
## Decision
**1. Melee combo is the player's PRIMARY verb.** Left-click / gamepad-West = the 23-hit combo; the ranged projectile (`Fire`) is demoted to right-click / gamepad-left-trigger. Both are direct device reads in `PlayerInputGatherSystem` (no `.inputactions` regen — the MC-1 Dash precedent), both suppressed while the build palette is open. Right-click stays the build-cancel (modal; the `!BuildPaletteState.Active` guard separates the two uses). Dash unchanged.
**2. The combo `Step` is path-dependent → it is REPLICATED, not derived.** Unlike the dash (a stateless-per-tick decision whose `DashState` is non-replicated and re-derived each tick), which chain-link you are on depends on the *sequence + timing* of prior presses, and the bounded input command buffer cannot reconstruct it across a reconnect / long rollback. So `MeleeCombo{ [GhostField] byte Step; [GhostField] uint SwingStartTick; [GhostField] uint LockUntilTick }` is **owner-predicted replicated state** (one player-ghost re-bake; in-family with `DashCooldown`/`AbilityCooldown`). The ADVANCE writes are **ABSOLUTE functions of (restored Step, tick)** — never an in-place `prev+1` of a non-restored field — so a rollback restores the authoritative anchor and the predicted re-sim converges (the `DashSystem` idempotency idiom). *(Pre-code review PRED-1/ROLLBACK-1 — this overrode the reuse-lens scope objection: correctness over saving a re-bake.)*
**3. Damage is SERVER-ONLY in the predicted group, mirroring `ProjectileDamageSystem`** (not for a whiff-punish reason — that premise was false; the Charger stagger is a multi-tick window scored once regardless of group). The combo STATE advance + movement-commit run on BOTH worlds (predicted, idempotent, instant local feel); the cleave (collect-all enemies in the per-step cone via the new `MeleeConeMath` predicate, append `SourceTick`-stamped `DamageEvent` + stamp `KnockbackState`) runs only `if (isServer)`. `MeleeComboSystem` sorts `[UpdateAfter(PlayerControlSystem)] [UpdateBefore(DashSystem)]` so a dash overrides the swing's movement (dash-cancel) and `HealthApplyDamageSystem` ([UpdateAfter(DashSystem)]) drains the cleave the same tick. Chain `PlayerControl < MeleeCombo < Dash < Health` is acyclic (Play-validated).
**4. The combo is fully LIVE-tunable — no per-step authored blob, and the MC-6 archetype byte is DEFERRED.** The whole per-step shape derives from ~9 live `TuningConfig` knobs (damage / range / cone-half-angle / recover / chain-grace / move-scale / knockback-speed / finisher-mult / combo-length) + one finisher multiplier — so the operator tunes feel mid-Play with no recompile/re-bake. Because the melee is its own verb (own input → own system, not an ability dispatch), the `Archetype`-byte-on-`AbilityDefBlob` dispatch infrastructure is **deferred to MC-6** where it is actually needed (avoids building breadth before it earns its place; pre-code review BURST-1/F5-1/SCOPE-1).
## Consequences
- The combo grammar is **dash-in → light → light → finisher → dash-out**, with the projectile as a ranged poke. The finisher (Step == ComboLength) widens range + scales damage/knockback/recovery by `MeleeFinisherMult`; `ComboLength` is a live knob (1 = heavy-only floor, 2 = light+finisher, 3 = light·light·finisher default).
- **Status: code-complete + reviewed; the MC-4 FUN-GATE is the open operator item** — `cleaveTargetsPerSwing > 1.5` in a swarm, dash-in/cleave/dash-out chosen over the projectile when surrounded, a blind-test watcher can tell cleave from projectile by feel. Tunable live via `DEV ▲` → the new "Melee …" rows. MC-4 cannot "pass" until MC-1's feel is held (it just was). After MC-4 passes → **EB-1** (machines can die) is the next committed milestone.
- Reversible via the same fork ritual; the live-singleton picks flip at playtest. The structural shapes (Step replicated, melee-primary binding, server-only cleave) are committed.