NEO-82: Add code review for cast combat wiring.
parent
e8be100f80
commit
0b40ae3598
|
|
@ -0,0 +1,63 @@
|
|||
# Code review — NEO-82 Wire ability-cast into combat engine + cast response
|
||||
|
||||
**Date:** 2026-05-25
|
||||
**Scope:** Branch `NEO-82-wire-ability-cast-combat-resolution` · commits `4126ac9`–`e8be100` vs `origin/main`
|
||||
**Base:** `origin/main`
|
||||
|
||||
## Verdict
|
||||
|
||||
**Approve with nits**
|
||||
|
||||
## Summary
|
||||
|
||||
NEO-82 delivers **E5M1-07**: after E1.M4 cast gates pass, `AbilityCastApi` invokes `CombatOperations.TryResolve`, returns nested wire `combatResolution` on accept, maps combat denies (notably `target_defeated`) to JSON cast denies without cooldown commit, and replaces the global prototype cooldown with per-ability catalog `cooldownSeconds` on successful resolve. Handler flow, DTO shape, kickoff decisions (nested block, no cooldown on defeated deny), Bruno happy + defeat spine, and README updates align with the implementation plan. Four new integration tests cover zero-damage accept, four-pulse defeat chain, and guard-vs-pulse catalog cooldown; existing cast tests assert resolution fields. Residual risk is low — server-only HTTP extension with clear deny vocabulary; module tracking docs should sync on merge (same follow-up pattern as NEO-81).
|
||||
|
||||
## Documentation checked
|
||||
|
||||
| Document | Result |
|
||||
|----------|--------|
|
||||
| [`docs/plans/NEO-82-implementation-plan.md`](../plans/NEO-82-implementation-plan.md) | **Matches** — kickoff decisions, scope, acceptance checklist, expected cast table, and reconciliation align with code. |
|
||||
| [`docs/plans/E5M1-prototype-backlog.md`](../plans/E5M1-prototype-backlog.md) · **E5M1-07** | **Matches** — AC checked, landed note added. |
|
||||
| [`docs/decomposition/modules/E5_M1_CombatRulesEngine.md`](../decomposition/modules/E5_M1_CombatRulesEngine.md) | **Partially matches** — prototype notes paragraph updated for NEO-82; **Status** still reads “E5M1-07+ pending”; no **Related implementation slices** entry for E5M1-07 (NEO-78–NEO-81 pattern). |
|
||||
| [`docs/decomposition/modules/module_dependency_register.md`](../decomposition/modules/module_dependency_register.md) | **Partially matches** — E5.M1 note cites NEO-81; **NEO-82 landed** (cast → `combatResolution`, catalog cooldown) not yet added. |
|
||||
| [`docs/decomposition/modules/documentation_and_implementation_alignment.md`](../decomposition/modules/documentation_and_implementation_alignment.md) | **Partially matches** — E5.M1 row still ends with “accepts without **`CombatResolution`** yet”; should cite NEO-82 landed after merge. |
|
||||
| [`docs/decomposition/modules/client_server_authority.md`](../decomposition/modules/client_server_authority.md) | **Matches** — server validates and computes all combat outcomes; client unchanged (NEO-85). |
|
||||
| [`docs/decomposition/modules/pvp_combat_integration.md`](../decomposition/modules/pvp_combat_integration.md) | **N/A** — prototype NPC targets only. |
|
||||
| [`server/README.md`](../../server/README.md) | **Matches** — cast `combatResolution` table, `target_defeated` deny, catalog cooldown policy, combat engine cross-link. |
|
||||
| Full-stack epic decomposition | **Matches** — plan documents NEO-85 client counterpart; no Godot change in scope. |
|
||||
| Manual QA | **N/A** — kickoff skip; Bruno + README sufficient. |
|
||||
|
||||
## Blocking issues
|
||||
|
||||
None.
|
||||
|
||||
## Suggestions
|
||||
|
||||
1. **Module doc status + slice entry** — In `docs/decomposition/modules/E5_M1_CombatRulesEngine.md`, update **Status** to cite **E5M1-07 NEO-82 landed** (cast POST returns `combatResolution`), and add **E5M1-07 (NEO-82)** under **Related implementation slices** linking the plan and README ability-cast section (mirror NEO-81 landed pattern).
|
||||
|
||||
2. **Dependency register + alignment table** — Extend the **E5.M1 note** in `module_dependency_register.md` and the E5.M1 row in `documentation_and_implementation_alignment.md` with **NEO-82 landed:** `AbilityCastApi` → `CombatOperations.TryResolve`, nested `combatResolution`, per-ability catalog cooldown, `target_defeated` cast deny.
|
||||
|
||||
3. **Bruno defeat spine HP stepping** — Plan §6 calls for asserting HP 75 → 50 → 25 → 0 on casts 1–4; `Post cast lock pulse defeat spine.bru` only captures/asserts the fourth cast. Consider storing intermediate cast bodies in pre-request and asserting `targetRemainingHp` on each pulse for stronger manual lock-in (non-blocking — fifth deny + integration test cover the critical path).
|
||||
|
||||
## Nits
|
||||
|
||||
- Nit: `PostAbilityCast_ShouldDefeatTargetAfterFourPulses_ThenDenyTargetDefeated` runs pulses 1–3 inside **Act**; move them to **Arrange** for stricter AAA (same note as NEO-81 four-pulse pattern).
|
||||
|
||||
- Nit: After successful `TryResolve`, `TryGetDefinition` runs again solely for `CooldownSeconds` — `CombatOperations` already loaded the definition internally. Acceptable for thin handler clarity; optional future refactor if catalog lookups become hot-path.
|
||||
|
||||
- Nit: `AbilityPrototypeCooldown.GlobalDuration` is `[Obsolete]` but retained — matches plan; no remaining runtime references in tests or accept path.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
cd /home/don/neon-sprawl/server
|
||||
dotnet test NeonSprawl.Server.Tests/NeonSprawl.Server.Tests.csproj \
|
||||
--filter "FullyQualifiedName~AbilityCastApiTests|FullyQualifiedName~CooldownSnapshotApiTests"
|
||||
dotnet test NeonSprawl.Server.Tests/NeonSprawl.Server.Tests.csproj
|
||||
```
|
||||
|
||||
**AbilityCast + CooldownSnapshot tests:** 22/22 passed (local run).
|
||||
|
||||
**Full suite:** 394/394 passed (local run).
|
||||
|
||||
**Bruno (manual):** Run `bruno/neon-sprawl-server/ability-cast/` folder — happy cast + defeat spine (seq 23, ~10s pre-request cooldown waits).
|
||||
Loading…
Reference in New Issue