# Session Fixes — March 16, 2026

Fixes made during EP001 pipeline test. All need to be carried into the refactored engine.

---

## Engine-Level Fixes (apply to new engine)

### 1. prompt_engine.py — Remove quality_guard from video prompt builders
- `build_video_prompt_from_plan()` (~line 1028): Remove `quality_guard` injection
- `build_video_prompt()` (~line 1665): Remove `quality_guard` injection
- **Keep** quality_guard in the 3 image builders: `build_prompt_from_plan()`, `build_cinematic_prompt()`, `build_two_character_prompt()`
- **Reason:** quality_guard is image-gen anatomy text ("five fingers per hand, anatomically correct proportions") that's noise for video models. Video models don't respond to positive anatomy instructions.

### 2. assembler.py — Update Kling negative prompts
- `KlingPayload.negative_prompt`: Change to `"morphing, flicker, facial distortion, extra fingers, text overlay, watermark"`
- `MultiShotPayload.negative_prompt`: Same value
- **Reason:** Research showed Kling works best with 3-7 focused items targeting temporal + anatomy artifacts. Old defaults had 9 items including irrelevant ones like "static, flat lighting, unnatural movement".

### 3. model_profiles.json — SeedDance + Veo negative prompt corrections
- **SeedDance 2.0:** Set `"negative_prompt_default": null`, add `"supports_negative_prompt": false`. Update notes: "Does NOT support negative_prompt — quality constraints must go in positive prompt."
- **Veo 3.1:** Change `"negative_prompt_default"` from `null` to `"morphing, face distortion, warping, duplicate limbs, text overlay, watermark"`. Add note: "Negative prompt uses bare nouns only (no 'don't'/'no' phrasing)."
- **Reason:** SeedDance 2.0 does not support negative_prompt at the API level (confirmed via fal.ai schema). Veo does support it via `types.GenerateVideosConfig(negative_prompt=...)` but was set to null.

### 4. generate_previs.py — Fix take overwriting
- Replace the archive-and-overwrite pattern with `_next_take_path()` that always writes to the next available take number
- New function `_next_take_path(ep_dir, shot_label) -> Path` scans for existing `shot_{label}.png` and `shot_{label}_take*.png`, returns next numbered path
- Old `_archive_as_take()` kept for backward compat but no longer called
- **Reason:** Old pattern renamed `shot_001.png` to `shot_001_takeN.png` then overwrote `shot_001.png`. This broke execution store references that pointed to the base filename.

### 5. generate_previs.py — Fix state machine transition
- Before writing `previs_generated` status, check if current status requires intermediate `previs_generating` transition
- Added: `if current not in ("previs_generating",) and store_status == "previs_generated": store.update_shot(shot_id, status="previs_generating")`
- **Reason:** Shots in `previs_pending` state (e.g., from Console regen) can't jump to `previs_generated` — need `previs_generating` intermediate step.

### 6. Previz prompts — Use full keyframe prompt, not stripped version
- `build_previs_prompt()` produces a 1-sentence mechanical prompt. Flash 3.1 is smart enough for the full keyframe prompt.
- Fix: `compiled_prompts.previs_flash` should be identical to `compiled_prompts.keyframe_nbp` (or at minimum, use the same prompt_skeleton compilation path)
- The `build_previz_context()` directive system is fine — it's the displayed/regen prompt that's too stripped
- **Reason:** Stripped prompts cause Flash to latch onto character description details (debt counter, etc.) instead of following cinematographic direction. Characters stare at camera because there's no camera direction guard.

### 7. project_config.json — Empty string override bug (FLAGGED, not yet fixed)
- `load_project_config()` in recoil_bridge.py line 341: `merged[key] = value` — empty strings in project_config override engine defaults from prompt_constants.json
- Tartarus and starsend-test both have `"quality_guard": ""` and `"negative_prompt": ""` which clobber defaults
- Fix: Either skip falsy overrides in the merge, or don't include empty-string fields in new project configs
- Leviathan has the values populated (works correctly)

### 8. project_config.json negative_prompt — Dead code (FLAGGED, not yet fixed)
- `negative_prompt` is loaded by `recoil_bridge.py` into project_config but NEVER consumed by `prompt_engine.py`
- Video models get their negative prompts from assembler.py dataclass defaults
- NBP/Flash don't support negative prompts (`supports_negative_prompt: false`)
- Fix: Either wire it into the prompt builders or remove the field

---

## Data Fixes (Tartarus project only)

These are project-level data changes, not engine code:

- Stripped "orange at the cuticles, permanent stain" from ep_001_plan.json, camera_tested/ep_001.json, storyboard_ep_001.json (caused orange fingernails in generation)
- Registered WREN in casting_state.json with hero (WREN_ref_03.jpeg) + 4 turnarounds
- Created location ref directories: `output/refs/locations/int_lower_decks_corridor/` (9 refs) and `int_lower_decks_maintenance_shaft/` (13 refs) — sliced from 2x2 grids
- Uploaded prop refs via Console: cryo_pod, salvage_hook, debt_counter heroes
- Removed 0-byte EP001_SH01_manual_fix.png and cleaned stale take entry
- Updated all 36 shots: `compiled_prompts.previs_flash` = `compiled_prompts.keyframe_nbp`
- Removed SH04 "counting on fingers" (pending JT decision)
