4.2 KiB
Code review: NEO-41 (gather interact → skill XP)
Date: 2026-05-10
Scope: Branch NEO-41-gather-loop-awards-skill-xp-activity (commits through c1e7728) vs origin/main. Linear issue NEO-41.
Base: origin/main
Follow-up: Suggestions and nits below are done (strikethrough + Done.).
Verdict
Approve — Implementation matches the adopted plan; review nits and optional test suggestion addressed in follow-up commit.
Summary
This work introduces shared SkillProgressionGrantOperations.TryApplyGrant (extracted from NEO-38 POST handling), wires POST /game/players/{id}/interact to call it when the resolved prototype entry has kind: resource_node, using fixed salvage + activity + 10 XP via GatherSkillXpConstants. Denied grants and missing progression store are intentionally silent on the interact path (outcome remains allowed), matching the plan. NEO-40 telemetry hook comments now live on the shared grant path so both HTTP POST and interact-triggered grants see the same hook sites. Docs, Bruno requests, manual QA, and decomposition updates accompany the code. Risk: Low; behavior is additive, authority remains server-side, and 136 server tests pass (dotnet test NeonSprawl.sln).
Documentation checked
docs/plans/NEO-41-implementation-plan.md— matches (prototyperesource_nodeinteract, shared grant path, silent no-op on deny/store miss, 10 XP,salvage+activity, constants/registry usage, tests and manual QA listed).docs/decomposition/modules/module_dependency_register.md— matches (E3.M1 row moved to In Progress; E2.M2 note consistent with NEO-41).docs/decomposition/modules/documentation_and_implementation_alignment.md— matches (E2.M2 / E3.M1 tracking rows updated for NEO-41).docs/decomposition/modules/E2_M2_XpAwardAndLevelEngine.md— matches (NEO-41 implementation snapshot paragraph).docs/decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md— Matches — Summary Status set to In Progress (aligned with register); prototype anchor paragraph retained.docs/manual-qa/NEO-41.md— matches intent (move → interact → GET progression).server/README.md(diff) — matches plan (prototype gather XP pointer).- Cross-cutting
client_server_authority.md/contracts.md— N/A for this slice (no new client authority; HTTP spikes unchanged in contract “Ready” sense).
Register / tracking: Implementation tracking table + register updated; E3.M1 module Summary Status aligned with register in follow-up.
Blocking issues
None.
Suggestions
-
Optional test from plan: The implementation plan called out an optional unit/integration test for a “corrupt catalog” / disallowedDone. (sourceKindpath ensuring the interact handler does not throw and still returnsAllowed: true. The current tests cover terminal (no XP) and resource node (XP) happy paths; a focused test with a stub registry that deniesactivityforsalvagewould fully close the stated defensive scenario without needing production catalog corruption.SalvageActivityDeniedRegistryWebApplicationFactory+PostInteract_ResourceNode_WhenSalvageDisallowsActivity_ShouldStillAllowInteract_AndNotApplyXp.) -
E3.M1 Summary table: Update the Status field inDone.docs/decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.mdfrom Planned to In Progress so it matchesmodule_dependency_register.mdand documentation_and_implementation_alignment.md (“Summary table Status field should match the register row”).
Nits
Nit:Done. (Comment on interact path in_ = SkillProgressionGrantOperations.TryApplyGrant(...)is clear enough; if the team prefers explicit fire-and-forget documentation, a one-line comment that the outcome is intentionally ignored on the interact path could mirror the plan wording (optional).InteractionApi.cs.)
Verification
dotnet test NeonSprawl.sln— passed (136 tests) after follow-up.- Manual: follow
docs/manual-qa/NEO-41.mdand/or Bruno flows underbruno/neon-sprawl-server/position/andbruno/neon-sprawl-server/interaction/for end-to-end smoke.