10 KiB
NEO-87 — Implementation plan
Story reference
| Field | Value |
|---|---|
| Key | NEO-87 |
| Title | E5M2-01: Prototype NpcBehaviorDef catalog + schemas + CI |
| Linear | https://linear.app/neon-sprawl/issue/NEO-87/e5m2-01-prototype-npcbehaviordef-catalog-schemas-ci |
| Module | E5.M2 — NpcAiAndBehaviorProfiles · Epic 5 Slice 2 · backlog E5M2-01 |
| Branch | NEO-87-e5m2-npc-behavior-catalog-schemas-ci |
| Precursor | E5.M1 Ready — passive dummies remain until E5M2-05 |
| Pattern | NEO-76 — row JSON Schema + catalog envelope + scripts/validate_content.py gate |
| Blocks | NEO-88 — server NPC behavior catalog load |
Kickoff clarifications
| Topic | Question | Agent recommendation | Answer |
|---|---|---|---|
| Radius / cooldown stat freeze | aggroRadius, leashRadius, attackCooldownSeconds per archetype? |
Archetype-specific table — melee 8/16/3.0 · ranged 10/20/4.0 · elite 8/18/5.0; radii sit above 6 m tab-lock; leash > aggro for anti-kite. | User: archetype-specific table (adopted below). |
| Catalog envelope | File shape? | { "schemaVersion": 1, "npcBehaviors": [ … ] } in content/npc-behaviors/prototype_npc_behaviors.json (mirror abilities / items). |
Adopted (NEO-76 precedent). |
| CI constant name | Slice gate identifier? | PROTOTYPE_E5M2_NPC_BEHAVIOR_IDS — Epic 5 Slice 2; avoids collision with E5M1 ability gate. |
Adopted. |
| Client counterpart | Godot issue for this story? | None — server-only content + CI; player-visible work starts at E5M2-04+ / NEO-97 / NEO-98. | Adopted (E5M2-01 out of scope). |
Goal, scope, and out-of-scope
Goal: Lock content shape and CI validation for three frozen NpcBehaviorDef rows before server load (NEO-88+).
In scope (from Linear + E5M2-01):
content/schemas/npc-behavior-def.schema.json.content/npc-behaviors/prototype_npc_behaviors.json— three frozen ids (full freeze table below).scripts/validate_content.py— schema validation, duplicateid, exact three-id allowlist, positive numeric guards (leashRadius>aggroRadius).- Expand Prototype Slice 2 freeze table in E5_M2 + designer note in
content/README.md. - CT.M1 PR gate paragraph for NPC behavior catalogs.
documentation_and_implementation_alignment.mdE5.M2 row → note NEO-87 catalog in progress / landed.
Out of scope (from Linear):
- Server loader, runtime engine, HTTP, Godot (NEO-88+).
- NPC instance registry / dummy migration (E5M2-05).
Acceptance criteria checklist
- PR gate validates NPC behavior JSON against schema.
- Exactly three prototype behavior ids; duplicate
idfails CI. - Stable id list documented in module doc freeze box.
Implementation reconciliation (shipped)
- Schema:
npc-behavior-def.schema.json— requiredid,displayName,archetypeKind,maxHp,aggroRadius,leashRadius,telegraphWindupSeconds,attackDamage,attackCooldownSeconds. - Catalog:
prototype_npc_behaviors.json— three frozen rows per kickoff stat table. - CI:
PROTOTYPE_E5M2_NPC_BEHAVIOR_IDSgate +leashRadius > aggroRadiusguard invalidate_content.py. - Docs: E5.M2 full freeze table,
content/README.md, CT.M1, alignment register, E5M2-01 backlog checkboxes.
Technical approach
-
Row schema (
npc-behavior-def.schema.json): Draft 2020-12 object;additionalProperties: false. Required:id,displayName,archetypeKind,maxHp,aggroRadius,leashRadius,telegraphWindupSeconds,attackDamage,attackCooldownSeconds.idpattern^[a-z][a-z0-9_]*$.displayNameminLength: 1.archetypeKindenummelee_pressure|ranged_control|elite_mini_boss.maxHpinteger ≥ 1.attackDamageinteger ≥ 1.aggroRadius,leashRadius,telegraphWindupSeconds,attackCooldownSecondsnumber withexclusiveMinimum: 0(strictly positive). -
Catalog file:
content/npc-behaviors/prototype_npc_behaviors.jsonwithschemaVersion: 1and three rows from the kickoff-adopted freeze table. -
Frozen content values (E5M2-01 — kickoff adopted):
NpcBehaviorDef.iddisplayNamearchetypeKindmaxHpaggroRadiusleashRadiustelegraphWindupSecondsattackDamageattackCooldownSecondsprototype_melee_pressureMelee Pressure melee_pressure100 8.0 16.0 1.5 15 3.0 prototype_ranged_controlRanged Control ranged_control80 10.0 20.0 2.0 12 4.0 prototype_elite_mini_bossElite Mini-Boss elite_mini_boss200 8.0 18.0 2.5 25 5.0 Rules: Do not rename frozen behavior
idvalues after ship — changedisplayNameonly, or add a newidin a follow-up issue. CI enforces exactly these three ids. Tune combat feel via numeric fields or new ids in a follow-up issue. -
validate_content.py:- Add
NPC_BEHAVIOR_SCHEMA,NPC_BEHAVIORS_DIR; discovercontent/npc-behaviors/*_npc_behaviors.json. _validate_npc_behavior_catalogs: envelopeschemaVersion: 1, top-levelnpcBehaviorsarray; validate each row againstnpc-behavior-def.schema.json; trackseen_ids; reject duplicates across files._prototype_e5m2_npc_behavior_gate: ids must equalPROTOTYPE_E5M2_NPC_BEHAVIOR_IDS(frozenset of three ids above)._prototype_e5m2_npc_behavior_numeric_gate: after schema pass, requireleashRadius > aggroRadiusper row (backlog anti-kite invariant).- Run NPC behavior validation after ability catalogs succeed (no cross-catalog refs in E5M2-01).
- Require NPC behavior schema file in
main()startup checks; extend module docstring + success summary with npc-behavior file + id counts. - Keep
PROTOTYPE_E5M2_NPC_BEHAVIOR_IDSin sync with E5.M2 freeze table and future NEO-88 server loader.
- Add
-
Docs:
content/README.md— addnpc-behaviors/table row + E5 Slice 2 NPC behavior freeze paragraph.E5_M2_NpcAiAndBehaviorProfiles.md— expand Prototype Slice 2 freeze (E5M2-01) table with full column set + CI rules line.CT_M1_ContentValidationPipeline.md— NPC behavior catalog PR gate paragraph.documentation_and_implementation_alignment.md— E5.M2 row notes NEO-87 catalog when complete.E5M2-prototype-backlog.md— E5M2-01 checkboxes when implementation completes.
-
No server/C#/client changes in this story.
Files to add
| Path | Purpose |
|---|---|
content/schemas/npc-behavior-def.schema.json |
JSON Schema for a single NpcBehaviorDef row. |
content/npc-behaviors/prototype_npc_behaviors.json |
Prototype three-behavior catalog (schemaVersion + npcBehaviors array). |
docs/plans/NEO-87-implementation-plan.md |
This plan. |
Files to modify
| Path | Rationale |
|---|---|
scripts/validate_content.py |
Load/validate NPC behavior catalogs; duplicate id; E5M2 three-id gate; leash > aggro guard; success summary. |
content/README.md |
Document content/npc-behaviors/, schema path, E5 Slice 2 freeze (active catalog). |
docs/decomposition/modules/E5_M2_NpcAiAndBehaviorProfiles.md |
Full freeze table + CI enforcement note; link to plan when complete. |
docs/decomposition/modules/CT_M1_ContentValidationPipeline.md |
PR gate paragraph for NPC behavior catalog validation. |
docs/decomposition/modules/documentation_and_implementation_alignment.md |
E5.M2 / NEO-87 status after catalog lands. |
docs/plans/E5M2-prototype-backlog.md |
E5M2-01 checkboxes + landed note when complete. |
Tests
| Item | Coverage |
|---|---|
| CI / PR gate | .github/workflows/pr-gate.yml already runs python scripts/validate_content.py — extended script is the regression signal. |
| Manual negative cases | From repo root after implementation: (1) duplicate behavior id → non-zero exit; (2) remove one frozen id → gate error; (3) break schema (zero aggroRadius or leashRadius <= aggroRadius) → schema or numeric gate error; (4) empty displayName → schema error. |
| Manual happy path | pip install -r scripts/requirements-content.txt && python3 scripts/validate_content.py — reports npc-behavior catalog + existing catalogs OK. |
No dedicated pytest module in-repo today (same as NEO-76 / NEO-50).
Open questions / risks
| Question / risk | Agent recommendation | Status |
|---|---|---|
| Catalog growth | E5M2 gate requires exactly the three frozen ids; expanding the roster needs a follow-up issue to change PROTOTYPE_E5M2_NPC_BEHAVIOR_IDS. |
adopted |
| C# vs Python drift | None until NEO-88; document “keep in sync” constant names in both places when server load lands (mirror NEO-77 / PROTOTYPE_E5M1_ABILITY_IDS). |
adopted |
| Radii vs tab-lock 6 m | aggroRadius 8–10 m keeps proximity re-aggro usable in the combat pocket without matching tab-lock exactly; E5M2-06 distance checks use behavior-def radii, not PrototypeTargetRegistry.SharedLockRadius. |
adopted |
| Runtime still uses alpha/beta dummies | Expected — content lands before E5M2-05 migrates combat targets to NPC instance ids. | adopted |
None blocking.