7.8 KiB
E2.M1 — SkillDefinitionRegistry
Summary
| Field | Value |
|---|---|
| Module ID | E2.M1 |
| Epic | Epic 2 — Skills and Progression Framework |
| Linear (Epic 2 project) | Epic 2 — Classless Skill and Progression Framework |
| Stage target | Prototype |
| Status | In Progress (see dependency register) |
Linear backlog (Epic 2 Slice 1)
Issues use label E2.M1. Dependency order: NEO-33 → NEO-34 → NEO-35 → NEO-36 (each issue’s description is canonical).
| Order | Issue | Summary |
|---|---|---|
| 1 | NEO-33 | Lock prototype SkillDef trio + CI catalog contract + designer note |
| 2 | NEO-34 | Server loads catalog at startup (fail-fast) |
| 3 | NEO-35 | SkillDefinitionRegistry service + lookup tests |
| 4 | NEO-36 | Read-only skill catalog HTTP projection + Bruno |
docs/plans/NEO-*-implementation-plan.md files should be added when implementation kicks off (per planning-implementation-docs).
Purpose
Central catalog for non-combat skill metadata: stable IDs, categories, allowed XP sources, and unlock prerequisites. All prototype activities reference skills by SkillDef.id validated against this registry. Combat role progression is not a SkillDef—use gig progression (docs/game-design/gigs.md).
Data contract (schema)
| Artifact | Path |
|---|---|
| JSON Schema | content/schemas/skill-def.schema.json |
| Sample catalog | content/skills/prototype_skills.json |
SkillDef fields (prototype):
| Field | Rule |
|---|---|
id |
Lowercase snake_case, immutable after ship. Used in saves, recipes, quests, XpGrantEvent.skillId, telemetry. Never rename to “fix” a skill—add a new id and migrate content if a skill splits. |
category |
One of gather | process | make | tech — aligned with docs/game-design/skills.md roster buckets (not gigs). |
displayName |
Player-facing string; may change without migrating progression data. |
allowedXpSourceKinds |
Non-empty set of grant channels E2.M2 may apply to this skill. Combat encounters must not use skill XP—those award gig XP; mission_reward covers explicit mission/contract skill payouts. |
allowedXpSourceKinds values:
| Kind | Meaning |
|---|---|
activity |
Primary loop (e.g. gather node complete, recipe craft complete, skill-based world interaction)—callers set XpGrantEvent.sourceKind to match. |
mission_reward |
Quest/contract hand-in or other scripted payout (docs/game-design/progression.md Mission rewards vs combat XP). |
trainer |
NPC or teaching beat. |
book_or_item |
Book, chip, training consumable, or similar one-shot grant. |
Add new enum values only with a schema version / migration note in CT.M1 when CI enforces catalogs.
Designer note: allowedXpSourceKinds and grant call sites
Every SkillDef row must include a non-empty allowedXpSourceKinds array (enforced by JSON Schema). Designers use it to agree with engineering which systems may ever grant XP to that skill:
activity— wire gather nodes, recipe completions, skill-based world objectives, and similar primary-loop payouts; setXpGrantEvent.sourceKind(or successor) toactivityon those code paths.mission_reward— wire explicit mission/contract hand-ins or scripted bonuses only; not a stand-in for combat encounter XP (docs/game-design/progression.md— mission vs combat).trainer/book_or_item— wire NPC teaching beats and consumable/one-shot grants respectively; do not use for combat kills.
Combat encounters award gig XP, not skill XP. If a grant channel is missing from a skill’s list, E2.M2 rejects the grant at apply time (NEO-38 HTTP grant path)—keep catalogs honest so call sites do not drift.
Prototype Slice 1 freeze (NEO-33)
The first shipped trio under content/skills/*.json is frozen for downstream references (quests, recipes, E2.M2, E3) until a deliberate migration or follow-up issue expands the roster.
SkillDef.id |
category |
Role |
|---|---|---|
salvage |
gather |
Prototype Gather anchor |
refine |
process |
Prototype Process anchor (satisfies “Process or Make” for Slice 1) |
intrusion |
tech |
Prototype Tech anchor |
Rules: Do not rename these id values to “fix” wording—change displayName only, or add a new id and migrate content. CI (scripts/validate_content.py) enforces exactly these three ids across all skill JSON files and category coverage (gather + tech + at least one of process/make). Relaxing or changing that gate belongs in a new Linear issue once the catalog intentionally grows.
Responsibilities
- Load and validate
SkillDeffrom data; exposeSkillCategoryandUnlockRequirementfor gating. - Reject unknown
skillIdor XP grants whosesourceKindis not listed on the target skill’sallowedXpSourceKinds(enforced in E2.M2 at grant time).
Key contracts
| Contract | Role |
|---|---|
SkillDef |
Per-skill metadata: id, category, displayName, allowedXpSourceKinds (+ future unlock fields). |
SkillCategory |
gather | process | make | tech for UX and balance. |
UnlockRequirement |
Prerequisites before XP or use counts apply. |
Acceptance criteria (E2.M1 / Slice 1)
- Every loaded
SkillDefvalidates againstskill-def.schema.jsonin CI (CT.M1 —scripts/validate_content.pyin PR gate) or at server boot. - Duplicate
idin a catalog fails validation. - Roster freeze for prototype: Slice 1 locks
salvage,refine, andintrusion; theiridvalues are stable—downstream content (recipes, quests) may reference them; changing anidrequires a migration or new row. - Document for designers: each new skill row must declare
allowedXpSourceKindsso engineers know which systems may grant XP (gather/craft hooks vs E7.M2 mission rewards only, etc.).
Module dependencies
- None
Dependents (by design)
- E2.M2 — XpAwardAndLevelEngine (primary): validates grants against
allowedXpSourceKinds.
Related implementation slices
Epic 2 Slice 1 — skill registry and prototype non-combat skills; invalid references fail at load or in CI.
Source anchors
- Game design:
docs/game-design/skills.md— roster, XP philosophy, gig/skill boundary. - Master plan:
neon_sprawl_vision.plan.md— Epic 2. - Module dependency register