Add SUMMARY.md documenting the seed pipeline (320 ClassProgression rows + 1
ClassFeatureOption row), the four auto-fix deviations resolved during execution
(env setup, v8 path, Prisma 7 typed-input, third-party tsc exclusion), and the
contract Plan 03b consumes when appending overlay data.
- The cloned Foundry pf2e repository ships its own TypeScript source files which
reference modules our project does not have ('@common/...', 'svelte', 'vite', 'peggy').
- That clone lives at server/prisma/data/foundry-pf2e/ (gitignored, dev-time only;
the seed reads the JSON files at runtime, never the TS source).
- Add 'prisma/data/foundry-pf2e' to tsconfig exclude list so 'tsc --noEmit' on our
codebase is unaffected by third-party content.
- Iterate over D16_CLASS_NAMES; read Foundry pf2e class JSONs; merge with hand-curated overlays
- Generic pipeline (Plan 03b appends data to overlay modules; no script changes needed)
- Idempotent findUnique → update OR create per row using compound unique keys
- Loud failure with SEED-README pointer when Foundry clone is missing
- Use Prisma.JsonNull for nullable Json fields per Prisma 7 typed-input contract
- No 'any' types; type-clean against tsconfig.json
- Define ClassFeatureOptionEntry interface as the contract Plan 03b appends to
- Include School of Battle Magic as the worked Wizard School entry (optionsRef: 'wizard-school')
- Add anchor comments naming all remaining class optionsRef strings so Plan 03b knows where to append
- No 'any' types; type-clean against tsconfig.json
- Define SpellTradition type and SpellSlotOverlayEntry interface as the contract Plan 03b appends to
- Wizard fully populated L1..L19 with ARCANE slot progression and L1 cantrip count (5)
- Stub keys for the other 15 D-16 classes set to empty arrays for Plan 03b to populate
- No 'any' types; type-clean against tsconfig.json
- Pin Foundry pf2e tag to pf2e-8.0.3 (current stable, includes Player Core + APG content for all 16 D-16 classes)
- Document clone command, run command, and failure modes
- Reference Plan 03 (Wizard worked example) vs Plan 03b (bulk curation) split
- applyAttributeBoost: PF2e boost-cap-at-18 rule (Pitfall #8 mitigation)
- Returns score + 2 when current < 18
- Returns score + 1 when current >= 18
- isValidBoostSet: validates exactly 4 distinct abilities for boost levels
- Pure-function module (no NestJS, no Prisma, no I/O imports)
- TypeScript strict, named exports only
- 9/9 tests pass — proves Jest infrastructure works on src/modules/**/*.spec.ts
- 5 cases for applyAttributeBoost (boost-cap-at-18 rule, Pitfall #8)
- 4 cases for isValidBoostSet (PF2e: 4 distinct abilities required)
- Test fails (RED gate) because module is not yet implemented
- Generate migration 20260427122603_add_level_up_sessions_and_class_progression
- Auto-creates LevelUpSession, LevelUpHistory, ClassProgression, ClassFeatureOption tables
- Adds Character.freeArchetype and Character.prereqViolations columns
- Hand-append partial unique index 'LevelUpSession_characterId_open_unique'
with WHERE "committedAt" IS NULL clause (Prisma 7 cannot emit partial indexes)
- Migration applied to dev database via prisma migrate dev
- Prisma Client regenerated and exposes new models + Character columns
- Add LevelUpSession model (DRAFT state, soft-archive on commit via committedAt)
- Add LevelUpHistory model (append-only audit log of committed level-ups)
- Add ClassProgression model (per-class, per-level grants and prof changes)
- Add ClassFeatureOption model (sub-choices like doctrines/schools/instincts)
- Extend Character with freeArchetype Boolean (D-08) and prereqViolations Json (D-06)
- Add reverse relations levelUpSessions and levelUpHistories on Character
- Schema formatted via prisma format and validated via prisma validate
Five pure-function modules (types + 4 logic) implemented strict-TDD.
46 passing Jest tests across 4 spec files. Pitfall #8 (boost-cap-at-18)
and Pitfall #9 (no hpCurrent in output) both enforced by spec.
3 documented deviations:
- Rule 3: created apply-attribute-boost.ts dependency (Plan 01-01 work
not yet merged into worktree base; content matches 01-01 spec exactly)
- Rule 1: corrected L5 expected step list (PF2e CRB has class/skill
feats only at even levels; plan said feat-class+feat-skill at L5)
- Rule 1: TS-strict type-guard helpers for EvalResult narrowing
Requirements completed: LVL-02, LVL-06, LVL-09, LVL-10, LVL-01, LVL-13, LVL-14
Rule 1 deviation: TS strict mode (noImplicitAny + strict) couldn't narrow
the EvalResult union via 'r.ok' direct access because the {unknown:true,raw}
variant has no 'ok' property. Added explicit type-guard helpers (isUnknown,
isOk, isFail) for both production and spec narrowing. Runtime behavior
unchanged; tsc --noEmit now exits clean for the leveling lib.
Files:
- prereq-evaluator.ts: 3 type-guard functions, used in OR/AND walkers
- prereq-evaluator.spec.ts: isFail() in lieu of result.ok=== checks
The plan's expected list for computeApplicableSteps(5, 'Fighter', ...) was
PF2e-incorrect. Per CRB, class feats and skill feats are slotted at EVEN
levels only (2, 4, 6, ..., 20). L5 is odd → no class/skill feat.
Plan said: [class-features, boost, skill-increase, feat-class, feat-skill, feat-ancestry, review]
PF2e-correct: [class-features, boost, skill-increase, feat-ancestry, review]
The plan's other tests are internally consistent (L4 has feat-class, L3
does NOT have feat-class) — only the L5 case was misstated. Project's
'regelkonform' goal (CLAUDE.md, PROJECT.md) requires PF2e correctness
above plan literalism.
Task 2 RED phase: 9 failing tests covering PF2e skill-increase cap rule
(VALIDATION.md rows 1-W1-06 to 1-W1-11). Implementation follows in next
commit (GREEN). Verified failure: module './skill-increase-cap' not found.
Rule 3 deviation: Plan 01-01 (wave 0) work not yet merged into this
worktree base (096edbf). Plan 01-02 imports applyAttributeBoost and
AbilityAbbreviation from this module — required for types.ts and
recompute-derived-stats.ts to compile. Content matches 01-01 plan exactly,
so orchestrator merge will be clean.
- export type AbilityScore = number
- export type AbilityAbbreviation = 'STR'|'DEX'|'CON'|'INT'|'WIS'|'CHA'
- export function applyAttributeBoost(score) — PF2e boost-cap-at-18 (Pitfall #8)
- export function isValidBoostSet(targets) — exactly 4 distinct
- Add library page with tabs for maps and combatants
- Create map upload modal with grid configuration
- Create NPC/monster template modal with abilities
- Add library link to campaign page (GM only)
- Add battle feature TODO documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add battle module with sessions, maps, tokens, and combatants
- Implement WebSocket gateway for real-time battle updates
- Add map upload with configurable grid system
- Create battle canvas with token rendering and drag support
- Support PC tokens from characters and NPC tokens from templates
- Add initiative tracking and round management
- GM-only controls for token manipulation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace vite.svg with Dimension47 logo as favicon
- Add comprehensive meta tags (OG, Twitter, keywords)
- Remove unused action icon files (old versions)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added external link to Archives of Nethys for all equipment items
- Notes section now only displays for non-weapon items
- Uses equipment.url field from database, prepends https://2e.aonprd.com if needed
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>