# Code review — NEO-43 (mission / quest reward skill XP prep)

**Date:** 2026-05-15

**Scope:** Branch `NEO-43-mission-quest-rewards-skill-xp` (commits on top of `origin/main` through `2af9b1c`), working tree clean at review time. Issue **NEO-43**.

**Base:** `origin/main`

## Verdict

**Approve**

## Summary

The branch adds a small **NEO-42-style** server prep slice: `MissionRewardSkillXpConstants`, `MissionRewardSkillXpGrant.GrantFromMissionReward` delegating to `SkillProgressionGrantOperations.TryApplyGrant` with fixed `sourceKind: mission_reward`, a denied-registry `WebApplicationFactory` plus three tests, manual QA, README, implementation plan, and an **E7.M2** decomposition anchor. Behavior matches the NEO-38 grant stack and prototype catalog (`salvage` allows `mission_reward`). Risk is low: additive API, no new HTTP routes, helper unused until E7.M2 wires quest payout.

## Documentation checked

| Document | Assessment |
|----------|------------|
| `docs/plans/NEO-43-implementation-plan.md` | **Matches** — helper, constants, factory pattern, tests (happy + GET alignment + deny), README, manual QA, E7 anchor align with plan and kickoff decisions. |
| `docs/decomposition/modules/E7_M2_RewardAndUnlockRouter.md` | **Matches** — new **Implementation anchor (server)** points to `MissionRewardSkillXpGrant.GrantFromMissionReward` and the NEO-43 plan. |
| `docs/decomposition/modules/module_dependency_register.md` | **N/A for code conflict** — E7.M2 remains **Planned**; prep hook does not require register churn. Optional follow-up: if the team treats any server hook toward E7.M2 as “started,” consider **In Progress** + Summary sync (not required for correctness). |
| `docs/decomposition/modules/documentation_and_implementation_alignment.md` | **Matches** — E2.M2 row updated: **NEO-43 landed** (prep) + **Slice 3 still open** lists **NEO-44** only. |
| `docs/decomposition/modules/E2_M2_XpAwardAndLevelEngine.md` | **N/A** — not edited; NEO-43 correctly extends the existing POST/grant story via shared operations. |
| `docs/game-design/progression.md` (referenced) | **Matches** — README / manual QA echo mission vs combat XP separation. |

~~**Register / tracking table:** Updating **`documentation_and_implementation_alignment.md`** (E2.M2 snapshot) is the main doc hygiene gap; see suggestions.~~ **Done.** (E2.M2 row updated; see **Suggestions** §1.)

## Blocking issues

_None._

## Suggestions

1. ~~**Implementation tracking table** — In `docs/decomposition/modules/documentation_and_implementation_alignment.md`, the **E2.M2** row still says **Slice 3 still open** and links NEO-43 as future work. After this story merges, add a **NEO-43 landed** line (mirror NEO-42: `MissionRewardSkillXpGrant`, tests, manual QA, README) and adjust the “still open” list so the inventory matches the repo (per **Status column** rule in that file).~~ **Done.** E2.M2 row: NEO-43 landed (prep) + Slice 3 still open → NEO-44 only; References column includes [NEO-43 plan](../plans/NEO-43-implementation-plan.md).

2. ~~**E7.M2 Summary table (optional)** — `E7_M2_RewardAndUnlockRouter.md` **Status** remains **Planned** in the Summary table, consistent with the register. No change required unless you want a one-line note under Summary that server-side **skill XP from quest bundles** has a named hook (the new anchor already covers this).~~ **Done.** Status cell notes NEO-43 prep hook; module remains Planned.

## Nits

- ~~**Nit:** In `NEO-43-implementation-plan.md` **Technical approach** §1, the constant is named `MissionRewardSourceKind` in code, not `SourceKind` as in one plan sentence — trivial naming drift inside the plan only.~~ **Done.** Plan now references `MissionRewardSkillXpConstants.MissionRewardSourceKind` (matches `MissionRewardSkillXpConstants.cs`).

## Verification

Already run during review:

```bash
cd server && dotnet test NeonSprawl.Server.Tests/NeonSprawl.Server.Tests.csproj --filter "FullyQualifiedName~MissionRewardSkillXpGrantTests"
```

Author should run full `dotnet test` on `NeonSprawl.Server.Tests` before merge if not already part of CI. Manual spot-check: follow `docs/manual-qa/NEO-43.md` (move + POST `mission_reward` + deny control with `trainer`).
