refactor(style): canonical v2 style config with hash-stable projection - #1174
Open
tombeckenham wants to merge 2 commits into
Open
refactor(style): canonical v2 style config with hash-stable projection#1174tombeckenham wants to merge 2 commits into
tombeckenham wants to merge 2 commits into
Conversation
Redesign the styles config blob around one canonical type (issue #858), re-implemented against current main after PR #863 was closed as stale. - New drizzle-free src/lib/style/style-config.ts: grouped v2 StyleConfigSchema (look/motion core + references, version tag, optional summary/tone and motion refinements shots/pace/energy, look medium/texture/composition), validated migrateStyleConfigV1ToV2, parseStyleConfig at every read boundary, StyleProjection with a real constructor, and total UI accessors. - Hash-stable by construction: styleConfigHashBody projects v2 back to the legacy flat key names and adds new fields only when authored, and all hashers (visual/motion prompt hashes + computeStyleConfigHash) share it. A pure reshape flips NO stored hash: no PROMPT_INPUT_HASH_VERSION bump, no null-sweep migration, no staleness data destroyed. Pinned by test. - Column typed StoredStyleConfig (v1 | v2) so skipping parseStyleConfig does not compile; corrupt blobs throw loudly, ZodError escalates to logger.error in shot staleness, and the v1 read branch logs a warn as an observable retirement signal. - Optionality fixed: category required on create (.extend — drizzle-zod keeps nullable columns optional under refinements), tags/useCases default [], references default [], config whole-or-omitted on update. - 81 templates stay v1-authored, converted+validated at the seed mapper; scripts/backfill-style-config-v2.ts validates v2-shaped rows instead of skipping them blind and never bumps updatedAt. - e2e fixture matches truncated at the style-block boundary so recorded replays survive the reshape. Closes #858 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Cloudflare Preview deployed successfully
|
Renders the same generated brief through the real pipeline with a base template vs its motion-enriched variant, into per-arm sample-video dirs that eval-style-sample-videos.ts / compare-eval-scores.ts consume. Resumable via persisted sequence ids. Results on #858. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Summary
Re-implements the #858 style-config redesign against current
main, replacing closed PR #863. Same design goal — one canonicalStyleConfigwith grouped look/motion signatures — but with the migration strategy inverted: instead of a null-sweep that erases all staleness data, hashing is shape-stable by construction, so the reshape ships with no migration at all.v2 shape
The speculative
design/casting/sound/sourcegroups from #863 are cut until their consumers (Phase 3/4) exist.Why no migration
All hashers (visual/motion prompt hashes +
computeStyleConfigHash) now share one projection,styleConfigHashBody, which keeps the legacy flat key names and joins the new optional fields only when authored. A v2 config with no authored refinements therefore hashes byte-identically to its v1 row — pinned by a test asserting deep equality with the raw v1 object.PROMPT_INPUT_HASH_VERSIONstays 4; no columns are nulled; genuinely-stale artifacts keep their banners. Authoringshots/pace/energylater flips staleness — correctly, because that IS an input change.What changed
src/lib/style/style-config.ts(new): v2 schema withversion: 2tag, validatedmigrateStyleConfigV1ToV2(output is schema-parsed — a constraint-violating legacy blob fails loudly instead of flowing into prompts),parseStyleConfig,StyleProjection+toStyleProjection,styleConfigHashBody, and total (never-throwing) UI accessors.styles.configisStoredStyleConfig(v1 | v2) until backfill — direct.look/.moodaccess does not compile; every read boundary goes throughparseStyleConfig(prompt-context, launchers, sequence-characters/locations, style catalog, enhancer,scripts/analyze-script.ts).EnhanceStyle.configis whole-or-absent parsed v2 (no morePartial),tagsalwaysstring[];toEnhanceInputsup-converts at the row boundary so UI and API feed identical shapes; prompt renders the motion refinements when authored.ZodErrorblanking the grid; shot-staleness catches escalateZodError(data corruption) tologger.errorwhile transient failures stay warns.categoryrequired on create (via.extend— drizzle-zod keeps nullable columns optional under refinement callbacks),tags/useCasesdefault[],referencesdefaults[], config whole-or-omitted on update. No existing caller sends creates without category (the create-style UI doesn't exist yet).scripts/backfill-style-config-v2.tsvalidates v2-shaped rows instead of skipping them blind (corrupt "v2-shaped" blobs are exactly what it exists to find), converts+validates everything before the first write, skipsupdatedAt, and is idempotent.match.userMessagestrings truncated at the<DIRECTOR_STYLE>/style-block boundary so replays survive the injected-JSON reshape (responses/timings untouched).Verification
bun typecheck0 errors ·bun run test2347 passed ·bun lint0 errors ·bun dead-codeclean ·bun format:checkcleanbun db:migrate:local && bun db:seed:local— 81 templates re-sync as valid v2bun test:e2e sequence-flow— 4 passed (script-enhance → analyze → visual/motion prompt fixtures replay through the truncated matches)Deploy notes
No DB migration. Deploy order is free: readers tolerate v1+v2 before and after the backfill. Run
bun scripts/backfill-style-config-v2.ts --d1any time after deploy; theup-converting v1 style config at read timewarn (PostHog logs, service openstory-prd) going quiet is the signal the v1 branch +StyleConfigV1can be deleted.Follow-ups
shots/pace/energythroughscore-style-previews/eval-style-sample-videos/compare-eval-scoresbefore investing in a new template generation (see Style schema design: aesthetics-blob vs identity-columns split + inconsistent optionality #858 discussion; the preferred vehicle is a new v2-authored template set with the old ones hidden).StoredStyleConfigto plainStyleConfigonce prod backfill is confirmed quiet.Closes #858
🤖 Generated with Claude Code