neon-sprawl/docs/plans/NEO-76-implementation-plan.md

9.5 KiB
Raw Blame History

NEO-76 — Implementation plan

Story reference

Field Value
Key NEO-76
Title E5M1-01: Prototype AbilityDef catalog + schemas + CI
Linear https://linear.app/neon-sprawl/issue/NEO-76/e5m1-01-prototype-abilitydef-catalog-schemas-ci
Module E5.M1 — CombatRulesEngine · Epic 5 Slice 1 · backlog E5M1-01
Branch NEO-76-e5m1-prototype-backlog
Precursor E1.M4 — hardcoded allowlist in PrototypeAbilityRegistry (unchanged this story)
Pattern NEO-50 / NEO-65 — row JSON Schema + catalog envelope + scripts/validate_content.py gate
Blocks NEO-77 — server ability catalog load

Kickoff clarifications

Topic Question Agent recommendation Answer
Prototype stat freeze baseDamage / cooldownSeconds / abilityKind per row? Recommended table — pulse 25 dmg / 3.0s; burst 40 / 5.0; guard 0 / 6.0 utility; dash 0 / 4.0 movement; four pulse casts = 100 HP dummy defeat; pulse cooldown matches NEO-32 global 3s. User: recommended table (adopted below).
abilityKind on rows Required on all four prototype rows? Include on all four — optional in schema but aids E5M1-04 GET / E5M1-11 HUD without follow-up schema churn. Adopted (bundled with stat freeze).
Catalog envelope File shape? { "schemaVersion": 1, "abilities": [ … ] } in content/abilities/prototype_abilities.json (mirror items / recipes). Adopted (NEO-50 / NEO-65 precedent).
CI constant name Slice gate identifier? PROTOTYPE_E5M1_ABILITY_IDS — Epic 5 Slice 1; avoids collision with economy Slice 14 numbering in validate_content.py. Adopted.

Goal, scope, and out-of-scope

Goal: Lock content shape and CI validation for four frozen AbilityDef rows before server load (NEO-77+).

In scope (from Linear + E5M1-01):

  • content/schemas/ability-def.schema.json.
  • content/abilities/prototype_abilities.json — four frozen ids (freeze table below).
  • scripts/validate_content.py — schema validation, duplicate id, exact four-id allowlist, non-empty displayName.
  • Designer note + Prototype Slice 1 freeze table in E5_M1 + content/README.md.
  • CT.M1 PR gate paragraph for ability catalogs.
  • documentation_and_implementation_alignment.md E5.M1 row → In Progress / NEO-76.

Out of scope (from Linear):

  • Server loader, combat engine, HTTP, Godot (NEO-77+).
  • Changing PrototypeAbilityRegistry or global cooldown behavior (NEO-77 / E5M1-07).

Acceptance criteria checklist

  • PR gate validates ability JSON against schema.
  • Exactly four prototype ability ids; duplicate id fails CI.
  • Stable id list documented in module doc freeze box.

Implementation reconciliation (shipped)

  • Schema: ability-def.schema.json — required id, displayName, baseDamage, cooldownSeconds; optional abilityKind.
  • Catalog: prototype_abilities.json — four frozen rows per kickoff stat table.
  • CI: PROTOTYPE_E5M1_ABILITY_IDS gate in validate_content.py.
  • Docs: E5.M1 freeze table, content/README.md, CT.M1, alignment register, E5M1-01 backlog checkboxes.

Technical approach

  1. Row schema (ability-def.schema.json): Draft 2020-12 object; additionalProperties: false. Required: id, displayName, baseDamage, cooldownSeconds. id pattern ^[a-z][a-z0-9_]*$. displayName minLength: 1. baseDamage integer ≥ 0. cooldownSeconds number exclusiveMinimum 0 (positive). Optional: abilityKind enum attack | utility | movement (present on all four prototype rows).

  2. Catalog file: content/abilities/prototype_abilities.json with schemaVersion: 1 and four rows from the freeze table.

  3. Frozen content values (E5M1-01 — kickoff adopted):

    AbilityDef.id displayName baseDamage cooldownSeconds abilityKind
    prototype_pulse Prototype Pulse 25 3.0 attack
    prototype_burst Prototype Burst 40 5.0 attack
    prototype_guard Prototype Guard 0 6.0 utility
    prototype_dash Prototype Dash 0 4.0 movement

    Rules: Do not rename id values after ship — change displayName only, or add a new id in a follow-up issue. Relaxing the four-id CI gate requires a new Linear issue. prototype_pulse at 25 dmg × 4 casts = 100 HP dummy defeat (E5M1 backlog max HP default). prototype_pulse cooldown 3.0s matches current AbilityPrototypeCooldown.GlobalDuration until E5M1-07 switches to per-ability catalog cooldowns.

  4. validate_content.py:

    • Add ABILITY_SCHEMA, ABILITIES_DIR; discover content/abilities/*_abilities.json.
    • _validate_ability_catalogs: envelope schemaVersion: 1, top-level abilities array; validate each row against ability-def.schema.json; track seen_ids; reject duplicates across files.
    • _prototype_e5m1_ability_gate: ids must equal PROTOTYPE_E5M1_ABILITY_IDS (frozenset of four ids above).
    • Run ability validation after existing catalogs succeed (no cross-catalog refs in Slice 1).
    • Require ability schema file in main() startup checks; extend module docstring + success summary with ability file + id counts.
    • Keep PROTOTYPE_E5M1_ABILITY_IDS in sync with E5.M1 freeze table and future NEO-77 server loader.
  5. Docs:

    • content/README.md — add abilities/ table row + E5 Slice 1 freeze paragraph.
    • E5_M1_CombatRulesEngine.md — add Prototype Slice 1 freeze (E5M1-01) subsection with id + stat table + CI rules line.
    • CT_M1_ContentValidationPipeline.md — ability catalog PR gate paragraph.
    • documentation_and_implementation_alignment.md — E5.M1 row → In Progress / NEO-76 catalog landed.
    • E5M1-prototype-backlog.md — E5M1-01 checkboxes when implementation completes.
  6. No server/C#/client changes in this story.

Files to add

Path Purpose
content/schemas/ability-def.schema.json JSON Schema for a single AbilityDef row.
content/abilities/prototype_abilities.json Prototype four-ability catalog (schemaVersion + abilities array).
docs/plans/NEO-76-implementation-plan.md This plan.

Files to modify

Path Rationale
scripts/validate_content.py Load/validate ability catalogs; duplicate id; E5M1 four-id gate; success summary.
content/README.md Document content/abilities/, schema path, E5 Slice 1 freeze (active catalog).
docs/decomposition/modules/E5_M1_CombatRulesEngine.md Freeze table + CI enforcement note; link to plan when complete.
docs/decomposition/modules/CT_M1_ContentValidationPipeline.md PR gate paragraph for ability catalog validation.
docs/decomposition/modules/documentation_and_implementation_alignment.md E5.M1 / NEO-76 status after catalog lands.
docs/plans/E5M1-prototype-backlog.md E5M1-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 ability id → non-zero exit; (2) remove one frozen id → gate error; (3) break schema (negative baseDamage or zero cooldownSeconds) → schema error; (4) empty displayName → schema error.
Manual happy path pip install -r scripts/requirements-content.txt && python3 scripts/validate_content.py — reports ability catalog + existing catalogs OK.

No dedicated pytest module in-repo today (same as NEO-50 / NEO-65).

Open questions / risks

Question / risk Agent recommendation Status
Catalog growth E5M1 gate requires exactly the four frozen ids; expanding the roster needs a follow-up issue to change PROTOTYPE_E5M1_ABILITY_IDS. adopted
C# vs Python drift None until NEO-77; document “keep in sync” constant names in both places when server load lands (mirror NEO-66 / PrototypeSlice3RecipeCatalogRules). adopted
Runtime still uses global 3s cooldown Expected — content lands before E5M1-07 wires per-ability cooldownSeconds; pulse 3.0s pre-aligns catalog with NEO-32 behavior. adopted
Zero-damage guard/dash before E5M1-06 Catalog values are forward-looking; cast accept path still has no damage until E5M1-07. Zero-damage rows support E5M1-06 unit tests. adopted

None blocking.