17 KiB
name, description, metadata
| name | description | metadata | ||||||
|---|---|---|---|---|---|---|---|---|
| forgerpg | ForgeRPG project state — Phase 7 (chargen) + Character Export (MD/PDF/JPG/DOCX, per-system sheets) BOTH LIVE on prod forge.timevans.uk; export proven e2e, Mac app rebuilt with export menus |
|
ForgeRPG = Tim's tabletop RPG tool: FastAPI backend (~/projects/ForgeRPG-api, github slaguru666/ForgeRPG-api, private) + SwiftUI Mac app (~/projects/ForgeRPG-mac, slaguru666/ForgeRPG-mac).
CHARACTER EXPORT FEATURE LIVE ON PROD 2026-07-05 (api 721b6c2 730 tests; mac 91937f1 253 tests). Deployed aa85c9e→721b6c2 (ff, NO migration); the WeasyPrint-native-stack docker build (the flagged risk) SUCCEEDED cleanly; runtime imports verified in-container; e2e proven on forge.timevans.uk (temp NPC → MD/PDF/JPG/DOCX all HTTP 200 valid, bad-format 422, deleted). Mac app rebuilt + relaunched with export menus. Export any saved NPC/PC (or a generated draft via save-then-export) as MD/PDF/JPG/DOCX, single or bulk-per-campaign zip, with per-system sheet layouts. Architecture: pure SheetModel (app/export/model.py) built from a LayoutDescriptor (registry app/export/layout.py, keyed by campaign system name substring → per-system JSON+CSS, else universal fallback) → 4 renderers (render_md, render_docx=python-docx, render_html+render_pdf=WeasyPrint, render_jpg=PyMuPDF raster of the PDF). Endpoints app/api/character_export.py: GET /library/npcs/{id}/export?format=, GET /campaigns/{cid}/pcs/{id}/export?format=, GET /campaigns/{cid}/export-characters?format=&kind=npc|pc|all (zip). JPG of a character WITH a portrait returns a ZIP (sheet+portrait) — Mac ExportStore reads Content-Type/filename FROM HEADERS, never assumes. Portraits from MinIO (load_portrait, None-safe). 2 flagship layouts shipped (sla-zero, cthulhu — CoC parchment, SLA dark-crimson mono); universal covers the rest; Wave 2+ layouts = authored data (backlog). Deploy notes: NO migration (pure read). Carries Dockerfile apt system-libs (libpango/pangocairo/cairo/gdk-pixbuf/libffi8/shared-mime-info/fonts-dejavu-core) + pip weasyprint==63.1/pymupdf==1.24.14/python-docx==1.1.2. RISK: the python:3.12-slim + WeasyPrint native stack has NEVER been docker-built (deps proven only on the Mac host, where brew reinstall pango gdk-pixbuf was needed to fix broken dylibs) — watch the first docker build apt/pip resolution. In-app export also needs the Mac app rebuilt (swift run). LESSON: content-fidelity tests can't catch visual CSS bugs → render + eyeball flagship sheets (caught a float:right cell-overlap bug all 15 fidelity tests missed; fixed with flexbox). Spec/plan: docs/superpowers/{specs,plans}/2026-07-05-character-export*.md.
PHASE 7 COMPLETE + DEPLOYED TO PROD 2026-07-05 — template-driven CHARACTER + NPC creation (api aa85c9e 694 tests; mac 558d17a 247 tests; both pushed). LIVE on forge.timevans.uk: prod fast-forwarded 7359632→aa85c9e (P7 additive only; P6 was already live via the cloud-art deploy — the old "P6 pending" note was stale), migrations e3aa1ae31d9a→50da6ad01970→d6765ee850f1 applied, 11 chargen templates seeded via the standalone python -m app.chargen.seed_templates (created 11, three-way merge — used standalone NOT full app.seed to avoid re-touching prod's 16 campaigns/history). PROD-VERIFIED e2e 2026-07-05: login→generate PC+NPC across ALL 11 systems = 22/22 (Mothership reduced block + Traveller skill-package archetypes legitimately have empty attributes — that's the mode, not a failure); SLA-Zero shiver delta-scaling proven exact across all 6 threat tiers (mook Δ−1 →2/2/2/2 hp4 armor1 … apex Δ+4 →5/5/5/5 hp14 armor6, matching clamp(v+Δ,2,5)/max(1,hp+Δ2)/clamp(armor,0,6)). Deploy verify harness: scratchpad/prod_verify.py (login regex from task-9-deploy-report.md, urllib, no-secret-print). Ops: standalone chargen seeder = surgical prod seeding path for template updates. Tim's ask: "template system... create characters and npcs, select the game template", "catch my sla-zero engine characters", survey vs public resources. Scoping: session-ready sheets (no lifepath minigames, Traveller compressed), editable in-app templates, optional AI flavor fill. Built: (1) safe expression evaluator app/chargen/exprs.py (hand-written recursive-descent, NO eval, MAX_NODES 10k iterative — closed a recursion-crash class); (2) template DSL app/chargen/dsl.py (TemplateSpec, evaluation-order contract = validator is engine-truth); (3) generation engine engine.py (dice/array/pointbuy, packages, skill-pool auto-spend, careers, provenance, seeded-deterministic); (4) NPC modes — archetype blocks + EXACT SLA-Zero threat/tier DELTA scaling + Mothership reduced blocks; (5) careers careers.py (Traveller qualify→terms→skills); (6) endpoint POST /library/generate-character {count 1-10, ai_fill claude|local, never 500s on AI failure→ai_error}; (7) templates CRUD /library/chargen-templates (400 detail is a structured {message,path} object — the editor's inline-error contract; builtin DELETE→409, builtin PUT allowed); (8) 11 seeded systems from a 5-lane research corpus, deep-reading Tim's OWN canonical rulebooks where they exist (CoC Luck contradiction found IN his Ch03; Stormbringer house SAN=POW5 + 19-row nationality table; RingWorld 55-skill list from his sheet; SLA-Zero verbatim from his zero-engine repo — 8 races/8 trainings/11 archetypes/scaling); (9) Mac ChargenStore + recursive ChargenJSON; (10) Character Forge wizard (spec-driven picks: dice/array/pointbuy editors, roll tables, NPC ARCHETYPE selector + threat tier → SLA-Zero delta-scaled blocks, dice-reveal, editable review grid w/ provenance chips, AI flavor, save as NPC/PC via existing stats JSONB); (11) template editor (JSON spec, inline 400 field errors, builtin badge, duplicate/delete-custom-only). SEEDER SAFETY: builtins are user-editable, so the seeder does a THREE-WAY merge keyed on a seed_hash baseline — creates missing, upgrades UNMODIFIED builtins to new shipped content, PRESERVES user-edited ones (never clobbers edits; "Reset built-ins" = the explicit restore path). Whole-phase 4-seam integration review: DSL round-trip / materialization / ai_fill all CLEAN; caught + FIXED the NPC archetype path being unreachable from the wizard (the SLA-Zero NPC feature Tim called out). SDD process: 10 tasks, every one implementer→adversarial-reviewer gated, controller closed test loops; 2 crash/data-loss classes closed (evaluator recursion T1, seeder overwrite T6). Backlog: custom-template camelCase pick/attr keys get snake_case-mangled on the wire (shipped seeds unaffected — all-caps/lowercase); client-side species-cap resolution for interactive pointbuy (currently auto-assigned); Grange Hill + Meta Alpha templates (Tim deferred); form-based editor v2. See tims-rpg-games.
As of 2026-07-04 BOTH are COMPLETE and pushed. Backend (HEAD 98a6d4e, 101/101 tests): full CRUD, JWT auth, MinIO assets, Claude streaming/structured generation, markdown importer, search, session journal, dice + random tables, entity backlinks, plot threads, AI recaps/preps, campaign export, pregen roster, procedural map system (BSP/CA/modern/scifi, top-down + isometric, Universal VTT export), art job queue (A1111 Stable Diffusion + Midjourney bridge) with /ws/jobs. Dev DB seeded with Tim's real gaming history (see tims-rpg-games).
P6.1 CLOUD ART DEPLOYED 2026-07-05 — api 7359632 (380 tests) + mac 3503a88 (231), BOTH LIVE ON PROD (server @ 7359632, keys in prod .env): "openai" + "gemini" providers in the artgen registry (key-presence availability; keys header-only, leak-proof error paths); Mac picker now server-driven. BOTH PROVEN e2e on local AND prod (real PNGs via forge.timevans.uk; OpenAI ~4¢/img gpt-image-1-mini medium; Gemini ~4¢/img gemini-2.5-flash-image). Gemini gotcha: his first "AQ.-prefix" key wasn't a Gemini API key (429) — working key is classic AIza format from AI Studio. Local SD is PAUSED by choice (renders under 16GB memory pressure took 3-12 min and starved the Mac; artgen read-timeout widened to 1800s in d370d3b so slow renders aren't orphaned when he does run it via forge-sd.sh up). MJ: still no official API (2026-07) — subscription/manual only. iPad companion design exploration published (ForgeRPG Table artifact) — kit is iOS-portable (Foundation+Security only), P7 candidate alongside multi-floor maps.
PHASE 6 COMPLETE 2026-07-05 (overnight autonomous night shift) — api 031419b 364 tests; mac 1982833 231 tests; both pushed; PROD REDEPLOY PENDING Tim's "redeploy" (carries migration e3aa1ae31d9a + SSE framing fix — prod content/recap/prep streaming is silently lossy until then). Shipped: map EDITOR (paint cells/stamps/room-renames/annotations over a locked JSONB edits overlay, PATCH regenerates assets so saves are visible, stroke-level undo surviving missed onEnded via @GestureState latch, top-down-only gate), village generator (roads/buildings/wells, zero-rng-when-disabled goldens), library v2 (PC creation, system stat templates from /library/stat-templates, art→portrait flow via single-key PUT), local AI (LM Studio provider llm:"claude"|"local" on content/recap/prep + forge-step, /generate/llm-providers), Scenario Forge wizard (5-step: premise→outline→scenes→NPCs/hooks→materialize, all streams editable, offline-capable). CRITICAL CONTRACT: SSE framing is now spec-compliant multi-line — api _sse_event splits chunks into per-line data: fields; mac streamSSE reassembles events joining with \n (NEVER parse SSE via AsyncLineSequence — it swallows the blank-line event boundaries); any new streaming endpoint MUST use _sse_event, wire fixtures MUST contain newlines. Fable phase-final review streak now 4/4 real seam bugs (P2 identity bleed, P3 editor swap, P5 status vocab, P6 SSE framing — both suites green on single-line fictions). Backlog in progress.md PHASE 6 COMPLETE entry; multi-floor maps = P7 candidate.
PHASE 5 COMPLETE 2026-07-05 (api 392cadf 227 tests; mac fe5ff44 183 tests; prod redeploy PENDING): maps overhaul (preview fit/zoom rebuild — the "empty map" was a 2× viewport illusion; Decor system + furnish/windows/density/decor/water options behind byte-identical goldens; render v2 glyphs/plates/room-numbers+legend; form presets) + WORKING LOCAL ART: A1111 proved broken at core on this Mac (step-count-dependent corruption; diffusers control clean) → replaced by scripts/forge_sd_server.py (159-line FastAPI diffusers microserver, same /sdapi/v1/txt2img subset, port 7860, managed by forge-sd.sh; DreamShaper 8 checkpoint at ~/ForgeRPG-sd/webui/models/). Status-vocab seam bug fixed (API pending/processing/complete ≠ Mac queued/running/completed — ingest normalization; BOTH suites had mocked their own fiction). Providers endpoint + honest failure UI + retry. LESSONS: cross-repo contract fixtures must use WIRE values; A1111 is abandonware-fragile on new macOS — diffusers direct is the durable path. PHASE 6 SCOPED (Tim): maps EDITOR (paint/stamps/annotations/village generator), library v2 (rich NPC/PC editors — PC creation flow currently missing, portraits from art studio, system-aware stat templates), Scenario Forge wizard with LOCAL AI via LM Studio (offline con prep).
PHASE 4 COMPLETE 2026-07-04 (mac f16bf28 168 tests; api eed7d42 127 tests): "Arcane Modern" design system (Theme.swift tokens — ember/arcane/ink/rust/wheel, one spring, reduceMotion-gated everywhere, DARK-PINNED — light mode is future work; app must launch via activation-policy fix, unbundled swift-run apps can't focus text fields otherwise), full restyle of chrome/dashboard/editor/tools, LOCAL MODE (api scripts/forge-local.sh + forge-checkout/checkin con scripts with hard size gates + type-PUSH confirm; runbook scripts/README.md), server switcher menu + login quick-picks (KnownServers) + sign-out. GOTCHAS LEARNED: Tim's Mac = light mode (design must pin dark); Tim confused foundry↔forge hostname (quick-picks fix); MJ pipeline scripts NOT on this Mac (RPGS/Stormbringer/scripts empty — stale memory in tims-rpg-games); prod art providers unconfigured so art jobs fail (Phase 5: local SD install + providers-availability endpoint; Tim chose MJ+SD, rejected OpenAI images).
PHASE 3 COMPLETE + DEPLOYED 2026-07-04 (api 1768a14 LIVE on VPS — image rebuilt with reportlab+jinja2, share_links migration b44e4a01f0c6 applied, foundry/pdf/portal smoke-verified through forge.timevans.uk; mac ad30af7, 168 tests). Adds: ⌘K deep-links into scenario/scene (NavigationCoordinator; two identity-reset fixes: .id(campaign.id) on dashboard, .id(scenario.id) on editor — SwiftUI stores capture ids at init, EVERY in-place swap needs an id reset); field clearing via clears: Set<String> on payloads (explicit JSON null; backend exclude_unset semantics); Foundry VTT export (zip of importable journals [GM pages ownership.default=0], actors, walled scenes); con-pack PDF (/export/pdf, reportlab); player portal (share tokens, /portal/{token} jinja2 pages, handout-tagged assets only, security-reviewed — GM content provably absent); Share menu in dashboard. Polish backlog (12 items) in progress.md ledger.
Mac app — Phases 1 + 2 + Amendment A COMPLETE (HEAD 9ca30b4, 123/123 tests; backend companion fa53fb9, 105 tests, deployed to prod): pure SwiftPM (swift run ForgeRPG), zero deps. Full feature set: login/Keychain + server-URL switching (stable injected client, 401→login sheet), campaign browser, scenario/scene markdown editor (GM notes, AI drawer, backlinks Links pane), library (NPCs/locations/factions/pregens), campaign dashboard tabs Scenarios|Sessions|Threads|Prep (journal with AI recaps, plot-thread lifecycle, Lazy-DM prep streaming + save-as-sheet), JSON/Markdown campaign export, dice roller + random tables, maps studio (4 kinds, 3 styles, topdown/iso preview, rerender, PNG + .dd2vtt export), art studio (SD/MJ jobs, live /ws/jobs status, thumbnails), ⌘K search palette (named results). Phase 2 ledger + polish backlog in .superpowers/sdd/progress.md (11 recorded non-blocking items; biggest: field-clearing explicit-null amendment, SceneStore flush-on-back, palette deep-links = Phase 3).
DEPLOYED 2026-07-04 to VPS root@77.68.99.134 (same box as graphiti/mailu/gitea/nextcloud — scope rule: only touch /opt/forgerpg + compose project forgerpg). SSH: this Mac's ed25519 key authorized for root AND tevans. Stack: /opt/forgerpg/app-src @ 98a6d4e, docker compose -p forgerpg -f docker-compose.prod.yml (server-side compose file; base compose's 9001 MinIO console port couldn't be suppressed by merge override). API on 0.0.0.0:8000, postgres/minio internal-only. Migrations+seed applied; on-box smoke all green. ADMIN_PASSWORD in .superpowers/sdd/task-9-deploy-report.md (MacMem).
LIVE at https://forge.timevans.uk (2026-07-04): Tim added the DNS A record and the Caddy vhost (reverse_proxy 172.18.0.1:8000 — host-gateway style, his edit) himself; real ANTHROPIC_API_KEY loaded; E2E verified from outside (login, 16 campaigns, real Claude SSE generation). Provider firewall keeps 8000/2222 closed externally — all traffic via Caddy 443, which is the intended end state.
Ops gotcha (bit us once): docker compose restart does NOT reload .env — env is baked at container creation. To apply .env changes: docker compose -p forgerpg -f /opt/forgerpg/app-src/docker-compose.prod.yml up -d --force-recreate api.
Mac Amendment A (client injection) DONE 2026-07-04 — app is production-ready: one stable SessionStore-owned APIClient (updateBaseURL retargets in place, client is let), zero ad-hoc APIClient() in views, 401 hook survives server switches; 27/27 tests. Commits a380771/f4c635c/6a0dcf4 (+ push once authorized). To use remotely: launch app, set Server URL to https://forge.timevans.uk in the login sheet, admin password from task-9-deploy-report.md. Toolchain gotcha: swift test prints two runner summaries — the "0 tests" line is swift-testing; XCTest's real line says "Executed 27 tests".
Remaining optional/deferred:
- Gitea mirror: needs Tim to register this Mac's pubkey in Gitea (gitea.timevans.uk) settings; then push via
-J root@77.68.99.134jump (external 2222 firewalled). - Art providers: SD_API_URL → Tailscale URL to his Mac's AUTOMATIC1111; MJ_BRIDGE_CMD → wrapper around
RPGS/Stormbringer/scripts/mj_bridge.py. - MinIO creds hardcoded
minioadminin compose (internal-network-only exposure; tidy in a future backend amendment). - V2 sync design decision parked: soft-deletes don't bump sync_version (updated_at auto-bumps via onupdate; backfillable).
Plan/spec/ledger live in MacMem repo: docs/superpowers/{plans,specs}/2026-06-29-forgerpg-*.md, .superpowers/sdd/progress.md.