Skip to content

feat(universe-builder): Phase A — add category kind + retire default characters bucket#264

Merged
atomantic merged 3 commits into
mainfrom
feat/ub-redesign-phase-a
May 17, 2026
Merged

feat(universe-builder): Phase A — add category kind + retire default characters bucket#264
atomantic merged 3 commits into
mainfrom
feat/ub-redesign-phase-a

Conversation

@atomantic
Copy link
Copy Markdown
Owner

Summary

Phase A of the Universe Builder redesign (PLAN.md Next Up #1). Data model + migration only — no UI changes yet.

  • Adds kind: 'characters'|'settings'|'objects'|'other' to every category bucket, tagging it to one of the 3 canon trunks the Phase C UI will render under.
  • Retires the default characters category — canon owns characters now. Variations from any incoming characters bucket get folded into universe.characters[] (via existing backfillCanonFromCategories) and the bucket is dropped on sanitize.
  • One-shot migration 018-categorize-universe-buckets.js makes the v3→v4 transition observable + atomic on upgrade (the on-read sanitizer also converges installs that skip it).

Design context

This rewrites the original "retire universe.categories entirely" PLAN item, which was a misread — canon (consistency workflow) and categories (visual-exploration workflow) are complementary, not redundant. The accepted framing unifies them under 3 canon trunks: canon entries are first-class entities with rich metadata; sub-buckets (formerly "categories") are organizational + bulk-generation surfaces within each trunk. See PLAN.md → "Categories vs canon — decision (2026-05-17)".

Multi-phase rollout (each phase is a separate PR):

  • Phase A (this PR): data model + migration.
  • Phase B: enrich expand LLM contract to return rich canon arrays (characters[]/settings[]/objects[]) alongside categories.
  • Phase C: tabbed-trunk layout (Bible / Cast / Places / Objects / Other / Composites / Render) with card grids + thumbnails. Canon entries become first-class batch-render targets.
  • Phase D: "Promote variation to canon" + polish.

Changes

  • server/services/universeBuilder.js — schema v3→v4; new CATEGORY_KINDS, DEFAULT_CATEGORY_KIND, WORLD_CATEGORY_DEFAULT_KINDS, RETIRED_CATEGORY_KEYS, resolveCategoryKind. sanitizeCategory accepts + persists kind; sanitizeCategories drops retired buckets; mergeCategories propagates kind.
  • server/routes/universeBuilder.jscategoryShape Zod accepts optional kind enum.
  • client/src/pages/UniverseBuilder.jsx — 1-line cleanup (dropped retired-default label).
  • scripts/migrations/018-categorize-universe-buckets.js — one-shot upgrade with per-universe error context.
  • PLAN.md — full design history captured (rejected framings → accepted unification), Phase A/B/C/D scoped.
  • .changelog/NEXT.md — user-facing entry.

Test plan

  • cd server && npm test — 5102 passing, 5 skipped, 234 files
  • cd client && npm run build — clean build
  • Migration test suite (7 cases): empty file no-op, schema-v4 skip, characters fold, dedupe-by-name, kind assignment for defaults + customs, explicit-kind precedence, idempotency
  • Internal review against /simplify (3 medium findings applied: extracted RETIRED_CATEGORY_KEYS, simplified mergeCategories fallback, added per-universe error context)
  • Manual smoke: create a new universe in the UI, verify it loads with the 4 default categories (no characters) and each has a kind
  • Manual smoke: open an existing universe (post-migration), verify any pre-v4 characters bucket variations now appear under canon Characters

Known deferred

  • arcPlanner.js#worldCategoriesText only renders from world.categories. With the characters default retired, character names that were in that bucket no longer appear in arc-planning prompts (they're in world.characters[] canon now). Captured in PLAN.md Backlog as Phase B follow-up: add renderCanonForPrompt(world) + worldCanonText context field.

🤖 Generated with Claude Code

atomantic added 3 commits May 17, 2026 05:22
…lt `characters` (Phase A)

Schema v3→v4: every category bucket now carries `kind:
'characters'|'settings'|'objects'|'other'` tagging it to one of the 3 canon
trunks the Phase C UI will render under. Built-in defaults get a known kind
(landscapes/environments/structures→settings, vehicles→objects); custom
buckets fall to 'other' until the Phase C Auto-sort action LLM-classifies
them.

The default `characters` category is retired — canon owns characters now.
Any incoming `characters` bucket gets folded into universe.characters[] (via
the existing backfillCanonFromCategories logic) and dropped on sanitize. A
new one-shot migration (017-categorize-universe-buckets.js) does the same
proactively on upgrade for observability + atomicity.

Phase A is data-model + migration only; Phase B enriches the expand LLM
contract and Phase C delivers the tabbed-trunk layout (see PLAN.md).
Copilot AI review requested due to automatic review settings May 17, 2026 12:26
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Phase A of the Universe Builder redesign: introduces a kind discriminator on each category bucket (mapping it to one of the canon "trunks") and retires the default characters bucket so canon becomes the sole home for characters. This is a data-model + migration change with no UI rework.

Changes:

  • Bump universe schema to v4 with CATEGORY_KINDS, WORLD_CATEGORY_DEFAULT_KINDS, and RETIRED_CATEGORY_KEYS; sanitizers/route Zod accept and persist kind, retired buckets are dropped (variations folded into canon).
  • Add one-shot migration 018-categorize-universe-buckets.js plus a dedicated test file (with vitest config updated to include scripts/migrations/**).
  • Update affected unit/route tests, drop the retired characters label in UniverseBuilder.jsx, and document the design decision in PLAN.md and the changelog.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.

Show a summary per file
File Description
server/services/universeBuilder.js Schema v4, kind constants, sanitizer/merge changes, retired-key drop
server/routes/universeBuilder.js Zod kind enum on categoryShape
server/services/universeBuilder.test.js New kind tests; swap retired characters for custom outfits in seed
server/services/universeBuilderExpand.test.js Update tests for retired characters default + kind tag
server/services/pipeline/arcPlanner.test.js Update arc-planner test for retired characters bucket
server/routes/universeBuilder.test.js Route tests for kind enum + bucket folding
server/vitest.config.js Add scripts/migrations/** to include glob
scripts/migrations/018-categorize-universe-buckets.js New v3→v4 migration
scripts/migrations/018-categorize-universe-buckets.test.js Migration test suite
client/src/pages/UniverseBuilder.jsx Drop retired characters label
PLAN.md Capture rejected/accepted framings + multi-phase plan
.changelog/NEXT.md User-facing entry

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@atomantic atomantic merged commit 2c13247 into main May 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants