Files
suaveplan/openspec/changes/enterprise-gaming-progression/proposal.md
2026-05-27 23:29:53 +01:00

169 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpenSpec Change: enterprise-gaming-progression
- **Change ID**: enterprise-gaming-progression
- **Package**: `@suaveplan/progression`
- **Category**: gaming/narrative
- **Target path**: `gaming/narrative/progression`
- **Status**: PROPOSED
- **Date**: 2026-04-24
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/progression.md`
---
## Summary
Deliver `@suaveplan/progression` on the genesis branch from scratch at enterprise quality. The package provides character progression with XP curves, skill trees, perks, and achievements. A `ProgressionManager` accumulates XP and triggers level-up events; an `XpCurve` computes required XP per level from configurable formulas (polynomial, exponential, flat table); a `SkillTree` represents an acyclic graph of `SkillNode` objects with prerequisite unlocking; a `PerkRegistry` holds passive modifiers unlockable at level milestones; an `AchievementTracker` monitors player statistics and fires unlock events. Genesis adds Zod schemas, structured errors, OTel XP counter, injectable clock, and 100% coverage.
---
## Current-state audit (genesis)
Package does not exist on genesis yet — fresh build.
---
## Available workspace deps on genesis
| Package | Role |
|---|---|
| `@suaveplan/error` (`workspace:^`) | `ProgressionError`; `PROG.*` codes |
| `@suaveplan/types` (`workspace:^`) | `Clock` |
| `@suaveplan/events` (`workspace:^`) | `prog:level_up`, `prog:skill_unlocked`, `prog:perk_unlocked`, `prog:achievement` |
| `zod` (`catalog:forms`) | Skill tree + achievement schemas |
| `@opentelemetry/api` (`catalog:observability`) | XP counter, level gauge |
---
## Public API surface
```ts
interface XpCurveOptions {
formula: 'polynomial' | 'exponential' | 'table'
base?: number
coefficient?: number
exponent?: number
table?: number[] // XP required per level (table formula)
}
function createXpCurve(options: XpCurveOptions): XpCurve
interface XpCurve {
xpForLevel(level: number): number
levelForXp(xp: number): number
}
function createProgressionManager(options: ProgressionManagerOptions): ProgressionManager
interface ProgressionManagerOptions {
curve: XpCurve
maxLevel?: number
clock?: Clock
}
interface ProgressionManager {
awardXp(playerId: string, amount: number, source?: string): void
getLevel(playerId: string): number
getXp(playerId: string): number
getProgress(playerId: string): number // 0–1 toward next level
}
// Skill tree
interface SkillNode {
id: string
name: string
description: string
cost: number // skill points required
prerequisites?: string[]
effects?: SkillEffect[]
}
interface SkillEffect {
stat: string
modifier: number
type: 'add' | 'multiply'
}
function createSkillTree(nodes: SkillNode[]): SkillTree
interface SkillTree {
canUnlock(nodeId: string, unlockedIds: Set<string>, availablePoints: number): boolean
unlock(nodeId: string, unlockedIds: Set<string>, availablePoints: number): Set<string>
computeEffects(unlockedIds: Set<string>): Map<string, number>
}
// Achievements
interface AchievementDefinition {
id: string
title: string
description: string
condition: { stat: string; threshold: number; op: '>=' | '<=' | '==' }
}
function createAchievementTracker(definitions: AchievementDefinition[]): AchievementTracker
interface AchievementTracker {
updateStat(stat: string, value: number): void
incrementStat(stat: string, by?: number): void
getUnlocked(): string[]
isUnlocked(id: string): boolean
}
```
### Error codes
```ts
type ProgErrorCode =
| 'PROG_PLAYER_NOT_FOUND'
| 'PROG_SKILL_NOT_FOUND'
| 'PROG_PREREQUISITES_NOT_MET'
| 'PROG_INSUFFICIENT_POINTS'
| 'PROG_MAX_LEVEL_REACHED'
```
---
## File layout
```text
gaming/narrative/progression/
package.json
tsconfig.json
vitest.config.ts
src/
index.ts
error-codes.ts
constants/index.ts
types/common.ts
types/common.md
core/
xp-curve/
xp-curve.ts
xp-curve.md
xp-curve.types.ts
xp-curve.test.ts
index.ts
progression-manager/
progression-manager.ts
progression-manager.md
progression-manager.types.ts
progression-manager.test.ts
index.ts
skill-tree/
skill-tree.ts
skill-tree.md
skill-tree.types.ts
skill-tree.test.ts
index.ts
achievement-tracker/
achievement-tracker.ts
achievement-tracker.md
achievement-tracker.types.ts
achievement-tracker.test.ts
index.ts
tests/
integration.test.ts
```
---
## Impact
**Downstream**: `@suaveplan/economy` reads player level for pricing; `@suaveplan/react-game-hud` shows XP bar. Prerequisites: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`.