neon-sprawl/docs/reviews/2026-05-28-NEO-95.md

4.9 KiB
Raw Blame History

Code review — NEO-95 (E5M2-09)

Date: 2026-05-28
Scope: Branch NEO-95-npc-attack-resolve-player-hp vs origin/main — commits ac4e1dfb702d9f
Base: origin/main

Follow-up: Suggestions and nits addressed in review follow-up commit; re-verified 2026-05-28.

Verdict

Approve

Summary

NEO-95 delivers the server slice cleanly: IPlayerCombatHealthStore (lazy-init 100 HP, damage floor, dev reset) mirrors the NPC ICombatEntityHealthStore pattern; NpcAttackOperations.TryResolveTelegraphComplete re-checks the threat holder before applying catalog attackDamage; NpcRuntimeOperations.AdvanceAll invokes resolve at telegraph windup completion and passes the store from NpcRuntimeSnapshotWorldApi poll; GET /game/players/{id}/combat-health gates on position row (same as cooldown snapshot) and returns schema v1 JSON. Dev fixture reset restores player HP. Tests cover store unit behavior, resolve no-ops, runtime windup→damage wiring, integration elite timeline (FakeClock 7.5 s → 75 HP), fixture reset, and Bruno smoke with documented sleep(8000). Build succeeds; NEO-95-filtered tests pass (40/40). Server-only scope — client HUD correctly deferred to NEO-97.

Documentation checked

Path Result
docs/plans/NEO-95-implementation-plan.md Matches — AC checkboxes done; dedicated GET (kickoff), damage flow, holder re-check, fixture reset, tests, and file list align with the diff.
docs/plans/E5M2-prototype-backlog.md (E5M2-09) Matches — AC checked, landed note present; client counterpart NEO-97 called out.
docs/decomposition/modules/E5_M2_NpcAiAndBehaviorProfiles.md Matches — NEO-95 implementation section + README/Bruno links; Summary Status marks E5M2-09 landed.
docs/decomposition/modules/documentation_and_implementation_alignment.md Matches — E5.M2 row includes NEO-95 landed (IPlayerCombatHealthStore, combat-health GET, Bruno folder, plan/README links).
docs/decomposition/modules/client_server_authority.md Matches — server owns NPC→player damage; client poll-only read model; no client damage math.
server/README.md Matches — session player combat HP section, GET route, fixture reset note, npc-runtime snapshot cross-link updated.

Blocking issues

None.

Suggestions

  1. Update documentation_and_implementation_alignment.md — Append NEO-95 landed to the E5.M2 tracking row (IPlayerCombatHealthStore, NpcAttackOperations, GET …/combat-health, Bruno combat-health/, plan/README links), matching NEO-87NEO-94 entries. Listed implicitly by review checklist; not in the NEO-95 plan “Files to modify” table but keeps alignment doc truthful. Done. (5efa5a4)

  2. E5.M2 Summary status table — Mark E5M2-09 / NEO-95 landed inline in the module Summary Status row (currently jumps from “NEO-94 runtime snapshot GET landed” to “NEO-95 NPC attack resolve + player combat HP → E5M2-12” without “landed”). Done. (5efa5a4)

Nits

  • Nit: NpcBehaviorState.AttackExecute branch in NpcRuntimeOperations is unreachable in the normal windup→recover flow (NEO-93); harmless defensive path but could carry a one-line comment or be removed until a visible execute phase is needed. Done. — one-line comment added.

  • Nit: PlayerCombatHealthApi.BuildResponse echoes normalized lowercase snapshot.PlayerId while CooldownSnapshotApi echoes the route {id} as provided — consistent for prototype lowercase ids; note if mixed-case route ids become a concern. Done.BuildResponse now echoes route {id} like cooldown snapshot.

  • Nit: Elite integration test GetPlayerCombatHealth_ShouldDecreaseAfterEliteTelegraphComplete performs setup GETs in Arrange (acceptable for multi-poll timeline); baseline/mid snapshot reads could move to Assert if stricter AAA parity with NEO-94 follow-up is desired. Done. — poll GETs kept in Arrange as timeline drivers only; ReadFromJsonAsync verification confined to Act/Assert.

Verification

# Build + NEO-95-related tests (passed 2026-05-28)
dotnet build NeonSprawl.sln
dotnet test server/NeonSprawl.Server.Tests/NeonSprawl.Server.Tests.csproj \
  --filter "FullyQualifiedName~PlayerCombatHealth|FullyQualifiedName~NpcAttackOperations|FullyQualifiedName~CombatTargetFixture|FullyQualifiedName~NpcRuntimeOperations"

# Full server suite (Postgres persistence tests require local DB)
dotnet test server/NeonSprawl.Server.Tests/NeonSprawl.Server.Tests.csproj

# Bruno (CI runs entire bruno/neon-sprawl-server/)
# bruno/neon-sprawl-server/combat-health/

Manual: run Get combat health after elite attack.bru against dev server — after ~8 s wait, currentHp should be 75 with elite cast accepted on prototype_npc_elite.