5.9 KiB
Code review — NEO-117 (E7M1-06)
Date: 2026-06-06
Scope: Branch NEO-117-quest-state-operations vs origin/main — commits 44ef5f2 … f053ffb
Base: origin/main
Verdict
Approve with nits
Summary
NEO-117 adds QuestStateOperations — static accept, step advance, and complete wrappers over IPlayerQuestStateStore with QuestStateReasonCodes and QuestStateOperationResult, mirroring the NEO-104/105 encounter store + operations pattern. Prerequisite enforcement reads catalog prerequisiteQuestIds; complete is idempotent at the operations layer (replay → Success: true with unchanged snapshot), including a defensive re-read after store denial for concurrent complete. Fifteen AAA tests cover accept prerequisites/denials, advance bounds, idempotent complete, and host DI smoke via InMemoryWebApplicationFactory. server/README.md documents operations and reason codes. Server-only infrastructure — correct scope; HTTP and objective wiring remain deferred. Risk is low; main follow-ups are test helper consistency, minor coverage gaps, and post-merge decomposition register updates.
Documentation checked
| Path | Result |
|---|---|
docs/plans/NEO-117-implementation-plan.md |
Matches — kickoff decisions adopted; acceptance checklist checked; reconciliation accurate. |
docs/plans/E7M1-prototype-backlog.md (E7M1-06) |
Matches — E7M1-06 acceptance checkboxes checked. |
docs/decomposition/modules/E7_M1_QuestStateMachine.md |
Matches — NEO-117 operations bullet + README link added. |
docs/decomposition/modules/documentation_and_implementation_alignment.md |
Matches — E7M1-06 / NEO-117 landed note appended. |
docs/decomposition/modules/module_dependency_register.md |
Matches — NEO-117 note appended. |
server/README.md |
Matches — quest operations section, reason-code table, idempotent complete semantics, HTTP deferral to NEO-119/NEO-120. |
| Full-stack epic decomposition | N/A — server-only; client counterpart explicitly NEO-120/NEO-122; plan does not claim prototype slice complete. |
Register / tracking: E7.M1 register row and module Status should gain an E7M1-06 / NEO-117 landed bullet after merge (register stays Planned until E7M1-07+ runtime and client capstone).
Blocking issues
(none)
Bugbot follow-up (2026-06-06)
-
TryActivate failure misclassified — Map store mutation failures from returned snapshots / re-read progress instead of alwaysDone.unknown_player.DenyActivateFailure/DenyAdvanceFailurehelpers; store replay onTryMarkCompletereturns idempotent success. -
Unknown player wrong deny code — CheckDone. AddedCanWritePlayerbefore prerequisite gate so unknown players getunknown_player, notprerequisite_incomplete.IPlayerQuestStateStore.CanWritePlayer(in-memory + Postgres);TryAcceptcalls it before prerequisites.
Suggestions
-
TestDone.ResolveDependenciespattern —QuestStateOperationsTests.ResolveDependenciescreates anIServiceScopethat is never disposed.EncounterCompletionOperationsTestsresolves fromfactory.Servicesroot (singleton stores). Align to avoid undisposed scopes and match the established encounter test pattern.ResolveDependenciesand host smoke test resolve fromfactory.Services. -
Done. Addedunknown_questcoverage on advance/complete — Accept path hasTryAccept_ShouldDenyUnknownQuest_WhenQuestIdNotInCatalog; advance and complete lack parity. Add two small[Fact]cases (mirrorEncounterCompletionOperationsTestsunknown-encounter test) for registry gate consistency.TryAdvanceStep_ShouldDenyUnknownQuest_WhenQuestIdNotInCatalogandTryMarkComplete_ShouldDenyUnknownQuest_WhenQuestIdNotInCatalog. -
Post-merge decomposition docs — Plan defers register/module updates; on story end append E7M1-06 / NEO-117 toDone. Alignment register, module doc, dependency register note, and E7M1-06 backlog checkboxes updated.documentation_and_implementation_alignment.md,E7_M1_QuestStateMachine.md(operations bullet + README link), and check E7M1-06 AC boxes inE7M1-prototype-backlog.md.
Nits
-
Nit:Done. Replaced switch with explicitTryAcceptprogress switch default_ => Deny(UnknownQuest)is unreachable whileQuestProgressStatusis onlyActive/Completed; if kept for exhaustiveness, a more accurate code (orNotActive) would aid future enum extensions.Completed/AlreadyActivebranches. -
Nit: Chain-quest setup tests hardcodeDone. Addedprototype_quest_combat_introandprototype_quest_refine_intro; plan deferredRefineIntroQuestId/CombatIntroQuestIdconstants — acceptable for now, but NEO-118 wiring will reuse these ids.RefineIntroQuestIdandCombatIntroQuestIdtoPrototypeE7M1QuestCatalogRules; tests updated. -
Nit:Done. SingleTryMarkCompletere-callsTryGetProgressafter the active-row read (lines 117–118) whereactivecould be reused on thenot_activedeny path — minor readability only.TryGetProgressread at start ofTryMarkComplete.
Verification
# Quest state operations (primary signal for this story)
cd server
dotnet test NeonSprawl.Server.Tests/NeonSprawl.Server.Tests.csproj \
--filter "FullyQualifiedName~QuestStateOperationsTests"
# Quest store regression (precursor)
dotnet test NeonSprawl.Server.Tests/NeonSprawl.Server.Tests.csproj \
--filter "FullyQualifiedName~InMemoryPlayerQuestStateStoreTests|FullyQualifiedName~PlayerQuestProgressPersistence"
# Full server suite (CI)
dotnet test NeonSprawl.Server.Tests/NeonSprawl.Server.Tests.csproj
Reviewer note: All 15 QuestStateOperationsTests and full server suite (663 tests) passed locally during review.
Manual: None required — no HTTP or player-visible surface in this story.