5.8 KiB
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
Follow-up: Code review suggestions and nits addressed in follow-up commit on NEO-82-wire-ability-cast-combat-resolution. Bugbot + CI fixes in 52bf9fc (definition-before-resolve; Bruno beta/alpha isolation).
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 |
Matches — kickoff decisions, scope, acceptance checklist, expected cast table, and reconciliation align with code. |
docs/plans/E5M1-prototype-backlog.md · E5M1-07 |
Matches — AC checked, landed note added. |
docs/decomposition/modules/E5_M1_CombatRulesEngine.md |
Matches — Status cites E5M1-07 NEO-82 landed; Related implementation slices entry added. |
docs/decomposition/modules/module_dependency_register.md |
Matches — E5.M1 note includes NEO-82 landed. |
docs/decomposition/modules/documentation_and_implementation_alignment.md |
Matches — E5.M1 row cites NEO-82 cast → combatResolution. |
docs/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 |
N/A — prototype NPC targets only. |
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
-
Module doc status + slice entry — InDone.docs/decomposition/modules/E5_M1_CombatRulesEngine.md, update Status to cite E5M1-07 NEO-82 landed (cast POST returnscombatResolution), and add E5M1-07 (NEO-82) under Related implementation slices linking the plan and README ability-cast section (mirror NEO-81 landed pattern). -
Dependency register + alignment table — Extend the E5.M1 note inDone.module_dependency_register.mdand the E5.M1 row indocumentation_and_implementation_alignment.mdwith NEO-82 landed:AbilityCastApi→CombatOperations.TryResolve, nestedcombatResolution, per-ability catalog cooldown,target_defeatedcast deny. -
Bruno defeat spine HP stepping — Plan §6 calls for asserting HP 75 → 50 → 25 → 0 on casts 1–4;Done. —Post cast lock pulse defeat spine.bruonly captures/asserts the fourth cast. Consider storing intermediate cast bodies in pre-request and assertingtargetRemainingHpon each pulse for stronger manual lock-in (non-blocking — fifth deny + integration test cover the critical path).neo82CastResultsstores all four casts; tests assert HP stepping.
Nits
-
Nit:Done. — Pulses 1–3 in Arrange; Act is 4th + 5th cast; Assert includes HP stepping.PostAbilityCast_ShouldDefeatTargetAfterFourPulses_ThenDenyTargetDefeatedruns pulses 1–3 inside Act; move them to Arrange for stricter AAA (same note as NEO-81 four-pulse pattern). -
Nit: After successfulDone. —TryResolve,TryGetDefinitionruns again solely forCooldownSeconds—CombatOperationsalready loaded the definition internally. Acceptable for thin handler clarity; optional future refactor if catalog lookups become hot-path. Deferred — no hot-path concern in prototype.TryGetDefinitionmoved beforeTryResolveso cooldown lookup cannot deny after HP mutation (Bugbot fix). -
Nit:
AbilityPrototypeCooldown.GlobalDurationis[Obsolete]but retained — matches plan; no remaining runtime references in tests or accept path. No action — intentional per plan.
Verification
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).