Merge pull request #285 from calesthio/codex/taste-governance

Add taste direction governance
This commit is contained in:
Calesthio
2026-07-05 06:58:18 -07:00
committed by GitHub
11 changed files with 458 additions and 2 deletions

View File

@@ -143,7 +143,7 @@ Orthogonal to *runtime* is *authoring mode*: **how** the composition is built. P
- **Templated** — assemble the stock `cut.type` scene-types (`text_card`, `stat_card`, `bar_chart`, …) into the `Explainer`/`CinematicRenderer` compositions. Fast, cheap, reliable — and the reason most videos look alike. Right for batch output, localization variants, quick drafts, and low-stakes internal clips.
- **Atelier** — **hand-author the composition from scratch**: bespoke scenes, a one-off theme, and motion written for this piece, rendered via `composition_mode: "atelier"` (see `video_compose``_render_via_atelier`). No reusable creative components; a fresh visual language every time.
**Default to atelier for hero work** — marketing, launches, brand pieces, any single-deliverable explainer that must impress. The deciding rule: *reuse engine knowledge, never creative components.* In atelier mode the stock scene-type catalog, `hyperframes-registry` blocks, fixtures, and finished components are **off-limits** — they are frozen looks that reintroduce sameness. Before building, route through **`skills/meta/bespoke-composition.md`**, which sequences: art direction (`visual-style`) → motion principles (Disney 12 via `framer-motion`/`lottie-bodymovin`) → engine mechanics (`remotion-best-practices` + the stock components read *only as a mechanics codex*) → render via the atelier path. Close with a **distinctness review**: *could this be any other product's video? does it reuse a look I've made before?* — the inverse of "does it match the reference." Atelier costs more tokens and iteration than templated; say so at proposal so the user opts in knowingly.
**Default to atelier for hero work** — marketing, launches, brand pieces, any single-deliverable explainer that must impress. The deciding rule: *reuse engine knowledge, never creative components.* In atelier mode the stock scene-type catalog, `hyperframes-registry` blocks, fixtures, and finished components are **off-limits** — they are frozen looks that reintroduce sameness. Before building, route through **`skills/meta/taste-direction.md`** to set the design read and taste dials, then **`skills/meta/bespoke-composition.md`**, which sequences: art direction (`visual-style`) → motion principles (Disney 12 via `framer-motion`/`lottie-bodymovin`) → engine mechanics (`remotion-best-practices` + the stock components read *only as a mechanics codex*) → render via the atelier path. Close with a **distinctness review**: *could this be any other product's video? does it reuse a look I've made before?* — the inverse of "does it match the reference." Atelier costs more tokens and iteration than templated; say so at proposal so the user opts in knowingly.
### Escalate Blockers Explicitly
@@ -630,10 +630,13 @@ Tool rules:
| Playbook | Best For |
|----------|----------|
| `clean-professional` | Corporate, educational, SaaS |
| `premium-minimalist` | Investor updates, expert explainers, product narratives |
| `flat-motion-graphics` | Social media, TikTok, startups |
| `minimalist-diagram` | Technical deep-dives, architecture |
| `ink-sketch` (Ink Theater) | Hand-drawn ink-on-white doodle animation; a character that draws itself, walks, dances; contraption explainers |
For custom, atelier, brand, launch, or hero work, read `skills/meta/taste-direction.md` before choosing a playbook. Carry its `taste_profile` into the proposal so later stages can preserve the design read, visual variance, motion intensity, information density, reference strategy, and anti-patterns.
### Hand-drawn "doodle" animation → Ink Theater / Ink Puppet
For any brief that wants a **hand-drawn ink doodle** look — "a sketch that comes to life", "a pencil / stick figure that walks or dances", "a little character that acts out the idea", whiteboard-doodle explainers — use the **Ink Theater** engine + **Ink Puppet** mocap system (`skills/creative/ink-theater.md`, `ink-theater/README.md`). It is a **style + reusable engine, not a new pipeline**: illustration / contraption pieces run on the `animation` pipeline; a mocap character (draws itself → walks / dances / waves via `InkPuppet.choreograph([...])`) runs on `character-animation`. Cross-tool entry points: **`/ink-art`** (create a vector doodle from scratch) and **`/animated-drawing`** (animate a *supplied* drawing with mocap — raster; `skills/creative/animated-drawing.md`). Never hand-tune character motion — the agent only chooses named mocap clips.

View File

@@ -164,6 +164,7 @@
"type": "string",
"description": "Required when composition_mode='atelier'. Short note (or path to art-direction.md) committing to a fresh visual language for THIS piece — palette, type, motion, signature device. Per skills/meta/bespoke-composition.md step 1, written down BEFORE authoring scenes."
},
"taste_profile": { "$ref": "#/$defs/taste_profile" },
"music_source": {
"type": "object",
"description": "Resolved music plan from the proposal stage",
@@ -331,5 +332,47 @@
},
"metadata": { "type": "object" }
},
"$defs": {
"taste_profile": {
"type": "object",
"required": ["design_read", "visual_variance", "motion_intensity", "information_density"],
"properties": {
"design_read": {
"type": "string",
"description": "Brief-specific read of what the video should feel like and why."
},
"visual_variance": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "How much scenes may vary visually while still feeling coherent."
},
"motion_intensity": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "How energetic the motion language should be."
},
"information_density": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "How much information can be on screen at once."
},
"palette_discipline": { "type": "string" },
"layout_variation": { "type": "string" },
"reference_strategy": { "type": "string" },
"anti_patterns": {
"type": "array",
"items": { "type": "string" }
},
"quality_gates": {
"type": "array",
"items": { "type": "string" }
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}

View File

@@ -159,6 +159,7 @@
"items": { "type": "string" },
"minItems": 1
},
"taste_profile": { "$ref": "#/$defs/taste_profile" },
"chart_palette": {
"description": "Ordered array of hex colors for chart data series.",
"type": "array",
@@ -238,6 +239,46 @@
"highlight": { "type": "string" }
},
"additionalProperties": false
},
"taste_profile": {
"type": "object",
"required": ["design_read", "visual_variance", "motion_intensity", "information_density"],
"properties": {
"design_read": {
"type": "string",
"description": "Brief-specific read of what the video should feel like and why."
},
"visual_variance": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "How much scenes may vary visually while still feeling coherent."
},
"motion_intensity": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "How energetic the motion language should be."
},
"information_density": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "How much information can be on screen at once."
},
"palette_discipline": { "type": "string" },
"layout_variation": { "type": "string" },
"reference_strategy": { "type": "string" },
"anti_patterns": {
"type": "array",
"items": { "type": "string" }
},
"quality_gates": {
"type": "array",
"items": { "type": "string" }
}
},
"additionalProperties": false
}
}
}

View File

@@ -281,6 +281,7 @@ Cross-cutting skills that apply to all pipelines:
| Checkpoint Protocol | `meta/checkpoint-protocol.md` | When/how to checkpoint and request human approval |
| Skill Creator | `meta/skill-creator.md` | Dynamically create new skills during pipeline runs |
| Animation Runtime Selector | `meta/animation-runtime-selector.md` | Choose render runtime + animation library per scene |
| Taste Direction | `meta/taste-direction.md` | Convert a brief into taste dials, anti-patterns, and reference strategy for proposal/playbook/atelier work |
| Bespoke Composition (Atelier) | `meta/bespoke-composition.md` | Hand-author a composition from scratch (hero work) — no stock scene-types; routes art-direction → motion principles → engine mechanics → atelier render |
## Style Playbooks
@@ -290,6 +291,7 @@ Style playbooks (`styles/*.yaml`) define visual language, typography, motion, au
| Playbook | Category | Mood | Best For |
|----------|----------|------|----------|
| `clean-professional` | motion-graphics | polished, trustworthy | Corporate, educational, SaaS |
| `premium-minimalist` | minimalist | calm, editorial | Investor updates, expert explainers, product narratives |
| `flat-motion-graphics` | motion-graphics | energetic, bold | Social media, TikTok, startups |
| `minimalist-diagram` | whiteboard | focused, technical | Technical deep-dives, architecture |

View File

@@ -43,7 +43,9 @@ Author in this order. Each step routes you to existing knowledge — do not skip
### 1. Commit to an art direction *for this subject* — the divergence engine
Before writing any component, decide a visual language that fits **this** topic and no other.
Use the **`visual-style`** Layer 3 skill (CREATE mode) to lock: palette, type personality,
Read **`skills/meta/taste-direction.md`** first and write the `taste_profile`: the design read,
`visual_variance`, `motion_intensity`, `information_density`, reference strategy, and
anti-patterns. Then use the **`visual-style`** Layer 3 skill (CREATE mode) to lock: palette, type personality,
motion character, layout system, and **one signature device** unique to this piece. Difference
between videos is guaranteed here — not by withholding components, but by forcing a fresh
direction each time. Write it down (a short `art-direction.md` in the project) and build to it.

View File

@@ -59,6 +59,17 @@ If a style playbook is active, verify:
Each violation is a **suggestion** severity finding.
### Step 4b: Taste Direction Review
If `proposal_packet.production_plan.taste_profile` or the active playbook's `taste_profile` exists, verify:
- [ ] `design_read` explains the brief, audience, and delivery promise; it is not just "modern/clean/professional"
- [ ] `visual_variance`, `motion_intensity`, and `information_density` are reflected in scene layout, pacing, callout density, and asset prompts
- [ ] `reference_strategy` is present when atelier work, AI image/video, product/brand visuals, or mood boards depend on visual nuance
- [ ] Listed `anti_patterns` are actually avoided
- [ ] Quality gates are concrete enough for the next stage to enforce
At proposal stage, a missing `taste_profile` is a **suggestion** for preset/low-stakes work and a **critical** finding for atelier, product/brand, launch, hero, or custom-playbook work. At scene_plan/edit/compose, treat dial violations as **suggestion** unless they break the approved delivery promise.
### Step 5: Evaluate Success Criteria
For each `success_criteria` item from the manifest:

View File

@@ -0,0 +1,126 @@
# Taste Direction - Meta Skill
## When to Use
Use this before committing to visual identity, mood boards, proposal packets, custom playbooks, atelier composition, image reference batches, or brand-heavy videos.
This skill defines OpenMontage's video taste profile contract. Do not treat it as a frontend style recipe. The output is a compact video taste profile that travels through proposal, scene planning, asset prompts, edit, compose, and review.
## Output Contract
Write a `taste_profile` when the proposal or playbook needs a stronger creative contract:
```json
{
"design_read": "Premium expert explainer: calm authority, high trust, low ornament.",
"visual_variance": 4,
"motion_intensity": 3,
"information_density": 5,
"palette_discipline": "Neutral base, one accent, no decorative gradients.",
"layout_variation": "Alternate editorial split frames with data-forward full-frame scenes.",
"reference_strategy": "One reference still per scene family before asset generation.",
"anti_patterns": ["generic AI-purple gradient backgrounds"],
"quality_gates": ["Every scene should carry the design read without explanatory labels."]
}
```
`visual_variance`, `motion_intensity`, and `information_density` are 1-10 integer dials:
| Dial | Low | Mid | High |
|------|-----|-----|------|
| `visual_variance` | Tight system, repeated grammar | Pattern with purposeful scene families | Each beat may use a distinct visual mode |
| `motion_intensity` | Calm holds, small transitions | Clear motion accents and reveals | Fast kinetic language, frequent directional changes |
| `information_density` | One idea per frame | Main idea plus support detail | Dense dashboards, diagrams, or layered callouts |
## Process
### 1. Make a Design Read
Before choosing a playbook or palette, state what the video needs to feel like and why. Tie it to the audience, promise, platform, and subject matter.
Good reads are specific:
- "Investor-facing AI launch: precise, restrained, and credible; avoid hype visuals."
- "Youth science short: bright, curious, and kinetic; make invisible physics feel tactile."
- "Security incident explainer: tense and surgical; high contrast, low ornament, readable evidence."
Weak reads are only adjectives:
- "modern and clean"
- "cinematic"
- "professional"
### 2. Set the Three Dials
Pick `visual_variance`, `motion_intensity`, and `information_density` before writing concepts. These numbers should explain later choices:
- High motion plus low information means short kinetic beats, not dense diagrams.
- Low motion plus high information means stable frames, chart builds, and long readable holds.
- High variance means scene families need stronger anchors: recurring type, palette, framing, or sound motif.
### 3. Choose a Style Path
Use the dials to pick one of three paths:
| Path | Use When | Artifact |
|------|----------|----------|
| Existing playbook | A preset honestly matches the read | `production_plan.playbook` |
| Custom playbook | The subject has its own visual world | generated `styles/<name>.yaml` with `taste_profile` |
| Atelier art direction | Hero work needs a one-off language | `production_plan.art_direction` plus `taste_profile` |
Do not let preset availability override the design read. If the content calls for a custom visual world, write the custom playbook or art direction.
### 4. Plan References
If the work uses AI image/video, mood boards, brand assets, or atelier composition, create a reference strategy:
- Use one reference still per scene family or major beat.
- Do not compress the whole direction into one mood board image.
- For brand/product work, create or inspect a brand kit before asset generation.
- For screen demos, inspect the real UI and write a redesign/audit note before styling overlays.
### 5. Carry the Profile Downstream
At proposal stage:
- Add `production_plan.taste_profile`.
- Log style/playbook selection in `decision_log`.
- Explain how the dials affect runtime, composition mode, and asset generation.
At scene planning:
- Vary layouts according to `visual_variance`.
- Keep on-screen text and callouts within `information_density`.
- Set transition families and camera movement from `motion_intensity`.
At assets:
- Include palette, texture, framing, and reference strategy in image/video prompts.
- Generate reference stills before full batches when the profile depends on visual nuance.
At edit/compose:
- Match hold times and cut rhythm to the motion dial.
- Avoid adding decorative overlays that violate the design read.
## Anti-Default Checklist
Flag these before moving forward:
- Generic AI-purple gradients or default corporate-blue visuals with no subject reason.
- Same transition on every cut when `visual_variance` is 4 or higher.
- Kinetic motion that makes narration harder to follow.
- Dense callouts when `information_density` is 4 or lower.
- Text-only slides unless the design read intentionally calls for typographic storytelling.
- Mood boards that look attractive but do not map to concrete scene families.
- Brand/product videos that never show or inspect the real brand/product surface.
## Review Hooks
Reviewer should check:
- Does `taste_profile.design_read` explain a real creative choice?
- Do scene plans and edits respect the three dials?
- Are anti-patterns actually avoided?
- Is the reference strategy present when AI images/video or atelier work depends on visual nuance?
- Could this video belong to any topic after replacing the title? If yes, the taste direction is too generic.

View File

@@ -46,6 +46,7 @@ A `render_runtime_selection` decision with only one option considered when both
| Tool registry | `support_envelope()` output | What's actually available right now |
| Cost tracker | `tools/cost_tracker.py` | Cost estimation data |
| Style playbooks | `styles/*.yaml` | Available visual styles |
| Meta skill | `skills/meta/taste-direction.md` | Design read, taste dials, reference strategy |
| User input | Topic, any preferences expressed | Creative direction |
## Process
@@ -121,6 +122,8 @@ Record all findings. **Do not propose an animation mode that requires tools you
This is the key differentiator from the explainer proposal. **Present the user with concrete animation approaches, explain what each looks like, what tools/keys they need, and what's already available.**
Before locking animation mode or visual identity, read `skills/meta/taste-direction.md` and write a `production_plan.taste_profile`. The three dials (`visual_variance`, `motion_intensity`, `information_density`) should explain whether the concept needs calm data builds, kinetic typography, dense diagrams, reference stills, or a custom/atelier visual system.
#### Step 3a: Tool Availability Scan
Before designing concepts, scan what's available and present it honestly. **Do NOT hardcode provider names, costs, or key names in this output** — they drift. Read them live from the registry:

View File

@@ -40,6 +40,7 @@ A `render_runtime_selection` decision with only one option considered when both
| Tool registry | `support_envelope()` output | What's actually available right now |
| Cost tracker | `tools/cost_tracker.py` | Cost estimation data |
| Style playbooks | `styles/*.yaml` | Available visual styles |
| Meta skill | `skills/meta/taste-direction.md` | Design read, taste dials, reference strategy |
| User input | Topic, any preferences expressed | Creative direction |
## Process
@@ -175,6 +176,8 @@ Choose the structure that best fits the research findings:
The existing playbooks (`clean-professional`, `flat-motion-graphics`, `minimalist-diagram`) are starting points, not destinations. Most videos should get a **custom visual identity** derived from the subject matter, audience, and tone. A video about coffee should feel warm and tactile. A video about cybersecurity should feel technical and urgent. A video about marine biology should feel deep and fluid.
Before choosing or generating a playbook, read `skills/meta/taste-direction.md` and write a compact `production_plan.taste_profile`. The taste profile records the design read, `visual_variance`, `motion_intensity`, `information_density`, reference strategy, and anti-patterns. Use it to explain why the selected playbook, `composition_mode`, and asset strategy fit the brief.
**How to design visual identity:**
1. **Start from the content.** What colors does the subject naturally evoke? What textures, materials, lighting? A video about volcanoes should feel different from a video about meditation — in colors, motion speed, typography weight, and transition style.
@@ -194,6 +197,7 @@ The existing playbooks (`clean-professional`, `flat-motion-graphics`, `minimalis
**Record your visual identity choices in the proposal_packet:**
- `production_plan.playbook`: name of preset OR "custom"
- `production_plan.taste_profile`: design read, taste dials, reference strategy, and anti-patterns
- If custom, include color choices and font choices in the concept's `visual_approach`
- Include the reasoning: "Warm amber palette because the subject is coffee craftsmanship"
- Log as decision: `category: "playbook_selection"`

View File

@@ -0,0 +1,117 @@
identity:
name: "Premium Minimalist"
category: minimalist
mood: calm, editorial, precise
pace: deliberate
best_for: "Investor updates, expert explainers, product narratives, high-trust launch videos"
taste_profile:
design_read: "Premium expert explainer: calm authority, high trust, low ornament."
visual_variance: 4
motion_intensity: 3
information_density: 5
palette_discipline: "Off-white field, charcoal text, restrained cobalt accent, no decorative gradients."
layout_variation: "Alternate editorial split frames, centered evidence frames, and full-bleed product/detail moments."
reference_strategy: "Create one reference still for each scene family before batch asset generation."
anti_patterns:
- "generic corporate-blue template cards"
- "decorative gradient backgrounds"
- "fast kinetic transitions that reduce comprehension"
quality_gates:
- "Every frame should feel intentionally sparse, not unfinished."
- "Motion should clarify hierarchy instead of decorating it."
visual_language:
color_palette:
primary: ["#111827", "#374151"]
accent: ["#2563EB", "#0F766E"]
background: "#F9FAFB"
text: "#111827"
muted: "#6B7280"
composition: asymmetrical editorial grid with large margins, hard alignment, and one focal object per frame
texture: flat matte fields, fine divider lines, subtle photographic grain only when source imagery needs cohesion
typography:
headings:
font: "Inter"
weight: 700
tracking: "-0.01em"
body:
font: "Inter"
weight: 400
line_height: 1.55
code:
font: "JetBrains Mono"
weight: 400
stat_card:
font: "Inter"
weight: 800
size_multiplier: 3.2
scale_system: "major_third"
weight_matrix:
title: 800
heading: 700
body: 400
caption: 500
motion:
transitions: [fade, dissolve, slide-left]
animation_style: "restrained ease-out, precise reveal, no bounce"
pacing_rules:
min_scene_hold_seconds: 2.75
max_scene_hold_seconds: 12
text_card_hold_seconds: 3.75
stat_card_hold_seconds: 3.25
transition_duration_seconds: 0.45
entrance: "fade-up 12px with opacity ramp"
exit: "soft fade with slight y-offset"
audio:
voice_style: "measured, expert, warm, low hype"
music_mood: "minimal pulse, clean synth bed, quiet confidence"
music_volume: 0.07
sfx_style: "small tactile ticks and soft paper-like swishes"
ducking_threshold_db: -4
asset_generation:
image_prompt_prefix: "premium minimalist editorial frame, restrained palette, precise composition, generous negative space, "
image_negative_prompt: "busy, glossy, decorative gradient, neon, cluttered, low contrast, generic corporate template"
diagram_style: "thin-line editorial diagram, charcoal text, cobalt highlight, large margins"
consistency_anchors:
- "Off-white background with charcoal typography"
- "Cobalt accent used only for hierarchy or proof points"
- "Large margins and hard alignment"
- "No decorative shapes unless they carry information"
overlays:
stat_card:
bg: "#FFFFFF"
border: "#D1D5DB"
radius: 6
shadow: "0 1px 6px rgba(17,24,39,0.08)"
key_term:
bg: "#EFF6FF"
text: "#1D4ED8"
radius: 4
code_block:
bg: "#111827"
text: "#F9FAFB"
highlight: "#93C5FD"
quality_rules:
- "Minimum contrast ratio 4.5:1 for all text"
- "No more than 2 accent colors on screen at once"
- "Keep one primary focal object or claim per frame"
- "Use motion to reveal hierarchy, not to add energy"
- "Avoid decorative gradients and oversized floating shapes"
chart_palette:
- "#2563EB"
- "#0F766E"
- "#111827"
- "#64748B"
color_rules:
harmony_type: "analogous"
contrast_validation: true
colorblind_safe: true

View File

@@ -0,0 +1,104 @@
"""Contract tests for taste-direction governance.
The taste-direction meta skill is an agent-facing contract: it must be easy to
discover, and its output must fit the canonical proposal/style artifacts.
"""
from __future__ import annotations
import json
from pathlib import Path
import jsonschema
import yaml
ROOT = Path(__file__).resolve().parent.parent.parent
def _load_json(path: Path) -> dict:
return json.loads(path.read_text(encoding="utf-8"))
def _taste_profile() -> dict:
return {
"design_read": "Premium expert explainer: calm authority, high trust, low ornament.",
"visual_variance": 4,
"motion_intensity": 3,
"information_density": 5,
"palette_discipline": "Neutral base, one blue accent, no decorative gradients.",
"layout_variation": "Alternate editorial split frames with data-forward full-frame scenes.",
"reference_strategy": "One reference still per scene family before asset generation.",
"anti_patterns": [
"generic AI-purple gradient backgrounds",
"reusing the same transition on every cut",
],
"quality_gates": [
"Each scene carries the design read without needing explanatory labels.",
"Motion stays purposeful and never outruns narration comprehension.",
],
}
def test_style_playbook_schema_accepts_taste_profile():
schema = _load_json(ROOT / "schemas" / "styles" / "playbook.schema.json")
assert "taste_profile" in schema["properties"]
playbook = yaml.safe_load((ROOT / "styles" / "clean-professional.yaml").read_text(encoding="utf-8"))
playbook["taste_profile"] = _taste_profile()
jsonschema.validate(instance=playbook, schema=schema)
def test_proposal_packet_schema_accepts_taste_profile():
schema = _load_json(ROOT / "schemas" / "artifacts" / "proposal_packet.schema.json")
proposal = {
"version": "1.0",
"concept_options": [
{
"id": f"c{i}",
"title": f"Concept {i}",
"hook": "A precise hook under twenty words.",
"narrative_structure": "problem_solution",
"visual_approach": "Premium minimalist scenes with data-led visual proof.",
"target_duration_seconds": 60,
"why_this_works": "It ties the audience problem to a visible payoff.",
}
for i in range(1, 4)
],
"selected_concept": {"concept_id": "c1", "rationale": "Best fit for the brief."},
"production_plan": {
"pipeline": "animated-explainer",
"stages": [{"stage": "proposal", "tools": [], "approach": "Plan the production."}],
"render_runtime": "remotion",
"taste_profile": _taste_profile(),
},
"cost_estimate": {
"total_estimated_usd": 0,
"line_items": [],
"budget_verdict": "no_budget_set",
},
"approval": {"status": "pending"},
}
jsonschema.validate(instance=proposal, schema=schema)
def test_taste_direction_is_discoverable_to_new_agents():
skill_path = ROOT / "skills" / "meta" / "taste-direction.md"
assert skill_path.is_file(), "Missing Layer 2 taste-direction meta skill"
index = (ROOT / "skills" / "INDEX.md").read_text(encoding="utf-8")
assert "Taste Direction" in index
assert "meta/taste-direction.md" in index
guide = (ROOT / "AGENT_GUIDE.md").read_text(encoding="utf-8")
assert "taste-direction.md" in guide
def test_premium_minimalist_playbook_exists_and_validates():
from styles.playbook_loader import load_playbook, list_playbooks
assert "premium-minimalist" in list_playbooks()
playbook = load_playbook("premium-minimalist")
assert playbook["taste_profile"]["motion_intensity"] <= 4
assert playbook["taste_profile"]["information_density"] >= 4