#2 Refactor/data extraction#655
Merged
datdamnzotz merged 106 commits intoOrcpub:developfrom Mar 13, 2026
Merged
Conversation
Dependency upgrades: Clojure 1.12.4, ClojureScript 1.12.134, Pedestal 0.7.0, Datomic Pro 1.0.7482, React 18.3.1, Reagent 2.0.1, re-frame 1.4.4, PDFBox 3.0.6, Buddy 3.x, figwheel-main 0.2.20, java-time 1.4.2, and supporting library updates. Key changes: - Datomic Free -> Pro (Java 21 compatibility) - Pedestal interceptor wrapping + CSP nonce handling (required by 0.7) - React 18 createRoot migration - clj-time -> java-time - lein-figwheel -> figwheel-main - CI updated to Java 21 - Devcontainer + scripts for Datomic Pro setup 74 tests, 237 assertions, 0 failures.
Migration index + per-topic docs covering Pedestal 0.7 (CSP, interceptor wrapping, Jetty 11 pin), Datomic Pro, React 18/Reagent 2, library upgrades, dev tooling, Java 21 compatibility, and environment variables. Also fixes CI workflow Java version 8 → 21.
Move dev_init.clj and dev_tools.clj into dev/user.clj so dev tooling stays off the production classpath (src/clj/ is AOT-compiled into the uberjar). The user namespace now serves as both REPL helper and CLI entrypoint via -main dispatch. - user.clj: add :gen-class, conn helper, user CRUD, -main CLI - project.clj: :init-db profile includes dev/ in source-paths - scripts: rewire start.sh, create_dummy_user.sh, dev-setup.sh - docs/migration/dev-tooling.md: rewrite for Clojure newcomers - README.md: full overhaul for modern stack (Java 21, Datomic Pro, Pedestal 0.7, React 18, figwheel-main) - Delete src/clj/orcpub/dev_init.clj and dev_tools.clj
Frontend: - Fix message component white-on-white text (Garden CSS class) - Fix login form input alignment (Garden CSS class) - Fix favicon.clj 196→192 size typo - Use :class instead of :class-name (Reagent 2.x merge behavior) Build: - Add externs.js for React 18 APIs (ReactDOM.Root.render, flushSync) - Upgrade cljs-http 0.1.45→0.1.49 (fixes no.en.core shadowing warnings) - Switch to lambdaisland/garden 1.9.606 (fixes clojure.core/abs shadowing) - Add simplelogger.properties to suppress PDFBox font fallback WARN - Add fonts-liberation to Dockerfile (root cause fix for font fallback) - All builds now 0 errors, 0 warnings Dev tooling: - CSP nonce interceptor is no-op in dev mode (eliminates console spam) - Figwheel uses fig:watch (headless) via start.sh; fig:dev for interactive - menu CLI for user management (create/verify/delete with .test-users log) - dev-setup.sh auto-creates test user (--no-test-user to skip) - Updated migration docs (CSP behavior, core shadowing, externs, figwheel modes)
Extract pure compute helpers to compute.cljc and shared utils to event_utils.cljc (moved from .cljs). Replace all 12 instances of @(subscribe [...]) inside event handlers with direct db reads, component-passed parameters, or replicated computation chains. Adds autosave_fx.cljs with track!-based template caching for the autosave handler that previously depended on @(subscribe [:built-character]).
Add fig:test alias and test.cljs.edn for figwheel-based CLJS testing. New tests: compute_test.cljc (plugin vals, spell/item filtering, sort order), event_utils_test.cljc (auth headers, mod config), events_test.cljs (re-frame handler integration via dispatch-sync). Fix character_test.cljc for CLJS compatibility with reader conditionals around JVM-only APIs.
Reagent 2.x changed :class-name behavior — it now OVERWRITES hiccup tag classes instead of merging them. This caused widespread visual regressions where base CSS classes on elements were silently dropped. 114 hiccup prop instances fixed across 6 files. Data map :class-name keys (D&D class names in character/template/spell data) left unchanged.
22 subscribe calls in options.cljc prereq-fn closures replaced with direct character/* pure function calls. These were never reactive — the subscribe signal wrapped the passed entity in a plain atom. Now prereq-fns receive built-char directly from callers (views_aux, character_builder, entity) matching the old data flow exactly. Also: fix meets-prereqs? when/if bug, overflow-x:hidden for horizontal scroll, user.clj clean exit, search-input-keypress fix.
…cljc 7 subscribe calls in prereq-fn closures replaced with direct char5e/ability-values and char5e/spells-known calls. Also removed unused re-frame.core/subscribe import.
Phase 2: 13 subscribes across options.cljc, pdf_spec.cljc, equipment_subs.cljs, and views.cljs replaced with pure functions, parameter threading, plugin-data maps, and reg-sub-raw. pdf_spec.cljc is now fully pure — no re-frame dependency. options.cljc threads race-map from caller instead of subscribing. equipment_subs ::mi5e/item converted to reg-sub-raw for conditional sub. Also fixes input-field flickering in components.cljc — tracks :prev-value to clear temp-val only when parent value catches up, instead of clearing in setTimeout (which raced with Reagent 2.x synchronous rendering).
Tests cover the SSOT pure functions and parameter threading changes from the subscribe refactor: - compute-all-weapons-map: PHB weapons, magic weapon merge, custom weapon expansion, nil/empty equivalence, custom doesn't clobber base - feat-prereqs: exact label assertions for ability/spellcasting/armor prereqs, race-map parameter threading, mixed prereq combinations - pdf_spec: class-string formatting (single/multi/subclass/empty), entity-vals key mapping and rename behavior 123 tests, 332 assertions, 0 failures.
…tion input-field now dispatches on every keystroke. The expensive entity/build call is debounced in the :built-character subscription with leading+trailing edge: first change computes immediately (dropdowns stay snappy), rapid keystrokes batch until 500ms quiet. input-field keeps a minimal local atom to buffer typed text and prevent controlled-input flicker while re-frame propagates.
option-language-proficiency-choice used def+partial which evaluated @(subscribe [::langs/languages]) at namespace load time, outside any reactive context. Converted to defn so subscribe runs during render.
Merges 24 commits from origin/develop:
- Character folders feature (13 commits)
- Equipment/weapon fixes: special, loading properties (5 commits)
- Docker verified users and setup scripts (3 commits)
- Additional test coverage
Conflict resolutions:
- views.cljs: merged folder UI with subscribe refactor + :class-name fixes
- docker-compose*.yaml: kept ${VAR:-default} pattern with datomic:dev:// URLs
- magic_items_test.clj: kept both compute-all-weapons-map and weapon property tests
- pdf_spec.cljc: threaded all-magic-items-map through plugin-data (new subscribe from develop)
Post-merge fixes:
- 4 new :class-name → :class conversions in folder/filter code (Reagent 2.x)
- Added :all-magic-items-map to plugin-data assembly in views.cljs
- Fix events/show-generic-error undefined alias in subs.cljs - Add on-failure handlers to all folder HTTP ops (re-fetch on error) - Client + server validation: reject blank folder names - Wrap check-folder-owner with interceptor/interceptor, add 404 - Use named tempid in create-folder (d/resolve-tempid) - Add default clause to folders subscription case statement - Fix builder-dropdown CSS class (undefined → builder-option-dropdown) - Add 3 server-side tests: blank rejection, trim, nil-name default - Update MIGRATION-INDEX test counts, frontend-stack subscribe totals - Add docs/STACK.md: library/dependency onboarding guide
Delete 4 static map wrapper subs (weapons-map, armor-map, equipment-map, treasure-map) superseded by homebrew-aware versions. Reader-discard 7 unused subs with explanatory comments. All pre-existing tech debt.
Use event-utils/show-generic-error instead of the def alias that appears later in the file. Brings lint errors from 1 to 0.
591 if-without-else converted to when/when-let/when-not across 33 files. Resolved 11 merge conflicts (re-ran fix script on breaking's versions). Fixed 2 pre-existing bugs: when with implicit do discarding first expr in classes.cljc (ranger terrain) and options.cljc (spell level title). Lint: 0 errors, 0 warnings. Tests: 174/444/0.
- Move all linter config from project.clj :lint profile to .clj-kondo/config.edn (single source of truth for both IDE and CLI) - Expand lint scope: src, native, test, web (was src only) - Bump clj-kondo 2024.05.22 → 2026.01.19 - Fix deprecated :if → :missing-else-branch linter name - Add :clojure-lsp/unused-public-var :exclude for live false-positives - Add :exclude-when-defined-by for re-frame registration macros - Add shadowed-var :exclude list for intentional shadows
#_ discard 43 dead vars: - common.cljc (4): ptime, hours-per-day, rounds-to-hours, rounds-to-minutes - character.cljc (6): add-namespaces + 2 cascade helpers, base-climbing-speed, saving-throw-advantages, max-armor-class - classes.cljc (4): blessings-of-knowledge-skill, spell-level-to-cleric-level, spell-in-spells-known?, pact-weapon-option - options.cljc (15): deprecated ua/scag refs, #_ template refs, zero-caller defs - template.cljc (14): ability roller UI (superseded by character_builder.cljs), amazon frames, content-list, custom-race-builder; #_ subscribe/dispatch refers (no live callers remain) Redundant expression fixes: - classes.cljc: remove nested (str (str ...)) - options.cljc: flatten (and (and ...)) in dual-wield checks, remove duplicate source destructuring param
#_ discard 49 dead vars: - views.cljs (25): dead style defs, duplicate constants, superseded components - events.cljs (22): dead defs (max-iterations, dnd-5e-characters-path, validate-registration, set-active-tabs, remove-subtypes, compute aliases), 17 never-dispatched reg-event-db/fx handlers - db.cljs (1): musical-instrument-choice-cfg (duplicate of classes.cljc) - subs.cljs (1): ::char5e/summary reg-sub (never subscribed to) Redundant expression fixes: - views.cljs, character_builder.cljs, events.cljs: remove (str "literal")
Native:
- Remove unused refers (atom, subscribe, dispatch, dispatch-sync)
- Add missing font-size param to remaining-bubble
- if→when for side-effect-only branches
Web:
- if→when for protocol redirect and route matching
Tests:
- Narrow :refer lists (deftest/is only, remove unused diff/testing)
- Fix misindented (* 2 v) in entity_spec_test
- if→when in event_handlers_test
Registration:
- Remove unreachable {} before cond-> in validate-registration
Docs:
- CHANGELOG: document lint commits (if→when, forward-ref fix), update status
- MIGRATION-INDEX: update lint status to 0 errors, 0 warnings
Merge feature/error-handling-import-validation into breaking/2026-stack-modernization. 29 conflicting files resolved, 21 new files auto-merged, 206 tests passing. New features: import/export validation pipeline, email change flow, missing content detection, conflict resolution UI, backend error handling, nil guards in PDF/routes, orcbrew CLI tool. Post-merge fixes: handle-api-response moved to event_utils.cljc, srd-link un-discarded, key-to-name → common/kw-to-name, :class-name → :class for Reagent 2.x, hiccup2 str wrapping.
Auto-merged content_reconciliation.cljs references these functions but they didn't survive the merge into common.cljc. Restored from feature branch. 0 CLJS warnings, 206 JVM tests passing.
…ions ::char5e/template is used by autosave_fx.cljs and as input signal for ::char5e/built-template. ::char5e/summary-map is used by the combat tracker in views.cljs. Both were false-positive dead code.
header-tab: on-mouse-over/out → on-mouse-enter/leave to prevent menu from disappearing when cursor moves from button to dropdown. mouse-enter/leave doesn't fire between parent and child elements. dropdown: map → map-indexed with index-prefixed keys to handle duplicate option values from homebrew plugin data (e.g., :alchemical-homunculus appearing twice in the same selection).
Builder: block save when option names are empty or duplicated, with inline red borders and error messages on offending fields. Import pipeline: dedup identical options silently, rename different-content same-name options with number suffixes. Dropdown: distinct-by safety net for pre-existing data in localStorage.
set-combat-path-prop now falls back to default-combat when the path interceptor extracts nil, preventing assoc-in from building maps with integer keys instead of vectors. Also improves the invalid-item log message to include the localStorage key name for easier debugging. Adds docs/TODO.md to track the broader localStorage cleanup strategy.
4 static equipment map subscriptions (weapons-map, armor-map, equipment-map, treasure-map) were deleted during orphan cleanup but are still used by character_builder's inventory-selector via dynamic sub vectors. Restores them — fixes IDeref crash on equipment page. Template cache init (autosave_fx) now retries if the subscription isn't registered yet. In dev mode each namespace loads as a separate script, and setTimeout 0 can fire before equipment_subs.cljs has loaded — preventing the IDeref crash on cold page load.
…sitives autosave_fx: require equipment-subs directly instead of retry logic. This guarantees ::char5e/template sub is registered before the defonce runs, so subscribe stays inside r/track! (reactive context, no warning). content_reconciliation: remove catch-all that labeled everything under a class path as "Class" content. Keys like :roll (HP method), :feat (ASI choice), :great-weapon-fighting (fighting style), :intimidation (skill pick) were being flagged as missing homebrew. Now only flags keys at content-relevant depths: class at [:class], subclass at [:class :archetype-type], race, subrace, background.
…193 → 640 lines) builders.cljs is now a pure shared toolkit: field factories, option-* helpers, plugin-datalist, spell/level selectors, builder-page infra. New files under builders/: feat, classes, item, monster, race, background, spell, selection, language, warlock Key decisions: - class → classes (JS reserved keyword avoidance) - spell-selector + modifier-level-selector stay shared (option-spell depends on both, used by race AND class) - boon + invocation share warlock.cljs (both Warlock features) - All child files import from builders.cljs only (no child→child deps) 0 CLJS warnings, 206 tests pass.
Points new agents at the KB architecture map and topic index before they scan the repo. Includes project conventions and known ClojureScript gotchas.
`lein uberjar` now compiles CLJS via figwheel-main as a prep-task, so a single command produces a complete jar with compiled JS. Previously CLJS had to be compiled separately (fig:prod) before packaging, and the uberjar clean step would wipe it if you forgot. Docker build is unaffected — uberjar-package profile uses ^:replace on prep-tasks, so the 3-step build (CLJS, AOT+timeout, jar) is unchanged.
Reverts the figwheel prep-task addition from 077753c. `run` as a prep-task in the :uberjar profile triggers the profile's own prep-tasks recursively — lein enters an infinite build loop. CLJS must remain a separate step: `lein fig:prod && lein uberjar`. Docker is unaffected (uberjar-package uses ^:replace prep-tasks).
Chains fig:prod (CLJS) then uberjar in one command via `lein do`. fig:prod runs without the :uberjar profile, avoiding the prep-task infinite recursion that happens when `run` is a direct prep-task. CLJS output (resources/public/) survives uberjar's clean (target/ only).
:clean-targets includes resources/public/js/compiled, so the uberjar clean prep-task was wiping the CLJS output that fig:prod just built. Fix: alias runs clean explicitly first, then fig:prod, then uberjar with uberjar-noclean profile (skips redundant clean). Standalone `lein uberjar` still cleans as before.
lein's jar/jar checks (:auto-clean project true) defaulting to true, which runs clean before jar creation even when "clean" is removed from prep-tasks. This deletes resources/public/js/compiled/ (CLJS output from fig:prod) causing orcpub.js 404 in production. Fix: add :auto-clean false to :uberjar profile, use ^:replace on prep-tasks. Remove :uberjar-noclean (absorbed into :uberjar). Simplify :uberjar-package (inherits auto-clean from :uberjar).
The monkey-patch on re-frame.core/subscribe used a variadic fn (fn [query-v & args] ...) which doesn't implement IFn's 1-arity .h method. In advanced compilation, all (subscribe [...]) call sites compile to Y.h(vec) using 1-arity protocol dispatch, causing "Y.h is not a function" TypeError on every render.
The inline script that fetches /homebrew.orcbrew ran unconditionally,
causing 400 errors when no server-side plugin endpoint exists. Now
only emits the fetch script when LOAD_HOMEBREW_URL is set. Also fixes
the protocol:// double-colon bug (window.location.protocol includes
the colon, so ${protocol}:// produced https:://).
- LEIN-UBERJAR-HANG.md: document :uberjar profile changes (auto-clean false moved from uberjar-package to uberjar), lein build alias, updated affected components table - ENVIRONMENT.md: add LOAD_HOMEBREW_URL variable, add index.clj to files-that-read-environment table - .env.example: add LOAD_HOMEBREW_URL (commented out by default) - docker-compose files: add LOAD_HOMEBREW_URL passthrough - core.cljs: clean up blank lines from debug wrapper removal
…n' into refactor/views-extraction
Move the ~9,200-line monsters-raw vector (356 SRD monster stat blocks) from monsters.cljc to a dedicated monsters_data.cljc sibling. The logic file (specs, display helpers, derived lookups) drops from 9,273 to 54 lines. Zero behavioral changes — monsters and monster-map still derive from the same data via a require alias.
Move school/duration/range constants, all 22 alphabetical spell vectors (a-spells through z-spells), and the derived spells/spell-map lookups from spells.cljc to a dedicated spells_data.cljc sibling. The logic file (specs + re-exports) drops from 4,229 to 59 lines. External consumers still import from spells.cljc — schools, spells, and spell-map are re-exported unchanged.
Move item predicates, generator helpers (horn-of-valhalla, dragon-scale- mail, ioun-stone, etc.), resistance/vulnerability data, and the 2,500- line raw-magic-items vector from magic_items.cljc to a dedicated magic_items_data.cljc sibling. The logic file (specs, internal-format converters, expansion/merge logic) drops from 3,214 to 512 lines. Uses :as-alias to resolve qualified keywords (::mi/type, ::mi/rarity, etc.) to the parent namespace's keyword space without creating a circular dependency.
Move all 12 class option builder functions (barbarian through warlock), their local helpers (bardic-inspiration-die, monk-weapon?, metamagic- selection, etc.), and spellcasting schedule defs from classes.cljc to a dedicated classes_data.cljc sibling. The logic file (specs + re-exports) drops from 3,147 to 45 lines. External consumers still import from classes.cljc — all 15 public vars are re-exported unchanged.
Pre-existing issue found during magic items data extraction — the homebrew item builder's saving throw dropdown is hardcoded to one option with no event wiring. Should match the ability/speed pattern.
Add navigability headers (;;; ─── Section ─────) to the four large data files created during the SRD data extraction refactor: - spells_data.cljc: constants, alphabetical spell groups (A-Z), derived lookups - magic_items_data.cljc: key aliases, predicates, generator helpers, resistance sets, item data - classes_data.cljc: shared helpers, then per-class sections (Barbarian through Warlock) - monsters_data.cljc: single header for alphabetical stat block data Also adds brief comments to non-obvious generator helpers in magic_items_data.
New agents need to know about the :as-alias pattern used in magic_items_data.cljc for cross-namespace keyword resolution.
lein-garden 0.3.0 (abandoned, 2016) injects ns-tracker 0.2.2 into its subprocess classpath via ^:displace. That version predates :as-alias (Clojure 1.11+) and treats it as a real dependency, causing false circular dep errors during AOT compilation (magic_items_data.cljc). Override by adding ns-tracker 1.0.0 to project :dependencies — the ^:displace metadata means the explicit version wins everywhere garden runs, including during uberjar prep-tasks. Also logs lein-garden replacement options in docs/TODO.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merge AFTER refactor/views-extract
refactor: extract SRD data to _data.cljc siblings (Tier 1)
(slowly laying the ground work for easier 5.24 integration)
Summary
.cljcfiles into dedicated_data.cljcsiblingsChanges
monsters.cljcmonsters_data.cljc(9,226)spells.cljcspells_data.cljc(4,187)schools/spells/spell-mapmagic_items.cljcmagic_items_data.cljc(2,721):as-aliasfor parent ns keywordsclasses.cljcclasses_data.cljc(3,137)Also adds section headers to all 4 data files and logs a pre-existing dead control (
item-saving-throw-bonuses) indocs/TODO.md.Test plan
lein test— 206 tests, 945 assertions, 0 failureslein fig:build— 0 CLJS warnings