neon-sprawl/docs/reviews/2026-05-30-NEO-100.md

4.7 KiB

Code review — NEO-100 (E5M3-01)

Date: 2026-05-30
Scope: Branch NEO-100-e5m3-encounter-reward-catalog-schemas-ci vs cb86645 (merge-base on main) — commits 4f16c84ee5e1a0
Base: cb86645 (main after PR #138)

Verdict

Approve — review follow-up applied (2026-05-30).

Summary

NEO-100 delivers the E5M3-01 content spine: three JSON Schemas (encounter-def, reward-table, reward-grant-row), prototype catalog files with the frozen prototype_combat_pocket encounter and prototype_combat_pocket_clear reward table, and scripts/validate_content.py extensions mirroring the NEO-87 / NEO-76 catalog pattern (schema validation, duplicate id rejection, prototype id allowlists, item / NPC instance / reward-table cross-refs, reward-table-before-encounter ordering). Documentation updates match the shipped artifacts. Review follow-ups (dependency register sync, duplicate fixedGrants rejection, uniqueItems on NPC ids, plan audit note) are Done.

Documentation checked

Path Result
docs/plans/NEO-100-implementation-plan.md Matches — scope, constants, file list, acceptance checklist, and implementation reconciliation align with the diff.
docs/plans/E5M3-prototype-backlog.md (E5M3-01) Matches — three AC items checked; landed note cites schemas, catalogs, and CI gates.
docs/decomposition/modules/E5_M3_EncounterAndRewardTables.md Matches — CI enforcement paragraph under freeze table; ids and cross-ref rules match validate_content.py constants.
docs/decomposition/modules/CT_M1_ContentValidationPipeline.md Matches — reward-table and encounter catalog paragraphs added with correct schema paths and gate semantics.
docs/decomposition/modules/documentation_and_implementation_alignment.md Matches — E5.M3 row notes NEO-100 catalog landed; server load still outstanding.
docs/decomposition/modules/module_dependency_register.md Matches — E5.M3 note cites NEO-100 catalog landed; server load still outstanding.
content/README.md Matches — NEO-100 paragraph and table rows for encounters/ / reward-tables/ match shipped ids and cross-ref rules (plan “verify only”).
Full-stack epic decomposition N/A — plan explicitly excludes client counterpart until E5M3-08+ / NEO-110 / NEO-111; no player-visible claim in this story.
server/NeonSprawl.Server/Game/Npc/PrototypeNpcRegistry.cs Matches (cross-ref) — CI PROTOTYPE_E5M2_NPC_INSTANCE_IDS matches server constants (prototype_npc_melee, prototype_npc_ranged, prototype_npc_elite).

Blocking issues

None.

Suggestions

  1. Update module_dependency_register.md E5.M3 note — Replace “implementation not started” with E5M3-01 / NEO-100 catalog landed (schemas + CI); server load/runtime still NEO-101+. Keeps register consistent with documentation_and_implementation_alignment.md and E5.M3 module doc. Done.

  2. Duplicate fixedGrants rows_prototype_e5m3_reward_grant_content_gate folds grants into a dict (last row wins). Duplicate itemId rows that merge to the frozen quantities pass CI (verified locally). For NEO-101 loader clarity, consider rejecting duplicate itemId in fixedGrants (schema uniqueItems on a composite key is awkward; a small loop in the grant gate matches mastery perkId duplicate rejection). Same pattern gap exists on recipe I/O rows — optional to defer until roster expansion. Done. _validate_reward_table_catalogs rejects duplicate itemId per table; E5.M3 + CT.M1 docs updated. Recipe I/O duplicate deferral unchanged.

Nits

  • Nit: requiredNpcInstanceIds schema omits uniqueItems: true; the set-equality gate catches wrong sets for the one-row prototype, but adding uniqueItems would fail fast on duplicate ids before the custom gate (and documents intent for NEO-101). Done.

  • Nit: Plan item 7 lists content/README.md verify — reconciliation section could explicitly note “verified, no edit required” for audit trail (optional). Done.

Verification

# Primary regression (also runs in PR gate)
python3 scripts/validate_content.py

# Manual negative spot-checks (from plan)
# 1. Duplicate encounter or reward-table id → non-zero exit
# 2. Remove frozen id from catalog → gate error
# 3. Unknown itemId in fixedGrants → cross-ref error
# 4. Wrong requiredNpcInstanceIds set → cross-ref error
# 5. Broken rewardTableId → cross-ref error
# 6. Invalid completionCriteria.kind or empty displayName → schema error

Before merge: Confirm PR gate green on the branch (validate_content.py is the sole automated test surface for this story).