4.1 KiB
4.1 KiB
Code Review — NEO-39
- Date: 2026-05-06
- Scope: Working tree / unstaged changes for NEO-39 (
Data-driven skill level curve + CI validation) - Base:
main(inferred)
Verdict
Request changes.
Summary
The change successfully introduces data-driven skill level thresholds, adds CI validation for *_skills.json and *_level_curve.json, and wires runtime level resolution through ISkillLevelCurve. API behavior for progression GET/POST remains stable and test coverage is healthy overall, with full server test suite passing.
The main risk is a startup-validation gap: runtime curve loading currently performs custom checks instead of schema evaluation and therefore does not enforce schema constraints such as additionalProperties: false. That allows schema-invalid curve content to pass startup, which conflicts with the story’s fail-fast validation intent.
Documentation checked
docs/plans/NEO-39-implementation-plan.md— partially matches (most acceptance criteria are implemented; startup validation is not schema-equivalent to declared contract strictness).docs/decomposition/modules/E2_M2_XpAwardAndLevelEngine.md— matches (module snapshot updated for NEO-39 landed behavior).docs/decomposition/modules/module_dependency_register.md— matches (E2.M2 remains In Progress; dependencies/contract shape unchanged).docs/decomposition/modules/documentation_and_implementation_alignment.md— partially matches (E2.M2 tracking row still lists NEO-39 as follow-on; should be updated after merge to avoid stale status narrative).
Blocking issues
Runtime level-curve validation is not schema-equivalent, so schema-invalid files can still boot successfully.Evidence:server/NeonSprawl.Server/Game/Skills/ContentBackedSkillLevelCurve.csvalidates only selected fields manually and does not evaluatecontent/schemas/level-curve.schema.jsonconstraints likeadditionalProperties: false.Impact: Violates fail-fast startup validation intent for invalid curve content and can permit config drift between CI and runtime.Recommendation: Validate the loaded JSON againstDone. Startup load now evaluateslevel-curve.schema.jsonat startup (or implement strict parity checks for all schema constraints, including additional properties and structural limits), then keep existing domain checks (strictly increasing rows, first row = level 1 / xp 0).level-curve.schema.jsonviaJsonSchema.NetinContentBackedSkillLevelCurve.Load(...)before domain checks, andContentBackedSkillLevelCurveTests.Load_ShouldThrow_WhenCurveHasUnexpectedTopLevelPropertyverifiesadditionalProperties: falseenforcement.
Suggestions
Updatedocs/decomposition/modules/documentation_and_implementation_alignment.mdE2.M2 snapshot text to reflect that NEO-39 is landed (currently phrased as a follow-on item).
Done. E2.M2 tracking row now records NEO-39 as landed (data-drivenLevelCurve+ CI + fail-fast startup checks) and linksdocs/plans/NEO-39-implementation-plan.mdplusdocs/manual-qa/NEO-39.md.Refresh stale placeholder wording inserver/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantApiTests.cscomments (the threshold behavior is now content-backed, not placeholder-based).
Done. Updated the stale arrange comment inPostSkillProgression_ShouldReportLevelUps_WhenThresholdCrossedto reference content-backed thresholds fromprototype_level_curve.json.
Nits
Nit:SkillDefinitionCatalogLoaderXML summary still sayscontent/skills/*.json; implementation now intentionally scopes to*_skills.json.
Done. Updated XML summary inserver/NeonSprawl.Server/Game/Skills/SkillDefinitionCatalogLoader.cstocontent/skills/*_skills.json.
Verification
python3 scripts/validate_content.pydotnet test server/NeonSprawl.Server.Tests/NeonSprawl.Server.Tests.csproj --no-restore- Manual negative check: add an extra top-level property to
content/skills/prototype_level_curve.jsonand verify server startup fails (expected once runtime schema validation parity is implemented).