refactor(style): redesign config into canonical v2 schema (look/motion) - #863
Conversation
Reshape styles.config from a flat blob into grouped look/motion/references with one canonical StyleProjection type, fix backwards optionality, and add a v1->v2 converter reused by read boundaries, the template seed, and a backfill. Motion is now a first-class core signature (camera + optional shots/pace/energy) instead of a single cameraWork string; new optional design/casting/sound/source slots future-proof LLM/vision style creation. Blob-internal reshape needs no DDL/table-rebuild; bump PROMPT_INPUT_HASH_VERSION 3->4 and add a data-only null-sweep migration so legacy rows read as untracked (no false "stale" banners, no regeneration storm). Closes #858 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Cloudflare Preview deployed successfully
|
|
Closing after a comprehensive five-agent review. The design direction survives — issue #858 stays open and the redesign will be re-implemented on current Why close instead of rebase
Key review findings (would block merge regardless of rebase)The null-sweep migration is being dropped entirely. Its column list was name-matched, not derivation-traced:
Replacement strategy: a stable hash projection — hash a v1-shaped projection of the config (legacy key names, new fields included only when populated) and keep Other confirmed defects:
Worth carrying forward: the canonical type + single v1→v2 converter reused at every boundary, Re-implementation follows on a fresh branch off 🤖 Generated with Claude Code |
Summary
Redesign the
stylesschema around a single canonical type (issue #858). AStylerow was fractured into two shapes — identity columns and an aesthetics JSON blobconfig— with no canonical type, backwards optionality, and motion under-specified by a singlecameraWorkstring. This reshapesconfiginto a grouped v2 structure, introduces one canonical projection type, fixes optionality, and lands it as a safe, no-DDL blob migration.v2
StyleConfigshapeA style encodes three signatures — narrative / look / motion — with motion in the core (it can't be derived from a still). Small required core + a wide optional surround so quick/LLM/vision styles stay compact while templates stay rich:
What changed
src/lib/style/style-config.ts(new, drizzle-free): v2StyleConfigSchema, onemigrateStyleConfigV1ToV2+parseStyleConfigconverter (reused at read boundaries, template seed, and backfill), and the canonicalStyleProjection.libraries.tsre-exports for existing import paths.EnhanceStyle,enhanceScriptInputSchema.style,StyleTemplateEntry) now derive from the canonical type; newstyle-brief.tscentralizes optional-field handling for the enhancer.parseStyleConfig(v1-tolerant during rollout).style.schemas.ts(category required on create; tags/useCases default[]; config whole-or-omitted on update).computeStyleConfigHash→ v2 fields;PROMPT_INPUT_HASH_VERSION 3→4; data-only null-sweep migration20260608120000_null_hashes_for_style_v2(mirrors the…v3_bumpprecedent).scripts/backfill-style-config-v2.ts(idempotent, dry-run, validates before write).motionsignature, somotion.shots/pace/energysurface automatically once authored.Migration safety
The blob reshape needs no DDL and no table rebuild (
configis one column), so the D1ON DELETE CASCADErebuild trap is not in play. Staleness is read-time and null→untracked, so the null-sweep avoids false "stale" banners with no regeneration storm.Verification
bun typecheckclean ·bun run test1210 passed ·bun lint0 errors ·bun format:checkcleanbun db:migrate:localapplies the null-sweep cleanly ·bun db:seed:localwrites 80 valid v2 stylesbun scripts/backfill-style-config-v2.ts --localmigrated a real legacy v1 row; re-run reports 0 to migrate (idempotent)Follow-ups (out of scope)
parseStyleConfigonce prod is fully backfilled.categoryto a DBNOT NULLcolumn (needs a manually-applied migration).Closes #858
🤖 Generated with Claude Code