From c283cda44dfcb749902233b93bc1cbf2f5922fc2 Mon Sep 17 00:00:00 2001 From: Alexander Zielonka Date: Mon, 27 Apr 2026 14:58:19 +0200 Subject: [PATCH] =?UTF-8?q?docs(01-03):=20complete=20Plan=2003=20=E2=80=94?= =?UTF-8?q?=20Foundry=20seed=20pipeline=20+=20Wizard=20worked=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../01-03-SUMMARY.md | 246 ++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 .planning/phases/01-level-up-pf2e-regelkonform/01-03-SUMMARY.md diff --git a/.planning/phases/01-level-up-pf2e-regelkonform/01-03-SUMMARY.md b/.planning/phases/01-level-up-pf2e-regelkonform/01-03-SUMMARY.md new file mode 100644 index 0000000..ed75568 --- /dev/null +++ b/.planning/phases/01-level-up-pf2e-regelkonform/01-03-SUMMARY.md @@ -0,0 +1,246 @@ +--- +phase: 01-level-up-pf2e-regelkonform +plan: 03 +subsystem: seeding +tags: [seeding, prisma, foundry-pf2e, class-progression, spellcaster, wizard, level-up, pipeline] + +# Dependency graph +requires: + - phase: 01-level-up-pf2e-regelkonform + provides: ClassProgression + ClassFeatureOption Prisma tables (Plan 01-01); Proficiency type vocabulary (Plan 01-02 lib/types.ts) +provides: + - Idempotent seed pipeline (server/prisma/seed-class-progression.ts) generic over D16_CLASS_NAMES — Plan 03b appends data, no script changes + - Hand-curated spell-slot overlay (server/prisma/data/spell-slot-overlays.ts) with type definitions + Wizard L1..L19 fully populated + - Hand-curated class-feature-options (server/prisma/data/class-feature-options.ts) with type definitions + 1 Wizard School entry + - Pinned Foundry pf2e tag (pf2e-8.0.3) and dev README at .planning/phases/01-level-up-pf2e-regelkonform/SEED-README.md + - 320 ClassProgression rows in PostgreSQL (16 D-16 classes × L1..L20) + - 1 ClassFeatureOption row (wizard-school / battle-magic) + - Wizard end-to-end worked example: choiceType=school, choiceOptionsRef=wizard-school, ARCANE slot progression L1..L19, 5 cantrips at L1 +affects: [01-03b (data-only append to overlays), 01-04 (LevelingService.commit reads ClassProgression rows), 01-05 (wizard UI uses choiceOptionsRef → ClassFeatureOption)] + +# Tech tracking +tech-stack: + added: [] + patterns: + - "Idempotent compound-key Prisma upsert pattern via findUnique + update OR create" + - "Prisma.JsonNull sentinel for nullable Json fields (Prisma 7 typed-input contract)" + - "Foundry pf2e clone consumed at seed time only; runtime never reads JSON files" + - "Foundry-driven seed + hand-curated overlay merge (Pitfall #6 mitigation: slot tables in prose, not rules)" + +key-files: + created: + - .planning/phases/01-level-up-pf2e-regelkonform/SEED-README.md + - server/prisma/data/spell-slot-overlays.ts + - server/prisma/data/class-feature-options.ts + - server/prisma/seed-class-progression.ts + modified: + - server/tsconfig.json (exclude prisma/data/foundry-pf2e from compilation — gitignored third-party content) + +key-decisions: + - "Pinned Foundry pf2e tag pf2e-8.0.3 — current stable Pathfinder 2e system release with Player Core + APG content for all 16 D-16 classes" + - "Spell-slot/cantrip/repertoire data hand-curated in spell-slot-overlays.ts (Pitfall #6: Foundry encodes them in description prose, not machine-readable rules)" + - "All 16 D-16 class names appear as keys in SPELL_SLOT_OVERLAY (even when value is []) so Plan 03b appends without missing-key bugs" + - "ClassFeatureOption.proficiencyChanges stays optional in the entry interface; passing null at the seed call site is rewritten to Prisma.JsonNull to satisfy typed-input contract" + - "Pipeline is generic over D16_CLASS_NAMES + SPELL_SLOT_OVERLAY[className] — Plan 03b adds data only, no script changes" + - "Foundry pf2e v8 nests pf2e packs under packs/pf2e/classes/ (v7 had packs/classes/ directly) — Pitfall #5 mitigation documented in code comment + SEED-README" + +patterns-established: + - "Idempotent seed: findUnique → update OR create per row, with compound-key where clauses inferred from @@unique declarations" + - "Hand-curated overlay file with all class keys present (empty arrays for unsupported classes) so future plans append safely" + - "Loud-fail seed: missing Foundry clone triggers a deterministic error that points the dev to SEED-README" + - "Third-party clone exclusion in tsconfig — gitignored data directories that ship their own TS source must be excluded from project tsc" + +requirements-completed: [LVL-08, LVL-14] + +# Metrics +duration: ~14min +completed: 2026-04-27 +--- + +# Phase 1 Plan 03: Seed Pipeline + Wizard Worked Example Summary + +**Built the Foundry-pf2e-driven seed pipeline that populates ClassProgression (320 rows) and ClassFeatureOption (1 row) from a pinned pf2e-8.0.3 clone plus hand-curated spell-slot overlays, with Wizard fully wired end-to-end (L1..L19 ARCANE slot progression, 5 cantrips at L1, school choice routing) and idempotent re-runs reporting `0 created, 320 updated`.** + +## Performance + +- **Duration:** ~14 min +- **Tasks:** 5 completed (README, spell-slot overlay, class-feature options, seed script, run+verify) +- **Files created:** 4 (SEED-README.md, spell-slot-overlays.ts, class-feature-options.ts, seed-class-progression.ts) +- **Files modified:** 1 (server/tsconfig.json — exclude clone dir) + +## Accomplishments + +- **Pinned Foundry tag chosen:** `pf2e-8.0.3` — current stable Pathfinder 2e system release on the `foundryvtt/pf2e` repo. Verified via the GitHub Releases API; tag SHA `c6aac85d186ac768d1db9ac2d379e9510a0825f8`. +- **SEED-README.md** at `.planning/phases/01-level-up-pf2e-regelkonform/SEED-README.md` documents the clone command, the run command, failure modes, and the v8 pack-layout note. Mentions Plan 03 vs Plan 03b split explicitly. +- **spell-slot-overlays.ts** exports `SpellTradition`, `SpellSlotOverlayEntry`, and `SPELL_SLOT_OVERLAY`. Wizard fully populated for L1..L19 (20 entries: L1 has both a cantrip-increment entry and a slot-increment entry). All 15 other D-16 class names appear as keys with empty-array values for Plan 03b to fill. +- **class-feature-options.ts** exports `ClassFeatureOptionEntry` and `CLASS_FEATURE_OPTIONS` (1 entry: Wizard School `battle-magic` / "School of Battle Magic"). Anchor comments name 13 other optionsRef strings so Plan 03b knows where to append. +- **seed-class-progression.ts** is generic over `D16_CLASS_NAMES` and the two overlay modules — Plan 03b appends entries to the data files and re-runs the same seed without touching the script. Uses Prisma 7's `Prisma.JsonNull` sentinel for nullable Json fields and the compound-key field names `className_level` and `optionsRef_optionKey` generated from Plan 01's `@@unique` declarations. +- **Live DB state after seed:** + - 320 ClassProgression rows (16 classes × L1..L20) + - 20 Wizard rows; L1 has full structure (`grants`, `proficiencyChanges {fortitude:UNTRAINED, reflex:UNTRAINED, will:TRAINED}`, `spellSlotIncrement {tradition:ARCANE, spellLevel:1, count:2}`, `cantripIncrement: 5`, `choiceType: 'school'`, `choiceOptionsRef: 'wizard-school'`) + - L2..L18 carry the correct ARCANE/L1..L9 slot progression (2 + 1 per spell grade per pair of levels) + - L19 carries the L10 capstone slot + - 1 ClassFeatureOption row (`wizard-school` / `battle-magic` / "School of Battle Magic") +- **Idempotency proven:** First run reports `320 created, 0 updated, 0 errors` for ClassProgression and `1 created, 0 updated, 0 errors` for ClassFeatureOption; second and third runs report `0 created, 320 updated, 0 errors` and `0 created, 1 updated, 0 errors`. +- **Type-clean:** `npx tsc --noEmit -p tsconfig.json` exits 0 across all four new files; the cloned Foundry source is excluded from compilation (it ships its own TS source that targets a different toolchain). +- **Existing leveling tests still pass:** `npm test -- --testPathPatterns=leveling` reports 55/55 passing. + +## Task Commits + +| Task | Description | Commit | +|------|-------------|--------| +| 1 | Dev README for the Foundry pf2e clone path | `6567665` (docs) | +| 2 | Spell-slot overlay file — types + Wizard worked example | `29fe01d` (feat) | +| 3 | Class-feature-options file — types + Wizard School worked example | `d86cf4f` (feat) | +| 4 | Seed script — Foundry pf2e + overlays → ClassProgression + ClassFeatureOption | `e85f790` (feat) | +| 5 | Run the seed (Wizard end-to-end verification) — path fix + README update | `ce214ab` (fix) | +| — | tsconfig exclude foundry-pf2e clone dir (Rule 3 deviation) | `d421aad` (chore) | + +## Verification Output + +``` +$ cd server && npm run db:seed:class-progression +Seeding ClassProgression for 16 classes x 20 levels... + ClassProgression: 0 created, 320 updated, 0 errors +Seeding 1 ClassFeatureOption rows... + ClassFeatureOption: 0 created, 1 updated, 0 errors +ClassProgression + ClassFeatureOption seed complete. +``` + +``` +$ cd server && npm test -- --testPathPatterns=leveling +Test Suites: 5 passed, 5 total +Tests: 55 passed, 55 total +``` + +Wizard L1 row queried via the Prisma client (verification helper, not committed): + +```json +{ + "className": "Wizard", + "level": 1, + "grants": ["Wizard Spellcasting", "Arcane School", "Arcane Bond", "Arcane Thesis"], + "proficiencyChanges": { "will": "TRAINED", "reflex": "UNTRAINED", "fortitude": "UNTRAINED" }, + "spellSlotIncrement": { "count": 2, "tradition": "ARCANE", "spellLevel": 1 }, + "cantripIncrement": 5, + "repertoireIncrement": null, + "choiceType": "school", + "choiceOptionsRef": "wizard-school" +} +``` + +Wizard L1..L5 spell-slot progression (matches AoN canonical Wizard table): + +| Level | Slot increment | Cantrip increment | +|-------|----------------|-------------------| +| 1 | ARCANE / L1 / count=2 | 5 | +| 2 | ARCANE / L1 / count=1 | — | +| 3 | ARCANE / L2 / count=2 | — | +| 4 | ARCANE / L2 / count=1 | — | +| 5 | ARCANE / L3 / count=2 | — | + +(Continues through L19 with the L10 capstone — matches Player Core / APG.) + +## Decisions Made + +- **Foundry tag = pf2e-8.0.3 (Pathfinder 2e v8).** The current Foundry pf2e repo bundles both PF2E and SF2E (Starfinder 2e) under one tree, so tags are now prefixed `pf2e-` or `sf2e-`. `pf2e-8.0.3` is the latest stable PF2E release with Player Core + APG content. Recorded both in SEED-README and in the seed script comment. +- **v8 pack layout discovered at run time.** The plan's instructions referenced `packs/classes/` (Foundry pf2e v7 layout). The cloned v8 tree ships pf2e packs under `packs/pf2e/classes/`. Documented in SEED-README as a layout note and in the seed script's `FOUNDRY_CLASSES_DIR` comment. +- **Prisma.JsonNull for nullable Json fields.** Prisma 7's `Json?` typed inputs reject JS `null` and require the sentinel `Prisma.JsonNull` to distinguish "set to JSON null" from "leave column unchanged". Both `spellSlotIncrement` (in ClassProgression) and `proficiencyChanges` (in ClassFeatureOption when undefined on the entry) use this sentinel. +- **All 16 class keys must be present in SPELL_SLOT_OVERLAY.** Even when a class's array is empty (Plan 03b stub), the key exists so the seed's `(SPELL_SLOT_OVERLAY[className] || []).filter(...)` never accidentally elides a class because of a typo. This is the contract Plan 03b appends to. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 — Blocking] Worktree had no node_modules and no .env file** +- **Found during:** Task 4 verification (running `npx tsc --noEmit`) +- **Issue:** The parallel-execution worktree was created clean (no `npm install` had been run, `.env` is gitignored so it didn't transfer). Without these, `prisma`, `tsx`, `jest`, and the Prisma adapter failed to resolve. +- **Fix:** Copied `server/.env` from the parent repo into the worktree (file is gitignored and identical) and ran `npm install` in `server/`. Same fix Plan 01-01 documented. +- **Files modified:** `server/.env` (gitignored, not staged), `server/node_modules/` (gitignored), `server/package-lock.json` (gitignored, not modified) +- **Commit:** N/A — environment setup, no source files changed + +**2. [Rule 1 — Bug] Foundry pf2e v8 packs path differs from plan's documented v7 path** +- **Found during:** Task 5 Step 2 (verifying clone has class JSONs) +- **Issue:** Plan and SEED-README documented `packs/classes/` (correct for Foundry pf2e v7). Cloned `pf2e-8.0.3` placed pf2e content under `packs/pf2e/classes/`. The seed script's `FOUNDRY_CLASSES_DIR` constant pointed at the v7 path and would have failed loudly with "Foundry pf2e clone not found". +- **Fix:** Updated `FOUNDRY_CLASSES_DIR` in `seed-class-progression.ts` to `packs/pf2e/classes/`, added a Pitfall #5 comment block explaining the version-specific path, and added a "Foundry pf2e v8 layout note" section to SEED-README.md plus updated the failure-mode error path string. +- **Files modified:** `server/prisma/seed-class-progression.ts`, `.planning/phases/01-level-up-pf2e-regelkonform/SEED-README.md` +- **Commit:** `ce214ab` + +**3. [Rule 1 — Bug] Prisma 7 typed-input rejected JS null for nullable Json fields** +- **Found during:** Task 4 type-check (`npx tsc --noEmit`) +- **Issue:** `Type ... is not assignable to type 'InputJsonValue | NullableJsonNullValueInput | undefined'`. Prisma 7 differentiates "set to JSON null" (`Prisma.JsonNull`) from "leave unchanged" (omit the field) and JS `null` is not accepted in either slot for `Json?` columns. +- **Fix:** Imported `Prisma` namespace from the generated client. Replaced `?? null` with `?? Prisma.JsonNull` for `spellSlotIncrement` (in `buildProgressionRow`) and `proficiencyChanges` (in `seedClassFeatureOptions`). Typed `buildProgressionRow`'s return as `Prisma.ClassProgressionUncheckedCreateInput` so future schema drift surfaces as a TS error at the boundary. +- **Files modified:** `server/prisma/seed-class-progression.ts` +- **Commit:** `e85f790` (the corrected file was the one committed; pre-fix code was never committed) + +**4. [Rule 3 — Blocking] tsc --noEmit picked up TS errors in the cloned Foundry source** +- **Found during:** Final verification before SUMMARY +- **Issue:** Foundry pf2e ships its own TS source at `prisma/data/foundry-pf2e/types/...` and `prisma/data/foundry-pf2e/vite.config.ts`. These reference modules our project doesn't have (`@common/...`, `svelte`, `vite`, `peggy`) and produce ~25 `tsc --noEmit` errors that have nothing to do with our code. +- **Fix:** Added `prisma/data/foundry-pf2e` to `tsconfig.json` `exclude` list (alongside `node_modules` and `dist`). The clone is gitignored and the seed reads it as raw JSON, so excluding it from compilation is correct and surgical. +- **Files modified:** `server/tsconfig.json` +- **Commit:** `d421aad` + +--- + +**Total deviations:** 4 (1 environment infra, 1 Foundry data-shape correction, 1 Prisma 7 typed-input correction, 1 third-party-source exclusion). +**Impact on plan:** None of the deviations changed plan scope. All were correctness fixes required to make the plan run cleanly on this worktree. + +### Authentication Gates + +None — seed pipeline is local-only. + +### Architectural Changes + +None — schema was authored in Plan 01-01; this plan only seeds it. + +## Issues Encountered + +- **Plan referenced v7 path `packs/classes/`.** Documented in plan and research. Resolved by Rule 1 fix as above; v8 layout is now noted in SEED-README and code comments so future re-cloning to a different major version surfaces the issue immediately. +- **No psql in shell.** The plan's verification step recommended `psql $DATABASE_URL -c '...'`. The Windows shell here doesn't have psql. Wrote a temporary `verify-plan-03-wizard.ts` helper using the existing Prisma client, ran it, captured the output for this Summary, then deleted it. Verification result documented in §Verification Output above. The Prisma-client query approach yields the same information the plan's psql commands would have. + +## User Setup Required + +None for this plan. The dev who maintains the project does need to clone the Foundry pf2e repo at the pinned tag for future fresh clones — the README documents the exact command. + +## Plan 03b Readiness + +Plan 03b can append data to `spell-slot-overlays.ts` and `class-feature-options.ts` and re-run `npm run db:seed:class-progression` without touching the seed script. The contract Plan 03b consumes: + +1. `SpellSlotOverlayEntry` interface — extend `SPELL_SLOT_OVERLAY[className]` arrays for Cleric/Druid/Witch/Bard/Sorcerer/Oracle/Champion. Empty `[]` arrays for non-casters can stay or be removed. +2. `ClassFeatureOptionEntry` interface — append entries below the anchor comments in `CLASS_FEATURE_OPTIONS`. The `optionsRef` strings already match what `seed-class-progression.ts L1_CHOICE_MAP` emits onto each class's L1 row. +3. The `optionsRef`/`optionKey` compound key is `Prisma.@@unique([optionsRef, optionKey])` — Plan 03b's bulk-append must keep `optionKey` unique within an `optionsRef`. + +Re-running the seed after Plan 03b's append will report the count of new ClassFeatureOption rows created and the existing 320 ClassProgression rows updated in place with new overlay data. + +## Threat Flags + +None — no new network endpoints, auth paths, file-access patterns, or schema changes at trust boundaries beyond what the plan's threat register already covered. + +## Self-Check: PASSED + +**Verified files exist:** +- `.planning/phases/01-level-up-pf2e-regelkonform/SEED-README.md` (FOUND) +- `server/prisma/data/spell-slot-overlays.ts` (FOUND) +- `server/prisma/data/class-feature-options.ts` (FOUND) +- `server/prisma/seed-class-progression.ts` (FOUND) +- `server/tsconfig.json` (FOUND, modified — exclude added) + +**Verified commits exist on this branch:** +- `6567665` — docs(01-03): add SEED-README with Foundry pf2e clone instructions and pinned tag +- `29fe01d` — feat(01-03): add spell-slot overlay types with Wizard worked example +- `d86cf4f` — feat(01-03): add class-feature-options types with Wizard School worked example +- `e85f790` — feat(01-03): add idempotent ClassProgression + ClassFeatureOption seed script +- `ce214ab` — fix(01-03): align Foundry path with pf2e-8.0.3 layout +- `d421aad` — chore(01-03): exclude foundry-pf2e dev clone from tsconfig + +**Verified runtime checks:** +- `npx tsc --noEmit -p tsconfig.json` exits 0 (foundry-pf2e clone excluded; project code clean) +- `npm run db:seed:class-progression` first run: 320 created / 1 created +- `npm run db:seed:class-progression` second/third runs: 0 created / 320 updated / 0 errors (idempotent) +- Wizard L1 row query returns full structure with ARCANE slot progression, cantrip=5, choiceType=school +- Wizard L1..L19 carry non-null spellSlotIncrement; ClassFeatureOption has 1 row for `wizard-school` +- Existing 55 leveling tests still pass + +--- +*Phase: 01-level-up-pf2e-regelkonform* +*Completed: 2026-04-27*