# Semantic String Debt LLM Audit Findings

- result chunks: `864`
- findings: `632`

## `backend/app/api/v1/entities.py`

- `433-477` **P1 / semantic_string_judgment**
  - evidence: _re.finditer(r'\[\[([^\]]+)\]\+\[([^\]]+)\]\]', t2i_text) ... lookup_name(_char_name_idx, c_name)
  - why: The code extracts character and outlook names from bracketed patterns within natural-language prompt text to resolve entities and attach reference images. This relies on the LLM producing exact name matches and specific syntax in the prose, which is brittle compared to using structured ID fields and directly affects reference attachment behavior.
  - fix: Rely exclusively on structured entity ID lists (e.g., in visible_entities_json) populated during the generation phase, instead of parsing names from the prompt string at read-time.

## `backend/app/api/v1/images.py`

- `107-115` **P1 / semantic_string_judgment**
  - evidence: prompt_used contains 'outlook_id:{outlook_id}'
  - why: The API documentation and implementation (via service call) rely on substring matching of technical IDs within a natural-language prompt field ('prompt_used') to filter images by entity. This is a brittle way to track entity-image associations and couples the prompt's prose to the database query logic.
  - fix: Store entity associations in a structured metadata table or a dedicated JSON field instead of embedding and parsing them within the T2I prompt string.

## `backend/app/core/asset_readiness.py`

- `435-440` **P1 / semantic_string_judgment**
  - evidence: gaze = ca.get("gaze_target", "") ... if gaze in ("dead", "severely_injured", "unconscious")
  - why: The 'gaze_target' field in the shot_staging checkpoint is overloaded to carry physical state information. The code uses a hardcoded list of natural-language strings to infer that a character requires a specific state-variant reference asset. This semantic judgment drives a fail-fast validation that blocks the pipeline if the inferred asset is missing, making the system brittle to LLM phrasing variations.
  - fix: Introduce a dedicated 'physical_state' or 'required_variant' field in the shot_staging schema and use a formal enum instead of overloading the gaze field with semantic strings.

## `backend/app/core/bg_state_vocab.py`

- `26-56` **P2 / schema_or_enum_drift**
  - evidence: STATE_CLASS_ENUM, validate_state_class
  - why: The STATE_CLASS_ENUM defines semantic visual states (e.g., 'ransacked', 'blood_scene', 'intrusion') that the LLM is expected to output exactly. The code (line 48) admits that this enum is forced in the LLM prompt and that violations trigger a retry. This creates a manual synchronization requirement between the prompt prose and the code's validation logic.
  - fix: Centralize the state vocabulary in a shared schema (e.g., JSON Schema or Pydantic) that can be used to both generate the prompt instructions and perform validation, reducing the risk of drift.

- `128-201` **P2 / schema_or_enum_drift**
  - evidence: LOCATION_SPACE_KEY_VOCAB, validate_location_space_profile
  - why: The LOCATION_SPACE_KEY_VOCAB defines semantic location types (e.g., 'kitchen', 'rooftop', 'yard') that must match the LLM's output. Line 126 explicitly states that this must be kept in sync with the entity_extractor system prompt. Validation failures (line 195) cause the background ID assignment to fail.
  - fix: Use a shared source of truth for location space keys that is injected into the LLM prompt and used for validation, rather than maintaining a hardcoded list in the code that requires manual prompt updates.

## `backend/app/core/name_matcher.py`

- `51-161` **P1 / semantic_string_judgment**
  - evidence: _BRACKET_PATTERN and lookup_name logic
  - why: The utility infers entity identity by stripping bracketed suffixes from LLM-generated strings to resolve 'drift' (e.g., mapping '이도령(혼)' to '이도령'). This is a brittle heuristic for mapping natural language names to database IDs, which can lead to collisions or incorrect entity resolution if the bracketed content is semantically significant or if the LLM produces unexpected formats.
  - fix: Transition to using immutable identifiers (UUIDs) or a canonical enum in the LLM output schema to avoid the need for heuristic string normalization for entity resolution.

## `backend/app/core/ref_contract_validator.py`

- `49-457` **P1 / semantic_string_judgment**
  - evidence: _CHARACTER_TOKENS, _GENERIC_VERB_TOKENS, classify_from_the_reference, and validate_attached_refs
  - why: The 'phantom guard' mechanism uses brittle keyword lists (e.g., 'mart', 'her hand', 'copy', 'poses') to classify the semantic target of phrases in the prompt and decide whether to skip or enforce reference presence. This natural-language parsing directly triggers RefContractError (HTTP 422), blocking generation based on fragile string matches rather than structured intent.
  - fix: Replace prompt-text parsing with structured metadata (e.g., reference-target IDs or instruction-type flags) provided by the LLM or the prompt-card schema during the generation phase.

## `backend/app/core/steps/analysis_steps_legacy.py`

- `810-817` **P2 / scenario_dependent_prompt**
  - evidence: 인물: 자기 물리적 몸으로 존재하는 인물만. 대사를 하더라도 빙의/원격접속 중이면 제외... 앞쪽 씬에서 인물A가 인물B의 몸에 접속/빙의/라이드했다면...
  - why: The prompt contains concrete scenario-specific mechanics (possession/remote access) that bias the LLM's analysis of physical presence, making the step less generalizable and prone to hallucinations in scenarios without these tropes.
  - fix: Move scenario-specific logic into a separate configuration or a specialized prompt variant, and use more abstract terms for physical presence rules in the base prompt.

- `852-863` **P1 / semantic_string_judgment**
  - evidence: clean = raw_id.replace("CHAR_", "").replace("BG_", "").replace("PROP_", "") ... if clean in name_to_uuid:
  - why: The code uses brittle string replacement and partial matching to infer entity identity from LLM output that failed to follow the provided short-ID schema. This result directly determines visible-entity membership in the scene.
  - fix: Rely on strict schema enforcement (enums) in the LLM call and handle validation errors by retrying or failing, rather than attempting to guess identity via string manipulation.

## `backend/app/core/steps/beat_shot_steps.py`

- `110-326` **P1 / scenario_dependent_code**
  - evidence: if r.get("rule_type") in ("possession", "projection", "ghost") and [물리적 존재 판단 기준]
  - why: The code hardcodes specific story tropes ('possession', 'projection', 'ghost') to filter visual guidelines in both BeatExtractStep and ShotExtractStep. It also injects hardcoded Korean semantic instructions regarding 'physical presence' based on these tropes. This makes the pipeline logic dependent on specific narrative genres and brittle to other types of non-physical entities (e.g., holograms, illusions) that might require similar visual handling.
  - fix: Replace the hardcoded trope list with a generic metadata flag in the rule schema (e.g., 'is_visual_guideline') and move the semantic instructions into the prompt templates or the rule data itself.

## `backend/app/core/steps/detail_steps.py`

- `251-310` **P1 / semantic_string_judgment**
  - evidence: _OUTLOOK_COMPOSITE_RE = re.compile(r'(C\d{2,3})(O\d{2,3})') and _STATE_VARIANT_GAZE_VALUES = ("unconscious", "dead", "severely_injured")
  - why: The code uses regex to parse generated prompt prose and string matching to check physical state values in the gaze_target field. These results directly change reference attachment behavior and validation policy (e.g., excluding dead characters from outlook requirements).
  - fix: Pass explicit physical state and reference usage flags as structured metadata from upstream steps instead of inferring them from natural-language fields or generated prose.

- `1939-1967` **P1 / semantic_string_judgment**
  - evidence: _base_name = re.split(r'\s*[\(（]', name)[0].strip()
  - why: The code infers semantic 'variant-of' relationships between entities by parsing natural-language names for parentheses. This brittle pattern matching determines which entities are grouped as variants, affecting prompt instructions and visibility logic.
  - fix: Use a canonical entity_id or parent_id field in the entity schema to define variant relationships rather than relying on display name patterns.

- `2286-2291` **P2 / llm_closed_list_instruction**
  - evidence: 긴장=어둡고 대비 강한, 슬픔=탈색/청색, 분노=적색 등
  - why: The prompt contains a hardcoded semantic mapping of emotions to specific visual styles. This functions as a closed-list classifier that biases the LLM's creative decisions for arbitrary scenarios.
  - fix: Move visual style mappings to a configurable world-building or style-guide module that can be adjusted per project.

- `2865-2870` **P1 / blind_string_mutation**
  - evidence: re.sub(r"focus on\s+'s", "focus on the figure's", prompt)
  - why: The code performs blind substring replacement on generated T2I prompt prose to fix specific grammatical or semantic errors. This is brittle and assumes a closed set of failure modes in open-world LLM output.
  - fix: Improve the system prompt to prevent these specific output patterns or use a structured 'focus_target' field that is formatted into the prompt by a controlled template.

## `backend/app/core/steps/director_steps.py`

- `126-127` **P2 / schema_or_enum_drift**
  - evidence: if r.get("rule_type") in ("possession", "projection", "ghost")
  - why: The code filters visual rules using a hardcoded list of semantic categories ('possession', 'projection', 'ghost'). This creates a brittle dependency on specific string values produced by an upstream LLM step, which may drift from the intended schema or miss new categories.
  - fix: Centralize the rule type definitions in a shared enum and use that enum for both the upstream classification and this filtering logic.

## `backend/app/core/steps/entity_steps.py`

- `453-461` **P2 / llm_closed_list_instruction**
  - evidence: 인물(character)은 다른 타입과 중복될 가능성이 거의 없으니 주로 배경/소품 간 중복을 확인하세요.
  - why: This instruction provides a semantic heuristic to the LLM based on entity types, which functions as a soft classifier rule for merging logic. While not scenario-specific pollution, it hardcodes a behavioral assumption about open-world entity relationships.
  - fix: Move such heuristics to a centralized system prompt or configuration rather than hardcoding them in the step runner's user prompt construction.

- `796-811` **P1 / schema_or_enum_drift**
  - evidence: validate_entity_metadata_shape(etype, md, short_id=name_to_sid.get(ename, "") or ename)
  - why: The code performs a fail-fast validation of LLM-generated metadata (specifically space_profile for locations, as noted in comments on lines 768-774). This implies a contract where the LLM must output values from a closed vocabulary (SpaceProfileError) that is enforced by code. If the prompt's schema guide and the validator's vocabulary drift, it causes P0-level generation failures.
  - fix: Ensure the vocabulary used in `validate_entity_metadata_shape` is programmatically injected into the LLM's system prompt to prevent drift between the classifier's instructions and the validator's enforcement.

## `backend/app/core/steps/image_steps.py`

- `638-642` **P2 / schema_or_enum_drift**
  - evidence: STATE_DESCRIPTIONS = { "dead": "...", "severely_injured": "...", "unconscious": "..." }
  - why: The keys in this dictionary act as a semantic classifier for character states but are defined locally within the step runner. This creates a drift risk where the LLM in the staging step must produce exact string matches for these keys without a shared schema enforcement.
  - fix: Centralize character state definitions in a shared schema enum and reference it in both the staging prompt and the image generation steps.

- `639-641` **P2 / scenario_dependent_prompt**
  - evidence: "dead": "lying motionless, pale/ashen skin...", "severely_injured": "visible bruises and cuts..."
  - why: The step runner hardcodes specific visual tropes (e.g., 'pale/ashen skin', 'bloodied areas') into the prompt generation logic for character states. These descriptions may bias or conflict with specific story contexts, character types (e.g., non-human), or artistic styles.
  - fix: Move these visual descriptions into a configurable style guide or the prompt template itself rather than hardcoding them in the Python logic.

- `665-666` **P1 / semantic_string_judgment**
  - evidence: gaze = ca.get("gaze_target", "") ... if gaze in self.STATE_DESCRIPTIONS:
  - why: The 'gaze_target' field is overloaded to carry character physical states ('dead', 'severely_injured', 'unconscious'). The code performs a brittle string match against this field (which is generated by an LLM in a previous step) to decide whether to trigger the generation of state-variant reference images. This couples visual state logic to a field intended for spatial orientation.
  - fix: Introduce a dedicated 'physical_state' field in the shot staging schema and use a formal enum instead of overloading the gaze target field.

## `backend/app/core/steps/location_consistency_step.py`

- `104-105` **P1 / semantic_string_judgment**
  - evidence: if name in heading: scenes_by_location[sid].append(si)
  - why: Uses a substring check on natural-language location names and scene headings to determine scene membership for consistency analysis. This is brittle (e.g., 'Room' matching 'Living Room') and directly affects the context provided to the LLM in the user prompt.
  - fix: Rely exclusively on structured entity IDs (short_id) for mapping. If a fallback is necessary, use a proper NLP entity linker or require the script to provide explicit ID-based headings.

- `179` **P2 / schema_or_enum_drift**
  - evidence: if summary.startswith("실패"):
  - why: Uses a hardcoded Korean string prefix ('실패') within a natural-language field ('analysis_summary') to drive logic for failure counting and resume skipping (line 122). This creates a brittle contract between the LLM output/fallback and the step runner logic.
  - fix: Introduce a structured 'status' enum field in the location schema (e.g., 'SUCCESS', 'FAILED_FALLBACK') instead of parsing natural-language summary text.

## `backend/app/core/steps/location_floor_plan_step.py`

- `714-734` **P1 / semantic_string_judgment**
  - evidence: _summarize_prompt using text.find(sep) with (". ", ".\n", "\n\n") and length check < 200
  - why: It attempts to extract the semantic summary of an open-world visual description (T2I prompt) using brittle punctuation patterns and magic number length constraints. This summary is then injected as context for subsequent generations, meaning a change in LLM output style (e.g., adding a preamble) can corrupt the spatial context for the rest of the building group.
  - fix: Instead of slicing the generated prompt, have the LLM explicitly return a structured 'summary' or 'spatial_context' field in its JSON response, or use a separate summarization call with a clear instruction.

## `backend/app/core/steps/render_prompt_card.py`

- `584` **P2 / scenario_dependent_prompt**
  - evidence: "(low / hip-height / overhead / ground level / quay level / floor level / from above)"
  - why: The prompt includes 'quay level' as a specific camera height example. This is scenario-specific pollution (maritime/port setting) that can bias the LLM's spatial reasoning in unrelated scenarios.
  - fix: Use generic camera height terms (e.g., 'surface level', 'eye level') or abstract placeholders.

- `1138-1140` **P2 / llm_closed_list_instruction**
  - evidence: "ethnicity": list(_ID_ETHNICITY_COMPONENTS), "age_band": list(_ID_AGE_BANDS)
  - why: The prompt asks the LLM to classify open-world demographic meaning from a closed list of ethnicities and age bands. This list may drift from the project's actual demographic SOT or bias the LLM against unlisted groups.
  - fix: Pass the allowed demographic vocabulary as a dynamic context field derived from the project's visual world rules rather than using a hardcoded module constant.

- `1187-1191` **P2 / llm_closed_list_instruction**
  - evidence: "triggered by 'focus on / close on / tight on / detail on' phrasing"
  - why: The prompt defines a semantic rule (body-part focus) based on a closed list of trigger phrases. This forces the LLM to act as a brittle string-pattern classifier rather than using structured intent.
  - fix: Define the 'body-part focus' state as a structured boolean or enum field in the input staging data rather than inferring it from phrasing.

- `1326-1334` **P2 / llm_closed_list_instruction**
  - evidence: "do not use any of: 'the existing X', 'from the reference', 'use the X from the reference', ..."
  - why: The prompt defines 'invalid phrasing' for close framing using a closed list of specific substrings. This is a brittle semantic classifier for output validation that may miss variations or over-penalize valid prose.
  - fix: Provide a general principle about not referencing absent images and use a post-generation semantic validator rather than exact phrase blacklists.

- `1494-1498` **P1 / blind_string_mutation**
  - evidence: "substitution": "replace the common-noun person reference inside fixed_elements[i].description ... with the matched C## or C##O##"
  - why: This instructs the LLM to perform a substring replacement on natural-language text based on a fuzzy semantic category ('common-noun person reference'). This is a contract for blind semantic mutation that relies on the LLM to correctly identify and slice arbitrary prose.
  - fix: Use a formal placeholder syntax in the description (e.g., [ENTITY_ID]) and have the LLM map IDs to those placeholders, or perform the replacement in code using structured entity mapping.

## `backend/app/core/steps/scene_consistency_step.py`

- `65-180` **P1 / semantic_string_judgment**
  - evidence: _ELEMENT_ID_CLOSE_REGEX, _DESCRIPTION_CLOSE_KEYWORDS, _classify_framing
  - why: The code infers visual framing (close-up vs. full-body) by searching for body parts (eye, wrist, etc.) and framing keywords (macro, tight shot) in natural language descriptions and element IDs. This classification drives a deterministic validator that can fail the step and block downstream processing if a conflict is detected.
  - fix: Update the LLM schema to include an explicit framing category field (e.g., 'framing_scope': 'close' | 'full') instead of inferring it from prose or ID suffixes.

- `352-620` **P2 / semantic_string_judgment**
  - evidence: summary.startswith("분석 실패"), summary.startswith("분석 차단")
  - why: The code uses string prefixes on the natural language 'analysis_summary' field to determine technical status (failed or blocked) for routing and validation. This is brittle and relies on exact Korean string matches in a field intended for human-readable summaries, creating a risk of silent failures if the summary text is modified.
  - fix: Rely exclusively on the structured 'status' field for all logic. For backward compatibility, check for the presence of data or use a migration to backfill the status field.

- `749-751` **P2 / scenario_dependent_prompt**
  - evidence: "사망/부상/의식불명", "깨진 창문, 열린 문, 혈흔"
  - why: The prompt contains concrete scenario-specific examples of character states (death, injury) and environmental props (broken windows, bloodstains). These specific tropes can bias the LLM's analysis towards certain genres or details even when processing unrelated scenarios.
  - fix: Replace concrete examples with abstract categories such as 'character physical states', 'static environmental changes', or 'fixed prop placements'.

## `backend/app/core/steps/scene_steps.py`

- `110-144` **P1 / semantic_string_judgment**
  - evidence: pattern.finditer(fulltext), avg_len < min_avg, and len(matches) >= threshold
  - why: The pipeline's primary structural segmentation (scenes) is determined by an LLM-generated regex that is validated using brittle heuristics (average character length and match count vs estimation). This logic directly controls the routing and creation of scene entities from natural language scenario text, making the core data structure of the episode dependent on pattern-matching success.
  - fix: Replace the global regex approach with a more robust line-by-line classification or a multi-stage structural analysis that does not rely on character-count heuristics to validate semantic boundaries.

- `131` **P2 / scenario_dependent_prompt**
  - evidence: f"씬 내부의 장소 전환('- 장소명')이 아니라 씬 번호('숫자.') 패턴으로 분리해야 합니다."
  - why: The retry instruction hardcodes specific Korean script formatting tropes ('- 장소명', '숫자.') as a semantic classifier to steer the LLM's regex generation, which biases the segmentation logic toward specific document styles and may fail on scripts with different conventions.
  - fix: Abstract the formatting tropes into a project-level configuration or provide them as neutral examples rather than hardcoded corrective instructions in the step runner.

## `backend/app/core/steps/shot_dependency_step.py`

- `141-142` **P1 / semantic_string_judgment**
  - evidence: if prev["location"] != cur_loc: continue
  - why: Shot dependency routing (which selects reference images for visual consistency) is gated by an exact string match on location names. These names originate from LLM-generated 'primary_location' fields (line 53) and are prone to minor variations in casing, punctuation, or synonyms, which would break the dependency chain. This is particularly problematic as the file already initializes a 'name_matcher' for locations (line 77) but fails to use it here.
  - fix: Resolve 'primary_location' names to canonical entity IDs (e.g., L##) using the 'name_matcher' already initialized in this file (line 81) before performing the comparison.

## `backend/app/core/visible_entities_validator.py`

- `102-128` **P1 / semantic_string_judgment**
  - evidence: _entity_specific_id_in_window using _ANCHOR_WINDOW = 60
  - why: The validator uses a fixed 60-character window and sentence boundary detection to infer semantic association between a character's natural-language name and their machine ID (C##). This heuristic is prone to false negatives in complex or descriptive prompts.
  - fix: Enforce ID association at the prompt-generation stage using structured templates or token-level tagging rather than post-hoc proximity heuristics.

- `139-161` **P1 / semantic_string_judgment**
  - evidence: _FACE_CLOSE_UP_PATTERNS and _is_face_close_up(prompt)
  - why: Hardcoded English keywords (face, eye, gaze, stare, expression) are used in a regex to infer visual framing semantics from the generated t2i_prompt. This result is used to deny validation exemptions, forcing ID enforcement based on brittle natural-language detection.
  - fix: Pass framing/focus metadata as a structured enum from the scene director rather than parsing the final prompt prose.

- `212-231` **P1 / semantic_string_judgment**
  - evidence: t.lower() in prompt_lower where t is from body_part_focus_rule.trigger_phrases
  - why: Validation routing (granting ID exemptions) depends on exact substring matches of LLM-generated phrases within the final prompt text. This creates a brittle dependency between two natural-language outputs where minor phrasing variations can cause validation failures.
  - fix: Use a structured boolean or enum in the prompt card to signal focus-based ID exemptions instead of relying on phrase matching.

## `backend/app/models/project.py`

- `34-199` **P2 / schema_or_enum_drift**
  - evidence: entity_type (line 34), variation_a_type (line 110), scene_type (line 127), asset_type (line 166), status (line 175), sanitization_strategy (line 179), prompt_type (line 187), variant_label (line 199)
  - why: Multiple columns use generic Text types to store specific semantic categories defined only in comments. This creates a brittle contract between LLM outputs and downstream logic, increasing the risk of drift. Additionally, values like 'aftermath' in sanitization_strategy (line 179) introduce scenario-specific narrative states into the technical schema.
  - fix: Use SQLAlchemy Enum types or CheckConstraints to enforce these values at the schema level, and synchronize these enums with the LLM prompt definitions.

- `193-297` **P2 / schema_or_enum_drift**
  - evidence: reference_image_ids (line 193) vs reference_image_ids (line 297)
  - why: The field 'reference_image_ids' is overloaded with different semantic meanings across tables: in ImageAsset it stores UUIDs (lineage), while in LLMCallLog it stores natural language 'labels' (e.g., 'character C01O02 in outfit'). Overloading a technical ID field with natural language descriptors creates a brittle semantic channel that requires string parsing to resolve identity.
  - fix: Rename LLMCallLog.reference_image_ids to reference_labels and define a structured schema for these labels instead of free-form strings.

## `backend/app/modules/llm/safety.py`

- `26-89` **P1 / blind_string_mutation**
  - evidence: _SAFETY_REPLACEMENTS_KO, _SAFETY_REPLACEMENTS_EN, sanitize_for_safety
  - why: The code performs blind substring and regex replacement on natural-language scenario text to mutate graphic terms (e.g., 'blood', 'corpse', 'kill') into 'movie set' euphemisms (e.g., 'paint', 'motionless figure', 'struck down'). This is a brittle semantic mutation that can corrupt prompts or lead to nonsensical descriptions when the context does not align with the assumed 'special effects' framing (e.g., 'melting' ice cream becoming 'deforming by effect').
  - fix: Move safety-related rephrasing to a dedicated LLM pass with contextual awareness rather than using hardcoded string replacement tables that ignore the surrounding prose context.

- `94-102` **P2 / scenario_dependent_prompt**
  - evidence: SAFETY_SYSTEM_SUFFIX
  - why: The prompt suffix contains concrete scenario-specific examples (e.g., 'dark red stage paint pool', 'motionless figure in character') and instructs the LLM to use them as a closed list of euphemisms. This biases the model's output towards a specific 'movie set' trope and limits its ability to handle diverse scenario contexts naturally, functioning as a semantic classifier for visual framing.
  - fix: Provide abstract instructions for safety-compliant rephrasing or use a dynamic few-shot approach that adapts to the specific scenario context instead of hardcoding specific prop/action names.

## `backend/app/modules/name_matcher.py`

- `8-51` **P1 / semantic_string_judgment**
  - evidence: _PAREN_RE, match_shot_char, and its use in filter_ve_by_shot_chars (line 49)
  - why: Visible-entity membership is decided by brittle string patterns (regex stripping and prefix matching) over natural-language character names. This can cause incorrect entity resolution in shots when names are similar or formatted inconsistently, directly affecting which characters are included in the visual context.
  - fix: Replace fuzzy name matching with unique entity IDs in shot descriptions, or use a canonical name-to-ID lookup table that avoids ad-hoc string logic.

## `backend/app/modules/pipeline/background_chain_planning.py`

- `151-154` **P1 / semantic_string_judgment**
  - evidence: if len(ename) >= 2 and (loc_raw in ename or ename in loc_raw): loc_id = esid
  - why: This logic uses substring matching on natural-language location names (generated by LLMs) to resolve entity IDs when an exact match fails. This is brittle and can lead to incorrect shot grouping/routing if location names overlap (e.g., 'Room' matching 'Living Room').
  - fix: Ensure the upstream LLM (scene_director) always outputs the canonical short_id (e.g., 'L01') for the primary_location field, and enforce this via schema or exact ID lookup only.

## `backend/app/modules/pipeline/background_chain_render.py`

- `57-61` **P1 / blind_string_mutation**
  - evidence: _BACKGROUND_ONLY_REINFORCEMENT = "BACKGROUND-ONLY architectural still — empty space, NO people, NO faces..."
  - why: The code blindly prepends a hardcoded semantic constraint string to a generated prompt (line 290) to override a generic sanitizer. This is brittle, bypasses LLM reasoning, and introduces a specific 'architectural' bias that may not fit all background scenarios (e.g., natural landscapes).
  - fix: Move the reinforcement instructions into the PromptSanitizer configuration or the system prompt as a conditional instruction, rather than performing blind string concatenation in the rendering loop.

- `89-92` **P2 / scenario_dependent_prompt**
  - evidence: Thoroughly describe wall/floor/ceiling/lighting/palette since later children inherit from this rendered photo.
  - why: Hardcodes architectural assumptions ('wall/floor/ceiling') into the prompt instructions for root background anchors, which may bias or confuse the LLM when generating prompts for outdoor or natural scenarios.
  - fix: Use more generic terminology such as 'surfaces', 'boundaries', or 'environment details' to accommodate both indoor and outdoor scenarios.

## `backend/app/modules/pipeline/background_classify.py`

- `147-168` **P2 / schema_or_enum_drift**
  - evidence: kind not in {"chain_bg", "prev_shot_ref"}
  - why: The classification categories ('chain_bg', 'prev_shot_ref') and their associated semantic constraints (e.g., requiring at least 3 shots and an indoor anchor for 'chain_bg') are hard-coded in the validator. This duplicates logic that should ideally be defined in the schema or a central source of truth, leading to potential drift between the LLM's instructions and the code's enforcement logic.
  - fix: Centralize the background category definitions and their validation rules (such as minimum shot counts or required attributes) into the schema or a shared configuration object that both the prompt and the validator can reference.

## `backend/app/modules/pipeline/background_render.py`

- `148-150` **P1 / semantic_string_judgment**
  - evidence: if not sanitized.lstrip().startswith("BACKGROUND-ONLY"): sanitized = _BACKGROUND_ONLY_REINFORCEMENT + sanitized
  - why: The code uses a brittle string prefix check on LLM-generated prompt text to decide whether to prepend a hardcoded reinforcement fragment. This creates a fragile dependency on the exact wording of the LLM output. Additionally, the reinforcement constant (line 22) contains scenario-biasing terms like 'architectural still' which may conflict with non-building backgrounds.
  - fix: Use a structured metadata field in the sanitizer response to indicate if the reinforcement was applied, and avoid hardcoding specific visual styles like 'architectural still' in global reinforcement strings.

## `backend/app/modules/pipeline/entity_extractor_v2_legacy.py`

- `72` **P2 / schema_or_enum_drift**
  - evidence: "entity_type": {"type": "string", "description": "character|location|prop"}
  - why: The schema defines a set of allowed values in a text description rather than a formal JSON enum. This creates a loose contract where the LLM is instructed to classify entities into categories that the downstream code expects to be stable, but does not enforce at the schema level.
  - fix: Convert the 'entity_type' field to a formal JSON enum to ensure output consistency and allow for schema-level validation.

- `193-196` **P1 / semantic_string_judgment**
  - evidence: e.get("importance") == "none" and int(e.get("appearances", 0)) < 2
  - why: The pipeline performs entity filtering (removing characters/locations/props from the scenario context) based on a brittle string comparison ('none') against an LLM's semantic assessment of 'importance'. This makes the core entity list dependent on exact keyword matching of subjective LLM output, which can lead to silent failures or inconsistent story context if the LLM uses synonyms or different casing.
  - fix: Define a formal enum for importance in the review schema and use it for filtering, or use a numeric threshold if the LLM provides a score.

## `backend/app/modules/pipeline/entity_extractor_v3.py`

- `84-169` **P2 / schema_or_enum_drift**
  - evidence: ENTITY_DETAIL_SCHEMA, metadata_json, entity_type
  - why: The schema defines entity_type as a generic string and makes it required, but the code in _gen_t2i ignores the LLM's output for this field in favor of an upstream variable. Furthermore, metadata_json uses permissive anyOf schemas for location and visual_identity, while comments (lines 96-104) specify strict per-type shapes (e.g., character must have null location) that are not enforced by the schema or validated by the code before forwarding.
  - fix: Use a string enum for entity_type in the schema. Refactor metadata_json to use a discriminator or separate schemas per entity type to ensure the LLM follows the expected structure for characters vs locations vs props, and validate these constraints in _gen_t2i.

## `backend/app/modules/pipeline/entity_filter.py`

- `71-83` **P1 / semantic_string_judgment**
  - evidence: re.sub(r'^[CLP]\d{2,3}\s*', '', raw_name).strip()
  - why: The code attempts to normalize LLM-generated names by stripping prefixes (like C01, L02) using a regex to match them against the original entity list. This is brittle because it relies on the LLM's output format for names and can lead to incorrect entity removal or retention if the name naturally contains similar patterns or if the LLM deviates from the expected prefix format.
  - fix: Instruct the LLM to return the 'short_id' in the response schema and use that exact technical identifier for filtering instead of performing regex-based name normalization.

## `backend/app/modules/pipeline/entity_lister.py`

- `199-371` **P1 / blind_string_mutation**
  - evidence: type_prompt.replace("scene_count", "shot_count") and _patch_schema_shot_count(schema)
  - why: The code adapts entity extraction logic from 'scenes' to 'shots' by performing blind substring replacements on natural-language prompt text and dynamically mutating JSON schema keys at runtime. This is brittle, as it assumes specific phrasing in the prompt templates and creates a fragile contract between the LLM output and the application logic.
  - fix: Use separate, explicitly defined prompt templates and schemas for shot-based extraction, or use a formal templating system (e.g., Jinja2) to inject the correct terminology and schema requirements.

## `backend/app/modules/pipeline/entity_relation.py`

- `15-50` **P1 / semantic_string_judgment**
  - evidence: bn = base_name(name) ... members.sort(key=lambda x: (len(x[0]), x[0]))
  - why: The code infers semantic 'variant' relationships between entities by matching natural-language names via base_name() and uses a brittle ID-length heuristic to determine which entity is the 'base'. This result is used to bias LLM relationship extraction via the candidate_block, which can lead to incorrect relationship direction or missed variants if naming/ID conventions vary.
  - fix: Shift the responsibility of identifying base/variant relationships entirely to the LLM or a more robust semantic similarity check, rather than relying on name-string patterns and ID lengths to pre-classify candidates.

## `backend/app/modules/pipeline/outlook_dedup.py`

- `72-83` **P1 / blind_string_mutation**
  - evidence: re.sub(r'C\d{2,3}O\d{2,3}', _replace_sid, text) ... re.sub(r'\s{2,}', ' ', result)
  - why: The function blindly removes duplicate entity markers (e.g., C01O02) from generated T2I prompt prose. This can leave dangling conjunctions or broken grammar (e.g., 'Character A and Character A' becomes 'Character A and ') because it does not account for the surrounding natural language context.
  - fix: Perform entity deduplication at the structured data level before prompt assembly, or use a grammar-aware template system that handles optional entity references.

- `136-145` **P2 / scenario_dependent_prompt**
  - evidence: "검은정장1"과 "검은정장2"는 다를 수 있음
  - why: The prompt contains concrete scenario-specific examples (Korean clothing names 'Black Suit 1' and 'Black Suit 2') to define deduplication logic. This biases the LLM towards specific naming conventions and types of props/outlooks found in specific stories.
  - fix: Replace concrete Korean examples with abstract descriptions of the logic, such as 'distinct numbered variants of the same base item should not be merged'.

- `288-300` **P1 / blind_string_mutation**
  - evidence: t2i_v.replace(remove_marker, keep_marker)
  - why: During outlook merging, the code performs blind substring replacement of entity markers (e.g., '[Red Dress]') within generated T2I prompt prose. This assumes the bracketed name pattern is unique and safe to replace globally, which risks unintended mutations if the name appears in other contexts or if the prompt structure is complex.
  - fix: Use a structured prompt representation where entity references are tracked by stable IDs, and only resolve them to names/markers during the final rendering step.

## `backend/app/modules/pipeline/outlook_merger.py`

- `97-105` **P1 / blind_string_mutation**
  - evidence: t2i.replace(f"[{old_name}]", f"[{new_name}]")
  - why: The code performs blind substring replacement on generated T2I prompt prose using names determined by an LLM. This treats natural-language visual descriptions as simple string buffers, which is brittle if names overlap, appear in unexpected contexts, or if the bracketed format is inconsistent in the generated output.
  - fix: Maintain T2I prompts as structured objects or token lists where entity references are tracked by unique identifiers rather than performing substring replacement on final prose.

## `backend/app/modules/pipeline/ref_image_pipeline.py`

- `66-337` **P2 / schema_or_enum_drift**
  - evidence: _VALIDATION_SCHEMA, _COMPARISON_SCHEMA, validation.get('severity') == 'severe', comparison.get('winner')
  - why: The JSON schemas for LVM validation and comparison define allowed values (e.g., 'ok', 'minor', 'severe', 'image_1', 'image_2') only in descriptions. The code at lines 322 and 337 performs exact string matches on these values to drive critical pipeline behavior (regeneration and winner selection). This is brittle as the schema does not use the 'enum' keyword to enforce these values, and line 303 even introduces an out-of-schema 'unavailable' value.
  - fix: Add 'enum' constraints to the JSON schemas for 'severity' and 'winner' fields, and ensure the code uses a shared constant or enum to handle these values consistently.

## `backend/app/modules/pipeline/scene_extractor_v2.py`

- `330` **P1 / semantic_string_judgment**
  - evidence: pos = fulltext.find(start_text, search_from)
  - why: Uses an LLM-generated natural language snippet (start_line_text) as a brittle anchor to determine scene boundaries in the original scenario text. If the LLM slightly alters punctuation or characters, the match fails, leading to incorrect scene routing.
  - fix: Use token-based offsets or unique line identifiers in the prompt to allow the LLM to return stable indices rather than arbitrary prose snippets.

- `450-451` **P1 / semantic_string_judgment**
  - evidence: if split_text in scene_text: split_pos = scene_text.index(split_text)
  - why: Similar to the segmentation anchor, this uses LLM-generated prose to find a split point for long scenes. Failure to match exactly results in keeping the original segment, which is a routing decision based on brittle string matching.
  - fix: Implement fuzzy matching for anchors or use structured line-by-line analysis to identify split points.

- `817-822` **P1 / blind_string_mutation**
  - evidence: if marker not in current_t2i ... var["t2i_prompt"] = current_t2i.rstrip() + " " + suffix
  - why: Blindly appends a suffix to the generated T2I prompt prose if a specific character/outlook marker pattern is missing. This is a post-hoc semantic mutation of generated text based on a brittle substring check.
  - fix: Instruct the LLM to include markers in a structured field or use a template-based prompt assembly method that ensures markers are present without post-generation string injection.

## `backend/app/modules/pipeline/scene_image_pipeline.py`

- `36-522` **P2 / schema_or_enum_drift**
  - evidence: _SCENE_VALIDATION_SCHEMA (severity), _COMPARISON_SCHEMA (winner), _IMPROVEMENT_SCHEMA (type)
  - why: Categorical fields like 'severity' (line 41), 'winner' (line 52), and 'type' (line 68) are defined as strings with allowed values listed only in the 'description' field of the JSON schema. Downstream code (lines 370, 391, 452, 505, 519) performs exact string comparisons on these values. This creates a brittle contract where the LLM might emit valid but slightly different strings (e.g., capitalization or extra whitespace) that the code fails to recognize, potentially bypassing logic like regeneration or variant selection.
  - fix: Update the JSON schema definitions to use the 'enum' keyword for these fields (e.g., 'enum': ['ok', 'minor', 'severe']). This ensures the LLM is constrained to the expected values and allows the schema validator to catch drift early.

## `backend/app/modules/pipeline/scene_validator.py`

- `144` **P2 / scenario_dependent_prompt**
  - evidence: "동녘(강의원)" 같은 표현 → 동녘의 몸만 있고, 강의원은 원격에서 조종 중이므로 강의원은 false
  - why: The prompt contains concrete character names and a specific plot situation (remote control) as a rule, which can bias the LLM's judgment in unrelated scenarios.
  - fix: Replace specific character names and plot points with abstract placeholders like 'Character A (Character B)' or generic descriptions.

- `222-236` **P1 / blind_string_mutation**
  - evidence: _clean_prompt using re.sub with escaped name and sid patterns
  - why: The code performs blind regex-based removal of entity names and markers from generated T2I prompt prose. This can result in broken grammar or accidental deletion of natural language text that happens to match the entity name.
  - fix: Instead of post-hoc regex cleaning, regenerate the prompt or use a structured prompt assembly method where entities are managed as objects rather than embedded strings.

## `backend/app/modules/pipeline/shot_director.py`

- `182-199` **P1 / semantic_string_judgment**
  - evidence: detect_gaze_pattern_exclusions(desc, name_to_char_id)
  - why: The code uses a pattern-matching helper to scan natural-language shot descriptions for gaze/offscreen cues and then mutates the 'visible_entity_ids' list. This overrides the LLM's semantic judgment of frame visibility using brittle string heuristics, directly contradicting the module's own docstring (line 79) which explicitly forbids code heuristics for open-world semantic judgment.
  - fix: Remove the post-process exclusion logic and rely on the LLM's structured output for frame visibility. If the LLM is unreliable, improve the prompt instructions or provide the gaze patterns as examples in the prompt rather than enforcing them via regex in code.

## `backend/app/modules/pipeline/shot_visibility.py`

- `37-445` **P1 / semantic_string_judgment**
  - evidence: _KOREAN_GAZE_STEMS, _KOREAN_FRAMING_NOUNS, _BODY_PART_NOUNS, _OFFSCREEN_PHRASES, detect_gaze_pattern_exclusions, detect_offscreen_drift
  - why: The module implements deterministic detectors that parse open-world natural language (shot descriptions and camera directions) using brittle Korean lexicons and proximity-based regex to decide entity visibility and gaze targets. This logic directly mutates the visible_entity_ids list or triggers VisibleStagingDriftError, making the pipeline's core visibility logic dependent on linguistic pattern matching rather than structured semantic signals.
  - fix: Replace the deterministic regex-based extraction with a structured LLM extraction step that identifies gaze targets and off-screen entities as part of the shot metadata, or enforce these as explicit fields in the upstream shot_director/shot_staging schemas.

## `backend/app/modules/pipeline/t2i_review.py`

- `383-454` **P1 / blind_string_mutation**
  - evidence: old.replace(target, suggestion) and old_prompt.replace(target, suggestion)
  - why: The functions _apply_entity_fixes and _apply_scene_fixes apply LLM-generated corrections to T2I prompts using simple substring replacement. This is a blind semantic mutation that can lead to corrupted prompts if the 'target' string appears multiple times, is a substring of another word, or if the LLM provides a slightly mismatched target string.
  - fix: Modify the LLM review schema to return the full corrected prompt string instead of target/suggestion pairs, or implement a token-aware replacement strategy.

## `backend/app/modules/pipeline/text_cleaner.py`

- `31` **P2 / scenario_dependent_prompt**
  - evidence: 예: "네메\\n시스" → "네메시스"
  - why: The prompt uses a specific proper noun ('Nemesis') as an example for word joining. This is concrete scenario pollution that can bias the LLM's extraction or correction behavior toward specific project-related terminology.
  - fix: Replace the specific name 'Nemesis' with a generic example or a placeholder like '가\\n나다' → '가나다'.

## `backend/app/modules/prompt_sanitizer.py`

- `67-106` **P2 / schema_or_enum_drift**
  - evidence: _STATE_GUIDANCE and the loop over preserve_pose, preserve_subject_state, etc.
  - why: The module hardcodes a vocabulary of semantic states (dead, unconscious) and constraint flags (preserve_pose, forbid_active_reaction) that must be manually synchronized with the upstream semantic_contract_router. This is an unenforced string contract prone to drift.
  - fix: Centralize the semantic state vocabulary and constraint flags in a shared schema or enum used by both the router and the sanitizer.

- `228-230` **P1 / blind_string_mutation**
  - evidence: if not sanitized.startswith(strategy["prefix"].strip()[:40]):
  - why: This performs a brittle substring check on LLM-generated prose to decide whether to prepend a strategy prefix. If the LLM output slightly varies the prefix (e.g., whitespace or punctuation), it results in double-prepending or inconsistent prompt structure.
  - fix: Use a technical marker or a separate field in the structured LLM response to indicate if the prefix was applied, rather than checking a 40-character slice of natural language.

## `backend/app/modules/reference_image_generator.py`

- `61-98` **P2 / scenario_dependent_prompt**
  - evidence: mapping = { "character": [ ..., "포박 상태", "현대 한국/근미래 한국 기준의 현실적 기본 복장", ... ] }
  - why: The character reference rules hardcode scenario-specific details such as 'Korean baseline clothing' and 'restraint state' (포박 상태). This pollutes the prompt with specific cultural and plot context that should be derived from the world_guide or entity description, biasing generation for non-Korean or non-action scenarios.
  - fix: Remove hardcoded scenario-specific phrases from the general character rules and rely on the world_guide or entity-specific traits for cultural or situational context.

## `backend/app/modules/scene_image_generator.py`

- `62-63` **P2 / blind_string_mutation**
  - evidence: world_summary = world_summary[:200].rsplit(".", 1)[0] + "."
  - why: This is a blind string mutation of natural language world context. It attempts to truncate to the last period within a character limit, which is brittle and can result in loss of critical semantic context or broken sentences if the text contains abbreviations or non-standard punctuation.
  - fix: Use an LLM-based summarizer or a robust sentence-aware truncation utility to ensure the world context remains semantically coherent.

- `89-97` **P2 / schema_or_enum_drift**
  - evidence: traits_data.get("visual_anchor_traits", [])
  - why: The code relies on a specific internal key ('visual_anchor_traits') within a JSON-string field ('stable_traits') to extract identity-fixing traits. This structure is not enforced by a central schema or enum, making the prompt generation logic vulnerable to silent failures if the upstream LLM's output format changes.
  - fix: Define a formal schema for entity traits and use a validated data model to access these fields instead of raw dictionary lookups on parsed JSON.

- `301-303` **P2 / scenario_dependent_prompt**
  - evidence: Keep exact face, hair, and build from this image.
  - why: The prompt instructions for character references contain hardcoded humanoid bias (e.g., 'face', 'hair', 'wardrobe' on line 145, and '인물' on line 105). This can bias or confuse the T2I model when the entity is a non-human character such as a robot, creature, or vehicle.
  - fix: Generalize the reference instructions to use neutral terms like 'visual features', 'identity', and 'appearance', or make the instructions dynamic based on the entity's type.

## `backend/app/modules/scene_still_extractor_legacy.py`

- `19-192` **P1 / semantic_string_judgment**
  - evidence: HEADING_PREFIXES = ("INT.", "EXT.", "INT/EXT.", "I/E.") ... if upper.startswith(prefix) and len(stripped) <= HEADING_MAX_LEN
  - why: The module identifies scene boundaries in natural-language screenplay text using a hardcoded list of English prefixes. This segmentation is used to build a 'heading_catalog' which the LLM is then required to reference by index (heading_catalog_index). This is brittle for non-English scripts or scripts with non-standard formatting, and it directly controls the structural routing and validation of the extraction process.
  - fix: Replace the brittle prefix check with a more robust screenplay parser or allow the LLM to identify and return scene boundaries as part of its structured output, rather than relying on Python-side string heuristics to define the scene index.

## `backend/app/modules/semantic_contract_router.py`

- `22-107` **P1 / semantic_string_judgment**
  - evidence: IMMOBILIZED_GAZE = frozenset({"dead", "unconscious", "severely_injured"}) ... gaze = entry.get("gaze_target") ... if gaze not in IMMOBILIZED_GAZE
  - why: The system infers a character's physical 'immobilized' state by matching specific semantic strings ('dead', 'unconscious') within the 'gaze_target' field. This is brittle as it relies on exact LLM output for open-world concepts and uses an overloaded field (gaze_target) to carry physical state information. This classification directly changes sanitizer behavior, such as forbidding active reactions or state rewrites.
  - fix: Implement the planned 'subject_state.immobility_state' structured field with a canonical enum as mentioned in the file header (lines 9-11), and update the router to use this field instead of matching semantic strings in 'gaze_target'.

## `backend/app/modules/t2i_visual_converter.py`

- `128-133` **P1 / blind_string_mutation**
  - evidence: ## [마커] 규칙 — 반드시 준수... 1. 각 씬 아래의 '★ 엔티티 목록'에 있는 이름만 [이름] 마커 사용 가능... 3. [이름]은 목록의 이름을 공백 포함 정확히 복사... 4. [] 마커는 참조 이미지 치환용이므로 목록 외 사용 시 시스템 오류 발생
  - why: This prompt instruction establishes a contract for blind substring replacement in downstream modules. It requires the LLM to perform exact string replication of natural-language names to serve as anchors for reference injection, which is highly susceptible to minor formatting variations or hallucinations that break the replacement logic. The prompt explicitly mentions that failure to follow this pattern causes system errors.
  - fix: Replace natural-language name markers with unique, stable identifiers (e.g., <ENTITY_ID>) in the prompt instructions, or move to a structured output format where the LLM explicitly maps entities to their positions in the generated prompt.

## `backend/app/modules/variation_recommender.py`

- `14-88` **P2 / schema_or_enum_drift**
  - evidence: _RESPONSE_SCHEMA
  - why: The fields 'variation_a.type', 'variation_b.type', and 'recommended' define allowed values (e.g., 'angle | color | angle+color | none', 'original | A | B') only within the description string rather than using a JSON 'enum'. This prevents the schema validator from enforcing these categories and forces downstream consumers to rely on brittle string comparisons for logic that depends on these types.
  - fix: Convert the 'type' and 'recommended' fields in _RESPONSE_SCHEMA to use the 'enum' keyword with the allowed string values.

## `backend/app/modules/variation_recommender_v2.py`

- `24-66` **P2 / schema_or_enum_drift**
  - evidence: type: { "type": "string", "description": "angle | color | angle+color | none" }, recommended: {"type": "string"}
  - why: The 'type' and 'recommended' fields are defined as strings in the JSON schema despite having a fixed set of expected values (as seen in descriptions and docstrings at line 90). This lacks formal enforcement via the 'enum' keyword, which can lead to the LLM producing slightly different strings (e.g., 'angle and color' vs 'angle+color') that pass JSON validation but break downstream logic expecting exact matches.
  - fix: Update the JSON schema to use the 'enum' keyword for 'type' and 'recommended' fields to enforce the allowed values at the API level.

## `backend/app/schemas/image.py`

- `28-84` **P2 / schema_or_enum_drift**
  - evidence: variant_type (line 28), prompt_type (line 33), status (line 84)
  - why: These fields use plain strings with allowed values documented only in comments (e.g., 'cinematic | closeup | original'). This lacks runtime validation and type safety, leading to drift if downstream logic (such as framing-based ID enforcement for 'closeup') expects specific exact strings.
  - fix: Use typing.Literal or Enum for variant_type, prompt_type, and status fields to enforce the allowed values at the schema level.

## `backend/app/services/checkpoint_sync/outlook_sync_service.py`

- `73-231` **P2 / schema_or_enum_drift**
  - evidence: ol.get("outlook_id") or ol.get("short_id", ""); sa.get("assignments", sa.get("characters", []))
  - why: The code uses fallback logic for multiple keys across different parts of the checkpoint data (outlooks and scene assignments), indicating inconsistent schema enforcement for LLM-generated outputs.
  - fix: Standardize the output schema for the outlook checkpoint and enforce single canonical keys in the validator.

- `233-238` **P1 / semantic_string_judgment**
  - evidence: csid_raw.split("O")[0] if "O" in csid_raw and csid_raw.startswith("C")
  - why: This logic infers character identity by parsing a composite string pattern (e.g., 'C01O02') from checkpoint data. It relies on a brittle, non-standard ID formatting convention to resolve entity references, which can break if the LLM or upstream process changes its output format.
  - fix: Ensure the upstream checkpoint generation (outlook_phase3) provides character_id and outlook_id as distinct, structured fields. Remove the string-splitting logic in favor of direct ID lookups.

## `backend/app/services/checkpoint_sync/scene_still_normalizer.py`

- `69-76` **P1 / semantic_string_judgment**
  - evidence: used = set(_BARE_ID_RE.findall(text)); ... return [sid for sid in director_ve if sid in used]
  - why: The function _shot_ve filters the list of visible entities by performing a regex search for entity IDs (e.g., C01, L02) within the generated t2i_prompt text. This uses brittle string matching over natural-language prose to decide visual entity membership, which directly affects downstream reference attachment and policy enforcement.
  - fix: Modify the T2I variation generation process to return a structured list of included entity IDs alongside the prompt text, rather than relying on regex parsing of the generated prompt string to infer visibility.

## `backend/app/services/prompt_service.py`

- `75-116` **P1 / semantic_string_judgment**
  - evidence: _classify_label uses substring checks like 'previous shot', 'same room', 'wearing', 'outfit', 'prop', 'background'
  - why: It infers the semantic role and visual instructions for a reference image by matching natural-language substrings in labels. This is brittle and can misclassify if these common words appear in different contexts.
  - fix: Use a structured enum for reference roles in the labeled_refs data structure instead of parsing natural language labels.

- `235-239` **P1 / semantic_string_judgment**
  - evidence: if sid in label: return idx
  - why: Resolves entity IDs (C01, P01, etc.) to reference images by checking if the ID is a substring of the natural-language label. This can lead to false positives if an ID appears in a description but is not the primary subject.
  - fix: Pass explicit entity-to-reference mappings in the payload rather than searching within label strings.

- `296-301` **P1 / blind_string_mutation**
  - evidence: re.sub(r"In a (low angle|dutch angle|high angle|bird eye|wide|tracking|over the shoulder)\s*(frame|composition|shot|view)\s*", "", cleaned)
  - why: Blindly strips camera framing and angle descriptions from the generated prompt text. This removes intentional cinematic direction provided by the LLM.
  - fix: If camera angles need to be handled separately, they should be extracted into a structured field rather than being blindly deleted from the prose.

- `368-369` **P2 / scenario_dependent_prompt**
  - evidence: "'from the reference', 'from Reference image N' 같은 표현은 절대 새로 만들지 마세요 (phantom guard 충돌)."
  - why: The prompt contains specific phrase-avoidance instructions designed to bypass a brittle downstream regex validator ('phantom guard'). This couples the LLM behavior to specific regex patterns.
  - fix: Improve the downstream validator to be context-aware or use structured references that do not rely on specific natural language phrases.

- `417` **P2 / blind_string_mutation**
  - evidence: cleaned.replace('Photorealistic cinematic still.', '').strip()
  - why: Blindly removes a specific style string from the prompt to avoid duplication. This assumes the string appears exactly as written and may fail or cause odd spacing if the LLM varies the phrasing.
  - fix: Manage style prefixes as a separate structured component of the prompt assembly rather than using string replacement on the final body.

## `backend/app/services/scene_generation_coordinator.py`

- `718-719` **P1 / blind_string_mutation**
  - evidence: if shot_name and shot_name.lower() not in var_t2i.lower(): var_t2i = f"[Camera: {shot_name}] {var_t2i}"
  - why: This uses a brittle case-insensitive substring check over natural-language prompt text to decide whether to prepend a camera directive. Variations in phrasing or punctuation in the generated prompt can cause redundant or missing directives.
  - fix: Pass camera directives as a separate structured field to the T2I generator or use a dedicated prompt assembly helper that handles deduplication semantically.

## `backend/app/services/scene_reference_service.py`

- `65-88` **P2 / semantic_string_judgment**
  - evidence: _re.search(r'character\s+(C\d{2,3}(?:O\d{2,3})?)', label)
  - why: Internal metadata (entity IDs) is extracted from intermediate string labels to decide how to further transform those labels and attach descriptions. This creates a brittle internal string contract between different parts of the service.
  - fix: Pass structured metadata (e.g., a dict or object) through the indexing pipeline instead of encoding/decoding information in label strings.

- `111-130` **P1 / blind_string_mutation**
  - evidence: rewritten = _re.sub(pattern, replacement, rewritten)
  - why: The function blindly replaces short IDs (C##, P##) within the generated T2I prompt text with descriptive phrases. This risks corrupting the prompt if these patterns appear naturally or in other metadata fields within the string.
  - fix: Use a template-based prompt generation system where placeholders are replaced in a controlled manner, or perform replacement on a structured representation of the prompt.

- `367-478` **P1 / semantic_string_judgment**
  - evidence: _re.finditer(r'(C\d{2,3})(O\d{2,3})', t2i_prompt), _re.finditer(r'\[\[([^\]]+)\]\+\[([^\]]+)\]\]', t2i_prompt)
  - why: The service resolves entity identity and decides which reference images to attach by parsing natural-language prompt text (both short_id patterns and legacy name-based patterns). This makes reference resolution dependent on the LLM's ability to maintain exact string formatting in prose.
  - fix: Pass a structured list of active entity IDs alongside the prompt instead of inferring them from the prompt text via regex.

- `932-988` **P1 / semantic_string_judgment**
  - evidence: ca.get("gaze_target", "") in ("unconscious", "dead", "severely_injured")
  - why: The 'gaze_target' field, which nominally describes orientation, is overloaded to carry physical/biological state information. Downstream code uses these specific strings to branch prompt label generation and reference image selection (state_variant).
  - fix: Introduce a dedicated 'physical_state' or 'status' field in the staging schema and use a formal enum for these values.

## `backend/app/services/scene_variation_service.py`

- `280-467` **P2 / schema_or_enum_drift**
  - evidence: var_type == "angle" / "color" / "angle+color"
  - why: The service routes image editing logic (i2i) based on exact string matches of 'var_type' produced by LLMs (VariationRecommender). These strings are not enforced by a shared Enum, making the pipeline brittle to minor changes in LLM output formatting or casing (e.g., 'Angle' vs 'angle').
  - fix: Define a central Enum for variation types and use it in both the LLM response schema and the service routing logic.

## `backend/experiments/entity_loc_prop_shots.py`

- `54-57` **P2 / scenario_dependent_prompt**
  - evidence: (아머+헬멧→아머), UI 화면
  - why: The prop extraction prompt contains concrete, genre-specific examples like 'Armor+Helmet' and 'UI Screen'. These examples can bias the LLM's extraction logic toward specific genres (fantasy/sci-fi) or cause it to incorrectly exclude valid props in other contexts (e.g., a modern office drama where a UI screen might be a key prop).
  - fix: Replace concrete examples with abstract categories or provide a broader, more diverse set of examples that cover multiple genres.

- `229-235` **P1 / semantic_string_judgment**
  - evidence: if name in existing_names: ... existing["shot_count"] += new_sc
  - why: The code uses exact string matching to determine if an LLM-generated entity name (location or prop) matches a previously extracted one for the purpose of aggregating shot counts. This is brittle because LLMs often produce slight variations for the same semantic entity (e.g., 'Living Room' vs 'The Living Room'), leading to fragmented data and incorrect counts.
  - fix: Use a semantic similarity check or a normalization step (e.g., LLM-based reconciliation or fuzzy matching) before aggregating counts, or rely on a stable unique identifier if available.

## `backend/scripts/experiment_360_interior.py`

- `37-50` **P2 / schema_or_enum_drift**
  - evidence: for k in ("stories", "primary_material", ...), for k in ("wall_finish", "floor_finish", ...)
  - why: The function manually enumerates keys from the environment_canon schema to build a prompt string. This creates a maintenance burden and risk of drift as the canonical schema evolves.
  - fix: Iterate over the dictionary keys dynamically or use a shared serialization utility that respects the canonical schema definition.

- `62-88` **P2 / scenario_dependent_prompt**
  - evidence: opposite the entry, weak floor lamp, faint old television glow, dust motes, scuff marks, subtle wear
  - why: The prompt contains concrete scenario-specific props (television, floor lamp) and layout assumptions (entry is opposite North) that bias the generation and may conflict with the provided environment canon or floor plan.
  - fix: Move specific prop and aesthetic details into the environment_canon or a separate style configuration. Remove spatial assumptions like 'opposite the entry' from the general direction descriptions.

## `backend/scripts/experiment_chain_bg_floorplan_rebuild.py`

- `55-98` **P2 / scenario_dependent_prompt**
  - evidence: NEW_CHAIN_BG_PROMPT, PROMPT_A_ORIGINAL
  - why: The prompts contain concrete scenario-specific details such as '옥탑방' (rooftop room), 'CRT television', and specific entity IDs like 'C04O06' and 'P06'. They also include negative constraints ('NOT a multi-room apartment') designed to override model biases for a specific shot, which biases arbitrary future scenarios if the script is reused as a template.
  - fix: Externalize scenario-specific descriptions, entity IDs, and layout constraints into a structured configuration file or use a template system with abstract placeholders.

- `221-222` **P2 / scenario_dependent_prompt**
  - evidence: character C04 identity, object P06
  - why: The reference labels sent to the LLM contain project-specific entity IDs ('C04', 'P06') rather than abstract roles, creating scenario pollution in the prompt assembly.
  - fix: Use abstract labels like 'Character A' or '<entity_id>' in the prompt assembly and map them to specific IDs in the execution context.

## `backend/scripts/experiment_chain_bg_floorplan_v3_tworoom.py`

- `54-337` **P2 / scenario_dependent_prompt**
  - evidence: MAIN BEDROOM (안방 — mother's room), DAUGHTER'S BEDROOM (수리영 방), character C04 identity, object P01 (small bloodstained photograph)
  - why: The prompts and reference labels contain concrete scenario-specific names, family relationships, project-specific IDs, and descriptive prop details. This biases the LLM towards a specific story and couples the generation logic to the plot, making the prompts non-reusable and prone to drift.
  - fix: Replace hardcoded names, IDs, and prop descriptions with generic placeholders (e.g., 'Character A', 'Object 1') and inject specific details dynamically from a structured data source.

## `backend/scripts/experiment_chain_shot_render_temp.py`

- `50-59` **P2 / scenario_dependent_prompt**
  - evidence: a Korean woman in her early 20s, slim, mid-length black hair, casual student look with a backpack; rooftop dwelling; rear courtyard; worn surface, dust, shadow
  - why: The prompt contains concrete scenario-specific examples (protagonist description and settings from 'The Road' project) and a specific visual interpretation of 'injury' (worn surface, dust, shadow). These bias the LLM's generation towards the current project's content and aesthetic, making the prompt less effective for arbitrary future scenarios.
  - fix: Replace concrete examples with abstract placeholders (e.g., 'a person of specific age/look', 'a specific type of room') and move project-specific visual interpretations to a separate style configuration.

## `backend/scripts/experiment_chain_structure_planning.py`

- `68-73` **P2 / scenario_dependent_prompt**
  - evidence: rooftop terrace overlook, rooftop terrace exterior
  - why: The system prompt contains concrete scenario-specific location examples ('rooftop terrace') within general heuristics and rules. This can bias the LLM's spatial reasoning or grouping logic when applied to different story environments (e.g., a forest or a spaceship) instead of remaining scenario-agnostic.
  - fix: Replace scenario-specific examples with generic placeholders or abstract descriptions, such as 'Location A', 'Exterior Area', or 'Sub-room B'.

## `backend/scripts/experiment_chain_structure_planning_gpt.py`

- `43-47` **P2 / llm_closed_list_instruction**
  - evidence: different room state (clean / lived-in / disturbed / heavily-ransacked) ... different lighting setup (window light only / television glow only / dawn spill / etc.)
  - why: The prompt provides a closed list of semantic states and lighting conditions as the primary criteria for node splitting. This biases the LLM toward these specific categories rather than allowing it to describe the open-world state of the scene.
  - fix: Rephrase as abstract criteria (e.g., 'significant changes in lighting or physical arrangement') and provide the specific states as non-exhaustive examples if necessary.

- `90` **P2 / scenario_dependent_prompt**
  - evidence: id: unique snake_case id (e.g., "interior_living_kitchen_day_normal", "interior_living_kitchen_dusk_ransacked", "small_bedroom_inside_night", "rooftop_terrace_night", "courtyard_stairs_approach")
  - why: The system prompt contains concrete scenario-specific location and state names (rooftop, living kitchen, ransacked) as ID examples. This pollutes the prompt with 'rooftop' project context, which can bias the LLM's naming and classification in other scenarios.
  - fix: Use abstract placeholders for examples, such as 'location_a_day_normal' or 'sub_region_b_night'.

- `189-244` **P1 / semantic_string_judgment**
  - evidence: extra_keywords = ["옥탑", "옥상", "rooftop"] ... any(kw in h or kw in txt for kw in extra_keywords)
  - why: The script performs a fallback scene discovery by searching for specific Korean and English substrings within natural-language scenario headings and text. This hardcodes the 'rooftop' scenario into the logic, making the tool brittle and scenario-dependent for routing decisions.
  - fix: Pass the required scene indices or location IDs explicitly via the API or configuration rather than inferring them from scenario prose using keywords.

## `backend/scripts/experiment_chain_structure_render.py`

- `57-58` **P2 / scenario_dependent_prompt**
  - evidence: NO people, NO blood, NO broken glass, NO action. Reflect atmosphere only via worn surfaces, dust, dim light, etc. ... open the prompt with an atmospheric anchor like 'Same room/space as the previous reference image...'
  - why: The system prompt hard-codes specific negative constraints (props/action) and aesthetic choices (worn surfaces, dust) that are scenario-specific. It also mandates a specific natural-language preamble to achieve visual consistency, which is a brittle way to handle cross-node semantics.
  - fix: Move scenario-specific constraints and aesthetic preferences to a configuration file or dynamic prompt segment. Use structured instructions for consistency anchors rather than hard-coding exact phrases in the system prompt.

- `128` **P1 / semantic_string_judgment**
  - evidence: if bp["id"] in gn or gn in bp["id"]:
  - why: The code uses a brittle substring match between a natural-language group name (gn) and a technical plan ID (bp['id']) to resolve which floor plan should be used as a reference image. This heuristic can easily fail or misroute if names are ambiguous or slightly different.
  - fix: Replace the substring heuristic with an explicit 'base_plan_id' field in the group or node schema to ensure deterministic routing of reference images.

## `backend/scripts/experiment_chain_structure_render_gpt.py`

- `81-119` **P1 / semantic_string_judgment**
  - evidence: extra_keywords = ["옥탑", "옥상", "rooftop"] ... if any(kw in h or kw in txt for kw in extra_keywords): scenes_in_scope.add(...)
  - why: The script determines the operational scope (which scenes/shots to process) by searching for specific natural-language keywords within scene headings and text. This is a brittle pattern-based approach to inferring scenario meaning and routing.
  - fix: Remove the keyword-based fallback. Scope should be explicitly defined in the input 'context.json' or 'step2_plan_specs.json' using structured identifiers rather than inferred from prose.

## `backend/scripts/experiment_floor_plan.py`

- `170-204` **P1 / scenario_dependent_prompt**
  - evidence: Suriyoung · 수리영, 민숙 방, S12 (엄마 시신 발견), S14 (시신 사라진 상태)
  - why: The system prompt is hard-wired with specific character names, room names, and plot points (e.g., 'mom's body discovery'). This biases the LLM's spatial reasoning and prevents the prompt from being reused for other scenarios or stories. It also instructs the LLM to prioritize specific scenes based on their narrative content, which functions as a closed-list semantic classifier embedded in the prompt.
  - fix: Replace specific names and plot points with generic placeholders (e.g., <character_name>, <room_name>) and move scene-specific prioritization logic to the user prompt or dynamic context.

## `backend/scripts/experiment_floor_plan_compare.py`

- `114-165` **P2 / scenario_dependent_prompt**
  - evidence: SYSTEM_PROMPT and build_user_message containing '옥탑방', '민숙 방', '수리영 방', '커튼 알코브', and specific prop lists like '찻잔 2개', '백팩+인형'.
  - why: The prompt hardcodes specific character names, room functions, and prop lists into the system instructions. This is concrete scenario pollution that biases the LLM and makes the prompt non-reusable for other floor plan generation tasks. It also functions as a closed-list classifier for props and labels (e.g., 'Minsook Room').
  - fix: Move scenario-specific details into the input context (ctx) and use generic placeholders or instructions in the system prompt to handle the provided context dynamically.

## `backend/scripts/experiment_floor_plan_v3.py`

- `107-113` **P2 / llm_closed_list_instruction**
  - evidence: id (snake_case): **일반 명사 기반만**. 인명·도시명·지역명·국가명·작품명 어떤 고유명사도 포함 금지.
  - why: Instructs the LLM to perform semantic classification (identifying proper nouns vs common nouns) on open-world scenario text to enforce a naming convention. This is a semantic judgment task that can lead to inconsistent IDs or loss of context if the LLM misclassifies a word.
  - fix: Instead of asking the LLM to filter proper nouns, provide a structured list of allowed categories or use a deterministic ID system that doesn't rely on the LLM's linguistic classification of scenario entities.

- `186-197` **P1 / llm_closed_list_instruction**
  - evidence: avoid: dead, corpse, deceased, victim, body / use: "motionless seated figure marker"
  - why: The prompt uses a closed list of keywords to classify open-world story events (death, injury, violence) and map them to specific visual symbols. This is a brittle semantic classifier that biases the LLM's interpretation of the scene based on keyword presence rather than holistic meaning.
  - fix: Replace the keyword-based 'avoid/use' list with a high-level instruction to describe physical states using neutral architectural or diagrammatic terminology, or move the mapping to a structured post-processing step if specific symbols are required.

## `backend/scripts/experiment_floor_plan_v4.py`

- `207-378` **P2 / schema_or_enum_drift**
  - evidence: SCHEMA_STEP1, SCHEMA_STEP2, visual_domain as string
  - why: Multiple fields such as 'visual_domain', 'type', and 'reference_strategy' are defined as generic strings in the JSON schema, but the prompts and downstream code (e.g., lines 429, 455, 1204) expect and validate exact values like 'interior', 'exterior', or 'site_map'. This drift makes the schema an unreliable contract.
  - fix: Update the JSON schemas to use 'enum' for these fields to ensure the LLM output is constrained to the values the code actually supports.

- `480-495` **P1 / llm_closed_list_instruction**
  - evidence: _SAFETY_NOTE_PLAN, _SAFETY_NOTE_PHOTO, avoid: dead, corpse, deceased, victim, body
  - why: The system prompts instruct the LLM to act as a semantic classifier and rewriter by providing a closed list of forbidden phrases and their 'safe' equivalents (e.g., replacing 'dead' with 'motionless seated figure marker'). This creates a maintenance burden where semantic rules are hardcoded in prompt prose.
  - fix: Define these semantic transformations as a structured style guide or use a post-processing step that operates on structured entity states rather than asking the LLM to perform phrase-level substitution.

- `491-493` **P2 / scenario_dependent_prompt**
  - evidence: "doll" + "backpack" + "dim bedroom" + "stain/footprint"
  - why: The safety instructions contain concrete scenario-specific props and locations as negative examples to avoid moderation triggers. This biases the model against specific visual tropes and pollutes the general-purpose prompt with arbitrary scenario details.
  - fix: Abstract these examples into general categories (e.g., 'vulnerable objects in dark settings') or move them to a scenario-specific configuration file.

- `1035-1071` **P1 / semantic_string_judgment**
  - evidence: call_llm_json_sanitized, grep_unsafe, grep_scenario, UNSAFE_WORDS_PLAN
  - why: The pipeline uses brittle substring matching (grep_unsafe/grep_scenario) over generated natural-language JSON fields (like t2i_prompt) to detect 'unsafe' or 'scenario-specific' words. Matches trigger a re-generation loop, making the system's success and behavior dependent on keyword lists rather than structured semantic validation.
  - fix: Move safety and scenario-compliance checks to a dedicated LLM-based validator or use structured metadata tags instead of scanning prose for forbidden substrings.

## `backend/scripts/experiment_fp_ref_bias.py`

- `46-72` **P2 / llm_closed_list_instruction**
  - evidence: PROMPT_A, PROMPT_B, PROMPT_D (e.g., 'reference floor plan', 'Strictly NOT a top-down view', 'use it ONLY to understand')
  - why: The prompts define semantic rules for how the LLM should interpret a specific category of reference ('floor plan') and how to map it to the output (eye-level vs top-down). This is prompt-side semantic routing based on the 'floor plan' keyword.
  - fix: Move reference interpretation logic into a structured metadata field that the system prompt uses to generate appropriate instructions based on the reference type.

- `76-105` **P2 / scenario_dependent_prompt**
  - evidence: PROMPT_F and PROMPT_E (e.g., '옥탑방', 'Seoul, Korea', 'vinyl-finish wallpaper', '2010s to early 2020s')
  - why: These prompts contain concrete scenario-specific locations, cultural tropes, and era-specific props. While used for experimentation, they represent scenario pollution that biases the model and contradicts the instruction on line 10 to avoid hardcoded scenario-dependent words.
  - fix: Parameterize these details or derive them from a structured world-rule configuration to ensure the prompt remains scenario-agnostic.

## `backend/scripts/experiment_gemini_45deg_chain.py`

- `47-128` **P2 / schema_or_enum_drift**
  - evidence: VIEW_KEYS vs RESPONSE_SCHEMA
  - why: The view identifiers ('view_0_deg', 'view_45_deg', etc.) are duplicated across a constant list (VIEW_KEYS), the JSON schema property names, and the schema's 'required' list. This creates a manual synchronization burden and risk of drift if the number or naming of views changes.
  - fix: Define the view identifiers in a single source of truth and programmatically generate the RESPONSE_SCHEMA and VIEW_KEYS list from that source.

- `60-81` **P2 / scenario_dependent_prompt**
  - evidence: labeled NORTH, toward EAST wall, worn wallpaper, dust, scuff, no blood, no broken glass
  - why: The system prompt contains concrete scenario-specific style preferences (gritty textures), narrative-negative constraints (blood/glass), and brittle assumptions about input image labels (NORTH/EAST). These bias the LLM toward a specific project genre (thriller/noir) and make the prompt dependent on specific labeling conventions in the floor plan images.
  - fix: Parameterize style preferences and narrative constraints. Instruct the LLM to identify orientation labels from the provided legend/metadata rather than assuming specific strings like 'NORTH'.

## `backend/scripts/experiment_gpt_planned_4view_chain.py`

- `58-72` **P2 / scenario_dependent_prompt**
  - evidence: 'soft natural daylight' (line 58), 'no blood, no broken glass' (line 72)
  - why: The system prompt contains concrete lighting preferences and negative constraints that are specific to a certain genre or scenario (e.g., daytime architectural, thriller/crime). These hardcoded details can bias the LLM's output and may conflict with the instruction to 'reflect scene atmosphere' when processing arbitrary scenarios.
  - fix: Move specific lighting and negative constraints to a scenario-specific configuration or use template variables that can be populated based on the input context.

- `96-321` **P2 / schema_or_enum_drift**
  - evidence: uses_prev (lines 96, 98, 175) vs loop logic (lines 315-321)
  - why: The 'uses_prev' field is defined as a required boolean in the RESPONSE_SCHEMA and requested in the prompt, but the actual generation loop ignores this value and hardcodes the logic (first view is an anchor, subsequent views are edits). This creates a drift between the contract and the implementation.
  - fix: Either remove 'uses_prev' from the schema and prompt if the chain logic is fixed, or use the field's value in the loop to decide between 'gpt_image_generate' and 'gpt_image_edit_with_prev'.

## `backend/scripts/experiment_line_art_composition.py`

- `120` **P1 / semantic_string_judgment**
  - evidence: if info["name"] == fe["character_name"]:
  - why: This performs a brittle exact-string match between two natural-language name fields (likely generated by LLMs in previous steps) to resolve entity identity. The result determines whether an entity is included in the prompt context (visible_entity_ids), directly affecting the generated T2I prompt content.
  - fix: Use canonical short_ids or UUIDs to link entities across checkpoints instead of natural-language names.

- `148-151` **P2 / llm_closed_list_instruction**
  - evidence: 인물 1 (주 인물): bright cyan lines (#00E5FF) ... 인물 2 (보조): bright magenta lines (#FF00FF)
  - why: This instructs the LLM to classify characters into a closed list of semantic roles (Main vs. Secondary) to satisfy a visual color-coding rule. This forces the LLM to make subjective open-world judgments about character importance.
  - fix: Assign colors based on stable identifiers (e.g., Character A, Character B) rather than inferred semantic roles like 'Main' or 'Secondary'.

- `152-160` **P2 / scenario_dependent_prompt**
  - evidence: 혈흔/액체 패턴: red dots (#FF0000) ... 핵심 소품과 혈흔/환경 상태의 색상과 위치
  - why: The system prompt contains concrete scenario-specific props ('blood/liquid patterns') hardcoded as a general rule. This biases the LLM to look for or invent these elements even in unrelated scenes, polluting the visual diagram generation.
  - fix: Remove scenario-specific props from the system prompt and pass them as dynamic context in the user prompt if applicable.

## `backend/scripts/experiment_line_elevation_quad.py`

- `40-53` **P2 / schema_or_enum_drift**
  - evidence: ('stories', 'primary_material', 'exterior_stairs', 'rooftop_features', 'window_pattern', 'weathering') ... ('wall_finish', 'floor_finish', 'ceiling', 'lighting_fixtures', 'general_clutter_level')
  - why: The script manually lists keys to extract from the environment_canon object. This creates a maintenance burden and drift if the upstream spatial analysis schema (e.g., in step1_spatial.json) is updated or renamed.
  - fix: Iterate over the dictionary keys dynamically or use a shared schema-aware utility to format the canon text.

- `93-135` **P2 / scenario_dependent_prompt**
  - evidence: 'aged residential interior, modest domestic clutter'
  - why: Hardcoded fallback scenario text biases the image generation toward a specific setting (aged residential) when no canon is provided, rather than using a neutral or template-based placeholder.
  - fix: Replace hardcoded strings with a generic placeholder or require the canon input to be explicitly provided.

- `127-129` **P2 / scenario_dependent_prompt**
  - evidence: dim domestic practicals (weak floor lamp, faint old television glow)... lived-in details (dust motes, scuff marks, subtle wear)
  - why: Concrete props (television, floor lamp) and specific 'lived-in' details are baked into the photorealistic style instruction, which will pollute generations for non-domestic or clean environments.
  - fix: Move specific prop and wear details into the dynamic canon text or a separate style configuration rather than hardcoding them in the base prompt.

## `backend/scripts/experiment_panorama_and_quad.py`

- `30-54` **P2 / schema_or_enum_drift**
  - evidence: compact_canon_text keys: stories, primary_material, exterior_stairs, rooftop_features, window_pattern, weathering, wall_finish, floor_finish, ceiling, lighting_fixtures, general_clutter_level
  - why: The function manually lists and iterates over specific keys expected in the environment_canon dictionary. This creates a maintenance burden where changes to the canonical environment schema must be manually synchronized with this script's serialization logic, leading to silent data loss if the schema evolves.
  - fix: Use a shared schema model (e.g., Pydantic) to handle serialization, or iterate over the dictionary keys dynamically while excluding known technical metadata.

- `72-101` **P2 / scenario_dependent_prompt**
  - evidence: soft natural daylight... weak floor lamp, faint television glow; aged residential interior, modest domestic clutter
  - why: The prompts contain concrete scenario-specific props (floor lamp, television) and style descriptions (aged residential) as either fixed instructions or fallback values. This biases the image generation towards a specific domestic setting even when the input plan might represent a different type of interior (e.g., office, warehouse, or modern laboratory).
  - fix: Remove specific prop mentions like 'television glow' and 'floor lamp' from the base prompt. Move the 'aged residential' fallback to a configuration file or make it a parameter, and use more generic lighting/style descriptions in the template.

## `backend/scripts/experiment_plan_to_photo.py`

- `59-73` **P1 / llm_closed_list_instruction**
  - evidence: Safety Vocabulary and Risk Combination Avoidance sections
  - why: The prompt defines a closed list of phrases and specific scenario-dependent combinations (e.g., 'doll' + 'backpack' + 'dim bedroom') as a semantic classifier to avoid moderation. This biases the LLM towards specific visual tropes and creates a brittle interface for describing environments based on hardcoded phrase patterns.
  - fix: Use abstract safety guidelines or a separate moderation layer instead of embedding specific prop/angle combinations in the generation prompt.

- `62-65` **P2 / scenario_dependent_prompt**
  - evidence: "overturned chair", "weathered red mark on wall", "circular stain", "faded ring shape", "dark dried floor stain"
  - why: These are concrete scenario-specific props and visual descriptions provided as examples, which can bias the LLM's generation of arbitrary future scenarios towards these specific tropes rather than allowing for open-world description.
  - fix: Use more abstract descriptions of 'disarray' or 'environmental marks' rather than specific prop names and shapes.

## `backend/scripts/experiment_set_regen.py`

- `40` **P1 / blind_string_mutation**
  - evidence: re.sub(r'NO people\s*[—–- ]\s*instead include.*?placement guides\.?', '', prompt, flags=re.DOTALL)
  - why: This performs a blind replacement of a specific semantic instruction within a generated prompt. If the LLM's phrasing for silhouette instructions changes slightly (e.g., different wording or punctuation), the removal will fail, leading to conflicting instructions when 'Empty room only' is later appended.
  - fix: Instead of post-processing the prompt string with regex, use a structured flag in the composition data to control whether the silhouette instruction is included during the initial prompt construction.

- `115-116` **P1 / semantic_string_judgment**
  - evidence: pattern = rf'{short_id}(O\d{{2,3}})' ... re.search(pattern, t2i_text)
  - why: The code infers the active outfit (visual state) by searching for ID patterns within the natural-language prose of a generated prompt. This result directly routes which reference images (composite vs. face) are attached to the generation request. It is brittle and depends on exact ID concatenation within the prose.
  - fix: Store the active outfit ID as a structured field in the shot metadata and use that field for reference routing instead of parsing the generated prompt text.

## `backend/scripts/experiment_set_shots.py`

- `96-97` **P1 / semantic_string_judgment**
  - evidence: pattern = rf'{short_id}(O\d{{2,3}})' ... m = re.search(pattern, t2i_text)
  - why: The code parses the generated T2I prompt (natural language/semantic text) using regex to identify which outfit (Oxx) is associated with a character (Cxx). This result is used to route reference image attachment (selecting a composite reference vs. an individual character reference).
  - fix: Pass the character-to-outfit mapping as structured metadata in the shot/scene data instead of extracting it from the prompt string via regex.

## `backend/scripts/experiment_set_v3.py`

- `313-345` **P1 / semantic_string_judgment**
  - evidence: re.search(rf'(?<![CO\d]){sid}', t2i_text), re.search(rf'{sid}(O\d{{2,3}})', t2i_text), and re.search(rf'(?<![A-Z]){sid}(?!\d)', t2i_text)
  - why: The script attempts to detect entity presence by searching for short IDs (C##, P##) within LLM-generated natural language prompt text. This makes reference image attachment dependent on the LLM's ability to verbatim include technical IDs in its prose output, which is brittle and prone to failure if the LLM rephrases or omits the IDs.
  - fix: Modify the Phase 1 LLM schema to return a structured list of entity IDs (e.g., 'active_entities': ['C01', 'P05']) alongside the character_prompt, and use that list for reference attachment instead of regex searching the prose.

## `backend/scripts/experiment_set_v4.py`

- `31-32` **P2 / scenario_dependent_code**
  - evidence: PROJECT_ID = "b789d6ce-f474-4f49-9388-b03c9d95020e"
  - why: The script contains hardcoded project and episode UUIDs, making it a one-off script tied to a specific scenario rather than a reusable pipeline component.
  - fix: Accept project and episode IDs as command-line arguments or environment variables.

- `77-402` **P1 / semantic_string_judgment**
  - evidence: re.findall(r'C\d{2,3}O\d{2,3}', t2i_prompt) and re.search(rf'(?<![CO\d]){sid}', t2i_text)
  - why: The code infers the presence of characters and props in a shot by searching for their short IDs within natural-language prompt text. This result directly controls which reference images are attached to the generation request, making the visual output dependent on the LLM's ability to perfectly preserve ID strings in prose.
  - fix: Pass entity membership as a structured list alongside the prompt rather than parsing it back out of the generated text.

- `177-179` **P2 / scenario_dependent_prompt**
  - evidence: NEVER include skin tone/face color modifiers (pale, drained, flushed, ashen, gray face, etc.)
  - why: The system prompt contains a concrete list of scenario-specific tropes and forbidden phrases. This biases the LLM's creative output for all future scenarios based on a specific set of safety-related keywords and preferred 'softened' replacements.
  - fix: Move safety-related style constraints to a separate style-guide configuration or a dedicated safety-filtering step.

- `431-442` **P1 / blind_string_mutation**
  - evidence: re.sub(r'blood-soaked torn shoulder and collarbone of the slumped corpse', 'a motionless figure slumped behind the curtain', text)
  - why: The sanitize_gore function performs hard-coded, scenario-specific string replacements on generated prompt text. Replacing specific anatomical descriptions with unrelated spatial descriptions (e.g., 'behind the curtain') is brittle and will cause visual hallucinations if the original scene context differs.
  - fix: Use a more abstract safety-rewriting prompt or handle safety constraints at the initial prompt generation stage rather than using regex post-processing.

## `backend/scripts/experiment_set_v5.py`

- `75-358` **P1 / semantic_string_judgment**
  - evidence: re.findall(r'C\d{2,3}O\d{2,3}', t2i_prompt) and re.search(rf'{sid}(O\d{{2,3}})', t2i_text)
  - why: Extracts character/outlook IDs by searching for patterns inside natural-language prompt text. This is used to route reference image attachment, making the system dependent on the LLM maintaining specific ID syntax within prose.
  - fix: Pass character and outlook IDs as structured metadata alongside the prompt instead of parsing them from the generated text.

- `98` **P1 / semantic_string_judgment**
  - evidence: is_indoor = any(kw in desc for kw in ["내부", "실내", "방", "사무실", "조타실"])
  - why: Uses a hardcoded list of Korean keywords to classify a location's physical nature (indoor/outdoor) from a natural-language description, which then routes the entire prompt generation logic.
  - fix: Use a structured metadata field for location type (e.g., an enum) or have the LLM classify the location type during an earlier analysis phase.

- `175-177` **P2 / llm_closed_list_instruction**
  - evidence: NEVER include skin tone/face color modifiers (pale, drained, flushed, ashen, gray).
  - why: Instructs the LLM to act as a semantic classifier/filter using a closed list of specific visual attributes. This creates drift between the prompt's exclusion list and the actual visual requirements of the scene.
  - fix: Use a more abstract instruction for style consistency or handle color normalization in a dedicated post-processing step.

- `189-192` **P2 / scenario_dependent_prompt**
  - evidence: TOP-LEFT (SET_TL): Kitchen/sink wall ... BOTTOM-RIGHT (SET_BR): Bedroom area
  - why: The prompt hardcodes specific room quadrants (Kitchen, Bedroom, etc.) for a specific location (L05), which biases the LLM and prevents the script from being used for arbitrary locations.
  - fix: Parameterize the quadrant definitions or allow the LLM to define the quadrants based on the location description.

- `386-394` **P1 / blind_string_mutation**
  - evidence: re.sub(r'blood-soaked torn shoulder and collarbone of the slumped corpse', 'a motionless figure slumped behind the curtain', text)
  - why: Performs blind semantic replacement of specific story-driven phrases in generated prompts. This is brittle, scenario-dependent, and bypasses the LLM's role in content safety/refinement.
  - fix: Move sanitization logic into the LLM system prompt or use a more general safety filter rather than hardcoded scenario-specific string replacements.

## `backend/scripts/experiment_set_v8.py`

- `73` **P2 / scenario_dependent_code**
  - evidence: if "L05" not in ve: continue
  - why: The script hardcodes a specific location ID ('L05') to filter scenes for processing. This makes the script scenario-dependent and limits its reusability across different projects or locations.
  - fix: Parameterize the target location ID or use a configuration file instead of hardcoding it in the data loading logic.

- `169-177` **P1 / semantic_string_judgment**
  - evidence: re.search(rf'(?<![CO\d]){sid}', t2i_text) and re.search(rf'{sid}(O\d{{2,3}})', t2i_text)
  - why: The script determines which reference images (character identity or specific outfits) to attach by searching for short ID patterns within the natural language prompt. This is brittle; if the LLM describes the scene without using the exact ID string, the system fails to attach the correct visual references.
  - fix: Require the LLM to output a structured list of active entities and their outfit IDs (e.g., in a JSON field) instead of parsing them from the prompt prose.

- `249-258` **P1 / blind_string_mutation**
  - evidence: re.sub(r'blood-soaked torn shoulder and collarbone of the slumped corpse', ...)
  - why: The function performs blind string replacement of highly specific, scenario-dependent gore descriptions. This hardcodes story-specific details into the pipeline and risks corrupting the prompt if the LLM's phrasing varies slightly from the expected pattern.
  - fix: Replace hardcoded regex substitutions with a structured LLM-based sanitization step or move safety constraints into the primary generation prompt.

## `backend/scripts/experiment_set_v9.py`

- `30-73` **P2 / scenario_dependent_code**
  - evidence: PROJECT_ID = "b789d6ce-f474-4f49-9388-b03c9d95020e", if "L05" not in ve: continue
  - why: The script is hardcoded to a specific project, episode, and location ID ('L05'), making it unusable for other scenarios without manual code modification.
  - fix: Parameterize project, episode, and location filters via environment variables or command-line arguments.

- `297-313` **P2 / llm_closed_list_instruction**
  - evidence: choose ONE background reference: - **"background"**: ... - **"prev_shot"**: ...
  - why: The prompt instructs the LLM to act as a semantic classifier for shot routing (deciding between a new background or a previous shot reference) using a closed list of strings, which is then consumed by exact string comparison in code.
  - fix: Use a structured comparison step that outputs a confidence score or use a more robust similarity metric for background continuity.

- `401-412` **P1 / semantic_string_judgment**
  - evidence: re.search(rf'(?<![CO\d]){sid}', t2i_text), re.search(rf'{sid}(O\d{{2,3}})', t2i_text)
  - why: The code uses regex to detect entity IDs (characters, props, outfits) within natural-language generated prompt text to decide whether to attach reference images. This is brittle as it depends on the LLM including exact technical IDs in the prose to drive reference attachment behavior.
  - fix: Pass structured entity visibility data alongside the prompt instead of parsing the prompt text to recover entity presence.

- `440-444` **P1 / blind_string_mutation**
  - evidence: re.sub(r'blood-soaked|corpse|dead body|dead woman|exposed flesh|torn shoulder', '', text, flags=re.IGNORECASE)
  - why: The function performs blind substring replacement on generated T2I prompts using a hardcoded list of scenario-specific gore terms. This can lead to mangled prompts and relies on a brittle, non-exhaustive list of terms to enforce safety/style.
  - fix: Use a dedicated LLM-based safety/style refiner or structured prompt parameters rather than regex-based sanitization.

## `backend/scripts/experiment_v4_main_shot_render_temp.py`

- `313-315` **P2 / scenario_dependent_prompt**
  - evidence: "Same room/space as the reference image — match its wall finish, floor, ceiling, lighting tone, color palette."
  - why: The prompt hardcodes indoor-specific architectural elements (wall, floor, ceiling), which biases the image generator and will cause issues for outdoor or non-room scenarios.
  - fix: Move these descriptors to a configuration field or use more generic terms like 'environment details' or 'surfaces' to allow for arbitrary scenario types.

## `backend/scripts/experiment_v4_main_shot_render_with_refs.py`

- `363-384` **P1 / scenario_dependent_code**
  - evidence: LOCATION_FALLBACK = {"L04": "...", "L05": "..."} ... if loc_id in visible: node_id = fb_node
  - why: The script hardcodes specific location IDs (L04, L05) and maps them to specific visual node identifiers to resolve background images when the primary mapping fails. This logic is specific to the 'Rooftop Room' scenario and will fail or produce incorrect results for other scenarios.
  - fix: Move scenario-specific fallbacks to a project-level configuration file or the database, or ensure the upstream planning process (chain v6) provides complete mappings for all shots.

## `backend/scripts/generate_line_art_s12_v2.py`

- `71` **P2 / scenario_dependent_prompt**
  - evidence: labeled_refs = [("Previous shot 1 reference — preserve style, layout, curtain, bed, corpse:", shot1_bytes)]
  - why: The label for the reference image contains concrete scenario-specific props ('curtain, bed, corpse'). This hardcodes scenario details into a technical label field, which can bias the model or lead to drift if the script is used as a template for other scenes.
  - fix: Use a generic label like 'Previous shot reference' and move specific preservation instructions to the main prompt body.

## `prompts/_base/background_chain_planning/1.202604271600/system.md`

- `14-68` **P2 / llm_closed_list_instruction**
  - evidence: Close-ups, prop inserts, hand-scale plates... clean / lived-in / disturbed / heavily-ransacked... window light only / artificial light only / dawn spill
  - why: The prompt instructs the LLM to classify open-world Korean scenario text into specific English categories (shot types, room states, lighting) to drive node grouping and splitting logic. This creates a dependency on these specific phrases for pipeline routing and clustering behavior, even though they are presented as examples.
  - fix: Formalize these categories into a structured schema or enum in the input/output, or provide more abstract criteria for 'tight views' and 'state changes' that do not rely on specific phrase lists.

## `prompts/_base/background_chain_planning/2.202604272110/schema.json`

- `7` **P1 / llm_closed_list_instruction**
  - evidence: (street, road, coast, sea, forest, yard, park, exterior rooftop, public square, beach, dock, vehicle exterior, etc.)
  - why: The prompt defines a semantic classifier for 'OUTDOOR/OPEN-AIR' using a list of specific scenario types. This classification directly controls the 'skip_chain' boolean flag, which changes the rendering pipeline's routing logic (skipping chain planning). This creates a brittle dependency on the LLM's interpretation of these specific examples to drive core architectural behavior.
  - fix: Introduce a formal 'environment_type' enum in the schema and move the skip logic to the application code based on that enum value, rather than relying on a descriptive list of examples to set a boolean.

## `prompts/_base/background_chain_planning/2.202604272110/system.md`

- `11-19` **P1 / llm_closed_list_instruction**
  - evidence: OUTDOOR / OPEN-AIR (street, road, alley, coast, sea, beach, dock, yard, garden, park, public square, forest, mountain, exterior rooftop view, vehicle exterior, open-air market, etc.)
  - why: The prompt instructs the LLM to set a boolean routing flag (skip_chain) based on whether a location matches a specific list of place types. This is a brittle semantic classifier for pipeline control flow that may fail on unlisted or ambiguous location types.
  - fix: Define the criteria for skipping (e.g., 'unbounded parallax' or 'natural lighting variance') rather than providing a list of specific place types.

- `29-87` **P1 / llm_closed_list_instruction**
  - evidence: Close-ups, prop inserts, hand-scale plates, 'background plate' shots, photograph inserts
  - why: The prompt uses a specific list of shot types to decide node membership and background reuse. This is a semantic classifier for entity/node clustering that relies on the LLM matching these exact categories in the scenario text.
  - fix: Provide a general rule for background reuse (e.g., 'if the background is a subset of a previously defined node') rather than a list of shot categories.

- `31-88` **P2 / schema_or_enum_drift**
  - evidence: clean / lived-in / disturbed / heavily-ransacked
  - why: The prompt repeatedly uses a specific vocabulary for physical states (day/night/dusk/dawn and clean/disturbed/ransacked) across multiple instructions. This creates an unenforced string contract that likely drifts from a central state enum and even drifts within the file (e.g., 'heavily-ransacked' vs 'ransacked').
  - fix: Define a formal state or condition enum in the schema rather than embedding it in the description prose.

## `prompts/_base/background_chain_planning/2.202604272110/user_template.md`

- `16-20` **P1 / llm_closed_list_instruction**
  - evidence: If SKIP applies (outdoor / open-air) ... Otherwise (indoor / enclosed / fixed-set)
  - why: The prompt instructs the LLM to perform a semantic classification based on a closed list of natural-language categories to decide whether to skip or execute background chain planning. This routes major pipeline behavior (skip_chain: true/false) based on the LLM's interpretation of open-world location descriptions against these specific phrases.
  - fix: Define the skip/render requirement as a structured boolean or enum in the location metadata schema rather than asking the LLM to infer it from the description during the planning phase.

## `prompts/_base/background_chain_planning/3.202604290417/schema.json`

- `5-7` **P2 / llm_closed_list_instruction**
  - evidence: OUTDOOR/OPEN-AIR (street, road, coast, sea, forest, yard, park, exterior rooftop, public square, beach, dock, vehicle exterior, etc.)
  - why: The prompt instructs the LLM to perform a semantic classification of the location based on a list of natural language examples to drive a boolean that changes the rendering pipeline's reference strategy.
  - fix: Define a formal environment_type enum in the schema and move the skip_chain logic to the pipeline code based on that enum.

## `prompts/_base/background_chain_planning/3.202604290417/system.md`

- `18-26` **P1 / llm_closed_list_instruction**
  - evidence: OUTDOOR / OPEN-AIR (street, road, alley, coast, sea, beach, dock, yard, garden, park, public square, forest, mountain, exterior rooftop view, vehicle exterior, open-air market, etc.)
  - why: The prompt uses a closed list of location types as a semantic classifier to determine the 'skip_chain' routing decision. This is a brittle way to handle open-world locations where the scenario text might not match these specific keywords but requires the same pipeline behavior.
  - fix: Define the skip condition based on abstract visual continuity requirements (e.g., 'environments with high natural variance or non-fixed spatial boundaries') rather than a list of specific location types.

- `36-42` **P2 / llm_closed_list_instruction**
  - evidence: clean / lived-in / disturbed / heavily-ransacked, Close-ups, prop inserts, hand-scale plates, open window with torn curtain
  - why: These lists act as semantic classifiers for node splitting and reuse. They include specific scenario states and prop examples (e.g., 'heavily-ransacked', 'torn curtain') that bias the LLM's grouping logic and function as a closed-world classifier for open-world visual states.
  - fix: Use abstract criteria for node management (e.g., 'significant change in lighting, geometry, or state') and provide these specific states as non-binding examples or move them to project-specific configuration.

## `prompts/_base/background_chain_planning/4.202604291315/schema.json`

- `5-7` **P2 / llm_closed_list_instruction**
  - evidence: true if this location is OUTDOOR/OPEN-AIR (street, road, coast, sea, forest, yard, park, exterior rooftop, public square, beach, dock, vehicle exterior, etc.)
  - why: The prompt uses a list of examples to define a semantic classifier for the 'skip_chain' boolean, which directly routes the rendering logic (chain vs. fallback). This relies on the LLM's interpretation of an open-world concept against a non-exhaustive list of examples.
  - fix: Define 'location_type' as a formal enum in the location schema and use that to drive the 'skip_chain' logic, rather than asking the LLM to infer it from a list of examples in a description.

## `prompts/_base/background_chain_planning/4.202604291315/system.md`

- `21-25` **P1 / llm_closed_list_instruction**
  - evidence: INDOOR / ENCLOSED / FIXED-SET... vs DETACHED OPEN AREA... (a road far from any building, an unrelated forest, a wide beach, a public street block, a mountain trail, a public square not attached to a tracked building)
  - why: The prompt defines a binary routing decision (skip_chain) based on a semantic classification of the location using a closed list of environment types and specific scenario examples. This forces the LLM to map open-world locations into a narrow set of categories to drive pipeline behavior.
  - fix: Move the skip_chain decision to an upstream metadata field or provide a more abstract set of criteria that doesn't rely on a list of specific environment examples.

- `45-51` **P1 / llm_closed_list_instruction**
  - evidence: Close-ups, prop inserts, hand-scale plates... vs different room state (clean / lived-in / disturbed / heavily-ransacked)
  - why: The prompt uses closed lists of shot types and room states as semantic classifiers to decide whether to group shots or split them into separate background nodes. This requires the LLM to perform brittle semantic mapping from natural language descriptions to determine the visual structure of the plan.
  - fix: Define these states and shot types in a formal schema and have the LLM output them as structured enums, or use a more robust method for determining node splits that doesn't rely on a fixed list of narrative states.

## `prompts/_base/background_chain_planning/4.202604291315/user_template.md`

- `14-21` **P2 / llm_closed_list_instruction**
  - evidence: If SKIP applies (outdoor / open-air) ... Otherwise (indoor / enclosed / fixed-set)
  - why: The prompt instructs the LLM to perform a semantic classification of the location (outdoor vs indoor) to determine pipeline routing via the skip_chain field. This logic is brittle as it depends on LLM interpretation of open-world descriptions against a closed set of categories to decide whether to bypass a generation stage.
  - fix: Move the skip logic to a structured metadata field (e.g., environment_type enum) in the location schema, and use that field to drive the skip_chain decision in code or via a simple boolean check.

## `prompts/_base/background_chain_render/2.202604282201/system.md`

- `11-43` **P1 / scenario_dependent_prompt**
  - evidence: Photoreal architectural still — empty room/space, Same room/space, wall finish, floor, ceiling, TV is in the upper-left, sofa cluster
  - why: The prompt is heavily biased towards indoor architectural scenarios, forcing specific terminology (room, floor, ceiling, furniture) and opening phrases that will cause hallucinations or failures for outdoor, natural, or non-building backgrounds.
  - fix: Generalize the instructions to handle any environment type (e.g., 'environment/setting' instead of 'room/space') and use abstract placeholders for props in examples.

- `44` **P1 / blind_string_mutation**
  - evidence: t2i prompt에 직접 prepend되므로 영어.
  - why: The instruction confirms a pipeline design where generated natural-language paragraphs (shot_guides) are blindly prepended to other prompts. This is a brittle semantic composition strategy that can lead to conflicting instructions or broken prompt syntax.
  - fix: Use structured prompt composition where the guide is passed as a separate field to the downstream generator or merged using a formal template rather than blind prepending.

## `prompts/_base/background_classify/3.202604300520/system.md`

- `18-20` **P1 / llm_closed_list_instruction**
  - evidence: Korean clues that often imply indoor: 내부 / 안 / 방 / 실 / 층 / 차내 / 매장 안 / 사무실 ... Korean clues: 외부 / 옥상 / 거리 / 도로 / 공터 / 골목 / 해안 / 숲 / 마당
  - why: The prompt defines semantic classification rules for 'is_indoor' based on a closed list of Korean substrings. This forces the LLM to act as a keyword-matching classifier rather than using its natural language understanding, leading to potential misclassification of locations described with synonyms or complex phrasing not covered by the list.
  - fix: Remove the specific keyword lists and instead provide a clear physical definition of indoor vs. outdoor spaces (e.g., enclosed structure vs. open sky), instructing the LLM to infer the state from the overall context of the location label and summary.

## `prompts/_base/background_master_plan/1.202604292000/system.md`

- `19-39` **P2 / scenario_dependent_prompt**
  - evidence: ok-tab-bang_living_room, dusk_ransacked, night_blood_curtain_drawn, blood/dust on surfaces
  - why: The prompt uses concrete, genre-specific examples (crime/thriller elements like 'blood', 'ransacked') and cultural-specific terms ('ok-tab-bang') to illustrate state labels and naming conventions. These can bias the LLM's planning and labeling for scenarios in other genres.
  - fix: Replace scenario-specific examples with neutral, generic ones (e.g., 'living_room_day', 'office_night_messy') to ensure the prompt remains genre-agnostic.

## `prompts/_base/background_master_plan/2.202605091400/system.md`

- `26-74` **P2 / schema_or_enum_drift**
  - evidence: "main" | "kitchen" | "rooftop" | "stairs" | "yard" | "exterior" | "office"
  - why: Closed list of sub-locations used as a semantic classifier. It forces open-world locations into a small set of keys, losing semantic precision and requiring manual synchronization between the prompt and the code's normalization logic.
  - fix: Allow for more flexible keys or inject the allowed vocabulary from the project configuration.

- `31-79` **P2 / scenario_dependent_prompt**
  - evidence: 예: 'dusk busy with employee pointing toward exit'
  - why: Concrete scenario-specific example ('employee pointing toward exit') that can bias the LLM's description style for unrelated scenes or genres.
  - fix: Use more abstract or generic examples such as 'time of day with specific activity or state'.

- `41` **P2 / schema_or_enum_drift**
  - evidence: normal / quiet / busy / busy_exit / ransacked / clean_after / blood_scene / intrusion / arrival / evidence_display / dream_or_vision_state
  - why: Hardcoded list of semantic states in the prompt that must match code-side expectations for grouping and validation. Includes scenario-specific values like 'blood_scene' and 'ransacked' that bias the model toward specific genres.
  - fix: Inject the enum values dynamically from a central schema definition into the prompt template instead of hardcoding them.

## `prompts/_base/background_master_plan/3.202605092023/system.md`

- `41-45` **P2 / llm_closed_list_instruction**
  - evidence: state_class enum (정확히 한 값. 그 외는 reject): `normal` / `quiet` / `busy` / `busy_exit` / `ransacked` / `clean_after` / `blood_scene` / `intrusion` / `arrival` / `evidence_display` / `dream_or_vision_state`
  - why: The LLM is forced to classify open-world story events (e.g., violence, break-ins, or dream sequences) into a rigid set of semantic strings which the code then uses for validation and retry logic. This creates a brittle interface between story meaning and system behavior.
  - fix: Move semantic classification to a separate analysis step or allow the LLM to provide descriptive labels that are then mapped via a more robust embedding-based or LLM-assisted classifier.

- `74-79` **P2 / scenario_dependent_prompt**
  - evidence: Example (group `bg_large_mart` covers L09 외부 + L10 매장 + L14 사무실): ... fp_sales_floor ... fp_exterior_entrance
  - why: The example uses concrete scenario-specific names (large mart, sales floor) and IDs (L09, L10, L14) which can bias the LLM's output for unrelated building types or story contexts.
  - fix: Use abstract placeholders like Group A, Location 1, Space A, and fp_alpha to demonstrate the logic without scenario pollution.

- `86-90` **P2 / llm_closed_list_instruction**
  - evidence: space_key_hint: controlled vocab ... 모르는 공간은 `main` 으로 fallback.
  - why: Forces spatial categorization into a narrow list and uses a blind 'main' fallback for unknown spaces. This loses semantic precision for complex architectural scenarios and relies on string-based classification of visual spaces.
  - fix: Allow free-text space keys or expand the vocabulary to be more comprehensive, and avoid blind fallbacks in favor of explicit 'other' categories or descriptive labels.

## `prompts/_base/background_planner/1.202604290417/schema.json`

- `21-25` **P2 / scenario_dependent_prompt**
  - evidence: e.g. 'okt_room'
  - why: The example 'okt_room' (rooftop room) is a culturally specific Korean drama trope. Including it in a base schema description can bias the LLM towards specific architectural or scenario settings during generation.
  - fix: Replace 'okt_room' with a generic technical example like 'building_a' or 'house_main'.

- `144-147` **P2 / llm_closed_list_instruction**
  - evidence: "enum": ["outdoor_3+", "low_freq_2", "single_shot"]
  - why: This enum functions as an overloaded semantic channel, forcing the LLM to map open-world location properties (outdoor vs indoor) and shot counts into a single composite string. This is a brittle classifier that duplicates information from the 'shot_count' field and creates a rigid semantic contract.
  - fix: Split the semantic properties into separate fields (e.g., a boolean 'is_outdoor') and handle the composite logic in code or via clearer prompt instructions.

## `prompts/_base/background_planner/2.202604291245/system.md`

- `10-60` **P2 / scenario_dependent_prompt**
  - evidence: CEO room, parking lot, office tower, mart_complex, cb_l05_living_night_blood
  - why: The prompt uses modern corporate and urban examples (CEO room, parking lot, mart_complex) and genre-specific state examples (night_blood) which can bias the LLM's architectural and state analysis for non-modern or non-violent scenarios, potentially contradicting the instruction in line 98 to use universal physical descriptors.
  - fix: Replace specific examples with era-neutral terms (e.g., 'main chamber', 'courtyard', 'market') and neutral state variants (e.g., 'night_variant_1').

## `prompts/_base/background_prompt/1.202604292053/system.md`

- `17` **P2 / scenario_dependent_prompt**
  - evidence: dusk_ransacked, night_blood_curtain_drawn
  - why: These examples introduce concrete, high-entropy scenario details (ransacking, blood on curtains) into a base system prompt. This can bias the LLM to assume a thriller or horror context even when the input state_label is more neutral.
  - fix: Replace scenario-specific examples with neutral or abstract placeholders such as 'day_clear', 'night_interior_variant', or 'state_label_example'.

## `prompts/_base/background_prompt/5.202605032354/schema.json`

- `19-24` **P1 / semantic_string_judgment**
  - evidence: objects_owned_by_background ... English canonical common nouns ... scene_detail 이 redraw 하지 않도록 contract
  - why: The schema establishes a contract where natural language nouns are used as identifiers to control downstream redrawing behavior in 'scene_detail'. This relies on brittle string matching and requires strict normalization (singular form, no adjectives, English only) to work, which is a form of semantic string judgment over generated prose.
  - fix: Use a structured entity ID system to track objects across components instead of relying on natural language noun matching to enforce redrawing policies.

## `prompts/_base/background_prompt/5.202605032354/system.md`

- `20` **P2 / schema_or_enum_drift**
  - evidence: objects_owned_by_background ... items MUST be English canonical common nouns ... contract 역할을 한다
  - why: The prompt establishes a 'contract' for object deduplication between pipeline stages (background vs scene_detail) based on 'English canonical common nouns'. Since there is no closed vocabulary or enforced enum, different LLM iterations or models may use slightly different terms (e.g., 'wardrobe' vs 'closet' or 'TV' vs 'television'), breaking the deduplication logic and potentially causing visual artifacts or redundant rendering.
  - fix: Implement a shared object vocabulary or use unique entity IDs from the world-state/layout-spec to synchronize objects across generation passes instead of relying on natural language noun consistency.

## `prompts/_base/background_prompt/6.202605091200/system.md`

- `15` **P2 / blind_string_mutation**
  - evidence: Convert numbered references (e.g., "number 2 (wardrobe)") into descriptive phrases using the input numbered_elements mapping
  - why: This instructs the LLM to perform pattern-based string replacement on input text to resolve entity references. Relying on the LLM to parse and mutate specific string patterns like 'number X (name)' is a brittle way to maintain entity identity across prompt segments.
  - fix: Pass structured entity objects or IDs directly to the prompt and allow the LLM to reference them naturally, rather than requiring the LLM to perform manual string-pattern resolution.

- `20` **P2 / schema_or_enum_drift**
  - evidence: objects_owned_by_background ... items MUST be English canonical common nouns ... 이 list 는 scene_detail 이 같은 객체를 다시 그리지 않도록 contract 역할을 한다.
  - why: The prompt establishes a visual consistency contract between components (background_prompt and scene_detail) using an unenforced, open-ended set of English nouns ('canonical common nouns'). Without a shared enum or schema, different LLM calls may use different synonyms (e.g., 'wardrobe' vs 'closet'), breaking the 'contract' intended to prevent redrawing.
  - fix: Define a canonical vocabulary or enum for common background objects in the schema and enforce its use across both background and scene detail prompts.

## `prompts/_base/character_state_variant/1.202604101200/system.md`

- `12` **P2 / scenario_dependent_prompt**
  - evidence: skin pallor, posture, wounds/blood as appropriate for the state
  - why: The prompt hardcodes specific visual tropes related to physical trauma or illness into a general 'state variant' instruction. This biases the model to consider these elements even when the requested state (e.g., 'happy', 'wet', 'glowing') does not involve them, potentially leading to unwanted morbid visual artifacts in arbitrary scenarios.
  - fix: Generalize the instruction to 'visual indicators relevant to the state' or move specific injury-related terms to a specialized template or dynamic variable.

## `prompts/_base/entity_all/2.202603260725/character.md`

- `14` **P2 / llm_closed_list_instruction**
  - evidence: 행인, 군중, 이름 없는 단역
  - why: Defines the 'extra' exclusion rule using a closed list of role types. This is a semantic classifier that relies on the LLM matching specific role names rather than a general functional definition of non-essential characters.
  - fix: Define extras by their functional role (e.g., 'characters whose visual identity is not required for continuity') rather than a list of role names.

- `25-28` **P2 / scenario_dependent_prompt**
  - evidence: 인간↔요괴, 인간↔괴물, 수술 전후, 빙의/합체
  - why: Uses specific genre tropes (fantasy, medical, supernatural) as primary examples for character splitting logic. This biases the LLM towards these specific scenarios and may lead to inconsistent behavior in scenarios that do not fit these specific categories.
  - fix: Replace specific tropes with abstract descriptions of visual change, such as 'significant change in facial features, body structure, or species'.

- `31` **P1 / semantic_string_judgment**
  - evidence: 이름 구분: "A", "A (변형 상태)" — 괄호 안에 변형 상태를 명시
  - why: Overloads the character name field with state metadata using a brittle string pattern (parentheses). This creates a contract where downstream logic must use pattern matching to decouple identity from state, which is prone to failure if the LLM deviates from the exact format.
  - fix: Separate identity and state into distinct schema fields (e.g., 'name' and 'variant_description') instead of encoding them into a single string.

## `prompts/_base/entity_all/2.202603260725/prop.md`

- `19-22` **P2 / llm_closed_list_instruction**
  - evidence: (수트, 우주복, 갑옷, 제복, 의상, 입는 장치나 로봇은 제외), (벽면 모니터, TV, CCTV 등), (문, 창문, 계단, 엘리베이터), (상태창, 모니터 화면, HUD)
  - why: These lists function as a semantic classifier to define the boundary of the 'Prop' entity. They contain genre-specific examples (space suits, armor, HUD) that act as a closed-world filter for an open-world extraction task, creating potential drift if other entity types (like outfits or backgrounds) change their definitions.
  - fix: Define entity boundaries using abstract category definitions (e.g., 'wearable items', 'architectural elements') and move specific examples to a centralized schema or shared documentation to ensure consistency across different entity extraction prompts.

## `prompts/_base/entity_all/3.202603290500/character.md`

- `25` **P2 / scenario_dependent_prompt**
  - evidence: 인간↔요괴, 인간↔괴물
  - why: Uses genre-specific tropes ('Yokai', 'Monster') as examples for transformation logic in a base prompt, which can bias the LLM's extraction behavior toward specific story types even when processing unrelated scenarios.
  - fix: Use neutral placeholders like 'Form A' and 'Form B' or 'Original' and 'Transformed' to illustrate visual changes.

- `31` **P2 / schema_or_enum_drift**
  - evidence: 이름 구분: "A", "A (변형 상태)" — 괄호 안에 변형 상태를 명시
  - why: Overloads the 'name' field with visual state metadata using a string pattern. This creates a dependency on string parsing (regex/substring) to identify the base character or the specific variant state in downstream processing, rather than using a structured field.
  - fix: Introduce a structured field for 'variant_description' or 'state' in the output schema instead of embedding it in the name string.

## `prompts/_base/entity_all/3.202603290500/prop.md`

- `21-28` **P2 / llm_closed_list_instruction**
  - evidence: 제외 기준 (중요!) ... (수트, 우주복, 갑옷, 제복, 의상, 입는 장치나 로봇은 제외) ... (피, 물, 불, 연기, 안개, 먼지, 눈, 비 등) ... (번호표, 명함, 영수증 등 텍스트만 다른 종이류)
  - why: The prompt uses closed lists of specific nouns and categories to force the LLM to exclude items from the 'prop' entity. This creates brittle semantic boundaries where unique or story-critical items (e.g., a 'magic receipt' or a 'sentient liquid') might be incorrectly filtered out because they match these hardcoded exclusion strings.
  - fix: Replace specific noun lists with abstract functional criteria or reference a central ontology. For example, instead of listing 'blood, water, fire', instruct the LLM to exclude items that are primarily environmental effects or handled by a separate VFX pipeline.

## `prompts/_base/entity_all/4.202603310100/character.md`

- `30` **P2 / scenario_dependent_prompt**
  - evidence: (이무기, 구미호, 요괴화, 뱀파이어 등)
  - why: The prompt provides a list of specific mythological and genre-specific modifiers (Imoogi, Gumiho, Yokai, Vampire) to guide the LLM in splitting character entities. This introduces scenario-specific bias into a base prompt intended for general use and functions as a closed-list semantic classifier.
  - fix: Replace specific mythological examples with abstract categories such as 'creature form', 'transformed state', or 'visual mutation' to maintain genre neutrality.

## `prompts/_base/entity_all/4.202603310100/prop.md`

- `21-28` **P2 / llm_closed_list_instruction**
  - evidence: 제외 기준 (중요!) ... 수트, 우주복, 갑옷 ... 피, 물, 불 ... 자동차, 트럭 ... 의자, 탁자 ...
  - why: The prompt uses specific lists of object categories to instruct the LLM on what to exclude from the 'prop' entity type. This functions as a closed-list semantic classifier for open-world scenario content. While intended to reduce noise, hard-coded lists like 'wearable robots' or 'liquids/phenomena' can cause the LLM to overlook visually unique or narratively critical items that happen to fall into these categories, especially when the 'unique visual features' exception is not applied consistently across all lists.
  - fix: Shift from exhaustive item lists to abstract criteria based on narrative role and visual uniqueness. Ensure the 'unique visual features' exception is explicitly applied to all categories, including wearables and effects, to prevent loss of critical scenario entities.

## `prompts/_base/entity_extract_v4/6.202603261200/prop.md`

- `22-25` **P2 / llm_closed_list_instruction**
  - evidence: 수트, 우주복, 갑옷, 제복, 의상, 입는 장치 나 로봇... 벽면 모니터, TV, CCTV... 문, 창문, 계단, 엘리베이터... 상태창, 모니터 화면, HUD
  - why: These lines provide a closed list of semantic categories and specific examples to instruct the LLM on what to exclude from the 'prop' entity type. This functions as a classifier for open-world scenario content and introduces genre-specific pollution (e.g., spacesuits, robots, HUDs) into a base prompt, which can lead to inconsistent extraction or bias across different story types.
  - fix: Replace specific object lists with abstract functional definitions (e.g., 'items permanently attached to the environment' or 'items worn as part of a character's outfit') or reference a centralized entity-type schema to ensure consistency across different extraction prompts.

## `prompts/_base/entity_extract_v4/7.202603261400/prop.md`

- `22-25` **P2 / scenario_dependent_prompt**
  - evidence: 수트, 우주복, 갑옷, 제복, 의상, 입는 장치 나 로봇은 제외 ... 상태창, 모니터 화면, HUD
  - why: The exclusion criteria use concrete, genre-specific examples (spacesuits, armor, robots, HUDs, status windows) to define the boundaries of what constitutes a 'prop'. This biases the LLM towards Sci-Fi, Fantasy, or Game-like scenarios and may lead to incorrect exclusions or inclusions in other genres (e.g., historical or slice-of-life).
  - fix: Replace genre-specific examples with abstract category descriptions or a more diverse set of examples spanning multiple genres (e.g., 'period-specific attire', 'household appliances', 'architectural elements').

## `prompts/_base/entity_extract_v4/8.202603290500/prop.md`

- `22-26` **P2 / llm_closed_list_instruction**
  - evidence: 수트, 우주복, 갑옷, 제복, 의상, 입는 장치나 로봇 / 벽면 모니터, TV, CCTV / 문, 창문, 계단, 엘리베이터 / 상태창, 모니터 화면, HUD / 피, 물, 불, 연기, 안개
  - why: The prompt uses specific noun lists to define the exclusion boundary for props. This functions as a semantic classifier that relies on enumeration rather than abstract definitions, leading to potential inconsistency when encountering similar but unlisted items (e.g., 'lava' vs 'water') or when definitions drift between different entity extractors (e.g., background vs prop).
  - fix: Replace specific noun lists with abstract category definitions (e.g., 'wearables', 'architectural elements', 'environmental effects') and provide a centralized ontology for entity classification to ensure consistency across the pipeline.

## `prompts/_base/entity_extraction/v5/chunk_system.md`

- `48-58` **P2 / schema_or_enum_drift**
  - evidence: Use concrete labels such as age, disguise, injury... Good examples: identity reveal, family tie, alliance...
  - why: The prompt provides specific semantic labels for 'variant_axes' and 'relation_facts' as examples. These strings are likely used as exact keys in the continuity graph or downstream logic, but they are defined here as informal examples rather than being enforced via a formal JSON enum in the schema. This leads to drift between the prompt's suggested vocabulary and the system's expected categories.
  - fix: Define these semantic categories (variant types and relationship types) as formal enums in the JSON schema and reference them in the prompt, rather than providing them as a list of examples.

## `prompts/_base/entity_extraction/v6/chunk_system.md`

- `48` **P2 / schema_or_enum_drift**
  - evidence: Use concrete labels such as `age`, `disguise`, `injury`, `costume`, `hair_makeup`, `time_of_day`, `weather`, `damage`, `crowd_density`, `open_closed`, `ownership`, `blood_stain`, or `loaded_empty`.
  - why: These labels function as semantic categories for state tracking. Providing them as 'examples' in a prompt suggests they are not enforced by the schema, leading to potential drift where downstream code might expect specific strings from this list to trigger logic.
  - fix: Move these standard variant axes into a formal enum in the schema to ensure consistency across different extraction passes.

- `55-56` **P1 / llm_closed_list_instruction**
  - evidence: Only extract: identity (same person/different name), transformation (appearance change — age, disguise, injury), possession (character carries/wears item), containment (entity is inside/part of location).
  - why: This forces the LLM to perform semantic classification of open-world narrative relationships into a narrow, closed set of four visual categories. This logic is hardcoded in the prompt rather than being handled by structured schema or downstream logic.
  - fix: Define these relationship types as a formal enum in the JSON schema and use the prompt to describe the selection criteria for each enum value.

## `prompts/_base/entity_extraction/v6/final_system.md`

- `5-22` **P2 / schema_or_enum_drift**
  - evidence: identity, transformation, possession, containment only. Exclude kinship, social, conflict, collaboration, membership, control, goal, and event relations.
  - why: The prompt defines a closed-list semantic classifier to filter 'visually relevant' relations. This logic is hardcoded in the prompt prose rather than being driven by the schema, creating a maintenance burden and potential for drift between the extraction policy and the data model.
  - fix: Define the allowed and excluded relation types in a central configuration or schema and inject them into the prompt as template variables.

## `prompts/_base/entity_extraction/v7/chunk_system.md`

- `16-24` **P2 / scenario_dependent_prompt**
  - evidence: (예: 아머 유닛, 가면, 무기류 등) ... (예: 은성<->ZRBB51)
  - why: Contains concrete scenario-specific examples like 'Armor Unit' and specific character names/IDs ('은성', 'ZRBB51') which can bias the LLM towards specific genres or naming conventions during entity extraction.
  - fix: Replace concrete examples with abstract placeholders or generic categories (e.g., 'Character A', 'Prop A').

- `78-79` **P2 / llm_closed_list_instruction**
  - evidence: Only extract: identity (same person/different name), transformation (appearance change — age, disguise, injury), possession (character carries/wears item), containment (entity is inside/part of location).
  - why: Instructs the LLM to classify open-world relationships into a hardcoded list of four semantic categories within the prompt prose. This logic should ideally be defined in the JSON schema as an enum to ensure consistency and prevent drift between the prompt and downstream code.
  - fix: Define these relationship types as an enum in the JSON schema and refer to the schema definition in the prompt.

## `prompts/_base/entity_extraction/v7/chunk_user.md`

- `4` **P2 / llm_closed_list_instruction**
  - evidence: identity, transformation, possession, containment only. Exclude kinship, social, conflict, collaboration, membership, control, goal, and event relations.
  - why: The prompt defines a semantic classifier for relations using a hardcoded list of allowed and excluded types in prose. This forces the LLM to map open-world screenplay meaning into a closed set of categories that are not formally defined in a schema, leading to potential drift and maintenance overhead as the continuity graph requirements evolve.
  - fix: Define the allowed relation types in a central schema enum and inject them into the prompt as a variable or schema definition to ensure consistency across the pipeline.

## `prompts/_base/entity_extractor_v2/4.202603242100/turn_entity_detail.md`

- `8` **P2 / scenario_dependent_prompt**
  - evidence: 예: "Set in near-future Korea."
  - why: The prompt uses a specific real-world location ('Korea') and a specific era ('near-future') as an example for the T2I prompt prefix. This is scenario pollution that can bias the LLM's output for arbitrary stories toward these specific settings.
  - fix: Use abstract placeholders like 'Set in [Era], [Location].' or a more neutral example.

- `14` **P2 / llm_closed_list_instruction**
  - evidence: 장식품(리본, 꽃 등), 상처/피/흙, 변장, 특수 메이크업
  - why: The prompt uses a closed list of specific props and states to define the semantic boundary between 'permanent' and 'temporary' features. This can lead to incorrect exclusions (e.g., a permanent scar being excluded because 'blood/wound' is in the list).
  - fix: Define the exclusion rule conceptually (e.g., 'exclude features that are not part of the entity's base design') rather than relying on a specific list of props/states.

## `prompts/_base/entity_extractor_v2/4.202604021900/system.md`

- `26-64` **P2 / llm_closed_list_instruction**
  - evidence: "전투 준비 상태", "결박된 상태", "부상 상태", "두 동강 난 상태", "부상, 결박, 사망", "A의 정신이 B의 몸에 들어가면"
  - why: The prompt uses a closed list of specific semantic states and narrative tropes to instruct the LLM on how to route scenario content (e.g., deciding if a state is a 'Variant' or a 'Scene Prompt'). This creates a brittle semantic classifier based on specific examples like 'cut in half' or 'possession' rather than generalized visual principles.
  - fix: Abstract the extraction logic into generalized principles (e.g., 'transient physical states', 'temporary equipment', 'visual identity vs. narrative soul') and move specific examples to a non-normative guidance section if necessary.

## `prompts/_base/entity_extractor_v2/4.202604021900/turn0_style.md`

- `11-15` **P2 / llm_closed_list_instruction**
  - evidence: visual_world_rules: "이 인물이 이 장소에 물리적으로 존재하는가?"를 판단하는 핵심 규칙만... 원격 접속/조종/빙의/텔레파시... 몽타주/교차편집
  - why: The prompt instructs the LLM to define physical presence logic based on a closed list of tropes (remote access, montage). This creates a semantic classifier for entity visibility that is biased towards these specific narrative devices rather than identifying the underlying logic of the scenario.
  - fix: Generalize the instruction to ask the LLM to identify any narrative or technical conditions in the scenario that affect whether a character is physically present in a scene, without pre-defining the tropes.

- `17-23` **P2 / scenario_dependent_prompt**
  - evidence: 조선시대, 한국 서울, 현대 한국 도시, 한옥, 한복
  - why: The prompt uses culturally specific examples (Joseon Dynasty, Seoul, Hanok, Hanbok) which can bias the LLM's extraction and interpretation for scenarios set in different cultures or eras, potentially leading to hallucinations or incorrect style associations.
  - fix: Replace culturally specific examples with more abstract or globally diverse ones (e.g., 'Historical Era', 'Metropolitan City', 'Traditional Architecture', 'Period-appropriate clothing').

## `prompts/_base/entity_extractor_v2/4.202604021900/turn1_7_detail_batch.md`

- `13` **P2 / schema_or_enum_drift**
  - evidence: 반드시 국적 또는 인종(예: Korean, East Asian, South Asian, Black, White, Hispanic 등)을 description 첫 부분에 명시
  - why: This instruction mandates a semantic classification (race/ethnicity) and requires it to be placed at a specific position within a natural-language string field. This creates a brittle contract where downstream logic likely relies on string splitting or prefix matching to recover this structured attribute for image generation (e.g., model selection or prompt weighting), rather than using a dedicated schema field.
  - fix: Move 'ethnicity' or 'nationality' to a separate structured field in the output schema with a defined enum, rather than embedding it as a prefix in the 'description' string.

## `prompts/_base/entity_extractor_v2/4.202604021900/turn_entity_detail.md`

- `8` **P2 / scenario_dependent_prompt**
  - evidence: "Set in near-future Korea."
  - why: The use of a concrete location and era in an example can bias the LLM towards those specific scenario elements even when the input scenario is different.
  - fix: Use abstract placeholders like "Set in [Era], [Location]."

## `prompts/_base/entity_extractor_v2/5.202603270930/turn_entity_detail.md`

- `5-16` **P2 / llm_closed_list_instruction**
  - evidence: 국적 또는 인종을 반드시 명기 ... (예: Korean, Japanese, American) ... (예: East Asian, Caucasian, Black, Middle Eastern)
  - why: The prompt instructs the LLM to classify visual identity into a closed list of nationality and race examples. This forces semantic classification based on a limited set of categories provided in the prompt.
  - fix: Define these categories in a central schema or allow the LLM to describe appearance naturally without forcing specific nationality/race labels.

- `9` **P2 / scenario_dependent_prompt**
  - evidence: 예: "Set in near-future 인천, Korea."
  - why: The prompt uses a concrete real-world location (Incheon, Korea) and era (near-future) as an example, which can bias the LLM's generation for arbitrary scenarios.
  - fix: Use abstract placeholders like 'Set in [Era], [Location].' without concrete examples.

## `prompts/_base/entity_extractor_v2/6.202605091300/system.md`

- `20-30` **P2 / llm_closed_list_instruction**
  - evidence: 허용되는 변형 예시: ... 금지되는 변형 (씬 T2I 프롬프트로 처리 가능): ...
  - why: The prompt uses a closed list of specific semantic examples (e.g., 'injured state', 'cut in half') to define the boundary of the 'variation' entity type. This forces the LLM to classify open-world scenario meaning based on a fixed set of phrase-based rules.
  - fix: Provide abstract criteria for what constitutes a visual variation (e.g., 'significant change in silhouette or age') rather than a list of specific forbidden states.

- `82` **P2 / schema_or_enum_drift**
  - evidence: allowed_space_keys 는 controlled vocab 안에서 선택: main / kitchen / rooftop / stairs / yard / exterior / office
  - why: This defines a hardcoded list of semantic sub-space categories in the prompt that must be synchronized with downstream logic (background_master_plan) mentioned in line 90. It functions as an unenforced schema enum.
  - fix: Define the allowed_space_keys in a shared schema or SOT and inject them into the prompt dynamically, or use a more flexible classification system.

## `prompts/_base/entity_extractor_v2/6.202605091300/turn2.md`

- `10-11` **P2 / llm_closed_list_instruction**
  - evidence: 허용: 20대→60대 같은 큰 나이 변화, 완전히 다른 실루엣(전신 갑옷 등), 변장... 금지: 의상만 바뀌는 경우(군복/정장/일상복...), 부상/결박/사망 상태
  - why: The prompt instructs the LLM to classify open-world character states into a 'visual variation' field based on a closed list of semantic examples. This creates a brittle boundary for entity extraction where states like 'injury' or 'death' are explicitly excluded via a prompt-side classifier rather than a structured schema or logic.
  - fix: Define the 'visual variation' criteria using abstract principles (e.g., 'structural changes to the character model') and move specific state exclusions (like injury/death) to a downstream validation or filtering step if they are consistently undesirable.

## `prompts/_base/entity_extractor_v2/6.202605091300/turn3.md`

- `7-9` **P2 / scenario_dependent_prompt**
  - evidence: 시간대 변화 (낮/밤/새벽), 날씨 변화 (맑음/비/안개), 상태 변화 (화재 이후/파괴된/정상)
  - why: The prompt provides specific scenario-based examples (fire, destruction) as definitions for visual variation states. This biases the LLM to interpret open-world scenarios through these specific tropes and may lead to incorrect or forced classifications when the actual scenario contains different types of variations (e.g., 'festive', 'abandoned', 'under construction').
  - fix: Replace concrete scenario examples with abstract descriptions of the variation types or a more diverse, neutral set of examples to avoid biasing the extraction toward specific plot points like fire or destruction.

## `prompts/_base/entity_extractor_v2/6.202605091300/turn_entity_detail.md`

- `8` **P2 / scenario_dependent_prompt**
  - evidence: Set in near-future Korea.
  - why: The use of a concrete scenario (near-future Korea) as an example in a base prompt can bias the LLM toward specific cultural or temporal tropes when generating for arbitrary scenarios.
  - fix: Replace with abstract placeholders like 'Set in [Era], [Location].'

- `10-18` **P1 / llm_closed_list_instruction**
  - evidence: Passport-style ID photo... Photorealistic cinematic establishing shot... Photorealistic product photo
  - why: The prompt forces open-world entities into a closed list of visual styles (ID photo, establishing shot, product photo) based on their type. This limits the visual flexibility for entities that do not fit these specific framing/style templates.
  - fix: Allow the LLM to determine the most appropriate framing/style based on the entity's description, or provide a wider, more abstract set of style guidelines.

- `21` **P2 / schema_or_enum_drift**
  - evidence: system prompt 의 controlled vocab 따라
  - why: The prompt refers to an external 'controlled vocab' for the space_profile field without defining it locally. This creates a synchronization risk where the LLM might use values not supported by downstream code.
  - fix: Explicitly list the allowed vocabulary for space_profile within this prompt or ensure it is injected dynamically.

## `prompts/_base/entity_extractor_v2/7.202605091845/system.md`

- `81-86` **P1 / llm_closed_list_instruction**
  - evidence: allowed_space_keys 는 controlled vocab 안에서 선택: main / kitchen / rooftop / stairs / yard / exterior / office
  - why: The prompt forces the LLM to classify open-world spatial sub-divisions into a narrow, hardcoded list of 7 strings. This is a semantic classifier that biases the extraction process and limits the system's ability to handle diverse environments (e.g., bedrooms, hallways, forests). Since these keys drive downstream deterministic ID assignment (line 90), this creates a brittle link between scenario content and system logic.
  - fix: Replace the hardcoded list with a requirement for the LLM to provide a descriptive common-noun key, or move the controlled vocabulary to a dynamic configuration that can be updated per-project without modifying the base prompt.

## `prompts/_base/entity_extractor_v2/7.202605091845/turn0_style.md`

- `11-15` **P2 / llm_closed_list_instruction**
  - evidence: 반드시 포함: 원격 접속/조종/빙의/텔레파시... 몽타주/교차편집
  - why: The prompt instructs the LLM to define 'physical presence' rules using a closed list of narrative tropes as mandatory criteria. This functions as a semantic classifier for visibility logic, potentially missing other reasons for non-physical presence.
  - fix: Rephrase to encourage the LLM to identify any relevant narrative mechanism for physical presence, treating the listed tropes as non-exhaustive examples.

- `17-22` **P2 / scenario_dependent_prompt**
  - evidence: 현대 한국 도시 + 미래 연구시설, 조선시대 한옥, 한복, 현대 군용차 + 미래 캡슐
  - why: The examples for era, building, clothing, and vehicle styles use concrete cultural and genre-specific tropes (Joseon era, Hanbok, specific sci-fi pairings) which can bias the LLM when extracting details for scenarios outside these specific contexts.
  - fix: Use more abstract or diverse examples (e.g., 'Ancient Civilization', 'Futuristic Metropolis') to avoid biasing the model toward specific Korean or Sci-Fi settings.

## `prompts/_base/entity_extractor_v2/7.202605091845/turn3.md`

- `9` **P2 / scenario_dependent_prompt**
  - evidence: 상태 변화 (화재 이후/파괴된/정상)
  - why: The inclusion of specific disaster-themed examples like 'fire' and 'destroyed' in a base prompt for entity extraction introduces scenario pollution. This biases the LLM toward specific story tropes and may cause it to overlook or misclassify other types of state changes in non-disaster scenarios.
  - fix: Replace scenario-specific examples with generic ones such as 'Clean/Dirty', 'Old/New', or 'Under construction', or use abstract placeholders to define the expected type of variation.

## `prompts/_base/entity_extractor_v2/7.202605091845/turn_entity_detail.md`

- `8` **P2 / scenario_dependent_prompt**
  - evidence: Set in near-future Korea.
  - why: The use of a concrete location and era (Korea, near-future) as an example can bias the LLM's entity extraction and T2I prompt generation toward specific cultural and temporal tropes, even when the input scenario differs.
  - fix: Replace concrete examples with abstract placeholders like 'Set in [Era], [Location].'

- `11-18` **P1 / semantic_string_judgment**
  - evidence: 의상/복장/바디 묘사 절대 금지, 장식품(리본, 꽃 등), 상처/피/흙, 변장, 특수 메이크업, 폭발 후, 파괴된 상태, 파손, 분해
  - why: The prompt instructs the LLM to perform semantic filtering of visual descriptions based on closed lists of temporary states or categories (e.g., wounds, blood, explosions). This creates brittle visual logic for defining 'permanent appearance' and directly mutates the generated T2I prompt content.
  - fix: Define 'permanent vs temporary' appearance using abstract semantic criteria or a structured classification schema rather than a list of specific visual examples.

## `prompts/_base/entity_extractor_v2/8.202605121200/system.md`

- `25-28` **P2 / llm_closed_list_instruction**
  - evidence: 금지되는 변형 ... "전투 준비 상태", "결박된 상태", "부상 상태", "두 동강 난 상태"
  - why: The prompt uses a specific list of semantic states as a negative classifier to decide whether to create a new entity variation. This relies on the LLM matching these specific concepts/phrases to enforce entity lifecycle policy, which is brittle for open-world scenarios.
  - fix: Define the variation policy using abstract criteria (e.g., 'permanent physical changes vs. temporary poses/states') rather than a list of specific scenario-like examples.

- `81-86` **P2 / llm_closed_list_instruction**
  - evidence: allowed_space_keys 는 controlled vocab 안에서 선택: main / kitchen / rooftop / stairs / yard / exterior / office
  - why: It forces the LLM to classify arbitrary open-world locations into a small, fixed set of semantic categories. This creates a brittle interface where any location not in the list (e.g., 'bedroom', 'hallway') must be collapsed into 'main', losing visual specificity and potentially causing collisions in downstream ID generation as noted in line 90.
  - fix: Allow the LLM to generate descriptive space keys or move the classification logic to a separate step that maps natural language descriptions to a broader, versioned taxonomy.

## `prompts/_base/entity_extractor_v2/8.202605121200/turn1_7_detail_batch.md`

- `13` **P2 / llm_closed_list_instruction**
  - evidence: 반드시 국적 또는 인종(예: Korean, East Asian, South Asian, Black, White, Hispanic 등)을 description 첫 부분에 명시
  - why: The prompt instructs the LLM to perform a semantic classification of ethnicity and embed the result as a string prefix within a natural-language field. This creates an overloaded semantic channel and encourages downstream code to use brittle string matching (e.g., checking if a description starts with 'Korean') instead of using a structured enum field.
  - fix: Define a structured 'ethnicity' field in the output schema with a canonical enum, and remove the requirement to embed this information in the 'description' string.

## `prompts/_base/entity_extractor_v2/8.202605121200/turn_entity_detail.md`

- `21-24` **P2 / schema_or_enum_drift**
  - evidence: metadata_json.location.space_profile ... single_space → ... multi_space → ...
  - why: The prompt defines a specific JSON schema and a closed list of semantic categories (single_space, multi_space) for location entities in prose. This creates a dependency where changes to the location model must be manually synchronized across prompts and downstream code that consumes this JSON, despite the prompt's own reference to a controlled vocabulary.
  - fix: Define the space_profile schema and its allowed values in a central JSON schema or shared system prompt fragment, and refer to it by name rather than duplicating the structure and examples here.

## `prompts/_base/entity_extractor_v2/9.202605130226/system.md`

- `97-101` **P1 / llm_closed_list_instruction**
  - evidence: allowed_space_keys 는 controlled vocab 안에서 선택: main / kitchen / rooftop / stairs / yard / exterior / office. ... 위 controlled vocab 밖 단어 사용 절대 금지.
  - why: This instruction forces the LLM to map arbitrary scenario locations (e.g., bedroom, laboratory, cockpit) into a very limited set of hardcoded semantic categories. It acts as a brittle semantic classifier that limits the system's ability to handle diverse environments and forces lossy 'main' fallback for any non-matching space, which directly affects the deterministic background ID assignment mentioned in line 106.
  - fix: Allow the LLM to generate descriptive keys based on the scenario text (e.g., 'bedroom', 'bridge') or expand the controlled vocabulary to a comprehensive set of common architectural spaces. If a fixed list is required for downstream logic, move the mapping to a post-processing step rather than a hardcoded prompt constraint.

## `prompts/_base/entity_extractor_v2/9.202605130226/turn0_style.md`

- `11-15` **P1 / llm_closed_list_instruction**
  - evidence: visual_world_rules: "이 인물이 이 장소에 물리적으로 존재하는가?" ... 원격 접속/조종/빙의/텔레파시 ... 몽타주/교차편집
  - why: The prompt uses a closed list of scenario tropes (remote access, possession, montage) as a semantic classifier to determine physical presence. This logic directly affects whether entities are rendered in images, making it a brittle natural-language routing mechanism that attempts to infer visual state from arbitrary prose.
  - fix: Move physical presence logic to a structured entity state field in the schema and use a dedicated classifier or explicit scenario tags rather than extracting rules from prose.

- `17-23` **P2 / scenario_dependent_prompt**
  - evidence: 조선시대, 한국 서울, 현대 한국 도시 + 미래 연구시설, 조선시대 한옥, 현대복 + 군복 + 미래 전투복
  - why: The prompt contains concrete, culturally specific examples (Joseon era, Seoul, specific SF/historical blends) that can bias the LLM's world-building extraction toward these tropes even when the input scenario is different.
  - fix: Replace specific cultural and genre examples with abstract placeholders like [Era], [Location], or [Style Description] to maintain neutrality.

## `prompts/_base/entity_extractor_v2/9.202605130226/turn2.md`

- `10-11` **P2 / llm_closed_list_instruction**
  - evidence: 허용: 20대→60대... 금지: 의상만 바뀌는 경우(군복/정장/일상복...), 부상/결박/사망 상태
  - why: The prompt uses a closed list of semantic categories and examples to instruct the LLM on how to classify open-world scenario states into the 'visual variation' field. This creates a brittle semantic boundary where the LLM must map arbitrary scenario descriptions (e.g., 'unconscious', 'bleeding') to these specific Korean terms to decide on exclusion from the entity list.
  - fix: Define the 'visual variation' field's scope in the schema using more abstract criteria or move the filtering logic to a post-processing step that uses a canonical state vocabulary.

## `prompts/_base/entity_filter/2.202603241900/system.md`

- `12-13` **P1 / llm_closed_list_instruction**
  - evidence: 수트, 우주복, 갑옷, 제복 ... 벽면 모니터, TV, CCTV
  - why: The prompt uses a closed list of specific object types (wearables and background equipment) as a semantic classifier for entity removal. This instruction forces the LLM to filter out items based on their category rather than their narrative importance, which can lead to the loss of plot-critical props or unique costumes (e.g., a specific 'spacesuit' or 'wearable robot') that require visual consistency tracking.
  - fix: Replace the category-based removal list with functional criteria that evaluate the entity's importance to the narrative and its need for visual consistency, regardless of whether it is worn or installed in the background.

## `prompts/_base/floor_plan_prompt/1.202604292033/system.md`

- `11` **P2 / scenario_dependent_prompt**
  - evidence: a curtain that hides a body, a broken window, a hidden compartment
  - why: These examples are concrete scenario fragments (thriller/mystery tropes) used to define 'plot-critical visual devices'. In a base prompt, such specific examples can bias the LLM toward certain narrative tones or types of props even when not present in the input spec.
  - fix: Use more neutral, architectural examples for plot-critical devices, such as 'a specific entry point, a line-of-sight obstruction, or a unique structural feature'.

## `prompts/_base/floor_plan_prompt/2.202604300800/system.md`

- `14` **P2 / llm_closed_list_instruction**
  - evidence: category (furniture | opening | prop | plot_device | area)
  - why: The LLM is instructed to classify open-world objects into a closed set of semantic categories. This creates a brittle mapping that may not cover all architectural or plot-critical elements and often drifts from the underlying schema if not centrally managed.
  - fix: Ensure these categories are defined in a central schema enum and passed to the prompt as a variable to prevent drift.

- `15` **P1 / semantic_string_judgment**
  - evidence: camera_position (use number references like "near number 1 (entrance)... "), framing_notes (e.g., "include numbers 2 and 3 prominently...")
  - why: This establishes a contract where semantic entity-to-camera relationships (proximity, visibility) are encoded in natural language prose. Downstream background prompts or logic must use brittle string parsing (e.g., regex for 'number X') to identify which floor plan elements are relevant to a specific shot.
  - fix: Add a structured field such as `visible_element_ids: number[]` or `proximal_element_ids: number[]` to the `camera_recommendations` object to explicitly track these relationships without parsing prose.

## `prompts/_base/floor_plan_prompt/3.202604301041/system.md`

- `10` **P2 / llm_closed_list_instruction**
  - evidence: living = pale yellow, bedroom = pale blue, kitchen = pale green, bathroom = pale cyan, rooftop = pale gray, hallway = pale beige
  - why: The prompt provides a specific mapping of room types to colors as examples. This encourages the LLM to act as a semantic classifier for visual zones based on a limited list, which can lead to inconsistent or missing styling for room types not explicitly mentioned.
  - fix: Define a canonical mapping of zone types to colors in a shared configuration or schema, and instruct the LLM to use that mapping rather than providing examples in the system prompt.

- `16` **P2 / scenario_dependent_prompt**
  - evidence: low ondol-friendly bed vs western mattress; wall-mounted air-con position; built-in wardrobe on a specific wall
  - why: The prompt uses concrete cultural (ondol) and era-specific (air-con) props as examples for layout derivation. These specific examples can bias the LLM's output toward these contexts even when the input scenario is unrelated (e.g., a fantasy or historical setting).
  - fix: Replace specific prop examples with abstract categories of layout considerations, such as 'heating-related furniture placement' or 'utility-dependent appliance positioning'.

- `17` **P2 / schema_or_enum_drift**
  - evidence: category (furniture | opening | prop | plot_device | area)
  - why: The prompt defines a closed list of semantic categories for output elements in prose. This creates a risk of drift if the downstream code or validation logic expects these exact strings but the formal schema does not enforce them.
  - fix: Ensure these categories are defined as a formal enum in the JSON schema and referenced in the prompt, rather than being listed as a string-based contract in the prose.

## `prompts/_base/floor_plan_prompt/4.202605091200/system.md`

- `10-13` **P1 / llm_closed_list_instruction**
  - evidence: living = pale yellow, bedroom = pale blue, kitchen = pale green, bathroom = pale cyan, rooftop = pale gray, hallway = pale beige... bed = rectangle with pillow shape; sofa = long rectangle with cushion division; table = simple rectangle/square; door = arc with line indicating swing; window = double parallel line in the wall; sink/toilet = standard plan symbols.
  - why: These instructions hardcode a visual vocabulary (colors and geometric descriptions) for open-world room and object types. This forces the LLM to perform semantic classification against a closed list of visual representations, which may not scale to all scenarios or may conflict with project-specific visual world rules.
  - fix: Move the visual vocabulary mapping (room-to-color and object-to-glyph) to a configuration object or schema injected into the prompt, allowing for scenario-specific or project-wide overrides.

- `16` **P2 / scenario_dependent_prompt**
  - evidence: low ondol-friendly bed vs western mattress; wall-mounted air-con position; built-in wardrobe on a specific wall
  - why: The prompt contains concrete cultural (ondol) and technological (air-con) examples in its instructions for layout derivation. These specific props can bias the LLM's generation toward certain eras or regions even when the input scenario is different.
  - fix: Replace concrete examples with abstract placeholders or a more diverse set of examples covering multiple eras and cultures.

## `prompts/_base/location_consistency/1.202604191800/system.md`

- `11` **P1 / blind_string_mutation**
  - evidence: 이 문장은 나중에 scene_detail이 t2i_prompt에 그대로 삽입하므로
  - why: This instruction establishes a contract for blind string mutation where a generated description is spliced into a downstream prompt. This prevents the downstream generator from adapting the location details to the specific context of a scene, leading to potential visual contradictions or poor prompt integration.
  - fix: Pass the fixed visual description as a structured reference to the downstream LLM rather than instructing it to perform a blind string insertion.

- `39-59` **P2 / scenario_dependent_prompt**
  - evidence: A small wooden fishing boat approximately 8 meters long... a traditional Korean fishing village harbor
  - why: The prompt uses concrete, culturally specific examples (fishing boats, Korean villages) and specific dimensions (8 meters, 4-meter-wide) to illustrate rules. These specific details can leak into the LLM's internal state and bias descriptions for unrelated scenarios.
  - fix: Replace specific scenario examples with more diverse or abstract templates (e.g., 'A [size] [material] [object]...') to minimize thematic bias.

## `prompts/_base/location_consistency/2.202604201230/system.md`

- `11-34` **P1 / blind_string_mutation**
  - evidence: 이 문장은 나중에 scene_detail이 t2i_prompt에 그대로 삽입하므로 ... 영어로 작성 (T2I 프롬프트에 직접 삽입)
  - why: The prompt establishes a contract for blind string insertion of LLM-generated natural language prose into a downstream T2I prompt. This is fragile as any failure in the LLM's filtering logic will pollute the final image generation prompt with inconsistent or unwanted elements across an entire episode.
  - fix: Instead of blind insertion of prose, use a structured representation of location attributes that the downstream component can compose safely, or use a template-based approach with validated slots.

- `23-83` **P1 / llm_closed_list_instruction**
  - evidence: 절대 포함 금지 — 환경 상태는 씬마다 달라짐 ... 이 문장에 날씨·조명·인물이 섞여 있는가? — YES라면 그 부분만 삭제
  - why: The prompt instructs the LLM to act as a semantic classifier and filter, stripping out open-world concepts (weather, lighting, characters, etc.) based on a closed list of categories. This relies on the LLM's ability to correctly categorize arbitrary prose into these buckets to maintain 'location consistency' through string manipulation.
  - fix: Define the 'fixed' attributes of a location in a structured schema (e.g., materials, architecture_style, layout) and have the LLM populate those fields, rather than asking it to filter a natural language description.

- `43-57` **P2 / scenario_dependent_prompt**
  - evidence: A compact one-room apartment with faded wallpaper and a worn linoleum floor ... utility pole wrapped with tangled wires
  - why: The examples contain concrete, specific props and architectural details (faded wallpaper, linoleum, utility poles) that are not abstract placeholders. These can bias the LLM towards specific urban/contemporary styles even when the target scenario is different (e.g., sci-fi or historical).
  - fix: Use more abstract or diverse examples, or replace specific props with placeholders like [material] or [specific_prop] to demonstrate the desired level of detail without biasing the content.

## `prompts/_base/location_floor_plan/1.202604282315/system.md`

- `17` **P1 / llm_closed_list_instruction**
  - evidence: Identify zone markers (e.g., '/거실', '/안방', '/욕실', '/현관', '/욕조')
  - why: The prompt instructs the LLM to use a specific slash-prefixed string pattern to classify text as zones. This is a brittle semantic classifier that depends on the scenario text following a specific, non-standard tagging format.
  - fix: Use a structured input format for zones and locations instead of asking the LLM to parse them from tagged natural language.

## `prompts/_base/location_floor_plan/2.202604290417/system.md`

- `17` **P2 / llm_closed_list_instruction**
  - evidence: Identify zone markers (e.g., '/거실', '/안방', '/욕실', '/현관', '/욕조').
  - why: The instruction defines a specific string pattern (prefixing with '/') and a list of examples to identify semantic zones. This encourages the LLM to rely on brittle string matching rather than natural language understanding to determine the floor plan's components, potentially missing rooms not explicitly marked or named in the list.
  - fix: Broaden the instruction to identify all rooms, zones, and locations mentioned in the screenplay text based on narrative context, and treat the provided markers as optional formatting hints rather than the primary identification method.

## `prompts/_base/location_floor_plan/3.202604291130/system.md`

- `22-25` **P1 / llm_closed_list_instruction**
  - evidence: Cues to look for: ... 거실/안방, 부엌/거실 ... 문을 열고 들어간다 ... 거실에서 안방으로
  - why: The prompt defines spatial layout logic (room separation and movement) using a brittle list of Korean keywords and phrases as semantic classifiers. This biases the LLM to only recognize these specific patterns when inferring the physical structure of a location.
  - fix: Generalize the instruction to identify spatial transitions and room labels based on the linguistic context of the screenplay language (Korean) without relying on a hardcoded list of phrases.

- `31` **P2 / scenario_dependent_prompt**
  - evidence: 옥탑방 안 / 실내, 한옥 / 안방 / 마루
  - why: The prompt uses specific Korean architectural tropes (Rooftop room, Hanok) as concrete examples for a general structural parsing rule (slash-separated zones). This can bias the LLM's interpretation of other locations toward these specific scenario types.
  - fix: Use generic placeholders or universal architectural examples (e.g., 'Living Room / Kitchen') to illustrate the zone separation logic.

## `prompts/_base/lvm_prompts/1.202603171237/ref_validation.md`

- `9` **P2 / schema_or_enum_drift**
  - evidence: 심각도: ok(문제없음), minor(사소한 차이), severe(핵심 누락/완전 다름)
  - why: The prompt defines classification labels (ok, minor, severe) alongside natural language descriptions in parentheses. This often causes LLMs to include the descriptions in the output, leading to parsing failures if downstream code expects exact enum values. It also creates a synchronization burden between prompt prose and code-side enums.
  - fix: Define the allowed values as a strict enum in a JSON schema and move the natural language descriptions to the schema's 'description' field or a separate mapping section.

## `prompts/_base/lvm_prompts/1.202603171237/style_rules_generator.md`

- `5-9` **P2 / scenario_dependent_prompt**
  - evidence: 조선시대, 한옥, 한복, 한국/일본/미국
  - why: The prompt uses culturally and historically specific examples (Joseon Dynasty, Hanok, Hanbok, and specific countries) to guide the LLM's extraction of style rules. This introduces bias towards these specific settings and can lead to skewed extractions when processing scenarios from other cultures or eras.
  - fix: Replace specific cultural and historical examples with abstract categories or a more diverse set of global examples (e.g., 'Historical/Modern/Future', 'Traditional/Modern/Industrial', 'Regional/Global').

## `prompts/_base/lvm_prompts/2.202603181600/style_rules_generator.md`

- `5-9` **P2 / scenario_dependent_prompt**
  - evidence: 조선시대, 한국/일본/미국, 한옥, 한복
  - why: The prompt includes specific cultural, historical, and geographical examples (Joseon Dynasty, Korea/Japan/USA, Hanok, Hanbok) to illustrate style categories. These concrete examples can bias the LLM towards Korean-specific tropes or the listed countries even when the input scenario belongs to a different cultural or historical context.
  - fix: Replace culturally specific examples with abstract placeholders or a broader range of non-specific examples (e.g., 'Historical period', 'Specific region', 'Traditional architecture') to ensure the prompt remains scenario-agnostic.

## `prompts/_base/outlook_extractor/10.202603261238/phase2.md`

- `13` **P2 / scenario_dependent_prompt**
  - evidence: 평상복→전투복, 정장→피의갑옷
  - why: The examples 'battle suit' (전투복) and 'blood armor' (피의갑옷) are concrete, genre-specific props that introduce scenario pollution into a base prompt, potentially biasing the LLM towards fantasy or action contexts during outfit extraction.
  - fix: Replace scenario-specific examples with generic placeholders or neutral descriptions like 'Casual -> Formal' or 'Outfit A -> Outfit B'.

## `prompts/_base/outlook_extractor/10.202603261238/phase3.md`

- `6` **P2 / scenario_dependent_prompt**
  - evidence: "고급선비복1"과 "고급선비복2"
  - why: The prompt uses culturally and era-specific prop names (Joseon-era scholar outfits) as examples for merging logic. This introduces scenario pollution into a base prompt, potentially biasing the LLM toward specific historical tropes or naming conventions during the outlook extraction phase.
  - fix: Replace the specific outfit names with abstract placeholders such as "의상 A" and "의상 B" or generic descriptions like "검은색 정장".

## `prompts/_base/outlook_extractor/11.202603311724/phase2.md`

- `12-13` **P2 / scenario_dependent_prompt**
  - evidence: 변신, 갑옷 착용, 피의갑옷
  - why: The prompt uses genre-specific terms like 'transformation' (변신), 'wearing armor' (갑옷 착용), and 'blood armor' (피의갑옷) as examples in a base prompt. This introduces scenario pollution that may bias the LLM when extracting outlooks for non-fantasy/action genres.
  - fix: Use more neutral examples for outfit changes, such as '환복' (changing clothes) or '의상 교체' (outfit swap), and use generic placeholders like '의상A→의상B' in examples.

## `prompts/_base/outlook_extractor/11.202603311724/phase3.md`

- `6` **P2 / scenario_dependent_prompt**
  - evidence: "고급선비복1"과 "고급선비복2"
  - why: The prompt uses a culturally and era-specific trope (Korean historical scholar outfit) as a concrete example for a general merging rule. This can bias the LLM's semantic judgment toward specific genres or naming patterns instead of remaining scenario-agnostic.
  - fix: Replace the specific example with generic placeholders such as 'Outfit A' and 'Outfit B' or neutral descriptions.

## `prompts/_base/outlook_extractor/9.202603261200/phase2.md`

- `9` **P2 / llm_closed_list_instruction**
  - evidence: V.O./회상/이름만 언급: 배정 안 함
  - why: The prompt instructs the LLM to classify character presence (an open-world semantic state) based on a closed list of phrases or technical terms found in the scene text, which can lead to incorrect exclusions if the scenario uses different terminology.
  - fix: Define 'presence' conceptually or provide a broader set of criteria that allows the LLM to reason about narrative presence rather than relying on a fixed list of terms.

- `13-20` **P2 / scenario_dependent_prompt**
  - evidence: 피의갑옷, 서바이벌강하복
  - why: Concrete, genre-specific prop names like 'Blood Armor' (피의갑옷) and 'Survival Descent Suit' (서바이벌강하복) are used as examples in a base prompt. This scenario pollution can bias the LLM's extraction and naming logic when processing unrelated stories or genres.
  - fix: Replace scenario-specific examples with generic placeholders or neutral examples such as 'Outfit A', 'Uniform', or 'Casual Wear'.

## `prompts/_base/outlook_extractor/9.202603261200/phase3.md`

- `6` **P2 / scenario_dependent_prompt**
  - evidence: "서바이벌강하복1", "서바이벌강하복2" → "서바이벌강하복"
  - why: The use of '서바이벌강하복' (Survival Descent Suit) as a concrete example in a base prompt introduces scenario-specific prop and genre pollution. This can bias the LLM's naming and merging logic toward specific action/sci-fi tropes even when processing unrelated scenarios.
  - fix: Replace the concrete example with abstract placeholders such as '의상A_1', '의상A_2' → '의상A' to maintain genre neutrality.

## `prompts/_base/prompt_sanitizer/v1/sanitize_system.md`

- `11-15` **P1 / llm_closed_list_instruction**
  - evidence: 안전 정책 가이드라인: - 폭력: ... - 무기: ... - 선정성: ... - 부상/피: ... - 아동: ...
  - why: The prompt instructs the LLM to classify open-world scenario content into five hardcoded safety categories and applies fixed visual transformation rules for each. This creates a brittle semantic mapping that is difficult to maintain and synchronize with evolving safety policies or diverse scenario requirements.
  - fix: Externalize the safety policy and transformation rules into a structured configuration or dynamic context provided at runtime, rather than hardcoding specific semantic mappings in the system prompt.

- `18-20` **P2 / scenario_dependent_prompt**
  - evidence: attempt 1 — film_previs ... attempt 2 — movie_poster ... attempt 3 — aftermath
  - why: These specific style and narrative strategies (previs, poster, aftermath) bias the LLM's output towards cinematic tropes, which may conflict with the original scenario's intended style or context, such as documentary or casual photography.
  - fix: Generalize the rewriting strategies or allow them to be passed as parameters that match the input scenario's original style.

## `prompts/_base/prototype_prompts/v5/entity_reference_en.md`

- `27-33` **P2 / scenario_dependent_prompt**
  - evidence: Korean baseline clothing ... Do not introduce historical, fantasy, medieval, retro-period-drama, or space-opera styling
  - why: These instructions hardcode a specific cultural (Korean) and temporal (present-day) setting as the 'neutral' baseline for character references. This biases the generation of reference images for entities that should belong to other cultures or genres, creating scenario pollution in a base template that is intended to be general-purpose.
  - fix: Remove the specific 'Korean' and genre-exclusion constraints from the base template. Move these requirements into the {world_guide_block} or a scenario-specific configuration layer to maintain template neutrality.

## `prompts/_base/prototype_prompts/v5/entity_reference_ko.md`

- `27-33` **P2 / scenario_dependent_prompt**
  - evidence: 현대 한국/근미래 한국 기준의 현실적 기본 복장 ... 사극, 전통 복식, 중세풍, 판타지풍 ... 금지
  - why: The prompt defines 'neutrality' by anchoring it to a specific culture (Korea) and era (Modern/Near-future), while explicitly banning genres like fantasy or historical. This creates a conflict when the entity being described belongs to one of the banned or non-Korean categories, leading to identity drift in the reference image.
  - fix: Replace specific cultural and genre anchors with abstract requirements for neutrality, such as 'standard attire consistent with the entity's world' and 'avoidance of temporary action-oriented details' without naming specific genres.

## `prompts/_base/prototype_prompts/v5/scene_image_en.md`

- `31-33` **P2 / scenario_dependent_prompt**
  - evidence: grounded in contemporary / near-future Korea ... modern military, police, industrial, or biotech equipment ... No full-body power armor, spacesuit styling, or giant mecha
  - why: The base prompt template hardcodes specific geographic (Korea), temporal (near-future), and prop-related (military/biotech) constraints. This creates scenario pollution that biases the model's output regardless of the provided world_guide_block, making the prompt less reusable and prone to era/style drift.
  - fix: Move project-specific setting and prop constraints into the {world_guide_block} or a separate project-level configuration file rather than hardcoding them in the base scene generation prompt.

## `prompts/_base/prototype_prompts/v5/scene_image_ko.md`

- `31-33` **P2 / scenario_dependent_prompt**
  - evidence: 동시대~근미래 한국 기준... 사극풍 복식, 판타지 갑옷, 중세풍 건축 금지... 현대 군/경/산업 장비... 전신 파워아머... 과장하지 마라
  - why: These lines hardcode a specific cultural and technological setting (modern/near-future Korea) and explicitly forbid other genres. This creates scenario pollution in a base prototype prompt, biasing the LLM's output for any story that does not fit this specific project's world-building.
  - fix: Abstract these constraints into the {world_guide_block} or a project-specific configuration variable to ensure the base prompt remains scenario-agnostic.

## `prompts/_base/ref_image_prompts/4.202603251000/prop_ref.md`

- `3-5` **P2 / llm_closed_list_instruction**
  - evidence: e.g. earring, necklace, bracelet, mask, weapon held in hand, shoulder armor, backpack ... ear, neck, wrist, face, hand, shoulder, torso ... e.g. chair, sword on display, book, bottle
  - why: The prompt uses a closed list of examples to define semantic categories ('worn/held' vs 'freestanding') and visual routing (silhouette inclusion). This biases the LLM towards the provided examples and creates a brittle classification mechanism for open-world prop descriptions that may fail for unlisted items like belts or anklets.
  - fix: Use a structured field in the input schema to specify the prop's mounting type or category, rather than relying on example-based classification within the prompt.

## `prompts/_base/ref_image_prompts/5.202603311724/prop_ref.md`

- `3` **P2 / llm_closed_list_instruction**
  - evidence: ONLY the relevant body part (ear, neck, wrist, face, hand, shoulder, torso)
  - why: The prompt instructs the LLM to classify props into a fixed set of body-part silhouettes for visual context. This closed list acts as a semantic filter but lacks coverage for common open-world items like footwear (feet), belts (waist), or rings (fingers), making the generation logic brittle for arbitrary props.
  - fix: Allow the LLM to dynamically determine the relevant body part based on the prop's description or provide a comprehensive anatomical list including waist, feet, and fingers.

## `prompts/_base/scene_camera_flow/1.202604151200/system.md`

- `26-37` **P2 / llm_closed_list_instruction**
  - evidence: flow_position: `start` / `mid` / `end` / `transition`, stage_label: establishing / approach / ..., camera_motion: `static` / ... / `cut` 중 하나
  - why: The prompt requires the LLM to classify open-world visual movement and shot roles into a closed set of string constants. This creates a brittle semantic contract where the LLM must map natural language descriptions to specific tokens, which are likely used for downstream routing or T2I prompt generation.
  - fix: Define these values as formal enums in the JSON schema to ensure validation and reduce drift between the prompt instructions and the data structure.

## `prompts/_base/scene_consistency/2.202604141200/schema.json`

- `19` **P2 / scenario_dependent_prompt**
  - evidence: dead_woman_by_door
  - why: The example provided for 'element_id' contains a specific scenario (a dead person, a specific gender, and a location) which can bias the LLM towards specific narrative tropes or styles when generating IDs for arbitrary scenes.
  - fix: Replace the concrete example with a generic placeholder like 'character_outfit' or 'room_background'.

## `prompts/_base/scene_consistency/2.202604141200/system.md`

- `9-21` **P2 / scenario_dependent_prompt**
  - evidence: 사망, 부상, 의식불명 ... a middle-aged woman lying face-down ... a dark blood pool ... shattered with jagged glass edges ... a crumpled white bedsheet
  - why: The prompt uses highly specific and morbid scenario fragments (death, injury, blood pools, shattered glass) as primary examples for general visual consistency categories. This concrete scenario pollution can bias the LLM to look for or prioritize similar details (e.g., tattoos, damage) even in unrelated or neutral scenarios.
  - fix: Replace specific scenario details with neutral placeholders or a broader variety of examples. For instance, use 'a person sitting in a specific posture' or 'a specific object placed on a surface' instead of crime-scene-specific descriptions.

- `28-31` **P2 / semantic_string_judgment**
  - evidence: 엔티티 ID(C##, L##, P##) 절대 금지 ... element_id와 character_name에 인물 이름을 포함하여 식별
  - why: The prompt explicitly forbids the use of structured technical identifiers (C##, L##, P##) and instead requires embedding natural-language character names into the 'element_id' field. This creates an overloaded semantic channel and forces downstream components to rely on brittle string matching for identity tracking rather than stable machine IDs.
  - fix: Allow the use of canonical entity IDs (e.g., C##) as the primary key in 'element_id' and keep 'character_name' as a separate metadata field.

## `prompts/_base/scene_consistency/3.202604201230/schema.json`

- `19` **P2 / scenario_dependent_prompt**
  - evidence: e.g. dead_woman_by_door
  - why: The example 'dead_woman_by_door' is a concrete scenario fragment (specific state, character, and location) used in a base schema. This can bias the LLM toward specific genres or morbid themes and encourages packing semantic details into the ID rather than using neutral identifiers.
  - fix: Replace the concrete example with a neutral, abstract placeholder such as 'character_a_outfit' or 'living_room_background'.

## `prompts/_base/scene_consistency/3.202604201230/system.md`

- `9-37` **P2 / llm_closed_list_instruction**
  - evidence: 수면·의식불명·기절·휴식·부상·사망 (line 9), 깨진 창문, 열린/닫힌 문, 벽 손상, 벽의 표식/낙서 (line 17), 문신·반점·흉터 (line 35)
  - why: These lists function as semantic classifiers that define the boundaries of 'character_state' and 'environment_state'. By providing a specific set of states and features, the prompt biases the LLM to look for these exact patterns in the open-world scenario text, potentially missing other valid consistency elements or misclassifying ambiguous states to fit the provided list.
  - fix: Rephrase the instructions to define the categories by their functional role (e.g., 'any physical state that remains constant across shots') rather than a list of specific states. Use the current lists as clearly labeled non-exhaustive examples.

## `prompts/_base/scene_consistency/4.202604201700/schema.json`

- `17-20` **P2 / scenario_dependent_prompt**
  - evidence: e.g. dead_woman_by_door
  - why: The example 'dead_woman_by_door' is a concrete scenario fragment (a specific state and location) rather than a neutral placeholder. This can bias the LLM toward specific narrative styles or naming patterns in unrelated scenarios.
  - fix: Use a neutral placeholder such as 'character_a_outfit' or 'background_object_id'.

## `prompts/_base/scene_consistency/4.202604201700/system.md`

- `30-35` **P1 / llm_closed_list_instruction**
  - evidence: camera_direction / character_angles를 기준으로 각 샷의 지배적 프레이밍을 판정하세요: ... close-up / tight on / focus on body part / detail shot
  - why: The prompt instructs the LLM to act as a semantic classifier for visual framing based on a brittle list of specific keywords. This classification directly controls the logic for splitting character states and applying them to shots, making the pipeline sensitive to the exact phrasing used in shot descriptions.
  - fix: Instead of keyword-based classification in the prompt, provide a structured framing field in the input schema or use a more robust semantic analysis that does not rely on a closed list of strings.

- `46-79` **P2 / scenario_dependent_prompt**
  - evidence: 씬 S12에 민숙(사망, C04)이 등장... dead_minsook_full... A middle-aged Korean woman...
  - why: The example uses concrete scenario data including a specific character name (민숙), scene ID (S12), entity ID (C04), and specific visual/narrative details (deceased woman on wooden floor). This scenario pollution can bias the LLM's generation for arbitrary future scenarios.
  - fix: Replace concrete names and IDs with abstract placeholders like 'Character A', 'Scene S1', and 'C01', and use more neutral visual examples.

## `prompts/_base/scene_consistency/5.202605021400/schema.json`

- `19` **P2 / scenario_dependent_prompt**
  - evidence: dead_woman_by_door
  - why: The example 'dead_woman_by_door' is a concrete scenario-specific identifier that can bias the LLM towards specific story tropes (e.g., crime/thriller) instead of remaining scenario-neutral.
  - fix: Replace the concrete example with an abstract placeholder like 'character_a_state' or 'main_prop_id'.

## `prompts/_base/scene_consistency/5.202605021400/system.md`

- `9` **P2 / llm_closed_list_instruction**
  - evidence: character_state: ... (수면·의식불명·기절·휴식·부상·사망 등 모든 '정지 상태' 해당)
  - why: The prompt provides a prescriptive list of physical states to define the 'character_state' category. This functions as a semantic classifier that may bias the LLM toward these specific tropes or cause it to miss other valid static physical states not explicitly listed.
  - fix: Use a functional definition of 'static physical state' (e.g., 'any physical posture or condition that remains constant across multiple shots') instead of a list of specific examples.

- `32-33` **P1 / llm_closed_list_instruction**
  - evidence: 전신형(full): ... 전신/상반신/미디엄, 확대형(zoom): ... close-up / tight on / focus on body part / detail shot
  - why: The prompt instructs the LLM to classify visual framing based on a closed list of Korean and English keywords. This classification is used to route descriptions to different element_ids (e.g., adding a '_close_up' suffix as per line 41) to prevent 'double rendering' artifacts. This is a brittle semantic classifier that may fail if the input scenario uses synonyms or varied cinematic terminology.
  - fix: Define framing scales using abstract visual criteria or rely on a pre-validated framing enum from the input schema rather than keyword matching in the prompt.

## `prompts/_base/scene_consistency/6.202605031033/system.md`

- `30-35` **P1 / llm_closed_list_instruction**
  - evidence: 전신형(full): ... 전신/상반신/미디엄 / 확대형(zoom): ... close-up / tight on / focus on body part / detail shot
  - why: The prompt instructs the LLM to classify open-world visual framing into 'full' or 'zoom' categories based on a closed list of natural language keywords. This classification is used to route descriptions to specific shots to prevent 'double body' rendering artifacts, making the visual logic dependent on brittle keyword matching over shot descriptions.
  - fix: Pass the framing classification as a structured metadata field (enum) from the upstream shot analysis rather than asking the LLM to infer it from natural language keywords in the description.

- `41` **P2 / semantic_string_judgment**
  - evidence: element_id에 _close_up 등 접미사
  - why: Instructing the LLM to encode semantic framing information into the element_id string (e.g., using a suffix) creates a brittle contract where downstream systems or human reviewers might rely on string parsing to understand the visual context of the element.
  - fix: Use a separate structured field for framing type (e.g., framing_type: 'zoom') instead of encoding it into the element_id string.

## `prompts/_base/scene_detail/10.202604301430/system.md`

- `48` **P1 / semantic_string_judgment**
  - evidence: 판단 기준: 'Focus on / close on / tight on / detail on + 특정 신체 부위' 패턴이 등장하면 무조건 보통명사.
  - why: This instruction forces the LLM to use a brittle substring-matching heuristic to classify visual framing. The result of this match (presence of 'Focus on', etc.) directly changes the behavior of character ID (C##) usage, which in turn controls whether face-reference images are injected into the T2I process.
  - fix: Instead of pattern matching on generated prose, the LLM should use a structured 'framing' or 'focus_target' field in its internal reasoning or output schema to decide ID usage policy.

- `134-144` **P1 / blind_string_mutation**
  - evidence: 고정 요소 description의 보통명사 인물 묘사("A Korean man", "a woman" 등)를 해당 C##으로 대체
  - why: This instructs the LLM to perform blind string replacement of natural language descriptions ('A Korean man') with technical identifiers ('C##'). This is prone to errors if the description is slightly different or if multiple characters of the same type exist, leading to 'double-drawing' or incorrect ID mapping.
  - fix: Pass the character state as a structured object where the ID and the description are separate fields, rather than asking the LLM to perform text-level surgery on prose.

- `207-225` **P1 / semantic_string_judgment**
  - evidence: Use the door from the reference image; do not generate a new one
  - why: This establishes a natural-language string contract ('Use the [object] from the reference') to handle entity persistence (Rule C). Downstream systems likely use regex to find these markers to prevent duplicate object generation, which is brittle and depends on the LLM following the exact phrasing.
  - fix: Use a structured 'persistent_entities' array or a 'source' field in the object description schema to indicate that an entity should be pulled from a specific reference image.

- `277-299` **P2 / llm_closed_list_instruction**
  - evidence: attacker / assailant / aggressor / predator / pursuer ... victim / prey / target
  - why: The prompt provides a closed 'Vocabulary Palette' for violence, acting as a semantic classifier for character roles. This biases the LLM toward specific tropes and may result in awkward mapping when the open-world scenario does not perfectly fit these predefined labels.
  - fix: Allow the LLM to describe the power dynamic and physical interaction using natural language guided by the scenario, rather than forcing a choice from a specific word list.

## `prompts/_base/scene_detail/11.202604301730/system.md`

- `29-49` **P1 / llm_closed_list_instruction**
  - evidence: Focus on / close on / tight on / detail on + 특정 신체 부위 ... 무조건 보통명사
  - why: The prompt instructs the LLM to act as a regex-like classifier, switching from character IDs (C##) to common nouns if specific 'Focus on' patterns are detected. This logic is brittle and should be handled by structured metadata about the shot's subject.
  - fix: Use a structured 'focus_target_type' field (e.g., FACE, BODY_PART, OBJECT) to determine whether to use character IDs or common nouns.

- `71-98` **P1 / llm_closed_list_instruction**
  - evidence: cut / slice / split / carve / bisect + 신체 부위 조합 절대 금지
  - why: This is a semantic string prohibition list. It forces the LLM to avoid specific verbs when describing lighting on body parts to prevent 'physical cutting' hallucinations. This is a workaround for model behavior using a brittle word blacklist.
  - fix: Move these constraints to a negative prompt or a post-processing validator rather than relying on the LLM to self-censor a specific list of verbs.

- `226-242` **P1 / semantic_string_judgment**
  - evidence: camera_direction ... ECU, XCU, extreme close-up, MCU, medium close-up, close-up, CU ... skip chain_bg reference image
  - why: This defines a behavioral routing rule where the presence of specific natural-language framing tags in the camera_direction field triggers an automatic skip of reference images in the composition pipeline. This is a brittle semantic classifier.
  - fix: Pass a structured framing enum from the upstream shot analysis rather than parsing natural-language tags to decide reference-skipping behavior.

- `350-375` **P2 / schema_or_enum_drift**
  - evidence: Asian, East Asian, South Asian, Southeast Asian, Black, Middle Eastern, Hispanic, Caucasian
  - why: The prompt defines a closed list of demographic descriptors that the LLM must use. If the downstream system or reference database uses a different set of labels, this creates a synchronization debt (drift) between the prompt and the canonical world-building schema.
  - fix: Inject the allowed demographic descriptors dynamically from the project's global configuration/schema rather than hard-coding them in the system prompt.

- `420-456` **P2 / scenario_dependent_prompt**
  - evidence: attacker / assailant / predator / tearing flesh / ripped skin / blood spray
  - why: The prompt contains a 'vocabulary palette' for violence that includes highly specific and graphic scenario pollution. Even if conditional, providing these specific tropes can bias the LLM toward more extreme imagery than the scenario requires.
  - fix: Abstract the violence intensity into a 'violence_level' enum and provide neutral instructions on how to handle power imbalances without providing a list of graphic nouns/verbs.

## `prompts/_base/scene_detail/12.202605021300/system.md`

- `48-341` **P1 / llm_closed_list_instruction**
  - evidence: Focus on / close on / tight on / detail on, ECU, XCU, extreme close-up, MCU, medium close-up, close-up, CU, 클로즈업, 손가락이, 손이, 눈이, 얼굴이
  - why: The prompt uses these keyword lists as semantic classifiers to determine framing scale from natural language. This classification then triggers critical logic: disabling character IDs (C##), skipping background references (Rule E), and enforcing entity visibility rules (Rule J). Mapping body parts like 'finger' or 'eye' to framing scale is brittle and limits open-world expression.
  - fix: Pass the framing scale as a structured enum from the upstream shot-list generator instead of inferring it from natural language or body part mentions.

- `135` **P1 / blind_string_mutation**
  - evidence: 고정 요소 description의 보통명사 인물 묘사("An Asian man", "a woman" 등)를 해당 C##으로 대체
  - why: This instructs the LLM to perform a blind string replacement of natural language descriptions with technical IDs. This is prone to errors if the description doesn't match perfectly or if there are multiple characters of the same demographic, leading to incorrect ID assignment in the final prompt.
  - fix: Provide the fixed elements with placeholders or structured entity references instead of requiring the LLM to perform string substitution on prose.

- `533` **P1 / llm_closed_list_instruction**
  - evidence: running / riding / walking / swimming 류)이나 "동작A하며 동작B" 같은 두 동작 합성 표현
  - why: This instructs the LLM to detect specific motion verbs to trigger a 'Reframe' strategy. This is a semantic routing decision based on a closed list of open-world actions, which may fail to capture other complex movements or incorrectly trigger for simple ones.
  - fix: Use a structured 'complexity' or 'motion_type' flag in the input schema to guide strategy selection.

## `prompts/_base/scene_detail/13.202605022141/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: 합성 단계가 'the character from Image N'으로 자동 치환
  - why: The schema establishes a contract where natural-language prompt text is expected to contain specific ID patterns (e.g., C01O02) that will be blindly replaced by a downstream process. This is fragile as it relies on the LLM maintaining exact string patterns within arbitrary prose.
  - fix: Use a templating system or a structured representation for entities within the prompt rather than performing substring replacement on generated natural language.

- `16` **P1 / llm_closed_list_instruction**
  - evidence: 신체 부위 클로즈업/사진·거울 속 인물 등 system prompt가 명시한 예외 구도에서는 보통명사로 대체
  - why: This instructs the LLM to perform semantic classification of the visual scene (identifying close-ups, reflections, or photos) to decide whether to use a structured ID or a natural language noun. This creates a brittle dependency where visual meaning dictates string syntax.
  - fix: Remove the conditional formatting logic from the prompt. Instead, have the LLM always output structured IDs and handle the conversion to common nouns in a post-processing step that uses explicit framing/context metadata.

- `17-29` **P2 / schema_or_enum_drift**
  - evidence: t2i_prompt의 복합 ID와 동일한 정보를 명시
  - why: The schema requires the LLM to synchronize information between a natural language string (t2i_prompt) and a structured array (outfit_assignments). This redundancy is prone to drift and indicates that the prompt text is being treated as a parallel source of truth for entity state.
  - fix: Treat the structured outfit_assignments as the single source of truth and generate the prompt string from it, or validate the prompt string against the structured data during post-processing.

## `prompts/_base/scene_detail/13.202605022141/system.md`

- `48` **P1 / semantic_string_judgment**
  - evidence: Focus on / close on / tight on / detail on + 특정 신체 부위 패턴이 등장하면 무조건 보통명사
  - why: Uses a phrase pattern to decide whether to use a character ID (C##) or a common noun. This directly controls whether a reference image is attached, making the routing dependent on exact string patterns in the prompt prose.
  - fix: Determine ID usage based on a structured 'focus_target' field or framing enum rather than pattern-matching the generated prompt text.

- `77-96` **P1 / semantic_string_judgment**
  - evidence: cut / slice / split / carve / bisect + 신체 부위 조합 절대 금지
  - why: Forbids specific verbs based on semantic context (body parts) to avoid visual artifacts. This creates a brittle linguistic constraint that may fail to capture other synonyms or valid artistic descriptions while blocking natural language.
  - fix: Use negative prompts or style-based guidance to prevent physical artifacts rather than forbidding specific natural-language verbs.

- `228-341` **P1 / semantic_string_judgment**
  - evidence: camera_direction... ECU, XCU, extreme close-up, MCU, medium close-up, close-up, CU... skip reference / close framing: close-up, CU, MCU, ECU, XCU, extreme close-up, 클로즈업, 손가락이, 손이, 눈이, 얼굴이
  - why: The prompt instructs the LLM to classify framing scale and route reference image attachment (Rule E) or entity visibility (Rule J) based on a brittle list of keywords and body parts found in natural-language descriptions.
  - fix: Pass framing scale as a structured enum from the upstream scenario analysis rather than inferring it from natural-language keywords or body-part mentions.

- `412-424` **P2 / scenario_dependent_prompt**
  - evidence: East Asian, Southeast Asian, South Asian, Caucasian, Black, Hispanic, Latina(o), Middle Eastern
  - why: The prompt provides a concrete list of demographic and regional examples. This biases the LLM towards a specific set of ethnicities and regions, which may not be appropriate for all future scenarios.
  - fix: Move demographic descriptors to a separate world-building configuration or use abstract placeholders like [ethnicity] in the base prompt.

## `prompts/_base/scene_detail/14.202605031033/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: t2i_prompt: "인물+아웃룩은 복합 ID(C01O02)를 사용 — 합성 단계가 'the character from Image N'으로 자동 치환."
  - why: This establishes a contract for blind substring replacement of technical IDs within a natural language prompt. This is brittle and can lead to grammatical errors or incorrect replacements if the ID pattern appears in unintended contexts or if the surrounding sentence structure is not preserved.
  - fix: Instead of blind replacement in a single string, use a structured prompt representation (e.g., a list of text and entity segments) or a templating engine that handles entity injection safely.

- `16` **P2 / llm_closed_list_instruction**
  - evidence: t2i_prompt: "신체 부위 클로즈업/사진·거울 속 인물 등 system prompt가 명시한 예외 구도에서는 보통명사로 대체."
  - why: The prompt instructs the LLM to perform semantic classification (identifying close-ups, mirrors, or photos) to decide between using a technical ID or a common noun. This logic is better handled by structured metadata or explicit framing enums rather than implicit LLM judgment during string generation.
  - fix: Define explicit framing or context flags in the schema and let the prompt assembly logic handle the string formatting based on those flags.

## `prompts/_base/scene_detail/14.202605031033/system.md`

- `48` **P1 / semantic_string_judgment**
  - evidence: Focus on / close on / tight on / detail on + 특정 신체 부위
  - why: This defines a phrase-pattern-based rule to switch from character IDs to common nouns. It relies on the LLM identifying specific framing phrases and body parts to decide whether to apply identity enforcement, which is brittle and prone to inconsistent application across different scenario phrasings.
  - fix: Centralize the logic for ID suppression based on a structured 'focus_target' field rather than pattern-matching natural language framing instructions.

- `119-130` **P1 / semantic_string_judgment**
  - evidence: 사진, 포스터, 그림, 초상화, 모니터, TV, 거울, 창유리 반사, 투영 — 은 C##O## 절대 금지
  - why: The prompt asks the LLM to classify whether an entity is 'real' or '2D/reflected' based on a list of media types. This decision changes the output token (ID vs common noun), which directly affects whether the face-reference system is engaged. This is a semantic classifier that relies on an incomplete list of media types.
  - fix: Define a structured 'entity_medium' or 'is_reflection' property in the entity schema to explicitly signal when an ID should be suppressed.

- `226-230` **P1 / semantic_string_judgment**
  - evidence: camera_direction 자연어에 close-framing tag — ECU, XCU, extreme close-up, MCU, medium close-up, close-up, CU — 가 하나라도 포함되면
  - why: The prompt instructs the LLM to infer the technical state of the composition pipeline (whether a reference image is available) by searching for framing keywords in a natural language field. This creates a brittle dependency where a slight variation in camera description terminology can lead to the LLM generating instructions for non-existent references.
  - fix: Pass an explicit boolean flag (e.g., 'is_reference_available') to the LLM instead of requiring it to infer pipeline state from natural language camera descriptions.

- `337-342` **P1 / semantic_string_judgment**
  - evidence: close-up, CU, MCU, ECU, XCU, extreme close-up, 클로즈업, 손가락이, 손이, 눈이, 얼굴이 ... wide shot, establishing, aerial, 전경, 전신
  - why: This instruction uses a brittle list of natural language keywords (including specific body parts like 'finger' or 'eye') to classify the visual framing scale. This classification then dictates strict visibility rules for all entities in the shot, potentially causing entities to be incorrectly excluded if the scenario uses synonymous but unlisted terms.
  - fix: Replace keyword-based classification with a structured framing_scale enum provided in the input schema, and have the LLM reason about visibility based on that enum rather than searching for substrings.

- `649-652` **P1 / semantic_string_judgment**
  - evidence: shot description이 동적 동사 (running, riding, walking, moving, chasing, pedaling, rowing)를 명시한 인물의 freeze 순간
  - why: This uses a closed list of verbs to detect 'motion' in open-world scenario text. If a scenario uses a verb not in this list (e.g., 'sprinting', 'cycling', 'gliding'), the 'mid-action freeze' logic will fail to trigger, leading to inconsistent visual results for similar actions.
  - fix: Use a structured 'is_motion' or 'action_type' field in the shot metadata to trigger freeze-frame logic, rather than relying on verb matching in the description.

## `prompts/_base/scene_detail/15.202605032354/detail_schema.json`

- `16` **P2 / llm_closed_list_instruction**
  - evidence: 신체 부위 클로즈업/사진·거울 속 인물 등 system prompt가 명시한 예외 구도에서는 보통명사로 대체
  - why: The instruction requires the LLM to semantically classify the visual context (e.g., mirror, photo, body-part close-up) to decide whether to use a trackable ID or a generic noun. This makes the downstream ID-replacement logic (which replaces IDs with 'the character from Image N') dependent on the LLM's subjective interpretation of these categories within the prompt string.
  - fix: Use a structured field for 'visual_context' or 'framing_type' and handle the ID-to-noun conversion in code based on that field, rather than instructing the LLM to mutate the prompt string semantically.

## `prompts/_base/scene_detail/15.202605032354/system.md`

- `11-511` **P2 / llm_closed_list_instruction**
  - evidence: 시간 연결어 절대 금지: 'and then', 'while ~ing'... / cut / slice / split / carve / bisect + 신체 부위 조합 절대 금지 / 사용 가능 어휘 팔레트... attacker / assailant...
  - why: The prompt contains several closed lists of forbidden or allowed semantic phrases used to constrain temporal logic, prevent lighting hallucinations, or bias vocabulary for violent scenes. These function as brittle semantic classifiers or vocabulary filters.
  - fix: Move these constraints into a centralized style/safety guide or use negative prompts in the T2I engine rather than hardcoding phrase lists in the system prompt.

- `31-48` **P1 / semantic_string_judgment**
  - evidence: 판단 기준: 'Focus on / close on / tight on / detail on + 특정 신체 부위' 패턴이 등장하면 무조건 보통명사
  - why: The prompt uses specific phrase patterns to decide whether to use character IDs (C##) or common nouns. This affects whether face reference images are attached, making the visual identity policy dependent on brittle string patterns in the generated prompt text.
  - fix: Decouple ID usage from framing phrases. Use a structured flag to indicate whether a shot is a body-part close-up exempt from face-reference injection.

- `207-231` **P1 / semantic_string_judgment**
  - evidence: 회피 표현: portal for door, screen for TV — 의미상 redraw 면 위반 / post-parse 단계가 LLM judge 로 위반을 검증
  - why: The system establishes a contract where a downstream judge uses semantic synonym matching (e.g., 'portal' for 'door') to block redraws of owned objects. This is a brittle and unpredictable way to enforce technical constraints, as it relies on open-world semantic equivalence checks.
  - fix: Enforce object persistence through structured entity IDs and negative prompts rather than attempting to catch semantic synonyms in generated prose.

- `233-346` **P1 / semantic_string_judgment**
  - evidence: camera_direction 자연어에 close-framing tag — ECU, XCU, extreme close-up... 가 하나라도 포함되면, 합성 단계는 chain_bg reference image를 자동 skip한다 / 판정 키워드... 손가락이, 손이, 눈이, 얼굴이
  - why: The system uses brittle keyword matching over natural-language camera directions and shot descriptions to route critical behavior, such as skipping reference images or excluding entities from the frame (Rule J). This can lead to incorrect visual routing if these common words appear in different semantic contexts.
  - fix: Replace keyword-based detection with a structured framing_scale enum in the shot metadata, or use a dedicated LLM classifier to determine framing intent without relying on specific substrings.

- `654-675` **P1 / semantic_string_judgment**
  - evidence: shot description이 동적 동사 (running, riding, walking, moving, chasing, pedaling, rowing)를 명시한 인물의 freeze 순간을 묘사할 때
  - why: The prompt instructs the LLM to trigger specific 'mid-action freeze' logic based on the presence of specific dynamic verbs in the natural-language shot description. This is a brittle semantic classifier that may fail to catch other motion verbs or misinterpret static descriptions containing these words.
  - fix: Introduce a structured motion_state field in the shot metadata to explicitly signal when a mid-action freeze pose is required.

## `prompts/_base/scene_detail/16.202605041200/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: 합성 단계가 'the character from Image N'으로 자동 치환
  - why: This establishes a contract for blind string replacement of structured IDs with natural language phrases ('the character from Image N') within the generated T2I prompt. This is brittle as it assumes the ID can be safely swapped for a phrase without breaking the surrounding prompt's grammar or semantics.
  - fix: Use a structured template or a post-processing step that understands the prompt's syntax rather than blind string replacement.

- `16` **P1 / llm_closed_list_instruction**
  - evidence: 신체 부위 클로즈업/사진·거울 속 인물 등 ... 보통명사로 대체
  - why: It instructs the LLM to use a closed list of semantic visual categories (close-ups, mirrors, photos) to decide whether to use a structured ID or a common noun. This creates a brittle dependency on the LLM's interpretation of these visual states to control the output format.
  - fix: Move the logic for ID vs. common noun replacement to a post-processor that uses structured framing fields rather than asking the LLM to change its output format based on semantic interpretation.

## `prompts/_base/scene_detail/16.202605041200/system.md`

- `64` **P1 / semantic_string_judgment**
  - evidence: 판단 기준: 'Focus on / close on / tight on / detail on + 특정 신체 부위' 패턴이 등장하면 무조건 보통명사.
  - why: String pattern matching over the generated prompt text is used to decide whether to use character IDs (C##), which directly affects reference image attachment and ID policy.
  - fix: Pass a structured 'focus_target' field to the prompt generator to explicitly control ID policy.

- `112` **P1 / semantic_string_judgment**
  - evidence: cut / slice / split / carve / bisect + 신체 부위 조합 절대 금지
  - why: Prohibits specific semantic combinations in the generated prompt to avoid T2I artifacts, functioning as a brittle semantic filter on natural language output.
  - fix: Use negative prompts or broader stylistic guidelines to avoid artifacts without banning specific verbs.

- `235-240` **P1 / semantic_string_judgment**
  - evidence: 위반 패턴 (post-parse judge 가 차단) ... A figure stands near a wooden door; a tall window beside her ... screen for TV
  - why: A downstream 'post-parse judge' uses synonym matching and phrase patterns to block redraws of 'owned' objects, which is brittle and prone to false positives.
  - fix: Use explicit object anchoring in the prompt structure and have the LLM tag referenced objects by ID.

- `249-363` **P0 / semantic_string_judgment**
  - evidence: camera_direction 자연어에 close-framing tag — ECU, XCU, extreme close-up, MCU, medium close-up, close-up, CU — 가 하나라도 포함되면, 합성 단계는 chain_bg reference image를 자동 skip한다
  - why: High-stakes routing (skipping reference images) and entity visibility rules (Rule J) are decided by brittle keyword matching over natural language descriptions (camera_direction, shot description).
  - fix: Use a structured framing enum in the input schema instead of parsing natural language strings.

- `503-513` **P2 / llm_closed_list_instruction**
  - evidence: 사용 가능 어휘 팔레트 ... attacker / assailant / aggressor ... tearing flesh, ripped skin ...
  - why: Provides a closed list of words and instructs the LLM to use them as a semantic classifier for violence intensity, biasing the output toward a fixed vocabulary.
  - fix: Provide a neutral intensity scale or general descriptive guidelines instead of a fixed word list.

## `prompts/_base/scene_detail/17.202605042018/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: 합성 단계가 'the character from Image N'으로 자동 치환
  - why: This defines a contract where technical IDs (C01O02) embedded in generated natural-language prompt prose are blindly replaced by semantic reference phrases during a later synthesis stage, which is brittle if the LLM places the ID in an unexpected linguistic context.
  - fix: Pass the character/outlook mapping as structured metadata alongside the prompt rather than performing substring replacement on the generated prose.

- `16` **P1 / llm_closed_list_instruction**
  - evidence: 신체 부위 클로즈업/사진·거울 속 인물 등 system prompt가 명시한 예외 구도에서는 보통명사로 대체
  - why: This instructs the LLM to use a closed list of semantic visual categories (body part close-ups, mirrors, photos) to decide whether to use a technical ID or a common noun. This creates a brittle dependency on the LLM's interpretation of visual framing to drive ID enforcement policy.
  - fix: Allow the LLM to always use structured IDs and handle the 'common noun' fallback in a downstream visual-processing or prompt-formatting layer based on explicit framing metadata.

## `prompts/_base/scene_detail/17.202605042018/system.md`

- `27-29` **P1 / semantic_string_judgment**
  - evidence: and then, while ~ing, after ~ing, as ~, before ~, ~하자, ~하며, ~한 뒤
  - why: It enforces a 'single moment' constraint by banning specific natural language substrings. This is a brittle way to control semantic output and may lead to awkward phrasing or failed validations.
  - fix: Instead of banning substrings, provide a structural instruction to describe the scene as a static composition and use a separate validator to check for temporal logic.

- `45-64` **P1 / semantic_string_judgment**
  - evidence: Focus on / close on / tight on / detail on + 특정 신체 부위
  - why: It uses a specific phrase pattern to trigger a fallback to common nouns, bypassing ID injection (C##O##). This makes ID policy dependent on the presence of specific substrings.
  - fix: Use a structured flag in the ID policy or asset requirements to indicate if a shot is a body-part close-up exempt from ID injection.

- `209-212` **P1 / semantic_string_judgment**
  - evidence: the existing X / from the reference / use the X from the reference / preserving the same room perspective
  - why: It bans specific phrases to handle the skipped_close_framing mode. This is a hard string-based filter for a semantic state that should be handled by the LLM's understanding of the context.
  - fix: Define the background binding mode clearly in the prompt and instruct the LLM to describe the environment from scratch when the reference is unavailable, without relying on a forbidden phrase list.

- `295-300` **P1 / semantic_string_judgment**
  - evidence: close-up, CU, MCU, ECU, XCU, extreme close-up, 클로즈업, 손가락이, 손이, 눈이, 얼굴이
  - why: It uses a brittle list of keywords (including Korean body parts) to infer the framing scale from natural language shot descriptions, which then dictates strict visibility and ID rules.
  - fix: Pass the framing scale as a structured enum in the RenderPromptCard instead of inferring it from natural language keywords.

- `435-456` **P2 / llm_closed_list_instruction**
  - evidence: attacker / assailant / aggressor / predator / pursuer, tearing flesh, ripped skin, blood spray
  - why: It provides a closed list of 'approved' semantic tokens for violence, which biases the LLM's open-world description of physical conflict and may lead to repetitive or trope-heavy generation.
  - fix: Replace the vocabulary palette with high-level instructions on maintaining intensity and power imbalance without prescribing specific words.

## `prompts/_base/scene_detail/18.202605041549/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: t2i_prompt ... 합성 단계가 'the character from Image N'으로 자동 치환
  - why: This defines a contract where LLM-generated natural language prose is subjected to blind substring replacement of IDs (e.g., C01O02). This is brittle because the replacement string ('the character from Image N') may not be grammatically or semantically compatible with the surrounding sentence structure generated by the LLM.
  - fix: Instead of embedding IDs for replacement, use a structured representation where the prompt template and the entity references are separate, or perform the substitution at a stage where the LLM can see the final text.

- `16` **P1 / llm_closed_list_instruction**
  - evidence: 신체 부위 클로즈업/사진·거울 속 인물 등 system prompt가 명시한 예외 구도에서는 보통명사로 대체
  - why: The schema instructs the LLM to use a closed list of visual contexts (close-ups, mirrors, photos) as a semantic classifier to decide whether to use a structured ID or a common noun. This creates a brittle dependency on the LLM's interpretation of these categories to drive technical string formatting.
  - fix: Standardize the output format regardless of visual context, and handle context-specific rendering logic in a downstream visual-aware component or via explicit metadata fields.

## `prompts/_base/scene_detail/18.202605041549/system.md`

- `41-44` **P1 / semantic_string_judgment**
  - evidence: trigger_phrases (focus on / close on / tight on / detail on + 신체부위) 패턴이 등장하면 ... C##O## 사용 금지
  - why: This rule uses a phrase-based pattern match over the intended visual description to decide whether to apply a critical ID enforcement policy. It forces a fallback to common nouns based on the presence of specific substrings.
  - fix: Define a boolean 'is_body_part_focus' or similar flag in the id_policy schema to explicitly control this behavior.

- `49-51` **P1 / semantic_string_judgment**
  - evidence: applies_to_surfaces (사진·포스터·모니터·거울·반사·투영 등) 안의 인물은 C##O## 절대 금지
  - why: It classifies the semantic nature of a surface (reproduction vs. real) using a phrase list to route ID policy. This is brittle as it relies on the LLM identifying these specific surface types to trigger a safety/consistency rule.
  - fix: Use a structured 'surface_type' attribute for entities or backgrounds to signal when an ID should be treated as a reproduction.

- `256-261` **P1 / semantic_string_judgment**
  - evidence: close-up, CU, MCU, ECU, XCU, extreme close-up, 클로즈업, 손가락이, 손이, 눈이, 얼굴이 ... 판정 키워드
  - why: The prompt instructs the LLM to classify the framing scale of a shot using a brittle list of English and Korean keywords. This classification (close vs. wide) then triggers 'Rule J', which dictates whether entities are removed or blurred, making visual composition dependent on string matches.
  - fix: Pass the framing scale as a structured enum in the RenderPromptCard rather than having the LLM infer it from natural language or metadata strings.

- `353-370` **P2 / scenario_dependent_prompt**
  - evidence: attacker / assailant / aggressor / predator / pursuer ... tearing flesh, ripped skin, gaping wound
  - why: The prompt contains a concrete 'palette' of highly specific, scenario-dependent vocabulary for violence. This biases the LLM toward specific tropes and graphic descriptions whenever a conflict is detected, rather than remaining a neutral scene analyzer.
  - fix: Move specialized genre-specific vocabularies to dynamic prompt injections that are only included when the scenario genre or content tags match.

- `525-546` **P1 / semantic_string_judgment**
  - evidence: running, riding, walking, moving, chasing, pedaling, rowing ... freeze 순간을 묘사할 때 ... motion direction을 자세 묘사에 포함
  - why: The prompt uses a specific list of action verbs to trigger 'mid-action freeze' logic. This makes the physical description of the character (e.g., hair flowing) dependent on the presence of specific verbs in the input description.
  - fix: Include a 'motion_state' or 'is_dynamic' flag in the shot metadata to explicitly signal when motion-blur or directional-freeze logic should be applied.

## `prompts/_base/scene_detail/19.202605050814/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: 합성 단계가 'the character from Image N'으로 자동 치환
  - why: This establishes a contract where the synthesis stage performs blind substring replacement of IDs (e.g., C01O02) within generated natural-language prompt text. This is brittle as it relies on the LLM placing the ID in a context where replacement is semantically valid and doesn't account for partial matches or unexpected prose usage.
  - fix: Use a structured representation for entities within prompts (e.g., a list of entity-to-index mappings) rather than performing blind substring replacement on the final prose.

- `16` **P1 / llm_closed_list_instruction**
  - evidence: 신체 부위 클로즈업/사진·거울 속 인물 등 system prompt가 명시한 예외 구도에서는 보통명사로 대체
  - why: The instruction requires the LLM to perform semantic classification of visual scenarios (body parts, photos, mirrors) to determine output formatting (ID vs. common noun). This couples visual meaning to string-level formatting rules and creates a dependency on a closed list of visual tropes.
  - fix: Maintain consistent ID usage across all compositions and handle visual exceptions (like 'photo of') in the synthesis/rendering logic rather than via conditional LLM output formatting.

## `prompts/_base/scene_detail/19.202605050814/system.md`

- `41-48` **P1 / semantic_string_judgment**
  - evidence: focus on / close on / tight on / detail on + face filling the entire frame
  - why: Specific natural language phrases are used as semantic triggers to disable character ID (C##O##) injection. This is brittle because it relies on exact phrase matching to decide a critical behavior (ID policy), which can fail if the scenario uses synonymous but unlisted phrases.
  - fix: Use a structured boolean flag or focus_target field in the shot metadata to control ID injection policy instead of parsing the prompt text for trigger phrases.

- `69-76` **P1 / semantic_string_judgment**
  - evidence: red light cuts across her eyes, crimson spill cuts across her features, a beam slicing through his face
  - why: The prompt defines a list of forbidden semantic patterns for lighting to prevent physical artifacts (e.g., 'cutting' the body). This is a semantic validator based on string patterns rather than physical or geometric constraints, which is difficult to maintain as scenario complexity grows.
  - fix: Move lighting safety validation to a dedicated review step or use more abstract instructions that focus on 'surface-only' lighting without listing specific forbidden phrases.

- `136-139` **P1 / blind_string_mutation**
  - evidence: the existing X, from the reference, use the X from the reference, preserving the same room perspective
  - why: The prompt mandates the exclusion of specific semantic phrases when the background binding mode is 'skipped_close_framing'. This creates a brittle contract where the LLM must avoid specific substrings, which is a form of blind semantic mutation/filtering.
  - fix: Instead of forbidding specific phrases, provide a clear instruction on what the output should focus on (e.g., 'describe only the immediate foreground surface') and let the LLM generate naturally.

- `222-227` **P1 / semantic_string_judgment**
  - evidence: close-up, CU, MCU, ECU, XCU, extreme close-up, 클로즈업, 손가락이, 손이, 눈이, 얼굴이
  - why: The prompt instructs the LLM to infer the visual framing scale (close/wide/medium) from a brittle list of Korean and English keywords in the shot description. This classification then dictates strict rules for entity visibility and ID usage, making the pipeline sensitive to minor phrasing variations.
  - fix: Pass the framing scale as a structured enum from the upstream shot extractor rather than inferring it from natural language keywords in the system prompt.

- `434-436` **P2 / scenario_dependent_prompt**
  - evidence: Asian man, Asian woman, East Asian person
  - why: The examples provided for character descriptions consistently use 'Asian' as the demographic descriptor. This introduces concrete scenario pollution that can bias the LLM towards a specific ethnicity for arbitrary future scenarios where demographics are not explicitly defined.
  - fix: Replace specific ethnicity descriptors in examples with abstract placeholders like [ethnicity] or [demographic_descriptor] to maintain neutrality.

## `prompts/_base/scene_detail/20.202605051240/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: 합성 단계가 'the character from Image N'으로 자동 치환... 신체 부위 클로즈업/사진·거울 속 인물 등... 보통명사로 대체
  - why: The schema codifies a brittle system where character IDs are blindly replaced in natural language prose and where the LLM must use visual framing as a semantic classifier to decide string formatting. This creates a high risk of grammatical errors and inconsistent entity representation.
  - fix: Use a structured prompt representation that separates entity references from natural language prose, and move framing-based formatting logic to a dedicated post-processing or rendering stage.

- `19` **P2 / schema_or_enum_drift**
  - evidence: t2i_prompt의 복합 ID와 동일한 정보를 명시
  - why: Requires the LLM to manually synchronize data between the structured outfit_assignments array and the natural language t2i_prompt string, which is prone to drift and validation failures.
  - fix: Derive the structured outfit_assignments from the prompt tokens or vice versa in a single source of truth, rather than asking the LLM to duplicate the information.

## `prompts/_base/scene_detail/20.202605051240/system.md`

- `27` **P1 / semantic_string_judgment**
  - evidence: 시간 연결어 절대 금지: 'and then', 'while ~ing', 'after ~ing', 'as ~', 'before ~', '~하자', '~하며', '~한 뒤'
  - why: It uses a closed list of temporal connectors to enforce the 'single moment' rule. This is a brittle way to control the temporal semantics of the output, as many other phrases can imply sequence or duration.
  - fix: Instead of a forbidden phrase list, provide a structural requirement for the prompt (e.g., 'describe only static states and positions') and use a semantic validator to detect temporal progression.

- `41-43` **P1 / semantic_string_judgment**
  - evidence: body_part_focus_rule.trigger_phrases ('focus on / close on / tight on / detail on' + 신체부위) 패턴이 등장하면 ... C##O## 사용 금지
  - why: This is a semantic classifier that changes the ID policy (routing) based on the presence of specific natural-language patterns. It creates a brittle dependency between the prompt's prose and the system's identity enforcement logic.
  - fix: Explicitly flag 'body_part_focus' as a boolean or enum in the input schema/card instead of relying on pattern matching over the generated description.

- `115` **P1 / blind_string_mutation**
  - evidence: character_name → C## 또는 C##O## 매핑이 id_policy 안에 존재 시 해당 보통명사를 C##/C##O## 로 치환
  - why: It instructs the LLM to perform blind string substitution of natural-language names with technical IDs. This is prone to errors if names are partial, misspelled, or used in different grammatical contexts, leading to 'double-description' or broken references.
  - fix: Use a structured entity mapping where the LLM only works with IDs, or perform the substitution in a post-processing step using a robust NER/linking tool.

- `136-138` **P1 / semantic_string_judgment**
  - evidence: 다음 6개 표현은 절대 출력 금지 — 'the existing X' / 'from the reference' / 'use the X from the reference' / 'preserving the same room perspective' / 'maintaining the reference's framing' / 'do not generate a new X'
  - why: It enforces a negative constraint based on exact natural-language substrings. This is brittle as the LLM might use synonymous phrases that bypass the filter while still violating the underlying 'skipped_close_framing' logic.
  - fix: Define the constraint semantically (e.g., 'do not anchor to background references') and use a validator to check for semantic intent rather than exact phrase matching.

- `151` **P1 / llm_closed_list_instruction**
  - evidence: close 판정 키워드 = 'close-up', 'CU', 'MCU', 'ECU', 'XCU', 'extreme close-up', '클로즈업', '손가락이', '손이', '눈이', '얼굴이' (총 11 entries)
  - why: It uses a brittle, closed list of 11 keywords (including specific body parts in Korean) to classify the visual framing scale. This classification then triggers significant behavioral changes in ID policy and entity visibility rules.
  - fix: Pass the framing scale as a structured enum in the RenderPromptCard rather than asking the LLM to infer it from a keyword list.

## `prompts/_base/scene_detail/21.202605061636/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: t2i_prompt: ... 합성 단계가 'the character from Image N'으로 자동 치환
  - why: The schema explicitly documents a downstream 'synthesis stage' that performs blind string replacement of IDs within the generated natural-language prompt prose, which is prone to collision and context loss.
  - fix: Pass IDs and their intended positions as a structured list of entity spans alongside the prompt, rather than performing blind substring replacement on the prose.

- `16` **P1 / semantic_string_judgment**
  - evidence: 신체 부위 클로즈업/사진·거울 속 인물 등 ... 예외 구도에서는 보통명사로 대체
  - why: This instruction forces the LLM to act as a semantic classifier for visual framing (close-ups, mirrors) to determine the string format (ID vs. common noun). This creates a brittle dependency where downstream logic must infer the visual context based on the presence or absence of specific string patterns.
  - fix: Maintain consistent ID usage in the prompt and use a structured field (e.g., 'composition_type' or 'is_indirect_view') to signal to the downstream renderer how to handle character references.

## `prompts/_base/scene_detail/21.202605061636/system.md`

- `41-43` **P1 / llm_closed_list_instruction**
  - evidence: body_part_focus_rule.trigger_phrases (`focus on / close on / tight on / detail on` + 신체부위) 패턴이 등장하면 ... C##O## 사용 금지
  - why: It triggers a significant change in ID policy (forbidding composite IDs) based on a closed list of phrase patterns. This is a semantic classifier that depends on exact wording.
  - fix: Introduce a structured boolean flag or enum in the input schema to explicitly signal body-part focus.

- `136-139` **P1 / semantic_string_judgment**
  - evidence: skipped_close_framing: ... 다음 6개 표현은 절대 출력 금지 — `the existing X` / `from the reference` / `use the X from the reference` / `preserving the same room perspective` / `maintaining the reference's framing` / `do not generate a new X`.
  - why: It enforces background binding policy by forbidding a specific list of natural language substrings. This is brittle and easily bypassed by paraphrasing while still violating the underlying intent.
  - fix: Define the constraint semantically (e.g., 'do not reference the background or reference image') rather than as a list of forbidden substrings.

- `151` **P1 / llm_closed_list_instruction**
  - evidence: primary_framing_rule.framing_scale_keywords: close 판정 키워드 = `close-up`, `CU`, `MCU`, `ECU`, `XCU`, `extreme close-up`, `클로즈업`, `손가락이`, `손이`, `눈이`, `얼굴이` (총 11 entries)
  - why: It uses a hardcoded list of 11 keywords, including specific body parts in Korean, to classify open-world visual framing. This is brittle and fails to capture the semantic variety of framing descriptions.
  - fix: Rely on the structured `framing_scale` field in the RenderPromptCard rather than inferring framing from natural language keywords.

- `170-174` **P1 / llm_closed_list_instruction**
  - evidence: entity-aware silhouette policy: ... 'face fully obscured' / 'no visible facial features' / 'face hidden in shadow' ... 류만 사용한다.
  - why: It infers visibility and silhouette policy from specific phrase patterns within the `stable_traits` field. This is a semantic classifier based on string matching in open-world trait descriptions.
  - fix: Use structured trait flags (e.g., `is_face_obscured: true`) in the entity canon rather than matching phrases in natural language traits.

- `446-450` **P1 / semantic_string_judgment**
  - evidence: entity_canon.name 이 prompt 안에 등장하면 그 specific entity 의 ID ... 가 같은 sentence + ±60 char window 안에 있어야 한다.
  - why: It defines a brittle validation rule based on character-window proximity between names and IDs in natural language. This is a high-risk fail-fast mechanism that relies on string patterns rather than structure.
  - fix: Use a structured output schema for entity mapping (e.g., an array of objects linking IDs to their specific descriptors) instead of relying on proximity in the prompt prose.

## `prompts/_base/scene_detail/21.202605062217/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: 합성 단계가 'the character from Image N'으로 자동 치환
  - why: The schema description explicitly documents a downstream process that performs blind string replacement on the generated prompt text. This is a brittle pattern that depends on the LLM producing specific ID formats that are later swapped.
  - fix: Pass the reference image index as a structured metadata field alongside the prompt instead of relying on string substitution.

- `16` **P1 / llm_closed_list_instruction**
  - evidence: 신체 부위 클로즈업/사진·거울 속 인물 등 ... 예외 구도에서는 보통명사로 대체
  - why: The LLM is instructed to classify visual meaning (body parts, mirrors, photos) to decide between using a structured ID or a common noun. This is a semantic classifier that controls string formatting, creating a brittle dependency between visual framing and prompt syntax.
  - fix: Use a structured field to indicate if the character representation is indirect or partial, rather than having the LLM mutate the prompt string based on framing.

## `prompts/_base/scene_detail/21.202605062217/system.md`

- `41-44` **P1 / semantic_string_judgment**
  - evidence: body_part_focus_rule.trigger_phrases ('focus on / close on / tight on / detail on' + 신체부위) 패턴이 등장하면 얼굴·비얼굴 가리지 않고 C##O## 사용 금지
  - why: It uses a brittle substring/pattern match over natural language scenario text to trigger a critical behavior change (disabling character ID enforcement). This is prone to false positives and ignores semantic context.
  - fix: Move the 'body_part_focus' detection to a structured field in the RenderPromptCard (e.g., a boolean or enum) rather than relying on the LLM to match phrases in the scenario.

- `115` **P1 / blind_string_mutation**
  - evidence: 해당 보통명사를 C##/C##O## 로 치환. 같은 인물 C##/C##O## + 보통명사 이중 묘사 금지
  - why: This instructs the LLM to perform blind string substitution of character names/nouns with IDs. This is a 'blind semantic string mutation' contract that can lead to broken grammar or incorrect entity mapping if the substitution context is not handled structurally.
  - fix: Use structured entity placeholders in the source text that are resolved by the pipeline rather than asking the LLM to perform string replacement on natural language.

- `151` **P1 / semantic_string_judgment**
  - evidence: close 판정 키워드 = 'close-up', 'CU', 'MCU', 'ECU', 'XCU', 'extreme close-up', '클로즈업', '손가락이', '손이', '눈이', '얼굴이' (총 11 entries)
  - why: It defines a closed list of keywords, including body parts in Korean, to classify the framing scale of a shot. This is a brittle semantic classifier that drives downstream logic (close_framing_rules).
  - fix: The framing scale should be a structured enum in the input metadata (RenderPromptCard) rather than being inferred from a list of keywords in the prompt.

- `170-174` **P1 / semantic_string_judgment**
  - evidence: trait 가 'face fully obscured' / 'no visible facial features' / 'face hidden in shadow' 같은 face-obscured 표현을 포함하면, face / jaw / feature 묘사 표현 금지
  - why: It performs semantic judgment by searching for specific natural-language phrases within the 'stable_traits' field to enforce a 'no-face' policy. This is brittle and depends on exact wording in the entity canon.
  - fix: Introduce a structured 'visibility_flags' or 'obscured_parts' array in the entity traits schema instead of parsing natural language descriptions.

- `462-466` **P1 / semantic_string_judgment**
  - evidence: entity_canon.name 이 prompt 안에 등장하면 그 specific entity 의 ID 가 같은 sentence + ±60 char window 안에 있어야 한다
  - why: This defines a brittle validation rule based on character windowing and substring matching of names and IDs within generated prose. This is a high-risk semantic validator that can fail due to minor formatting or phrasing changes.
  - fix: Validate entity presence using structured metadata or token-level tagging rather than character-distance heuristics over natural language.

## `prompts/_base/scene_detail/22.202605122049/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: 합성 단계가 'the character from Image N'으로 자동 치환
  - why: This documents a contract for blind substring replacement within the generated T2I prompt prose. This is prone to collision or failure if the LLM-generated text contains the ID patterns (like C01O02) in unintended contexts or if the LLM produces slightly malformed IDs.
  - fix: Pass the prompt and the entity mapping as separate structured fields to the synthesis stage, or use a more robust templating syntax (e.g., {{C01O02}}) that is less likely to collide with natural language.

- `16` **P1 / semantic_string_judgment**
  - evidence: 신체 부위 클로즈업, reproduction surface ... 등 예외 구도에서는 보통명사로 대체
  - why: The LLM is instructed to use semantic visual categories (body part close-ups, reproduction surfaces) as a classifier to decide whether to use structured IDs or natural language. This creates a brittle boundary where the LLM must pivot its string formatting logic based on visual interpretation, which is better handled by structured metadata.
  - fix: Introduce structured boolean or enum fields (e.g., 'is_detail_shot', 'is_reproduction_surface') to explicitly signal these states to downstream processors instead of relying on the LLM to mutate the prompt string format.

## `prompts/_base/scene_detail/22.202605122049/system.md`

- `41-44` **P1 / llm_closed_list_instruction**
  - evidence: body_part_focus_rule.trigger_phrases ('focus on / close on / tight on / detail on' + 신체부위) 패턴이 등장하면 ... C##O## 사용 금지
  - why: Changes the ID policy (stripping character IDs) based on the presence of specific natural language phrase patterns. This makes reference attachment dependent on brittle string matching.
  - fix: Use a boolean flag like 'is_body_part_focus' in the id_policy schema instead of inferring it from prompt text patterns.

- `119` **P1 / semantic_string_judgment**
  - evidence: fixed_elements[i].description 안 보통명사 인물 ("an adult figure" / "the seated person" 류) 이 ... 치환
  - why: Performs entity resolution by matching generic natural language nouns in descriptions to character IDs. This is highly brittle as descriptions vary significantly in prose.
  - fix: Ensure fixed_elements use stable entity IDs or structured roles rather than natural language descriptions for substitution logic.

- `155` **P1 / llm_closed_list_instruction**
  - evidence: close 판정 키워드 = 'close-up', 'CU', 'MCU', 'ECU', 'XCU', 'extreme close-up', '클로즈업', '손가락이', '손이', '눈이', '얼굴이'
  - why: Uses a hardcoded list of 11 English and Korean phrases to classify framing scale. This is brittle and fails to capture semantic variations (e.g., 'palm' vs 'hand') or different languages/synonyms.
  - fix: Replace keyword-based classification with a structured framing_scale enum in the RenderPromptCard that is determined by the upstream staging analysis.

- `174-176` **P2 / llm_closed_list_instruction**
  - evidence: trait 가 "face fully obscured" / "no visible facial features" / "face hidden in shadow" 같은 face-obscured 표현을 포함하면
  - why: Triggers a specific silhouette rendering policy based on exact string matches within entity traits. This creates a hidden dependency on specific wording in the entity canon.
  - fix: Add a structured 'visibility_state' or 'is_face_obscured' boolean to the entity stable_traits schema.

- `466-470` **P2 / semantic_string_judgment**
  - evidence: entity_canon.name 이 prompt 안에 등장하면 ... 같은 sentence + ±60 char window 안에 있어야 한다
  - why: Enforces entity-ID mapping using a brittle character-window distance check. This can lead to false positives/negatives in complex sentences or multi-character descriptions.
  - fix: Use structured entity-to-ID mapping in the output schema rather than validating proximity in the natural language prompt string.

## `prompts/_base/scene_detail/23.202605141758/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: 합성 단계가 'the character from Image N'으로 자동 치환
  - why: This establishes a contract where the generated natural-language 't2i_prompt' will be modified via blind string replacement of IDs. This is prone to grammatical errors and context-blind substitution when the ID is embedded in complex prose.
  - fix: Use a templating system or a structured prompt format where entity placeholders are distinct from the natural language prose, or perform the substitution at a stage where the sentence structure can be validated.

- `16` **P1 / llm_closed_list_instruction**
  - evidence: 신체 부위 클로즈업, reproduction surface ... 등 예외 구도에서는 보통명사로 대체
  - why: This instructs the LLM to perform semantic classification of the visual scene (detecting close-ups or reflections) to determine whether to use IDs or common nouns. This creates inconsistent entity referencing logic that depends on the LLM's interpretation of open-world visual tropes.
  - fix: Use a structured boolean or enum field (e.g., 'is_close_up', 'is_reproduction_surface') to explicitly signal these states, and handle the naming convention logic in the prompt assembly code rather than as a conditional instruction within the LLM's prose generation task.

## `prompts/_base/scene_detail/23.202605141758/system.md`

- `41-44` **P1 / semantic_string_judgment**
  - evidence: body_part_focus_rule.trigger_phrases (focus on / close on / tight on / detail on + body part)
  - why: Uses a regex-like phrase pattern over natural language to decide whether to disable character ID injection (C##O##). This is a brittle semantic classifier for safety/policy routing.
  - fix: Pass a explicit boolean flag or focus_target_type in the structured card instead of relying on phrase matching.

- `119` **P1 / blind_string_mutation**
  - evidence: cross_shot_id_substitution_rule ... 보통명사 인물 ... 을 C##/C##O## 로 치환
  - why: Instructs the LLM to perform blind string replacement of natural language descriptions with structured IDs. This is a semantic mutation that can lead to grammatical errors or incorrect identity assignment.
  - fix: Allow the LLM to generate the correct ID directly in the first pass based on the context, rather than performing a post-hoc substitution.

- `140-143` **P2 / llm_closed_list_instruction**
  - evidence: skipped_close_framing: the existing X / from the reference / use the X from the reference / preserving the same room perspective / maintaining the reference's framing / do not generate a new X
  - why: Uses a closed list of forbidden phrases to control semantic output for a specific rendering mode. This is brittle and may fail if the LLM uses synonymous phrasing.
  - fix: Define the negative constraint as a high-level instruction (e.g., 'do not refer to the background reference') rather than a list of exact substrings.

- `155` **P1 / semantic_string_judgment**
  - evidence: primary_framing_rule.framing_scale_keywords: close-up, CU, MCU, ECU, XCU, extreme close-up, 클로즈업, 손가락이, 손이, 눈이, 얼굴이
  - why: Uses a hardcoded list of 11 keywords (including natural language body parts in Korean) to classify visual framing scale, which then triggers different visibility and ID policies.
  - fix: Move framing classification to a structured field in the input schema (e.g., an enum in RenderPromptCard) rather than inferring it from prose keywords.

- `511-516` **P1 / semantic_string_judgment**
  - evidence: entity_canon.name ... ±60 char window 안에 있어야 한다
  - why: Enforces a semantic relationship (identity grounding) using a brittle character-distance heuristic (60-character window) between names and IDs in generated prose.
  - fix: Use structured mapping in the output JSON where IDs are explicitly associated with their descriptive labels, rather than relying on proximity in a flat string.

## `prompts/_base/scene_detail/24.202605151451/detail_schema.json`

- `16` **P1 / blind_string_mutation**
  - evidence: 합성 단계가 'the character from Image N'으로 자동 치환
  - why: This defines a contract for blind substring replacement of technical IDs with natural language reference phrases in the final T2I prompt, which can lead to grammatical errors or broken prompt logic if the context changes.
  - fix: Use a structured prompt assembly system or templating engine that handles reference resolution before final string generation rather than post-hoc string replacement.

- `16` **P1 / semantic_string_judgment**
  - evidence: 신체 부위 클로즈업, reproduction surface... 등 예외 구도에서는 보통명사로 대체
  - why: Visual framing (close-up) and semantic context (reproduction surface) are used as classifiers to decide whether to use structured IDs (C01O02) or common nouns. This implies downstream logic infers the 'exception' state by the absence of ID patterns, which is a brittle way to handle framing-based ID exemptions.
  - fix: Add a structured 'framing_context' or 'is_id_exempt' boolean/enum to the variation object instead of relying on the presence or absence of ID patterns in the prompt string.

## `prompts/_base/scene_detail/24.202605151451/system.md`

- `41-44` **P1 / semantic_string_judgment**
  - evidence: body_part_focus_rule.trigger_phrases (focus on / close on / tight on / detail on + body part)
  - why: The prompt instructs the LLM to use a specific list of natural-language phrases to classify a shot as a body-part focus, which then triggers a behavior change: prohibiting the use of character IDs (C##O##) in favor of common nouns.
  - fix: Pass a structured boolean flag (e.g., is_body_part_focus) in the RenderPromptCard instead of relying on the LLM to detect focus from prose patterns.

- `119` **P1 / blind_string_mutation**
  - evidence: fixed_elements[i].description 안 보통명사 인물 ... 이 ... 매핑이 id_policy 안에 존재 시 해당 보통명사를 C##/C##O## 로 치환
  - why: This is a contract for blind semantic mutation where natural-language nouns in a description are replaced with structured IDs based on a mapping. This assumes the noun uniquely and correctly identifies the entity in arbitrary prose.
  - fix: The source description should already use placeholders or IDs, or the mapping should be handled by a structured entity-linking step rather than string replacement.

- `219-221` **P1 / semantic_string_judgment**
  - evidence: stable_traits ... 'face fully obscured' / 'no visible facial features' ... face / jaw / feature 묘사 표현 금지
  - why: The prompt asks the LLM to classify the character's visual state by searching for specific phrases within the 'stable_traits' text and then enforces a negative vocabulary constraint on the output based on that match.
  - fix: Use a structured enum or boolean (e.g., face_visible: false) in the entity traits schema to control vocabulary constraints.

- `369` **P1 / semantic_string_judgment**
  - evidence: running / riding / walking / moving / chasing / pedaling / rowing ... re-frame 가능
  - why: The prompt uses a closed list of motion verbs to classify the complexity of a scene and instructs the LLM to change its depiction strategy (Reframe) based on the presence of these words in the input description.
  - fix: The complexity or 'motion' status of a shot should be a structured attribute provided by the upstream staging/scenario analysis rather than inferred via verb matching.

- `511-516` **P1 / semantic_string_judgment**
  - evidence: entity_canon.name ... 같은 sentence + ±60 char window ... ID 가 ... 있어야 한다
  - why: This defines a brittle semantic rule for entity linking that uses character proximity (60-character window) to validate that a name mentioned in prose is correctly associated with an ID. This is prone to false positives/negatives in complex sentences.
  - fix: Use structured entity-to-ID mappings or markup (e.g., [Name](ID)) in the source text instead of proximity-based heuristics.

## `prompts/_base/scene_detail/7.202604201230/system.md`

- `21-25` **P2 / llm_closed_list_instruction**
  - evidence: C## 사용 여부는 얼굴이 식별 가능한지로 판단: ... 완전히 뒤돌아선 인물 ... 실루엣 ... OTS에서 뒷통수/어깨만
  - why: The LLM is acting as a semantic classifier to decide entity referencing (C## vs noun) based on a closed list of visual scenarios. This logic is better handled by upstream metadata or a dedicated visibility/orientation field.
  - fix: Define a 'visibility_state' enum in the schema (e.g., FACE_VISIBLE, BACK_TO_CAMERA, SILHOUETTE) and use it to drive referencing logic.

- `48` **P1 / llm_closed_list_instruction**
  - evidence: 판단 기준: 'Focus on / close on / tight on / detail on + 특정 신체 부위' 패턴이 등장하면 무조건 보통명사.
  - why: This instructs the LLM to use a brittle string-matching heuristic to decide between using a structured character ID (C##) and a common noun. It forces a semantic decision based on specific phrase patterns rather than the underlying visual intent.
  - fix: Replace phrase-based triggers with a structured 'framing' or 'focus_target' field in the input schema that explicitly signals when a shot is a body-part close-up.

- `96-135` **P2 / scenario_dependent_prompt**
  - evidence: middle-aged Korean woman, Korean man in his 30s, young Korean woman
  - why: The prompt contains multiple concrete examples specifying 'Korean' ethnicity and specific age groups. This constitutes scenario pollution that can bias the LLM's generation for scenarios involving different cultures or demographics.
  - fix: Use abstract placeholders like [ethnicity], [gender], or [age_group] in examples to maintain neutrality.

- `107` **P1 / blind_string_mutation**
  - evidence: 고정 요소 description의 보통명사 인물 묘사...를 해당 C##으로 대체
  - why: This is a direct instruction for the LLM to perform blind substring replacement of natural language text with technical IDs. This is prone to grammatical errors, incorrect mapping if multiple characters share descriptions, and breaks the separation between prose and metadata.
  - fix: Provide the description as a template with placeholders or ask the LLM to generate a new description using the provided IDs rather than performing a 'replace' operation.

## `prompts/_base/scene_detail/8.202604201530/system.md`

- `29-48` **P1 / semantic_string_judgment**
  - evidence: "Focus on / close on / tight on / detail on + 특정 신체 부위" 패턴이 등장하면 무조건 보통명사
  - why: The prompt defines a semantic classifier based on a closed list of phrase patterns to determine entity referencing logic (C## vs common noun). This makes the system's behavior brittle and dependent on specific natural-language wording in the scenario.
  - fix: Pass a structured 'framing' or 'focus_target' field to the prompt instead of relying on the LLM to parse phrase patterns from the description.

- `95-100` **P2 / scenario_dependent_prompt**
  - evidence: "middle-aged Korean woman", "Korean man in his 30s", "young Korean woman"
  - why: The prompt contains concrete demographic and cultural examples (Korean ethnicity, specific age groups) that can bias the LLM's generation for arbitrary future scenarios that may require different settings or characters.
  - fix: Replace specific demographic examples with abstract placeholders like 'a middle-aged woman' or 'a man in his 30s' to maintain neutrality.

- `106-116` **P1 / blind_string_mutation**
  - evidence: 고정 요소 description의 보통명사 인물 묘사("A Korean man", "a woman" 등)를 해당 C##으로 대체
  - why: This instructs the LLM to perform blind substring replacement on natural language prose (fixed_elements). This is a brittle way to manage entity references and can result in ungrammatical or nonsensical sentences if the match is imperfect.
  - fix: Use structured templates for fixed elements where character placeholders are already defined, rather than asking the LLM to find and replace substrings.

- `168-184` **P1 / llm_closed_list_instruction**
  - evidence: "사용 가능 어휘 팔레트" (attacker / assailant / aggressor / predator / pursuer, victim / prey / target, etc.)
  - why: The prompt restricts open-world semantic description of violence to a closed list of specific terms. This biases the LLM's output and forces it to classify complex scenarios into a narrow set of predefined labels.
  - fix: Allow the LLM to use natural language appropriate to the scenario or provide these as non-binding examples rather than a strict 'palette' for selection.

- `282-288` **P2 / schema_or_enum_drift**
  - evidence: "normal", "montage", "flashback", "dream", "voiceover", "transition"
  - why: These scene types are defined as a list of strings in the prompt and are likely consumed as exact values by downstream logic. This creates an unenforced string contract that is prone to drift between the prompt and the code.
  - fix: Define these scene types in a central schema or enum and reference that SOT in both the prompt and the code.

## `prompts/_base/scene_detail/9.202604201700/system.md`

- `19-102` **P1 / llm_closed_list_instruction**
  - evidence: C## 사용 여부는 얼굴이 식별 가능한지로 판단... Focus on / close on / tight on / detail on + 특정 신체 부위 패턴... 2D 매체 속 이미지인가?
  - why: Uses a combination of phrase patterns and semantic categories (visibility, body parts, 2D vs 3D medium) to route between structured IDs (C##) and common nouns. This brittle logic controls reference attachment and face-injection behavior.
  - fix: Move visibility, medium, and focus-target classification to structured metadata in the scene/shot schema, allowing the pipeline to handle ID-to-noun conversion deterministically.

- `106-110` **P1 / blind_string_mutation**
  - evidence: 고정 요소 description의 보통명사 인물 묘사를 해당 C##으로 대체
  - why: Instructs the LLM to perform blind string replacement of natural language descriptions with structured IDs to merge entity states. This is a brittle way to handle semantic data integration.
  - fix: Provide fixed elements as structured data with ID mappings already resolved, or use a template system that doesn't require the LLM to perform manual string replacement.

- `204-226` **P2 / scenario_dependent_prompt**
  - evidence: attacker / assailant / aggressor / predator / tearing flesh, ripped skin, blood spray
  - why: Provides a concrete, high-intensity vocabulary palette for violence/horror scenarios. This biases the LLM towards specific tropes and pollutes the prompt with scenario-specific language.
  - fix: Remove the specific word lists. Use abstract instructions for intensity or move the vocabulary to a separate style-guide module that is injected only when relevant.

- `323-332` **P1 / semantic_string_judgment**
  - evidence: visible_entities 엄격 규칙... 목소리만 들리는 인물 제외... 회상/환상/꿈에만 등장 제외
  - why: The LLM is tasked with filtering entity membership based on complex narrative semantics (V.O., flashback, remote presence). This determines the behavior-changing 'visible_entities' array.
  - fix: Derive visibility from structured narrative metadata (e.g., 'presence_type' or 'is_onscreen') rather than asking the LLM to infer it from prose.

## `prompts/_base/scene_detail_owned_judge/1.202605032354/system.md`

- `16-25` **P1 / llm_closed_list_instruction**
  - evidence: create / render / add / draw / place / generate / place a new <owned>, portal for door, near the doorway, from the reference
  - why: The prompt instructs the LLM to classify whether an object is being redrawn or referenced based on specific phrase patterns and synonym lists. This creates a brittle semantic classifier that may fail on natural language variations not explicitly listed, forcing the LLM to act as a string-pattern matcher rather than a semantic reasoner.
  - fix: Define the classification criteria using abstract semantic principles (e.g., 'existential introduction' vs 'spatial/source anchoring') rather than specific verb or phrase lists, and provide abstract examples of the logic.

## `prompts/_base/scene_detail_owned_judge/2.202605051641/system.md`

- `16-31` **P1 / llm_closed_list_instruction**
  - evidence: 패턴 예시: create / render / add / draw / place / generate... anchor 참조: near the doorway, beside the table... ambiguous case... 명시적 reference 표현이 없으면 redraw_violation 으로 분류
  - why: The prompt instructs the LLM to perform semantic classification (distinguishing between creating a new object and referencing an existing one) based on a closed list of phrase patterns and a rigid fallback rule. This creates a brittle semantic classifier that may fail on natural language variations or synonyms not included in the list, and forces a 'violation' verdict on ambiguous but potentially valid prose.
  - fix: Define the semantic intent of 'redrawing' vs. 'referencing' using abstract criteria rather than specific phrase patterns. Allow the LLM to use its linguistic understanding to determine intent, or move the pattern matching to a post-processing step if strict string matching is required.

## `prompts/_base/scene_detail_owned_judge/3.202605051746/system.md`

- `7` **P1 / llm_closed_list_instruction**
  - evidence: owned 어휘는 t2i_prompt 의 English token 과 정확히 매칭되어야 한다 (semantic gloss / 번역 매칭 금지)
  - why: This instruction explicitly forbids the LLM from using semantic understanding, forcing it to perform exact string matching between a list of nouns and natural language prompt text. This is brittle and prevents the model from correctly identifying referred objects that use synonyms or descriptive variations.
  - fix: Allow the LLM to use semantic matching and normalization to identify objects, rather than enforcing strict token-level identity.

- `18-45` **P1 / llm_closed_list_instruction**
  - evidence: redraw 동사 화이트리스트 (create, render, draw, generate, paint, build, furnish, add, place, put, insert, hang, mount, install, set up) and anchor_reference phrases (from the reference, from chain_bg, the existing X, leaning into, framed together between, etc.)
  - why: The prompt uses closed whitelists of verbs and spatial phrases as a primary classifier for visual intent (determining if an object is being redrawn or merely referenced). This creates a brittle semantic router that depends on specific keyword presence rather than the actual meaning of the generated prompt.
  - fix: Define the classification categories (redraw vs. reference) conceptually and provide the lists as illustrative examples rather than a strict 'whitelist' or 'phrase match' requirement.

## `prompts/_base/scene_director/6.202603251200/analyze_schema.json`

- `11` **P2 / schema_or_enum_drift**
  - evidence: "scene_type": {"type": "string", "description": "normal | montage | flashback | dream | voiceover | transition | other"}
  - why: The allowed values for scene_type are defined only in the description string rather than as a formal JSON enum. This forces downstream code to rely on exact string matching of LLM output without schema-level enforcement, increasing the risk of drift or unexpected values.
  - fix: Change the scene_type definition to use an 'enum' array containing the listed strings.

## `prompts/_base/scene_director/6.202603251200/system.md`

- `7-33` **P1 / llm_closed_list_instruction**
  - evidence: 영상통화, CCTV, 방송 화면, 홀로그램, VR, 원격 조종/빙의 기술, 유령, 영혼, 아스트랄 투영, V.O., 내레이션, 변장, 쌍둥이 교체, 바디더블, 회상(플래시백), 미래 예견(플래시포워드), 꿈/환상/상상
  - why: The prompt uses a closed list of specific narrative tropes and technical devices to define the 'physical presence' of entities. This acts as a semantic classifier that biases the LLM toward specific scenario types (e.g., sci-fi or fantasy) and creates brittle logic for entity membership in the output array based on keyword-like concepts.
  - fix: Define 'physical presence' using abstract spatial criteria (e.g., 'Does the entity's physical body occupy the scene's coordinate space?') rather than a list of tropes. If specific exclusions like 'holograms' are required, they should be handled via structured metadata or a more generalized rule about 'physical body location'.

## `prompts/_base/scene_director/7.202604031800/analyze_schema.json`

- `11` **P2 / schema_or_enum_drift**
  - evidence: "scene_type": {"type": "string", "description": "normal | montage | flashback | dream | voiceover | transition | other"}
  - why: The allowed values for scene_type are provided as a pipe-separated list in the description rather than a formal JSON enum. This creates a brittle contract where the LLM might produce near-miss strings that downstream logic expects to be exact matches.
  - fix: Convert the scene_type property to use an enum: ["normal", "montage", "flashback", "dream", "voiceover", "transition", "other"].

## `prompts/_base/scene_director/7.202604031800/system.md`

- `7-33` **P2 / llm_closed_list_instruction**
  - evidence: V.O.(보이스오버), 내레이션, CCTV, 방송 화면, 홀로그램, VR, 원격 조종/빙의, 유령, 변장, 쌍둥이 교체, 바디더블
  - why: The prompt instructs the LLM to classify entity visibility based on a closed list of narrative markers and specific tropes (e.g., possession, body doubles). This creates a brittle semantic classifier that relies on the LLM identifying these specific patterns in natural language and may bias results toward these specific scenarios.
  - fix: Generalize the visibility criteria to focus on physical presence in the frame and move specific trope handling to genre-specific prompt layers or structured metadata.

## `prompts/_base/scene_director/8.202604081200/analyze_schema.json`

- `11` **P2 / schema_or_enum_drift**
  - evidence: "scene_type": {"type": "string", "description": "normal | montage | flashback | dream | voiceover | transition | other"}
  - why: The allowed values for scene classification are defined in a natural-language description string rather than a formal JSON enum. This creates a contract that is not enforced by the schema validator, leading to potential drift or parsing failures if the LLM produces variations of these terms (e.g., 'flash-back' vs 'flashback').
  - fix: Convert the 'scene_type' property to use a formal JSON 'enum' array containing the allowed values.

## `prompts/_base/scene_director/8.202604081200/system.md`

- `7-24` **P2 / llm_closed_list_instruction**
  - evidence: 교차편집/몽타주... 영상통화, CCTV, 방송 화면, 홀로그램, VR, 원격 조종/빙의 기술... V.O.(보이스오버), 내레이션... 변장, 쌍둥이 교체, 바디더블... 회상/꿈/환상/상상... 유령... 빙의/원격접속
  - why: The prompt instructs the LLM to determine entity visibility (present_entity_ids) by matching scene text against a closed list of specific scenario tropes and cinematic techniques. This functions as a semantic classifier that may bias the model or fail to generalize to scenarios not explicitly listed (e.g., reflections, shadows, or different types of remote presence).
  - fix: Generalize the visibility criteria into a physical/optical principle (e.g., 'Is the entity's visual form or its direct representation captured by the camera lens in this scene?'). Move specific trope-based edge cases to few-shot examples or a separate configuration.

## `prompts/_base/scene_extractor_v2/15.202604091500/system.md`

- `47` **P1 / semantic_string_judgment**
  - evidence: <몽타주> 표시
  - why: The prompt instructs the LLM to classify a scene as 'montage' based on the presence of a specific string literal, which is brittle and fails if the scenario text uses different terminology or lacks the specific tag.
  - fix: Replace string-based triggers with semantic descriptions of scene structure or use a structured metadata field for scene types.

- `58` **P1 / llm_closed_list_instruction**
  - evidence: V.O., 전화 통화, 무전, 방송 음성
  - why: Uses a closed list of natural language phrases as a semantic classifier to determine entity visibility (exclusion). This may fail to capture other ways of describing off-screen presence in open-world scenarios.
  - fix: Instruct the LLM to reason about physical presence based on the scene context rather than matching specific phrases.

- `59-63` **P2 / scenario_dependent_prompt**
  - evidence: "원격 조종/접속 인물", "동녘(강의원)", "캡슐속 남자들"
  - why: The prompt contains logic and examples (remote control mechanics, specific character names, and specific props) that are highly specific to a single project's scenario, which can bias the LLM's extraction logic for unrelated stories.
  - fix: Replace project-specific names and props with abstract placeholders like 'Character A', 'Character B', or 'Prop A'.

## `prompts/_base/scene_extractor_v2/15.202604091500/turn1_split_long.md`

- `8-11` **P1 / blind_string_mutation**
  - evidence: split_after_line 규칙 ... 원문에서 정확히 복사한 한 줄이어야 함 (띄어쓰기, 문장부호 포함 100% 일치)
  - why: The prompt mandates an exact 100% match of a line from the scenario to be used as a split marker. This is a brittle contract for structural mutation (splitting) of natural language text, as minor LLM hallucinations in punctuation or spacing will break the downstream logic.
  - fix: Pass the scenario text with line numbers or unique IDs and have the LLM return the ID of the line after which to split, avoiding reliance on exact string matching.

## `prompts/_base/scene_extractor_v2/15.202604091500/turn_scene_detail.md`

- `43-45` **P2 / llm_closed_list_instruction**
  - evidence: "soft_light_intimate" → "soft warm light...", "dutch_angle" → "the frame is tilted...", "over_the_shoulder" → "the camera is positioned..."
  - why: The prompt defines a hardcoded mapping of technical identifiers to visual prose descriptions. This creates a semantic classifier within the prompt that must be manually synchronized with the system's camera technique vocabulary.
  - fix: Move the visual expansion logic to a central configuration or include the description directly in the input data for the camera_effect field.

- `66-68` **P2 / scenario_dependent_prompt**
  - evidence: "Korean police officer", "Korean-style apartment", "Korean convenience store", "Joseon-era nobleman"
  - why: The prompt uses concrete, culture-specific and era-specific examples (Korean, Joseon-era) to illustrate general rules. This can bias the LLM's generation toward these specific tropes even when the target scenario is different.
  - fix: Replace specific cultural/historical examples with abstract placeholders like "[Region]-style apartment" or "[Era] nobleman".

- `91` **P2 / scenario_dependent_prompt**
  - evidence: "캡슐속 남자들"이 헬기에 타고 있다면 → 캡슐은 헬기에 없으므로 제외
  - why: Uses a highly specific scenario example (men in capsules in a helicopter) to explain entity exclusion logic, which is unnecessary scenario pollution.
  - fix: Use a generic example of spatial exclusion, such as an object mentioned as being in a different location or a container not present in the current scene.

## `prompts/_base/scene_extractor_v2/16.202604091800/system.md`

- `47-58` **P1 / llm_closed_list_instruction**
  - evidence: <몽타주>, V.O., 전화 통화, 무전, 방송 음성
  - why: The prompt instructs the LLM to classify scene types (montage, voiceover) and determine entity visibility based on a closed list of specific string patterns and phrases rather than general semantic understanding. This creates a brittle dependency on exact script formatting.
  - fix: Define these categories using abstract semantic descriptions or provide a wider, more varied set of examples that do not rely on exact string matches.

- `60-63` **P2 / scenario_dependent_prompt**
  - evidence: "동녘(강의원)", "캡슐속 남자들"
  - why: The prompt uses concrete scenario-specific character names and props as examples for visibility logic. These specific names and tropes can bias the LLM toward specific story contexts or genres during generation.
  - fix: Replace specific names and props with abstract placeholders like 'Character A', 'Character B', or generic objects like 'a chair' or 'a car'.

## `prompts/_base/scene_extractor_v2/16.202604091800/turn1_split_long.md`

- `8-11` **P1 / blind_string_mutation**
  - evidence: split_after_line 규칙... 원문에서 정확히 복사한 한 줄이어야 함... 그 줄 직후에서 씬이 분할됩니다
  - why: The prompt requires the LLM to provide an exact substring from the scenario to serve as a structural delimiter. This is a brittle contract for blind string mutation; any minor hallucination or formatting change by the LLM will cause the split logic to fail.
  - fix: Pass line numbers or unique identifiers to the LLM and have it return the index/ID where the split should occur, rather than relying on exact string matching of natural language prose.

## `prompts/_base/scene_extractor_v2/16.202604091800/turn_scene_detail.md`

- `76-78` **P2 / scenario_dependent_prompt**
  - evidence: Korean police officer, Korean-style apartment, Joseon-era nobleman
  - why: The prompt uses concrete, culture-specific examples to illustrate regional context rules, which can bias the LLM toward Korean/historical tropes even for unrelated scenarios.
  - fix: Replace specific cultural examples with abstract placeholders like '[Region]-style [Building]' or '[Era]-era [Role]'.

- `84-85` **P2 / llm_closed_list_instruction**
  - evidence: 카메라 구도 선택지: low angle / high angle ... 색감 선택지: warm amber / cold blue ...
  - why: The prompt provides a closed list of visual descriptors for camera angles and color palettes, restricting the LLM's ability to describe open-world visual variety and creating a brittle string-based contract for the camera_effect field.
  - fix: Provide these as non-exhaustive examples or move the selection logic to a structured configuration.

## `prompts/_base/scene_extractor_v2/17.202604101200/system.md`

- `47-58` **P2 / llm_closed_list_instruction**
  - evidence: V.O., 전화 통화, 무전, 방송 음성, <몽타주> 표시
  - why: The prompt instructs the LLM to classify scene types and determine entity visibility based on the presence of specific natural language phrases or markers. This is a brittle way to handle open-world scenario semantics.
  - fix: Instead of relying on specific phrase patterns, instruct the LLM to infer visibility and scene type from the overall context and physical presence described in the scenario.

- `60-63` **P2 / scenario_dependent_prompt**
  - evidence: 예: "동녘(강의원)", 예: "캡슐속 남자들"
  - why: The prompt uses concrete character names ('동녘', '강의원') and specific props ('캡슐') from a particular scenario as examples. This pollutes the base prompt and can bias the LLM's behavior in unrelated scenarios.
  - fix: Replace scenario-specific names and props with abstract placeholders like 'Character A', 'Character B', or 'Prop A'.

## `prompts/_base/scene_extractor_v2/17.202604101200/turn1_split_long.md`

- `8-11` **P1 / blind_string_mutation**
  - evidence: split_after_line 규칙 (매우 중요): - 원문에서 정확히 복사한 한 줄이어야 함 (띄어쓰기, 문장부호 포함 100% 일치) ... 그 줄 직후에서 씬이 분할됩니다
  - why: This establishes a contract where the LLM must perfectly reproduce a natural language substring to control scenario structure. Any minor hallucination or formatting change by the LLM will cause the downstream splitting logic to fail or corrupt the scenario.
  - fix: Use line numbers or unique block identifiers to define split points instead of relying on exact natural language string matching.

## `prompts/_base/scene_extractor_v2/17.202604101200/turn_scene_detail.md`

- `34-38` **P1 / semantic_string_judgment**
  - evidence: 얼굴/형태 식별 불가 인물 — short_id 사용 금지: 실루엣, 그림자, 창문 반사, 역광, 안개 속... C##O## short_id를 사용하지 마세요.
  - why: This instruction asks the LLM to classify visual identifiability from a closed list of semantic conditions (silhouette, shadow, etc.) and use that to decide whether to suppress structured entity IDs. This breaks the entity tracking chain and reference attachment based on a semantic guess.
  - fix: Pass identifiability or visual state as a structured field from the upstream extractor rather than having the LLM infer it and mutate the ID format.

- `83-85` **P2 / scenario_dependent_prompt**
  - evidence: 예: 한국 배경이면 'Korean police officer', 'Korean-style apartment'... 예: 조선시대면 'Joseon-era nobleman'... generic 묘사 금지 ('police officer' -> 'Korean police officer')
  - why: The prompt contains concrete scenario-specific examples (Korean, Joseon) and explicitly forbids generic descriptions, biasing the LLM towards a specific culture/era regardless of the actual world-building context provided in the system prompt.
  - fix: Replace specific cultural examples with abstract placeholders or move them to a project-specific configuration/system prompt.

- `105-109` **P1 / semantic_string_judgment**
  - evidence: visible_entities 주의사항: 이 씬의 화면에 물리적으로 존재하는 대상만 넣으세요... 텍스트에 이름/단어가 등장해도, 실제로 그 공간에 없으면 제외
  - why: This is a semantic classifier instruction that asks the LLM to determine entity membership in the 'visible_entities' list based on spatial/physical presence inferred from natural language. This logic is brittle and affects downstream reference attachment and validation.
  - fix: Use structured spatial data or a dedicated visibility classifier rather than relying on LLM inference from scene prose during extraction.

## `prompts/_base/scene_extractor_v2/18.202605150955/system.md`

- `47` **P1 / semantic_string_judgment**
  - evidence: (<몽타주> 표시 또는 빠른 컷 전환)
  - why: Instructs the LLM to classify a scene as 'montage' based on the presence of a specific Korean string pattern in the input scenario text, which is a brittle way to infer cinematic structure.
  - fix: Instruct the LLM to identify montage sequences based on semantic characteristics (e.g., rapid time jumps, multiple locations) rather than specific bracketed markers.

- `60` **P2 / scenario_dependent_prompt**
  - evidence: rule_type=possession, remote_identity, visible_body
  - why: Hardcodes a specific 'possession' or 'remote control' story mechanic into the base scene extraction logic. This is scenario pollution that assumes the existence of specific supernatural or sci-fi tropes in arbitrary scenarios.
  - fix: Move scenario-specific entity relationship rules to a dynamic configuration or a specialized prompt layer rather than the base system prompt.

## `prompts/_base/scene_extractor_v2/18.202605150955/turn1_split_long.md`

- `8-11` **P1 / blind_string_mutation**
  - evidence: split_after_line 규칙 (매우 중요): - 원문에서 정확히 복사한 한 줄이어야 함 (띄어쓰기, 문장부호 포함 100% 일치)
  - why: This instruction requires the LLM to provide an exact substring from the scenario to drive structural splitting. Natural language text is prone to minor variations (whitespace, punctuation) during LLM generation, making exact string matching a brittle mechanism for scenario mutation.
  - fix: Use line indices or unique line IDs to identify the split point instead of relying on exact natural-language substring matching.

## `prompts/_base/scene_extractor_v2/18.202605150955/turn_scene_detail.md`

- `34-38` **P1 / semantic_string_judgment**
  - evidence: 얼굴/형태 식별 불가 인물 — short_id 사용 금지: 실루엣, 그림자, 창문 반사, 역광, 안개 속 등으로 인물의 얼굴이나 신체 형태를 식별할 수 없는 경우 C##O## short_id를 사용하지 마세요.
  - why: This instruction requires the LLM to perform semantic judgment on the scenario text (identifying visual states like 'silhouette' or 'backlight') to decide whether to include or exclude a character's short_id. This is a brittle routing mechanism that affects entity membership and reference attachment in the generated image.
  - fix: Pass a structured 'visibility_state' or 'is_silhouette' flag for each entity from the previous analysis step instead of asking the LLM to infer it from prose.

- `91-92` **P2 / llm_closed_list_instruction**
  - evidence: 카메라 구도 선택지: low angle / high angle / dutch angle / over-the-shoulder / bird's eye / extreme wide / tight medium
색감 선택지: warm amber / cold blue / high contrast / desaturated / golden hour / neon-lit / silhouette backlight
  - why: The prompt provides a closed list of semantic categories for camera angles and color palettes. If downstream code or validators expect these exact strings, it creates a schema drift risk where the prompt and code must be manually synchronized.
  - fix: Define these options in a central schema/enum and inject them into the prompt dynamically, or ensure the downstream consumer handles arbitrary descriptive text.

- `105-109` **P1 / semantic_string_judgment**
  - evidence: visible_entities 주의사항: 이 씬의 화면에 물리적으로 존재하는 대상만 넣으세요 ... 예: "<container descriptor> 안의 인물들"이 <transport vehicle>에 타고 있다면 → container 는 transport vehicle 에 없으므로 제외
  - why: The LLM is instructed to perform complex semantic filtering of entities based on physical presence and containment logic described in natural language. This is a high-risk area for inconsistent entity membership across scenes.
  - fix: Move entity visibility logic to a dedicated structured analysis step that uses a world-state model rather than relying on LLM interpretation of prose during prompt generation.

## `prompts/_base/scene_generator/v1/scene_rules_en.md`

- `5-6` **P2 / scenario_dependent_prompt**
  - evidence: Korean aesthetics, fantasy armor, or medieval architecture
  - why: These are concrete scenario-specific style and genre constraints embedded in a base rule file, which biases the model against non-Korean or non-contemporary settings.
  - fix: Relocate scenario-specific constraints to a project-level or scenario-level prompt template.

## `prompts/_base/scene_generator/v1/scene_rules_ko.md`

- `5-6` **P2 / scenario_dependent_prompt**
  - evidence: 동시대~근미래 한국 기준, 사극풍 복식, 판타지 갑옷, 중세풍 건축 금지
  - why: The prompt hardcodes a specific setting (Korea, contemporary/near-future) and specific genre exclusions (historical drama, fantasy, medieval) into base rules, which biases the model against arbitrary scenarios or different cultural contexts.
  - fix: Move setting-specific and genre-specific constraints to a dynamic configuration or a project-specific prompt layer rather than including them in the base scene rules.

## `prompts/_base/scene_generator/v1/style_rules_generator.md`

- `5-10` **P2 / scenario_dependent_prompt**
  - evidence: 조선시대 (line 5), 한국, 일본, 미국, 유럽 (line 6), 한복 (line 9)
  - why: The base prompt includes specific cultural and historical examples (Joseon Dynasty, Korea, Japan, Hanbok) within its analysis categories. These concrete references can bias the LLM's stylistic analysis and rule generation, potentially leaking specific cultural or historical elements into unrelated or fictional scenarios where they do not belong.
  - fix: Generalize the examples by removing specific cultural/national names and historical periods, or use abstract placeholders like 'Specific Historical Period' and 'Regional/Cultural Style' to ensure the base prompt remains neutral.

## `prompts/_base/scene_generator/v2/scene_rules_en.md`

- `6` **P2 / scenario_dependent_prompt**
  - evidence: No ... fantasy armor, or medieval architecture
  - why: Hardcoding specific genre-based exclusions (fantasy, medieval) in a base prompt biases the model and may conflict with the dynamic 'world rules' mentioned in line 5, which are intended to define the era and region.
  - fix: Remove specific genre/era examples from the base rules and move them to the project-specific world rules or style guide to maintain the base prompt's neutrality.

## `prompts/_base/scene_generator/v2/scene_rules_ko.md`

- `6` **P2 / scenario_dependent_prompt**
  - evidence: 사극풍 복식, 판타지 갑옷, 중세풍 건축 금지
  - why: These are concrete genre-specific exclusions (historical drama costumes, fantasy armor, medieval architecture) hard-coded into base scene rules. This biases the LLM against these themes, which may conflict with scenarios defined in the world rules mentioned in line 5, and prevents the generator from being truly scenario-agnostic.
  - fix: Move genre-specific negative constraints to a project-specific configuration or dynamic style guide injection instead of hard-coding them in the base prompt.

## `prompts/_base/scene_image/1.202603181600/translate_prompt.md`

- `5` **P2 / scenario_dependent_prompt**
  - evidence: a young Korean man
  - why: The use of a specific ethnicity ('Korean') in a generic instruction example can bias the LLM towards that demographic when generating descriptions for arbitrary characters in open-world scenarios.
  - fix: Use more neutral or abstract placeholders in examples, such as 'a [age] [ethnicity] [gender]' or 'an elderly person'.

- `10` **P2 / llm_closed_list_instruction**
  - evidence: no 'close-up', 'wide shot', 'medium shot'
  - why: The prompt uses a closed list of framing terms to instruct the LLM to perform semantic filtering. This is brittle as it may miss synonyms (e.g., 'tight shot', 'POV', 'long shot') or incorrectly filter natural language that happens to use these words in a non-technical context.
  - fix: Instruct the LLM to remove all camera-related technical terminology and framing descriptions generally, rather than relying on a specific phrase list.

## `prompts/_base/scene_image/2.202603251100/translate_prompt.md`

- `5` **P1 / blind_string_mutation**
  - evidence: Replace character/object IDs (C##O##, P##, etc.) with "the character/object from Reference image N" format
  - why: This establishes a contract for the LLM to perform blind substring replacement of entity IDs within generated prompt prose. This is brittle as it relies on the LLM to correctly identify and replace these patterns without context-aware validation, which can lead to broken references if IDs appear in non-entity contexts or are hallucinated.
  - fix: Pass structured entity metadata and use a templating system or a scene-graph-aware replacement logic rather than asking the LLM to perform string-level ID mapping.

- `11` **P1 / llm_closed_list_instruction**
  - evidence: Do NOT include camera angles or shot types (no "close-up", "wide shot", "medium shot")
  - why: This is a semantic classifier instruction that uses a closed list of phrases to filter visual framing from open-world prose. It is brittle because it may miss synonyms or incorrectly strip valid descriptive text that happens to use these words in a non-framing context.
  - fix: Define framing as a separate structured field in the schema and instruct the LLM to ignore framing entirely during translation, rather than relying on a keyword-based exclusion list.

## `prompts/_base/scene_image/3.202605101200/translate_prompt.md`

- `23-26` **P1 / semantic_string_judgment**
  - evidence: PHANTOM PHRASE PROHIBITION (strict): ... phrases trigger a downstream phantom-reference validator and will fail the render
  - why: The prompt explicitly identifies a downstream validator that uses brittle string patterns (e.g., 'from the reference') over generated natural-language prose to fail-fast the rendering process. This forces the prompt to include complex negative constraints to avoid accidental semantic triggers.
  - fix: Replace the downstream string-matching validator with a structured check or a semantic model that understands context, or move reference tracking to a non-natural-language metadata field that is not part of the final T2I prompt string.

## `prompts/_base/shot_dependency_t2i/3.202604101200/schema.json`

- `28` **P2 / scenario_dependent_prompt**
  - evidence: Ignore the blood on the floor.
  - why: The example uses a concrete, genre-specific visual element ('blood on the floor') which can bias the LLM towards specific scenario types or tropes during generation, even when the actual scenario is neutral.
  - fix: Replace the concrete example with a generic placeholder or a neutral architectural element, such as 'Ignore the chair' or 'Ignore the specific prop'.

## `prompts/_base/shot_dependency_t2i/3.202604101200/system.md`

- `23-30` **P2 / llm_closed_list_instruction**
  - evidence: ref_usage: "exact_background", "atmosphere_reference"
  - why: The prompt requires the LLM to classify complex visual relationships into a closed set of strings. This is a semantic classifier that creates a brittle contract between the prompt and downstream processing logic.
  - fix: Formalize these categories in a JSON schema enum and inject them into the prompt dynamically to ensure the code and prompt stay synchronized.

- `42-49` **P2 / scenario_dependent_prompt**
  - evidence: "blood stains on the floor", "police tape and detectives", "broken glass on the table"
  - why: The prompt uses concrete, genre-specific examples (crime scene props) to illustrate formatting rules. These specific details can bias the LLM's generation toward crime/thriller scenarios regardless of the actual input story.
  - fix: Use abstract placeholders (e.g., [object_A], [character_B]) or generic, non-genre-specific examples (e.g., 'the chair', 'the person') to demonstrate the rules.

## `prompts/_base/shot_dependency_t2i/4.202604141200/schema.json`

- `28` **P2 / scenario_dependent_prompt**
  - evidence: Ignore the blood on the floor.
  - why: The use of a specific, high-impact scenario example ('blood on the floor') in a base schema description can bias the LLM towards generating or assuming violent or thriller-themed contexts for arbitrary scenarios.
  - fix: Replace with a neutral, generic example such as 'Ignore the chair' or 'Ignore the background posters'.

- `33` **P2 / scenario_dependent_prompt**
  - evidence: immobile characters (dead/unconscious bodies)
  - why: This instruction provides a concrete scenario-specific definition for 'immobile characters' that biases the model toward specific plot points (death/injury) and functions as a semantic classifier for character state within a base schema.
  - fix: Use more abstract descriptions like 'characters in a fixed physical state' or provide generic examples like 'statues' if applicable.

## `prompts/_base/shot_dependency_t2i/4.202604141200/system.md`

- `23-27` **P2 / schema_or_enum_drift**
  - evidence: "exact_background", "atmosphere_reference"
  - why: These string constants define a semantic classification of shot relationships. Defining them in prompt prose without a corresponding schema enum creates a risk of drift where the LLM might use slightly different terms or the downstream code might expect different values.
  - fix: Define these values in a central JSON schema enum and reference that schema in the prompt.

- `31-37` **P1 / semantic_string_judgment**
  - evidence: 죽은, 의식불명, 심하게 다친 인물... 이 인물은 환경의 일부입니다
  - why: The LLM is instructed to perform semantic classification of character health/state (dead, unconscious, severely injured) to decide whether an entity belongs in 'keep_elements' (environment) or 'ignore_elements' (actors). This routes visual continuity logic based on open-world narrative interpretation rather than structured state metadata.
  - fix: Pass a structured 'is_static' or 'is_environment' flag for each entity based on the scene state rather than asking the LLM to infer it from health descriptions.

- `46-47` **P1 / semantic_string_judgment**
  - evidence: 엔티티 ID (C01, O02, P03, L04 등) 사용 절대 금지 → 보통명사만 사용
  - why: Forcing the LLM to discard structured identifiers in favor of natural language descriptions ('the woman in red') creates a brittle semantic link. Downstream masking or reference-attachment logic must then attempt to re-identify these entities from prose, which is error-prone compared to using stable IDs.
  - fix: Allow or require the use of entity IDs in ignore_elements to maintain a strict link to the project's entity manifest.

## `prompts/_base/shot_dependency_t2i/5.202604201700/schema.json`

- `28` **P1 / blind_string_mutation**
  - evidence: Use common nouns only (no entity IDs). No add/replace/adjust instructions. No conditional phrasing
  - why: This instruction defines a contract for downstream code to perform blind string manipulation on natural language prose. It forces the LLM to produce simplified substrings to accommodate a brittle string-matching processor (likely for negative prompting or token removal).
  - fix: Use structured entity references or semantic tags instead of natural language substrings for element exclusion.

- `28-33` **P2 / scenario_dependent_prompt**
  - evidence: Ignore the standing man by the door. ... dead/unconscious bodies
  - why: The schema includes concrete scenario-specific examples ('standing man by the door', 'dead/unconscious bodies') which can bias the LLM's output for arbitrary scenarios by suggesting specific physical states or character types.
  - fix: Replace concrete scenario examples with abstract placeholders or generic, neutral examples like 'the red chair' or 'stationary objects'.

## `prompts/_base/shot_dependency_t2i/5.202604201700/system.md`

- `20-59` **P1 / semantic_string_judgment**
  - evidence: ref_usage 유형 판단, zoom_in_detail, exact_background, atmosphere_reference
  - why: The prompt asks the LLM to classify the visual and temporal relationship between shots into a closed list of categories using natural-language checklists (e.g., 'same moment', 'same space', 'camera framing change'). This classification directly routes how the T2I engine utilizes the reference image.
  - fix: Move the shot relationship classification to an upstream structured analysis step or provide the classification as a machine-readable input rather than asking the LLM to infer it from prose.

- `36-111` **P2 / scenario_dependent_prompt**
  - evidence: 바닥에 쓰러진 인물, detective walking in, police tape, the body lying face-down on the floor
  - why: The prompt is saturated with concrete crime-scene specific examples and tropes (detectives, bodies, police tape). This biases the model towards thriller/crime interpretations and may lead to incorrect handling of other genres, such as misidentifying a sleeping character as a 'body' or 'environment'.
  - fix: Replace scenario-specific examples with abstract placeholders (e.g., Character A, Object B) or generic continuity examples that apply across all genres.

- `61-70` **P1 / semantic_string_judgment**
  - evidence: 죽은/의식불명/움직이지 않는 인물 처리, 이 인물은 환경의 일부입니다, keep_elements에 이 인물의 시각적 묘사를 반드시 포함하세요
  - why: The prompt forces a routing change (treating an entity as environment) based on the semantic state of a character (dead, unconscious, or injured). This is a brittle classifier that relies on the LLM's interpretation of character status to decide reference attachment and visibility policy.
  - fix: Use a structured 'physical_state' or 'is_static' flag in the character metadata to drive this logic instead of relying on semantic inference in the prompt.

## `prompts/_base/shot_dependency_t2i/7.202605151200/schema.json`

- `26-29` **P1 / blind_string_mutation**
  - evidence: No add/replace/adjust instructions. No conditional phrasing (no 'if...', 'when...', 'only if'). E.g. 'Ignore the standing man by the door.'
  - why: The field 'ignore_elements' is a natural language string but the prompt forbids semantic logic (conditionals, verbs), indicating it is used for blind concatenation or simple replacement in downstream prompts. It also contains a concrete scenario example ('standing man by the door') that can bias generation.
  - fix: If the downstream logic requires specific actions like replacement or conditional logic, these should be modeled as structured fields in the schema. Remove concrete scenario examples from the description.

- `39-49` **P2 / llm_closed_list_instruction**
  - evidence: character state (dead/unconscious/pose) is handled by separate layers (scene_consistency / character_state_variant / semantic_contract_router)
  - why: The instructions for 'kind' and 'keep_elements' use a specific list of semantic states ('dead', 'unconscious') to define a routing boundary for the LLM. This creates a brittle semantic contract where the LLM must classify open-world meaning against a closed list of examples to decide which field to populate.
  - fix: Define the boundary using abstract categories (e.g., 'non-human entities only') rather than listing specific character states, and ensure the schema structure itself enforces the separation.

## `prompts/_base/shot_dependency_t2i/7.202605151200/system.md`

- `20-59` **P2 / llm_closed_list_instruction**
  - evidence: ref_usage (zoom_in_detail, exact_background, atmosphere_reference)
  - why: The prompt asks the LLM to classify open-world visual relationships between shots into a closed list of three semantic categories. This is a semantic classifier that routes downstream image generation behavior.
  - fix: Ensure these categories are part of a central SOT enum and provide more objective, technical criteria for classification to reduce semantic drift.

- `146-163` **P1 / semantic_string_judgment**
  - evidence: human / person / character / body / figure / man / woman / detective / prisoner / child / person silhouette
  - why: The prompt uses a brittle list of natural-language words to validate the semantic content of the 'label' field. If any of these words appear, the output is rejected (fail-fast), which is a string-pattern-based judgment of open-world meaning (personhood).
  - fix: Instead of a negative lexicon, use a structured schema where characters and environment/props are separate entities, and rely on the LLM's understanding of the schema rather than keyword filtering.

- `161` **P2 / schema_or_enum_drift**
  - evidence: immobilized_character / character / pose 등 enum 외 값 절대 금지
  - why: The prompt explicitly forbids specific strings that are not in the defined enum, suggesting that the LLM frequently emits these values or that they exist in other parts of the system, indicating a lack of strict schema enforcement.
  - fix: Enforce the enum at the schema level (e.g., JSON schema) rather than using negative instructions in the prompt.

## `prompts/_base/shot_director/1.202603301500/system.md`

- `20-22` **P2 / scenario_dependent_prompt**
  - evidence: 백련이 요괴화된 후이면, 백련이 아직 변형 전이면
  - why: The system prompt uses a specific character name ('백련') and a specific story event ('요괴화') as examples, which constitutes scenario pollution in a base prompt meant for general use.
  - fix: Replace specific character names and story events with abstract placeholders like '캐릭터A' or '변형 이벤트'.

## `prompts/_base/shot_director/2.202604031800/system.md`

- `21-23` **P2 / scenario_dependent_prompt**
  - evidence: 백련이 요괴화된 후이면 → C01 대신 C02
  - why: The prompt uses a specific character name ('백련') and a specific plot point ('요괴화' - monster transformation) as examples. This can bias the LLM towards similar fantasy/transformation tropes in unrelated scenarios.
  - fix: Replace '백련' and '요괴화' with abstract placeholders like 'Character A' and 'Variant form' (e.g., '캐릭터A가 변형된 후이면').

## `prompts/_base/shot_director/3.202605101200/system.md`

- `15-33` **P1 / llm_closed_list_instruction**
  - evidence: Gaze-target close-up 패턴, 명시적 off-camera/off-screen phrase, 차단(blocking) 패턴, Reaction-only 패턴
  - why: The prompt instructs the LLM to determine entity visibility (routing logic) by matching specific Korean/English phrase patterns and grammatical structures. This turns the LLM into a brittle string classifier for open-world visual meaning, which is prone to failure if the scenario description uses slightly different phrasing.
  - fix: Replace phrase-based classification with high-level semantic instructions or provide a more diverse set of examples that focus on the visual intent rather than specific substrings.

- `19-44` **P2 / scenario_dependent_prompt**
  - evidence: 혜수, 수리영, 인우, 백련
  - why: The prompt uses concrete character names and specific plot points (e.g., '백련이 요괴화된 후') from a particular scenario in its examples. This scenario pollution can bias the LLM's generation or interpretation when working on different stories or genres.
  - fix: Replace specific character names and plot-specific transformations with abstract placeholders like 'Character A', 'Character B', or '<character_name>'.

## `prompts/_base/shot_director/4.202605121200/system.md`

- `15-33` **P1 / llm_closed_list_instruction**
  - evidence: Gaze-target close-up 패턴... 명시적 off-camera/off-screen phrase... 차단(blocking) 패턴... Reaction-only 패턴
  - why: The prompt defines visibility logic (visible_entity_ids membership) using specific Korean/English phrase patterns and grammatical structures, forcing the LLM to act as a brittle string-pattern classifier for open-world visual meaning.
  - fix: Replace specific phrase lists and grammatical templates with high-level semantic instructions regarding camera framing and character presence.

## `prompts/_base/shot_director/5.202605131800/system.md`

- `31-49` **P1 / llm_closed_list_instruction**
  - evidence: Gaze-target close-up 패턴 (X[를을] (응시하|...)), 명시적 off-camera/off-screen phrase, 차단(blocking) 패턴, Reaction-only 패턴
  - why: The prompt instructs the LLM to use specific Korean and English string patterns and phrase lists to determine if an entity is physically visible in the frame. This turns semantic visual analysis into brittle keyword/pattern matching, which fails to capture the variety of natural language descriptions and biases the LLM towards specific phrasing.
  - fix: Replace pattern-based instructions with high-level semantic criteria for visibility. Instead of providing regex-like strings, describe the visual logic (e.g., 'if the character is the subject of a close-up while looking at another, the target is off-camera') and allow the LLM to apply its reasoning.

## `prompts/_base/shot_essence_extraction/1.202604281800/system.md`

- `25-57` **P1 / llm_closed_list_instruction**
  - evidence: 폐허, 깨진 유리, 핏자국 ... 사망/부상/의식불명 인물의 자세는 essence ... 그 인물 옆 혈흔은 atmospheric
  - why: The prompt instructs the LLM to classify open-world visual elements into categories (essence vs atmospheric) based on a closed list of specific props and states (bloodstains, ruins, death). This creates brittle semantic routing that may fail for shots where these elements are the primary focus or intended to be handled differently by the pipeline.
  - fix: Replace specific prop/state examples with abstract visual priority rules (e.g., 'primary narrative focus' vs 'environmental context') to allow for flexible classification across different genres.

- `39-49` **P2 / scenario_dependent_prompt**
  - evidence: 민숙이 거실 바닥에 엎어진 채 누워있다
  - why: The prompt uses a specific character name ('민숙' - Minsuk) and a concrete scenario in its examples, which can bias the LLM towards specific character types or settings in future generations.
  - fix: Replace specific names with generic placeholders like '인물 A' or '<character_name>'.

## `prompts/_base/shot_essence_extraction/2.202604290900/system.md`

- `13-83` **P2 / llm_closed_list_instruction**
  - evidence: 혈흔, 깨진 유리, 부상 흔적, 사망/부상/의식불명 인물의 자세
  - why: The prompt instructs the LLM to classify specific open-world visual tropes and character states into the 'essence' category based on a closed list of examples to compensate for pipeline limitations (chain bg). This creates a brittle semantic classifier within the prompt.
  - fix: Define the 'essence' category by its functional role (e.g., 'elements that change per shot and are not handled by background consistency') rather than a list of specific tropes.

- `44-70` **P2 / scenario_dependent_prompt**
  - evidence: 민숙, 인형 백팩, 수리영
  - why: Concrete names ('민숙', '수리영') and specific props ('인형 백팩') from a particular scenario are used as examples in a base prompt, which can bias the LLM's extraction for unrelated stories.
  - fix: Replace specific names with generic placeholders like '여인', '남성', or '인물A' and props with generic terms like '가방' or '물건'.

## `prompts/_base/shot_essence_extraction/3.202605081814/system.md`

- `13-83` **P2 / llm_closed_list_instruction**
  - evidence: 혈흔, 깨진 유리, 부상 흔적
  - why: The prompt instructs the LLM to classify specific visual props (bloodstains, broken glass, injury marks) as 'essence' rather than 'atmospheric' to bypass technical limitations of the background consistency system (chain bg). This creates a semantic classifier based on a closed list of props.
  - fix: Define the 'essence' category using abstract criteria for 'one-time event consequences' or 'irreversible state changes' rather than listing specific props like blood or glass.

- `44-66` **P2 / scenario_dependent_prompt**
  - evidence: 거실 바닥에 엎어진 채 누워있다, 인형 백팩
  - why: The prompt uses concrete scenario examples (a woman lying on a living room floor, a doll backpack) to illustrate classification and ID-to-name mapping. These specific props and settings can bias the LLM's extraction logic toward similar tropes or specific object types in arbitrary future scenarios.
  - fix: Replace concrete scenario examples with more generic or abstract placeholders (e.g., 'a person performing an action with a specific prop') to avoid biasing the model.

## `prompts/_base/shot_extract/10.202604151200/system.md`

- `14-19` **P1 / semantic_string_judgment**
  - evidence: 시간 연결어 절대 금지... ~하자, ~하면서, ~하며, ~하고, ~한 뒤, ~한 후, ~하고 나서... and then, while ~ing, after ~ing, as ~
  - why: The prompt defines a semantic classifier for 'mixed moments' based on a brittle list of natural language substrings. This forces the LLM to avoid specific linguistic patterns to satisfy a visual constraint, which is a form of pattern-based semantic judgment that can lead to unnatural descriptions or missed multi-moment detections.
  - fix: Define the 'still moment' requirement conceptually and provide positive/negative visual examples of atomic vs. sequential actions instead of blacklisting specific substrings.

- `35-51` **P2 / scenario_dependent_prompt**
  - evidence: 외계인/귀신/돌연변이... 나이 변화, 변장/성형 전후, 빙의... 인간→동물, 인간→비인간형... 부상, 출혈, 창백해짐, 피멍, 화상... 눈 색, 비늘, 손톱/송곳니, 꼬리
  - why: The prompt includes concrete scenario-specific tropes (aliens, ghosts, mutants, possession, specific injuries, fangs, etc.) to define the boundaries of 'humanoid' and 'transformation'. These examples pollute the base prompt with genre-specific assumptions that may bias the model's interpretation of arbitrary scenarios.
  - fix: Replace specific genre tropes with abstract categories (e.g., 'structural identity changes' vs 'temporary physical states') and move concrete examples to a separate, scenario-specific configuration.

## `prompts/_base/shot_extract/10.202604151200/user.md`

- `18-20` **P1 / llm_closed_list_instruction**
  - evidence: 시간 연결어 절대 금지: '~하자' / '~하면서' / '~하며' / '~하고' / '~한 뒤' / '~한 후' / '~하고 나서', 영어 금지: 'and then', 'while ~ing', 'after ~ing', 'as ~', 'before ~', 진행형 묘사 금지: '당기고 있는' -> '쥔 채 멈춘'
  - why: The prompt uses a brittle list of linguistic tokens (conjunctions and progressive tense) to define the visual/temporal boundary of a 'Shot'. This forces the LLM to perform semantic classification based on surface-level string patterns rather than the underlying concept of a single moment, which may lead to false negatives or awkward phrasing.
  - fix: Replace the forbidden phrase list with a few-shot approach showing diverse examples of atomic vs. non-atomic shots, and instruct the LLM on the conceptual definition of a single camera frame.

- `49-63` **P2 / scenario_dependent_prompt**
  - evidence: 빙의로 얼굴이 바뀜, 인간→동물, 비늘, 손톱/송곳니, 꼬리, 한국인 경찰, 동양인 노파
  - why: The prompt contains concrete scenario-specific examples (fantasy/horror tropes like 'possession' and 'scales', and specific ethnicities like 'Korean/Asian') within general rules for character transformation and unnamed character description. This biases the LLM towards specific genres and cultures in a base prompt intended for arbitrary scenarios.
  - fix: Replace scenario-specific examples with abstract placeholders (e.g., 'Character A (Transformed)', 'Character B (Disguised)') or generic physical descriptions that do not imply a specific genre or ethnicity.

## `prompts/_base/shot_extract/11.202604201230/system.md`

- `15-18` **P1 / llm_closed_list_instruction**
  - evidence: "~하자", "~하면서", "and then", "while ~ing", "after ~ing", "as ~"
  - why: The prompt defines the semantic concept of a 'still moment' (the core task) by blacklisting specific linguistic patterns. This is brittle because it relies on token-level matches to infer temporal duration/motion, which can lead to false positives or missed dynamic descriptions that use different phrasing.
  - fix: Replace the phrase list with a semantic definition of temporal singularity (e.g., 'a single point in time with zero duration') and provide contrastive examples of static vs. dynamic descriptions.

- `35` **P2 / scenario_dependent_prompt**
  - evidence: 인간형(외계인/귀신/돌연변이 포함)이면 인종/국적을 반드시 포함
  - why: The prompt contains concrete scenario-specific examples (aliens, ghosts, mutants) and mandates attributes (race/nationality) that may not be applicable to all genres or scenarios, potentially biasing the LLM to invent irrelevant details.
  - fix: Use abstract terms like 'humanoid entities' and instruct the LLM to include 'relevant physical or cultural identifiers' only when appropriate for the specific scenario context.

- `42-50` **P1 / llm_closed_list_instruction**
  - evidence: "나이 변화, 분장/변장 전후", "부상, 얼룩, 창백해짐, 멍, 화상"
  - why: This section uses a hardcoded list of examples to define the semantic boundary between a 'transformation' (which requires special notation) and a 'temporary state'. This functions as a brittle classifier for a behavior-changing notation (parentheses) that likely affects downstream ID or outlook logic.
  - fix: Define 'transformation' semantically (e.g., 'fundamental change to the entity's base identity or species') and 'temporary state' (e.g., 'transient visual overlays') rather than relying on a manual list of allowed/disallowed words.

## `prompts/_base/shot_extract/11.202604201230/user.md`

- `18-19` **P1 / llm_closed_list_instruction**
  - evidence: 시간 연결어 절대 금지: "~하자" / "~하면서" / "~하며" / "~하고" / "~한 뒤" / "~한 후" / "~하고 나서", 영어 금지: "and then", "while ~ing", "after ~ing", "as ~", "before ~"
  - why: The prompt uses a closed list of temporal connectors as a semantic classifier to enforce the 'single moment' rule. This forces the LLM to perform string-based semantic routing rather than understanding the visual simultaneity of the scene.
  - fix: Replace the phrase list with a conceptual instruction to avoid sequential actions or multiple verbs, and rely on the 'single verb/state' rule (line 17) without brittle keyword bans.

- `63` **P2 / scenario_dependent_prompt**
  - evidence: "한국인 경찰", "동양인 노파"
  - why: The prompt includes concrete demographic and role examples (Korean police, Asian old woman) to illustrate how to describe unlisted characters. These specific examples can bias the LLM toward certain ethnicities or archetypes in arbitrary future scenarios.
  - fix: Use abstract placeholders or more diverse, non-specific examples like "[Race/Nationality] [Occupation/Role]" to avoid demographic bias.

## `prompts/_base/shot_extract/9.202604081200/user.md`

- `31-42` **P1 / llm_closed_list_instruction**
  - evidence: 변형이란 얼굴이 크게 달라지거나... 나이 변화, 변장/성형 전후, 빙의... 괄호 표기하지 않는 것: 부상, 출혈, 창백해짐, 피멍, 화상... 부분적 변화: 눈 색 변화, 비늘 올라옴...
  - why: This defines a semantic classifier that instructs the LLM to distinguish between 'Transformation' and 'State' based on a closed list of visual examples. This logic determines whether the output uses parentheses, which likely acts as a routing signal for downstream image generation or character consistency logic. It is brittle and subjective.
  - fix: Move this classification logic to a structured field in the schema (e.g., an enum for 'visual_state_type') rather than relying on the LLM to apply complex semantic rules to format a natural language string.

- `47` **P2 / scenario_dependent_prompt**
  - evidence: 예: '한국인 경찰', '동양인 노파'
  - why: The prompt uses specific ethnic and national examples ('Korean', 'Asian') for describing extras. This can bias the LLM towards these specific demographics even when the input scenario might be set in a different cultural or geographical context.
  - fix: Use abstract placeholders like '[Race/Nationality] [Occupation]' or a more diverse set of examples that cover various contexts.

## `prompts/_base/shot_selection/4.202604191600/system.md`

- `54-65` **P1 / llm_closed_list_instruction**
  - evidence: 연결 순간 단독 선택 금지, 일상 이동 남용 금지, before+during+after 모두 선택 금지, 대사만 오가는 반복 정면 샷, 접촉 직전
  - why: The prompt uses a closed list of semantic scenario patterns (e.g., 'approaching before contact', 'repetitive dialogue shots') as mandatory exclusion criteria. This is prompt-side semantic routing that attempts to classify open-world visual meaning through a fixed set of phrase-like categories.
  - fix: Move these semantic rules into a structured evaluation step where the LLM identifies shot attributes (e.g., 'is_transition', 'is_repetitive_dialogue') as boolean flags rather than relying on a list of prohibited scenario descriptions.

- `71-76` **P2 / schema_or_enum_drift**
  - evidence: 서사 High / 시각 High — <왜 이 순간이 서사 전환점인지>
  - why: The prompt instructs the LLM to encode structured metadata (Narrative/Visual weight enums) into a natural language string field ('reason'). Line 76 further enforces this by telling the LLM to 'give up selection' if the reason cannot be formulated this way, creating a brittle string-based logic gate that drifts from a proper structured schema.
  - fix: Separate the 'reason' field into structured enum fields (narrative_weight, visual_expressibility) and a separate natural language 'justification' field.

## `prompts/_base/shot_selection/4.202604191600/user.md`

- `18-23` **P2 / schema_or_enum_drift**
  - evidence: Low 서사 샷, reason: 서사 High 또는 Medium / 시각 High 또는 Medium
  - why: The prompt mandates a closed-list semantic classification (Low/Medium/High) for narrative and visual importance. Line 18 uses 'Low' as a hard exclusion filter, and line 23 requires these labels to be embedded in a natural language string. This forces downstream consumers to use string parsing to extract structured priority data and creates a brittle contract between the prompt and the parser.
  - fix: Define 'narrative_importance' and 'visual_importance' as explicit enum fields in the output schema instead of embedding them in the 'reason' string.

## `prompts/_base/shot_staging/10.202605141617/schema.json`

- `11-23` **P2 / schema_or_enum_drift**
  - evidence: perspective, perception_mode, angle
  - why: These fields define specific allowed values (e.g., subjective_pov, direct, facing_camera) within their descriptions but are typed as generic strings. This creates a contract that is not enforced by the JSON schema validator, leading to potential drift between prompt instructions and code expectations.
  - fix: Convert these string fields into formal JSON enums using the values listed in their descriptions.

- `25` **P1 / semantic_string_judgment**
  - evidence: "gaze_target": {"type": "string", "description": "... 'unconscious', 'dead', 'severely_injured'"}
  - why: The gaze_target field is used as an overloaded semantic channel to communicate character physical states (unconscious, dead, injured) rather than just spatial targets. This forces downstream logic to parse these states from a string field to determine character behavior or reference policy.
  - fix: Move physical state indicators to a separate 'character_state' or 'status' field and use a formal enum for gaze targets.

## `prompts/_base/shot_staging/10.202605141617/system.md`

- `99` **P2 / scenario_dependent_prompt**
  - evidence: courtroom oath, funeral farewell, roll call, speech podium, wedding vow
  - why: The prompt uses concrete, culturally specific scenario examples to define exceptions for a pose rule. This biases the LLM toward these specific tropes when deciding if a static pose is appropriate, potentially limiting creativity in other contexts.
  - fix: Replace specific scenario names with abstract criteria, such as 'formal ceremonies' or 'structured group formations'.

- `131-138` **P1 / schema_or_enum_drift**
  - evidence: gaze_target: distant, void, closed, unconscious, dead, severely_injured
  - why: The gaze_target field is overloaded to carry both spatial directions and complex physical/medical states (dead, unconscious). It also uses multiple synonyms (distant/void) which suggests downstream code relies on exact string matching for semantic state, creating a brittle contract.
  - fix: Separate physical state (e.g., character_status) from spatial gaze direction. Use a formal enum for status and ensure the gaze field only contains spatial targets or coordinates.

- `164-170` **P2 / llm_closed_list_instruction**
  - evidence: directionality_class: content_surface, reflective_surface, transparent_surface, directional_3d, non_directional
  - why: This instruction forces the LLM to map arbitrary open-world objects into a closed set of technical categories based on their visual function. This is a semantic classification task that is brittle when applied to diverse props and backgrounds.
  - fix: Move this classification to a dedicated metadata lookup or allow the LLM to describe the object's visual properties in natural language for a more robust downstream processor.

- `214-227` **P2 / llm_closed_list_instruction**
  - evidence: reason: movement_direction, points_to_anchor, looks_to_anchor, shared_space_relation, required_background_position, primary_subject_isolation
  - why: The LLM is required to categorize the complex spatial intent of a shot into a single enum value. This is a semantic classifier that may fail to capture nuanced or overlapping spatial requirements.
  - fix: Allow multiple reasons or use a more descriptive field that doesn't force a single-choice classification of spatial logic.

## `prompts/_base/shot_staging/11.202605150319/schema.json`

- `16-28` **P2 / schema_or_enum_drift**
  - evidence: perspective, perception_mode, angle
  - why: These fields define a closed set of valid categories within their prose descriptions (e.g., 'subjective_pov', 'hallucination', 'facing_camera') but do not enforce them using the JSON 'enum' keyword. This creates a brittle contract where downstream code expects specific strings that are not validated by the schema itself.
  - fix: Convert the listed values in the descriptions into formal JSON 'enum' arrays for each field.

- `30` **P1 / semantic_string_judgment**
  - evidence: gaze_target: ..., 'unconscious', 'dead', 'severely_injured'
  - why: The gaze_target field is used as an overloaded semantic channel to communicate character physical states (unconscious, dead, injured) using magic strings. This likely drives downstream logic such as reference selection or pose enforcement through brittle string matching on a field intended for spatial orientation.
  - fix: Move physical state to a dedicated 'character_state' enum field and restrict 'gaze_target' to spatial targets or 'closed' eyes.

## `prompts/_base/shot_staging/11.202605150319/system.md`

- `121-123` **P2 / schema_or_enum_drift**
  - evidence: "closed", "unconscious", "dead", "severely_injured"
  - why: The gaze_target field is overloaded to carry non-spatial semantic states. This forces downstream logic to parse a spatial target field for biological state information, which should be a separate semantic dimension.
  - fix: Separate character physical/biological state into a dedicated schema field and keep gaze_target strictly for spatial entities or directions.

- `150-155` **P2 / llm_closed_list_instruction**
  - evidence: content_surface, reflective_surface, transparent_surface, directional_3d, non_directional
  - why: Asks the LLM to classify objects into technical categories based on their visual function in the shot. This is a semantic classifier that might be better handled by structured asset metadata rather than LLM inference from prose.
  - fix: Move directionality classification to a persistent asset database or provide clearer visual examples to reduce classification ambiguity.

- `202-213` **P2 / llm_closed_list_instruction**
  - evidence: movement_direction, points_to_anchor, looks_to_anchor, shared_space_relation, required_background_position, primary_subject_isolation
  - why: Forces the LLM to categorize the trigger for a spatial contract into a fixed list of semantic reasons. This can lead to inaccurate classification if the cinematic intent doesn't perfectly match the provided enum.
  - fix: Allow a free-text reason field or expand the enum to cover a broader range of cinematic intents.

- `225` **P2 / schema_or_enum_drift**
  - evidence: target_id is an exception... must use C## / P##
  - why: The prompt establishes a general rule to use natural language names for characters (Line 190), but the spatial contract section requires a manual override to use technical IDs to satisfy schema constraints. This creates inconsistent identification logic for the LLM.
  - fix: Unify the identification method across all prompt sections, preferably using the structured IDs required by the schema.

- `236-238` **P2 / llm_closed_list_instruction**
  - evidence: none, points_to, reaches_for, looks_toward, moves_toward
  - why: Requires the LLM to map open-world character actions to a closed set of semantic labels for spatial constraints. This is a brittle classifier for complex physical interactions.
  - fix: Use a more flexible action description or ensure the downstream consumer can handle natural language action descriptions.

## `prompts/_base/shot_staging/6.202604151200/schema.json`

- `11-38` **P2 / schema_or_enum_drift**
  - evidence: perspective (line 13), perception_mode (line 21), angle (line 38)
  - why: These fields define specific semantic categories within the description text instead of using a JSON enum. This creates a brittle contract where downstream code depends on exact string matches that are not formally enforced by the schema.
  - fix: Convert these fields from type string to enum with the listed values to ensure schema-level validation.

- `40` **P1 / semantic_string_judgment**
  - evidence: gaze_target: 'closed', 'unconscious', 'dead', 'severely_injured'
  - why: The gaze_target field is used as an overloaded semantic channel, carrying both spatial gaze information and physical/biological state. This forces downstream logic to parse gaze strings to determine character status, which is a brittle pattern-based judgment.
  - fix: Split physical state into a separate field or enum to avoid inferring biological status from gaze direction.

## `prompts/_base/shot_staging/6.202604151200/system.md`

- `35-39` **P2 / llm_closed_list_instruction**
  - evidence: 어떻게 보는가 (camera_direction에 반영): ... 환각/환영/꿈 ... 거울, 유리, 수면 ... CCTV, 휴대폰 화면 ... 기억, 회상, 투영
  - why: The prompt instructs the LLM to classify the 'perception mode' from a closed list of semantic categories and reflect them in the camera_direction prose. This is a semantic classifier list that should be handled by a structured enum rather than natural language instructions.
  - fix: Define a formal 'perception_mode' enum in the schema and map these categories to it, rather than instructing the LLM to reflect them indirectly in camera_direction prose.

- `62-71` **P1 / semantic_string_judgment**
  - evidence: gaze_target ... "closed" 또는 "unconscious" ... "dead" ... "severely_injured"
  - why: The gaze_target field is overloaded to carry physical state information (dead, injured, unconscious) which is semantically distinct from eye direction. This creates a brittle string-based contract where downstream logic must parse these specific words to understand character status, and it forces the LLM to use a single field for two different semantic concepts.
  - fix: Separate physical state (e.g., character_status: alive/injured/dead/unconscious) from visual gaze direction (e.g., gaze_direction: camera/object/character/void).

## `prompts/_base/shot_staging/7.202604181200/schema.json`

- `11-38` **P2 / schema_or_enum_drift**
  - evidence: perspective, perception_mode, angle
  - why: These fields define specific allowed values (e.g., subjective_pov, facing_camera) within the description string rather than using the JSON 'enum' property. This creates an unenforced contract that is prone to drift and requires manual string matching in downstream code, rather than relying on schema-level validation.
  - fix: Convert the lists of values in descriptions into formal JSON 'enum' arrays to ensure schema-level validation.

- `40` **P1 / semantic_string_judgment**
  - evidence: gaze_target: ... 'unconscious', 'dead', 'severely_injured'
  - why: The gaze_target field is overloaded to carry physical character states. This uses a specific string-based channel to communicate character status (dead/injured) instead of a dedicated state field, which downstream logic must then parse from a field intended for spatial orientation. This is a documented anti-pattern where a field name and its values carry divergent semantic meanings.
  - fix: Move physical states (dead, unconscious, injured) to a dedicated character_state field and keep gaze_target for spatial/entity targets.

## `prompts/_base/shot_staging/7.202604181200/system.md`

- `114-139` **P2 / schema_or_enum_drift**
  - evidence: angle: [facing_camera, ...], gaze_target: [..., "dead", "severely_injured"]
  - why: The character_angles object uses unenforced string enums for 'angle' and 'gaze_target'. Furthermore, 'gaze_target' is semantically overloaded with physical states (dead, severely_injured) that are not gaze directions. This creates a brittle semantic channel where a single field carries disparate types of information that downstream code must parse via exact string matching.
  - fix: Define 'angle' as a formal enum in the schema. Separate physical status into its own field (e.g., character_status) and use a formal enum for gaze_target directions.

- `189` **P2 / llm_closed_list_instruction**
  - evidence: camera_direction: ... 샷 타입 용어와 앵글 용어는 반드시 포함
  - why: The instruction forces the LLM to embed specific classification tokens (e.g., ECU, MS, low angle) within a natural language prose field. This establishes a contract for downstream regex-based parsing of generated descriptions to recover structured metadata, which is brittle compared to structured fields.
  - fix: Extract shot_type and camera_angle into separate structured fields in the output schema instead of embedding them in the camera_direction prose.

## `prompts/_base/shot_staging/8.202604201230/schema.json`

- `11-40` **P2 / schema_or_enum_drift**
  - evidence: perspective, perception_mode, angle, gaze_target
  - why: Categorical values for camera POV, perception mode, character angles, and gaze targets are defined only in descriptions rather than using the JSON Schema 'enum' keyword. This creates a brittle contract where downstream code (e.g., for visibility rules or reference selection) must use exact string matching on unenforced LLM outputs.
  - fix: Use JSON Schema 'enum' for fields with a fixed set of values. For gaze_target, use 'anyOf' to allow both a fixed enum and arbitrary character/object names.

- `40` **P2 / schema_or_enum_drift**
  - evidence: gaze_target: ..., 'unconscious', 'dead', 'severely_injured'
  - why: The gaze_target field is an overloaded semantic channel where physical state information (unconscious, dead, injured) is mixed with gaze direction. This forces downstream logic to parse the gaze field to determine character status or policy exemptions.
  - fix: Move physical state indicators to a separate 'character_state' or 'status' field to decouple gaze direction from physical condition.

## `prompts/_base/shot_staging/8.202604201230/system.md`

- `129-138` **P1 / semantic_string_judgment**
  - evidence: gaze_target ... "closed", "unconscious", "dead", "severely_injured"
  - why: The gaze_target field is used as an overloaded semantic channel. It mixes spatial targets (names, nouns, directions) with physical character states (death, injury, consciousness). This forces downstream logic to perform string-based classification to distinguish between where a character is looking and what their physical status is, which are fundamentally different semantic categories.
  - fix: Separate physical character states (dead, injured, unconscious) into a dedicated 'character_status' or 'physical_state' field in the schema, keeping gaze_target strictly for spatial entities or directions.

- `189` **P1 / semantic_string_judgment**
  - evidence: camera_direction: ... 샷 타입(ECU/CU/MS/WS 등) + 앵글(low/high/Dutch 등) ... 반드시 포함
  - why: The prompt requires the LLM to embed technical shot type and angle enums into a 2-3 sentence English prose field (camera_direction). This creates a brittle contract where downstream consumers must use regex or substring matching to extract structured metadata from natural language descriptions, rather than relying on structured fields.
  - fix: Define explicit 'shot_type' and 'shot_angle' fields in the JSON output schema and instruct the LLM to populate them with the canonical enum values, rather than embedding them in the prose description.

## `prompts/_base/shot_staging/9.202605121441/schema.json`

- `11-38` **P2 / schema_or_enum_drift**
  - evidence: perspective, perception_mode, angle
  - why: These fields define a specific vocabulary of allowed values in their descriptions (e.g., subjective_pov, hallucination, facing_camera) but do not use the JSON enum property. This creates a brittle contract where the LLM may produce variations that downstream string-matching logic will fail to recognize.
  - fix: Move the listed values from the description into a formal enum constraint in the JSON schema for each of these fields.

- `40` **P1 / schema_or_enum_drift**
  - evidence: "gaze_target": ... "unconscious", "dead", "severely_injured"
  - why: This is an overloaded semantic channel. The field is intended for spatial gaze targets but is used to communicate high-level character physical states (death, injury, consciousness). This forces downstream logic to infer character status from a gaze field, and these states are listed in the description rather than enforced by a schema enum.
  - fix: Separate physical status into a dedicated field (e.g., physical_status) and use a formal enum for fixed gaze tokens like 'camera', 'up', 'down'.

## `prompts/_base/shot_staging/9.202605121441/system.md`

- `129-139` **P2 / schema_or_enum_drift**
  - evidence: gaze_target ... "unconscious" ... "dead" ... "severely_injured"
  - why: The gaze_target field is overloaded to carry physical/medical state information (dead, injured, unconscious) in addition to spatial gaze targets. This creates a multi-modal semantic channel where a single field must be parsed for both entity names and state constants, which is a known debt pattern in this pipeline.
  - fix: Separate physical_state or health_status into a distinct schema field instead of overloading the gaze_target field.

- `164-170` **P2 / llm_closed_list_instruction**
  - evidence: directionality_class ... content_surface ... reflective_surface ... transparent_surface ... directional_3d ... non_directional
  - why: The prompt instructs the LLM to classify arbitrary open-world objects into a closed list of 5 semantic categories based on complex natural-language judgment criteria (e.g., whether a surface has 'meaningful content' on one side). This forces the LLM to act as a semantic classifier for visual properties that may be better handled by technical metadata or vision models.
  - fix: If these classes drive specific rendering logic, consider moving the classification to a dedicated metadata lookup or a more robust vision-language model step.

## `prompts/_base/shot_validator/1.202604181200/system.md`

- `11-15` **P1 / llm_closed_list_instruction**
  - evidence: 시간 연결어 절대 금지: "~하자", "~하면서", "~하며", "~하고", "~한 뒤", "~한 후", "~하고 나서", "~하려는 찰나", "~하기 직전", "~을 지으며", "and then", "while ~ing", "after ~ing", "as ~"
  - why: The prompt uses a closed list of linguistic patterns as a proxy for the open-world semantic concept of 'temporal sequence.' This forces the LLM to act as a brittle string-based classifier, which can lead to incorrect validation of natural language descriptions that are semantically valid but use forbidden connectors, or vice versa.
  - fix: Replace the phrase-based blacklist with high-level semantic guidelines and few-shot examples that demonstrate the difference between a single moment and a sequence, allowing the LLM to use its reasoning capabilities rather than rigid pattern matching.

## `prompts/_base/shot_validator/2.202604201230/system.md`

- `11-29` **P1 / llm_closed_list_instruction**
  - evidence: 시간 연결어 절대 금지 (~하자, ~하면서, ~하며, ~하고, ~한 뒤, ~한 후, ~하고 나서, ~하려는 찰나, ~하기 직전, ~을 지으며, and then, while ~ing, after ~ing, as ~) and linguistic rules for ~한 채/~은 채
  - why: The prompt instructs the LLM to use a specific list of temporal connectors and grammatical patterns as a hard classifier for 'still moment' violations. This forces the LLM to act as a string matcher rather than evaluating the visual semantics of the scene, which can lead to brittle validation and inconsistent results if descriptions use synonyms or complex grammar not explicitly listed.
  - fix: Replace the phrase-based blacklist with a high-level semantic instruction to identify descriptions implying temporal progression or sequential actions, relying on the '1/1000s shutter' principle rather than specific keyword matches.

## `prompts/_base/shot_validator/3.202604301730/system.md`

- `12-16` **P1 / llm_closed_list_instruction**
  - evidence: 아래 표현은 두 동작 사이의 시간 순서를 나타내므로 위반 — 재작성 대상: - "~하자", "~하면서", "~하며", "~하고", "~한 뒤", "~한 후", "~하고 나서" ... "and then", "while ~ing", "after ~ing", "as ~"
  - why: The prompt instructs the LLM to use a closed list of grammatical markers and conjunctions as a semantic classifier for temporal progression. This is brittle for open-world natural language where temporal sequence can be implied without these specific tokens, leading to inconsistent validation.
  - fix: Define the semantic requirement (e.g., 'no temporal progression or sequential actions') and provide diverse examples of violations rather than a 'forbidden' phrase list.

- `36-42` **P1 / llm_closed_list_instruction**
  - evidence: 대상 동작 카테고리 (어휘는 다양 — 원문 언어에 따라 한국어든 영어든 가능): - locomotion: running / sprinting / walking / striding / climbing ... - chasing/fleeing: chasing, fleeing, escaping
  - why: The prompt uses a closed taxonomy of motion verbs to trigger the 'mid-action freeze' logic. This creates a semantic bottleneck where actions outside this list or described with different vocabulary might bypass the required visual preservation logic.
  - fix: Instruct the LLM to identify any 'continuous physical displacement or high-momentum action' semantically, using the categories as illustrative examples rather than a trigger list.

## `prompts/_base/shot_validator/4.202605061408/system.md`

- `12-16` **P1 / llm_closed_list_instruction**
  - evidence: "~하자", "~하면서", "and then", "while ~ing", "after ~ing"
  - why: The prompt uses a closed list of linguistic patterns to classify whether a description violates the 'still moment' principle, which is a semantic judgment over open-world natural language.
  - fix: Instruct the LLM to identify temporal progression or sequential logic conceptually rather than relying on a specific list of forbidden conjunctions.

- `79-81` **P1 / semantic_string_judgment**
  - evidence: entity name 정확 일치 또는 description 안 character 표현이 entity name substring 일치
  - why: Instructs the LLM to perform entity mapping based on exact or substring matches between the description and the entity map. This is brittle for open-world character descriptions (e.g., 'the tall man' vs 'John').
  - fix: Encourage semantic mapping based on the provided entity traits and context rather than enforcing substring matching logic.

- `111-117` **P2 / llm_closed_list_instruction**
  - evidence: 찌르기/베기: stabbing, slashing..., 타격: punching, striking...
  - why: Provides a closed vocabulary for classifying 'active contact' types. While labeled as a guide, it biases the LLM toward specific verb categories when deciding how to preserve 'mid-impact' semantics.
  - fix: Describe the physical principles of active contact (force, resistance, impact) instead of providing a list of specific verbs.

- `157-161` **P1 / semantic_string_judgment**
  - evidence: 신체 부위 표현 (얼굴, 손, 다리...), 동작 동사 등장 (잡기, 보기, 말하기...)
  - why: This defines 'visible-human-action' using a brittle keyword list. This classification directly triggers a fail-fast validation rule (line 172) that enforces character ID presence.
  - fix: Define the requirement for character IDs based on the presence of any human agent or person-like entity in the scene context rather than a specific list of body parts and verbs.

## `prompts/_base/shot_validator/5.202605081700/system.md`

- `12-116` **P1 / llm_closed_list_instruction**
  - evidence: 시간 연결어 절대 금지 (~하자, ~하면서, and then, while ~ing), 대상 동작 카테고리 (locomotion, riding/driving, water/swim), Active contact freeze rule (stabbing, punching, pinning)
  - why: The prompt instructs the LLM to classify temporal flow and physical impact using closed lists of connectors and verbs. This is brittle for open-world scenario text and will fail to correctly transform shots if synonyms or complex phrasing are used.
  - fix: Replace phrase lists with high-level semantic descriptions of the desired 'still moment' state and provide diverse examples of the transformation logic rather than a keyword-based classifier.

- `80-86` **P1 / semantic_string_judgment**
  - evidence: entity name substring 일치, name / stable_traits substring 매칭
  - why: The prompt explicitly instructs the LLM to use substring matching to resolve entity IDs from natural language descriptions. This is a brittle pattern-matching approach that fails to handle semantic synonyms, nicknames, or descriptive references that do not contain the exact name string.
  - fix: Instruct the LLM to perform semantic entity resolution based on the context and traits provided in the entity map, rather than enforcing a substring match contract.

- `157-161` **P1 / llm_closed_list_instruction**
  - evidence: visible-human-action 판정 기준 (얼굴, 손, 다리, 팔, face, hand, leg, arm, 잡기, 보기, 말하기, hold, look, talk)
  - why: This section defines a semantic classifier for human presence/action based on a closed list of body parts and verbs. This classification directly drives a fail-fast/correction rule at line 172, creating a validation bypass risk if the description uses terms outside the list.
  - fix: Instruct the LLM to identify human action based on the presence of any human entity or anatomical interaction described in the scene, rather than relying on a specific keyword list.

## `prompts/_base/t2i_review/1.202604051200/entity_schema.json`

- `17-18` **P1 / blind_string_mutation**
  - evidence: target (T2I 원문에서 정확히 찾을 수 있는 치환 대상), suggestion (target을 대체할 문자열)
  - why: The schema establishes a contract for the LLM to perform blind substring replacement on natural-language T2I prompts. This is brittle because it relies on exact string matching in generated prose, which can lead to collisions or failed matches if the LLM output is slightly inconsistent with the source text.
  - fix: Transition to a structured prompt format where specific attributes are modified as discrete fields, or use a more robust patching mechanism that includes context anchors.

## `prompts/_base/t2i_review/1.202604051200/entity_system.md`

- `13` **P2 / scenario_dependent_prompt**
  - evidence: (예: "Incheon" → "인천"이어야 함)
  - why: The prompt uses a specific real-world location (Incheon) as a concrete example for a translation rule. This can bias the LLM towards specific regions or languages when evaluating proper nouns in arbitrary scenarios.
  - fix: Replace the concrete location with an abstract placeholder like [Location Name] or [Proper Noun].

- `22-24` **P1 / blind_string_mutation**
  - evidence: target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 ... suggestion: target을 대체할 문자열
  - why: This establishes a contract for the LLM to perform blind substring replacement on generated T2I prompts. This is brittle as it lacks structural context and can lead to corrupted prompts if the target string appears in multiple contexts or is partially matched.
  - fix: Use a structured edit format or return the entire corrected prompt rather than relying on exact substring matching.

## `prompts/_base/t2i_review/1.202604051200/scene_schema.json`

- `18-19` **P1 / blind_string_mutation**
  - evidence: target: T2I 원문에서 정확히 찾을 수 있는 치환 대상, suggestion: target을 대체할 문자열
  - why: The schema defines a contract for blind substring replacement within generated T2I prompts. This assumes the LLM can identify and provide an exact, unique substring for replacement, which is prone to collision or failure in natural language prose.
  - fix: Shift from substring replacement to whole-prompt regeneration or structured template updates where the LLM provides the full corrected field rather than a mutation pair.

## `prompts/_base/t2i_review/1.202604051200/scene_system.md`

- `14-17` **P1 / semantic_string_judgment**
  - evidence: 1. 국적/인종 누락 ... 2. 고유명사 번역 ... 3. 원어 어색
  - why: The prompt instructs the LLM to act as a semantic classifier for open-world concepts like nationality, cultural paraphrasing, and proper noun translation. These judgments drive the brittle target/suggestion replacement mechanism.
  - fix: Move these semantic requirements into the primary generation prompt as constraints or use a structured visual context model that explicitly tracks nationality and cultural metadata for all entities.

- `26-28` **P1 / blind_string_mutation**
  - evidence: target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 / suggestion: target을 대체할 문자열
  - why: This establishes a contract for blind substring replacement of generated T2I prompts. Downstream code or processes using these pairs will perform semantic mutations without structural awareness, risking collateral damage in the prompt prose.
  - fix: Instead of substring replacement, have the LLM output the full corrected prompt or use a structured template where specific fields (e.g., character_description, location_details) are updated independently.

## `prompts/_base/t2i_review/2.202604301730/entity_schema.json`

- `17-18` **P1 / blind_string_mutation**
  - evidence: "target": {"type": "string", "description": "T2I 원문에서 정확히 찾을 수 있는 치환 대상"}, "suggestion": {"type": "string", "description": "target을 대체할 문자열"}
  - why: The schema establishes a contract for the LLM to provide exact substrings for replacement in generated T2I prompts. This leads to blind semantic mutation where natural language prose is modified without context, risking corruption if the target string appears in multiple contexts or is part of a larger semantic unit.
  - fix: Shift from substring replacement to a structured prompt generation or full-string rewrite. If specific entities need modification, use unique identifiers or a templating system rather than searching for natural language substrings.

## `prompts/_base/t2i_review/2.202604301730/entity_system.md`

- `21-23` **P1 / blind_string_mutation**
  - evidence: target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 / suggestion: target을 대체할 문자열
  - why: This defines a contract for blind substring replacement on generated T2I prompt text. Substring-based mutation is prone to collisions and context-blind errors when modifying semantic prose.
  - fix: Transition to structured prompt updates, such as full-field rewrites or a more robust AST-based modification system, rather than raw substring replacement.

## `prompts/_base/t2i_review/2.202604301730/scene_schema.json`

- `28-29` **P1 / blind_string_mutation**
  - evidence: target: unique sub-string, suggestion: target을 대체할 문자열
  - why: The schema establishes a contract where an LLM identifies a semantic substring in generated T2I text for blind replacement. This is brittle as it relies on the LLM's ability to find a unique match and the code's blind application of the suggestion to natural language prose, which can lead to unintended side effects in the final image prompt.
  - fix: Instead of blind substring replacement, use structured prompt components or a more robust patching mechanism that operates on semantic tokens or structured fields rather than raw string search-and-replace.

## `prompts/_base/t2i_review/2.202604301730/scene_system.md`

- `3-92` **P1 / blind_string_mutation**
  - evidence: target/suggestion 형태로 치환 정보를 제공하면 시스템이 자동으로 적용합니다. ... target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 (sub-string 매치)
  - why: The prompt establishes a contract for blind substring replacement on generated T2I prompt text. This is brittle as it depends on the LLM producing exact matches for its own previous output or the input prompt, which can fail due to minor variations in punctuation or spacing.
  - fix: Use a structured edit format (e.g., JSON with specific fields to update) or a more robust diffing mechanism rather than blind substring replacement.

- `16-19` **P2 / llm_closed_list_instruction**
  - evidence: missing_ethnicity — 보통명사 인물의 국적/인종 누락 ... 보통명사 인물(직원, 경찰, 행인 등)
  - why: The prompt asks the LLM to classify 'common nouns' from an open-world scenario and enforce a specific semantic rule (adding ethnicity) based on a small example list.
  - fix: Define a formal entity classification system where 'common nouns' requiring demographic attributes are explicitly tagged in the input data.

- `31-39` **P1 / semantic_string_judgment**
  - evidence: close_framing_existing_ref ... 검출 패턴 (camera_direction에 close-framing tag 있을 때만 적용) ... "the existing X" ... "the reference X"
  - why: This rule uses a closed list of framing tags to decide whether to skip reference images and then uses specific phrase patterns to detect 'leakage' in the prompt. This is a brittle semantic classifier that attempts to infer visual reference logic from natural language substrings.
  - fix: Pass framing and reference intent as structured metadata rather than inferring it from camera direction strings and prompt prose.

- `49-78` **P1 / semantic_string_judgment**
  - evidence: physical_inconsistency ... unshared_fg_bg_actors ... 검출 패턴 — 모순 조합 ... 카메라 "low at ground/floor/quay level" + 묘사 "<surface> visible behind subject's hands"
  - why: These rules attempt to validate physical/spatial consistency and connectivity by matching specific string patterns in the camera direction against specific phrase patterns in the scene description. This is a brittle way to enforce spatial logic and will fail to catch variations or produce false positives.
  - fix: Use structured spatial metadata or a formal layout schema to validate physical consistency rather than natural language pattern matching.

## `prompts/_base/t2i_review/2.202605081200/entity_schema.json`

- `17-18` **P1 / blind_string_mutation**
  - evidence: "target": {"type": "string", "description": "T2I 원문에서 정확히 찾을 수 있는 치환 대상"}, "suggestion": {"type": "string", "description": "target을 대체할 문자열"}
  - why: The schema establishes a contract for blind substring replacement ('target' and 'suggestion') on generated T2I prompt prose. This is brittle as it relies on exact string matching within natural-language text, which can lead to incorrect mutations if the target string appears in multiple contexts or if the LLM fails to provide an exact match.
  - fix: Replace blind substring mutation with a structured update mechanism. Instead of providing raw strings for replacement, the LLM should return the full corrected prompt or identify specific structured fields/entities to be modified.

## `prompts/_base/t2i_review/2.202605081200/entity_system.md`

- `21-23` **P1 / blind_string_mutation**
  - evidence: target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 / suggestion: target을 대체할 문자열
  - why: This establishes a contract for blind substring replacement on generated T2I prompt text. LLM-generated targets are prone to collisions or partial matches that can corrupt the semantic meaning of the prompt during mutation if the target string appears in multiple contexts.
  - fix: Shift to a structured prompt reconstruction approach or use unique block identifiers for replacement instead of arbitrary substring matching.

## `prompts/_base/t2i_review/2.202605081200/scene_schema.json`

- `38-39` **P1 / blind_string_mutation**
  - evidence: target: unique sub-string, suggestion: target을 대체할 문자열
  - why: The schema establishes a contract for the LLM to identify and replace substrings within generated natural-language prompt text. This blind mutation approach is brittle and prone to errors when the same substring appears in different contexts or when the LLM fails to provide an exact match in the generated prose.
  - fix: Transition to full-text regeneration or structured attribute updates instead of substring-based patching of generated prose.

## `prompts/_base/t2i_review/2.202605081200/scene_system.md`

- `3-89` **P1 / blind_string_mutation**
  - evidence: target/suggestion 형태로 치환 정보를 제공하면 시스템이 자동으로 적용합니다 ... target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 (sub-string 매치)
  - why: The prompt establishes a contract for blind substring replacement of generated T2I prompt prose. This is brittle and can lead to malformed sentences or unintended side effects if the target string is not unique or contextually isolated.
  - fix: Instead of raw substring replacement, use a structured edit format (e.g., identifying specific entity blocks or using a diff-based approach) or have the LLM regenerate the full prompt section.

- `32-39` **P1 / semantic_string_judgment**
  - evidence: camera_direction에 close-framing tag (`ECU`, `XCU`, ...)가 하나라도 포함된 경우 ... 검출 패턴: "the existing X", "the reference X", "from the reference image"
  - why: The prompt instructs the LLM to classify visual context (reference leakage) by matching specific natural language phrases against generated prompt prose. This relies on brittle string patterns to decide whether reference-based generation logic should be bypassed.
  - fix: Use structured metadata to track reference dependencies rather than searching for 'reference' or 'existing' keywords in natural language descriptions.

- `52-56` **P1 / semantic_string_judgment**
  - evidence: 카메라 "low at ground/floor/quay level" + 묘사 "<surface> visible behind subject's hands"
  - why: This defines spatial/physical validity rules by matching specific natural language phrases in camera directions against phrases in the prompt description. This is a brittle way to enforce physical consistency that should be handled by structured spatial coordinates or higher-level scene logic.
  - fix: Define camera height and subject positioning using structured enums or numeric ranges that can be validated programmatically without relying on exact phrase matches.

## `prompts/_base/t2i_review/2.202605081600/entity_schema.json`

- `17-18` **P1 / blind_string_mutation**
  - evidence: target: {type: string, description: T2I 원문에서 정확히 찾을 수 있는 치환 대상}, suggestion: {type: string, description: target을 대체할 문자열}
  - why: This schema establishes a contract for blind substring replacement ('target' to 'suggestion') within generated T2I prompt text. This is brittle because it assumes the target string is unique and safe to replace without context, which can corrupt the prompt if the substring appears in multiple places or as part of other words.
  - fix: Shift from substring replacement to a structured update mechanism where the LLM provides the full corrected sentence or uses a more robust template-based approach.

## `prompts/_base/t2i_review/2.202605081600/entity_system.md`

- `21-23` **P1 / blind_string_mutation**
  - evidence: target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 / suggestion: target을 대체할 문자열
  - why: This defines a contract for blind substring replacement on generated prompt text. Downstream code likely uses string.replace() which can cause unintended side effects if the target string appears multiple times or in different contexts within the generated prose.
  - fix: Transition to a structured entity-based update mechanism or use unique markers/IDs to identify the specific segment of the prompt being modified instead of relying on exact substring matches.

## `prompts/_base/t2i_review/2.202605081600/scene_schema.json`

- `38-39` **P1 / blind_string_mutation**
  - evidence: "target": ... "unique sub-string", "suggestion": ... "target을 대체할 문자열"
  - why: The schema establishes a contract for blind substring replacement in natural-language T2I prompts. This is brittle because it assumes the LLM can identify a unique, safe-to-replace substring in generated prose, which often leads to collisions or broken sentences during the mutation phase.
  - fix: Move away from substring replacement for prompt fixes. Use structured prompt fields or a more robust patch format that operates on semantic tokens rather than raw strings.

## `prompts/_base/t2i_review/2.202605081600/scene_system.md`

- `3-89` **P1 / blind_string_mutation**
  - evidence: target/suggestion 형태로 치환 정보를 제공하면 시스템이 자동으로 적용합니다. ... target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 (sub-string 매치)
  - why: The system uses the LLM to identify exact substrings in generated T2I prompts for automated replacement. This is a blind mutation mechanism that can lead to broken prompts or context loss if the substring is not unique or if the LLM hallucinates the exact text.
  - fix: Instead of substring replacement, have the LLM return the full corrected prompt or use a structured edit format that operates on semantic blocks rather than raw strings.

- `16-19` **P1 / semantic_string_judgment**
  - evidence: 보통명사 인물(직원, 경찰, 행인 등)에 국적/인종이 빠진 경우. target: 인종 형용사가 누락된 보통명사 (예: "a man in a security uniform")
  - why: The LLM is instructed to identify 'common nouns' and check for missing demographic descriptors. This is a semantic classifier that relies on the LLM's interpretation of what constitutes a 'common noun' versus a 'registered character'.
  - fix: Ensure all entities in the scene are typed in the input schema so the LLM can distinguish between registered characters and background actors without relying on noun-pattern heuristics.

- `34-39` **P1 / semantic_string_judgment**
  - evidence: 검출 패턴 (camera_direction에 close-framing tag 있을 때만 적용): "the existing X", "the reference X", "from the reference image"
  - why: The prompt instructs the LLM to use a closed list of natural language phrase patterns to classify whether a prompt incorrectly assumes a reference image exists. This is brittle semantic judgment over open-world prose.
  - fix: Use a more robust semantic check that evaluates the intent of the prompt relative to the framing, rather than searching for specific 'reference' keywords.

- `52-55` **P1 / semantic_string_judgment**
  - evidence: 검출 패턴 — 모순 조합: 카메라 "low at ground/floor/quay level" + 묘사 "<surface> visible behind subject's hands"
  - why: This defines physical/spatial consistency rules based on specific phrase combinations. It forces the LLM to act as a regex-like classifier for complex visual logic, which is prone to missing variations in natural language.
  - fix: Define spatial constraints in a structured format (e.g., camera height vs. object height) and have the LLM validate against those constraints rather than matching specific phrases.

## `prompts/_base/t2i_review/3.202605121200/entity_schema.json`

- `17-18` **P1 / blind_string_mutation**
  - evidence: target (T2I 원문에서 정확히 찾을 수 있는 치환 대상), suggestion (target을 대체할 문자열)
  - why: The schema instructs the LLM to provide an exact substring ('target') from the generated T2I prompt for replacement by a 'suggestion'. This establishes a contract for blind string mutation on natural language prose, which is prone to errors if the substring appears multiple times or if the LLM fails to provide an exact match.
  - fix: Transition to a structured prompt representation where specific attributes (like ethnicity or proper nouns) are modified as data fields rather than through substring replacement on the final prose.

## `prompts/_base/t2i_review/3.202605121200/entity_system.md`

- `21-23` **P1 / blind_string_mutation**
  - evidence: target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 / suggestion: target을 대체할 문자열
  - why: This establishes a contract for blind substring replacement within generated T2I prompt prose. Relying on exact string matches for semantic updates is brittle and can lead to incorrect mutations if the target string appears in multiple contexts or if the LLM fails to provide a verbatim match.
  - fix: Replace blind substring mutation with a structured update mechanism, such as identifying specific prompt components or providing the full corrected prompt string.

## `prompts/_base/t2i_review/3.202605121200/scene_schema.json`

- `38-39` **P1 / blind_string_mutation**
  - evidence: "target": {"type": "string", "description": "T2I 원문에서 정확히 찾을 수 있는 치환 대상 (unique sub-string)"}, "suggestion": {"type": "string", "description": "target을 대체할 문자열"}
  - why: The schema establishes a formal contract for blind substring replacement of generated T2I prompt text. This is brittle because it relies on the LLM correctly identifying a 'unique sub-string' in natural language prose, which can lead to unintended mutations or failed matches if the prompt text is slightly different or contains duplicate phrases.
  - fix: Replace the substring replacement logic with a structured update mechanism or have the LLM return the full corrected version of the specific prompt field.

## `prompts/_base/t2i_review/3.202605121200/scene_system.md`

- `3-92` **P1 / blind_string_mutation**
  - evidence: target/suggestion 형태로 치환 정보를 제공하면 시스템이 자동으로 적용합니다 ... target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 (sub-string 매치)
  - why: The system uses raw substring replacement to apply LLM-suggested fixes to generated T2I prompts. This is brittle and prone to collisions or partial replacements in natural-language prose.
  - fix: Transition to a structured edit model where the LLM rewrites specific prompt blocks or the entire prompt, rather than providing raw substrings for blind replacement.

- `16-19` **P2 / llm_closed_list_instruction**
  - evidence: 보통명사 인물(직원, 경찰, 행인 등)에 국적/인종이 빠진 경우
  - why: The prompt uses a small list of example occupations as a trigger for a semantic requirement (ethnicity). This functions as a closed-list classifier for open-world character types.
  - fix: Generalize the rule to all non-registered human entities without relying on a specific list of example nouns.

- `31-32` **P1 / semantic_string_judgment**
  - evidence: camera_direction에 close-framing tag (`ECU`, `XCU`, `extreme close-up`, `MCU`, `medium close-up`, `close-up`, `CU`)가 하나라도 포함된 경우, 합성 단계는 chain_bg reference image를 자동 skip합니다
  - why: Pipeline routing (skipping background references) is decided by searching for specific framing keywords within a natural-language camera direction field. This makes a critical visual behavior dependent on brittle string matching.
  - fix: Use a structured framing enum in the shot schema and have the pipeline check the enum value instead of parsing natural-language strings.

- `34-39` **P1 / llm_closed_list_instruction**
  - evidence: "the existing X", "the reference X", "from the reference image", "preserving the same X perspective"
  - why: The prompt instructs the LLM to classify whether a prompt incorrectly assumes a reference based on a closed list of specific phrase patterns. This is a brittle semantic classifier for open-world visual descriptions.
  - fix: Instruct the LLM to identify the semantic intent of reference dependency rather than matching specific substrings.

- `52-56` **P1 / llm_closed_list_instruction**
  - evidence: 카메라 "low at ground/floor/quay level" + 묘사 "<surface> visible behind subject's hands"
  - why: It uses specific string patterns to detect complex spatial and physical inconsistencies. This approach is brittle for validating open-world camera and staging logic.
  - fix: Use high-level spatial reasoning instructions or a dedicated spatial validator rather than phrase-based contradiction rules.

## `prompts/_base/t2i_review/4.202605150957/entity_schema.json`

- `17-18` **P1 / blind_string_mutation**
  - evidence: target: T2I 원문에서 정확히 찾을 수 있는 치환 대상, suggestion: target을 대체할 문자열
  - why: The schema instructs the LLM to provide exact substrings for replacement in generated T2I prompts. This is a brittle 'blind' mutation pattern that can lead to incorrect replacements if the target string appears multiple times or in unintended contexts within the natural language prompt.
  - fix: Shift from raw substring replacement to a structured prompt assembly where specific attributes (like ethnicity or proper nouns) are tracked as metadata or separate fields, allowing for targeted updates without string searching.

## `prompts/_base/t2i_review/4.202605150957/entity_system.md`

- `21-23` **P1 / blind_string_mutation**
  - evidence: target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 / suggestion: target을 대체할 문자열
  - why: This defines a contract for blind substring replacement of generated T2I prompt text. Relying on exact substring matches for semantic fixes in natural language is brittle and can lead to incorrect mutations if the target string appears in multiple contexts or as part of other words.
  - fix: Shift from substring replacement to a structured prompt reconstruction or use unique markers/IDs for segments that require modification.

## `prompts/_base/t2i_review/4.202605150957/scene_schema.json`

- `38-39` **P1 / blind_string_mutation**
  - evidence: target: "T2I 원문에서 정확히 찾을 수 있는 치환 대상 (unique sub-string)", suggestion: "target을 대체할 문자열"
  - why: The schema establishes a protocol for blind substring replacement of generated T2I prompt text. This is brittle and can lead to semantic corruption or unintended mutations if the target string appears in multiple contexts or if the replacement disrupts the surrounding natural language structure.
  - fix: Replace blind substring replacement with a structured prompt update mechanism or a more robust diff/patch format that operates on semantic tokens or specific prompt fields.

## `prompts/_base/t2i_review/4.202605150957/scene_system.md`

- `3-89` **P1 / blind_string_mutation**
  - evidence: target/suggestion 형태로 치환 정보를 제공하면 시스템이 자동으로 적용합니다 ... target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열
  - why: This establishes a contract for blind substring replacement of generated natural-language prompt prose. If the LLM selects a non-unique or slightly different substring, the mutation will fail or corrupt the prompt.
  - fix: Move from substring replacement to a structured rewrite where the LLM provides the full corrected prompt or uses a template-based approach with stable identifiers.

- `31-32` **P1 / semantic_string_judgment**
  - evidence: close-framing tag (`ECU`, `XCU`, `extreme close-up`, `MCU`, `medium close-up`, `close-up`, `CU`)
  - why: These specific string tags in the camera direction are used as a semantic classifier to trigger logic that skips reference images and activates specific prompt cleanup rules.
  - fix: Use a structured framing enum in the shot metadata that explicitly carries a 'skip_reference' boolean or similar flag rather than inferring it from string tags.

- `34-39` **P1 / semantic_string_judgment**
  - evidence: the existing X, the reference X, from the reference image, use the X from the reference
  - why: The prompt instructs the LLM to identify 'reference leakage' by matching these specific natural-language phrase patterns in generated T2I prompts.
  - fix: Instead of post-hoc regex-like detection in the reviewer, ensure the T2I generator prompt explicitly forbids these phrases when the reference-skip flag is set.

- `52-55` **P1 / semantic_string_judgment**
  - evidence: low at ground/floor/quay level + <surface> visible behind subject's hands
  - why: The reviewer is instructed to detect physical inconsistencies by matching specific camera height phrases against visual description patterns, which is a brittle way to enforce spatial logic.
  - fix: Define spatial constraints (e.g., camera_height vs. visible_range) in the schema so that inconsistencies can be detected via coordinate/range logic rather than phrase matching.

## `prompts/_base/t2i_visual_converter/v1/system.md`

- `6-8` **P2 / scenario_dependent_prompt**
  - evidence: "Soul Ride vehicle", "Dr. Nex's laboratory", "Club House"
  - why: These examples contain concrete names and visual descriptions (futuristic, neon, underground) from a specific story world (TheRoad), which can bias the LLM's output style for unrelated scenarios even when used as negative examples.
  - fix: Replace project-specific examples with generic, genre-neutral ones (e.g., 'The Hero's Sword' or 'The Secret Base') to illustrate the rule of replacing proper nouns with visual descriptions without biasing the aesthetic.

## `prompts/_base/t2i_visual_converter/v2/system.md`

- `15-18` **P2 / llm_closed_list_instruction**
  - evidence: Three shot types only: 1. Establishing shot... 2. Relationship shot... 3. Action moment shot
  - why: This instruction forces the LLM to classify open-world visual meaning into a closed set of three semantic categories, which restricts the descriptive range for arbitrary scenes and functions as a semantic classifier.
  - fix: Change the instruction to suggest these as common examples rather than an exhaustive 'only' list, or expand the list to cover standard cinematic shot types.

- `47-87` **P2 / scenario_dependent_prompt**
  - evidence: Korean security officer, glowing human pods, mechanical devices on their necks
  - why: The base prompt contains concrete scenario-specific details (ethnicity, specific sci-fi props) that can bias the LLM's generation towards a specific story or genre even when the input screenplay differs.
  - fix: Replace scenario-specific examples with generic placeholders or diverse, neutral examples (e.g., 'a person in uniform', 'a distinctive accessory', 'a modern office').

## `prompts/_base/t2i_visual_converter/v3/system.md`

- `17-67` **P1 / blind_string_mutation**
  - evidence: 이 마커는 나중에 실제 참조 이미지로 치환됩니다 ... [엔티티명] 마커를 반드시 포함하세요
  - why: The prompt establishes a contract where the LLM must embed specific entity names in brackets within natural language prose for later string replacement. This is blind semantic mutation that relies on the LLM's ability to maintain exact string matches within generated sentences, which is brittle and prone to grammatical or hallucination errors.
  - fix: Pass entities as a structured list and have the LLM refer to them by index or ID in a separate field, rather than performing substring replacement on the final prompt prose.

- `19-49` **P2 / scenario_dependent_prompt**
  - evidence: 청록색 발광 ... 지하 극저온 저장 시설 ... [경비원]이 발광 장치들이 늘어선 어두운 시설 복도
  - why: The prompt uses concrete sci-fi and industrial scenario examples (cryogenic facility, security guard, cyan glow) to illustrate formatting rules. These specific details can bias the model's output toward these tropes even when the input scenario is from a different genre or setting.
  - fix: Replace concrete scenario examples with abstract placeholders (e.g., [Character A], [Location B]) or a wider variety of genre-neutral examples.

## `prompts/_base/t2i_visual_converter/v4/system.md`

- `16-67` **P1 / blind_string_mutation**
  - evidence: 제공된 엔티티 이름을 그대로 [] 안에 사용, [엔티티명] 마커를 반드시 포함하세요
  - why: The prompt establishes a contract for exact substring replacement of natural-language entity names within brackets. This is brittle because LLMs may alter the name, and in Korean, markers are often followed by grammatical particles (e.g., [경비원]이), which will remain after replacement (e.g., URL이), potentially corrupting the final T2I prompt.
  - fix: Use unique, language-agnostic IDs (e.g., [ENT_0], [ENT_1]) for markers and provide a separate mapping, or use a structured JSON output where entities and descriptions are separated.

- `46-49` **P2 / scenario_dependent_prompt**
  - evidence: 지하 극저온 저장 시설, 투명 원통형 캡슐, 산업용 파이프, 발광 장치들이 늘어선 어두운 시설 복도
  - why: The examples use highly specific sci-fi/industrial scenario details. These concrete props and settings can bias the LLM's generation towards these tropes even when the input scenario is in a different genre or era.
  - fix: Replace specific sci-fi examples with a broader set of generic examples across different genres (e.g., a park, a historical room, a modern street) to demonstrate the structural rules without biasing the content.

## `prompts/_base/variation_recommender/v2/system.md`

- `6` **P2 / schema_or_enum_drift**
  - evidence: Variation types: angle (camera position change), color (lighting/color grading), angle+color (both), or none (no variation needed).
  - why: The list of allowed variation types omits 'composition', which is defined as one of the three primary systems in lines 21-26. This creates a drift between the top-level classification enum and the actual output fields available to the LLM, potentially leading to routing errors or missing recommendations.
  - fix: Update the variation types list to include 'composition' and all valid combinations (e.g., angle+composition, composition+color, etc.) to match the system architecture.

- `23` **P1 / llm_closed_list_instruction**
  - evidence: Examples: "tight close-up on face", "wide establishing shot", "over-shoulder framing", "low angle hero shot"
  - why: The examples for 'composition' contain terms that belong to the 'angle' system as defined in lines 14-19. Specifically, 'low angle' is a vertical tilt (line 16) and 'wide' is a zoom/focal length property (line 17). Including these in the composition text field contradicts the 'CRITICAL' separation rule (line 10, 22) and instructs the LLM to bypass the dedicated 3D angle system by putting spatial data into the i2i text prompt.
  - fix: Refine the composition examples to exclude camera position and zoom properties. Use terms strictly related to framing and lens character that are not covered by the 3D angle parameters.

## `prompts/_base/visual_world_rules/1.202603231200/rules_schema.json`

- `9` **P2 / schema_or_enum_drift**
  - evidence: "rule_type": {"type": "string", "description": "규칙 유형 (possession, transformation, ghost, time_period, costume, technology 등)"}
  - why: The schema specifies a set of semantic categories (possession, transformation, ghost, etc.) within a description string instead of using a formal JSON enum. This creates a contract for LLM classification that is not structurally enforced, leading to potential drift where the LLM produces synonyms or variations that downstream logic (expecting exact keys) cannot handle.
  - fix: Define 'rule_type' as a JSON enum containing the canonical category strings to ensure structured validation and consistent downstream routing.

## `prompts/_base/visual_world_rules/1.202603231200/system.md`

- `16-22` **P2 / scenario_dependent_prompt**
  - evidence: 조선시대, 한복
  - why: The prompt includes culture-specific examples (Joseon Dynasty, Hanbok) in a base rule extractor. These can bias the LLM toward Korean historical contexts even when analyzing scenarios from other cultures or eras.
  - fix: Replace culture-specific examples with more generic ones (e.g., 'Historical Era', 'Traditional Clothing') or move them to a scenario-specific configuration layer.

- `28` **P2 / llm_closed_list_instruction**
  - evidence: rule_type은 다음 중 선택: possession, transformation, ghost, projection, superpower, body_deformation, time_period, costume, technology, other
  - why: The prompt forces open-world visual phenomena into a closed set of 10 semantic categories. This functions as a classifier that likely drives downstream logic (e.g., character ID swapping for 'possession'), creating a brittle link between natural language analysis and system behavior.
  - fix: Define these categories in a shared schema and use the schema to validate LLM output. Ensure the pipeline handles 'other' or unknown types gracefully without failing.

## `prompts/_base/visual_world_rules/2.202603231200/rules_schema.json`

- `20` **P2 / scenario_dependent_prompt**
  - evidence: 예: A가 B의 몸을 소울라이드 중이면 A는 물리적 존재가 아님
  - why: The schema description for 'director_notes' contains a concrete, project-specific scenario example ('soul-ride' / 소울라이드). This functions as scenario pollution within a base schema definition and may bias the LLM's reasoning about physical presence in unrelated stories.
  - fix: Replace the specific 'soul-ride' example with a generic placeholder or a more universal concept, such as 'If a character is a hologram or a ghost, they are not a physical entity'.

## `prompts/_base/visual_world_rules/2.202603231200/system.md`

- `28` **P2 / llm_closed_list_instruction**
  - evidence: rule_type은 다음 중 선택: possession, transformation, ghost, projection, superpower, body_deformation, time_period, costume, technology, other
  - why: The LLM is instructed to classify open-world supernatural and technical phenomena into a closed set of semantic tokens. This creates a brittle interface where novel scenario types must be forced into existing categories or labeled as 'other', losing semantic precision.
  - fix: Allow the LLM to generate descriptive category names or move the enum definition to a shared schema that is dynamically injected based on the project type.

- `52` **P2 / scenario_dependent_prompt**
  - evidence: 인물의 기본 국적/인종 (예: "All human characters are Korean unless stated otherwise.")
  - why: Hardcoding 'Korean' as the specific example for nationality in a base prompt can bias the LLM toward that nationality even when the scenario context differs, especially as it is part of a 'must include' instruction block.
  - fix: Replace the concrete example with a generic placeholder such as 'All human characters are [Nationality] unless stated otherwise.'

## `prompts/_base/visual_world_rules/3.202604161200/rules_schema.json`

- `9` **P2 / schema_or_enum_drift**
  - evidence: possession, transformation, ghost, time_period, costume, technology
  - why: Semantic categories are listed in the description as examples rather than being enforced via a JSON 'enum' property, creating a brittle string-based contract for downstream logic.
  - fix: Move these categories into a formal 'enum' field in the JSON schema to ensure valid and consistent output.

- `20` **P2 / scenario_dependent_prompt**
  - evidence: A가 B의 몸을 소울라이드 중이면 A는 물리적 존재가 아님
  - why: The description contains a concrete story-specific concept ('soul-ride') as an example, which biases the model's logic for physical presence toward specific supernatural scenarios.
  - fix: Replace the specific 'soul-ride' example with a generic physical state example, such as 'Character A is a hologram' or 'Character A is a reflection'.

## `prompts/_base/visual_world_rules/3.202604161200/system.md`

- `28` **P2 / schema_or_enum_drift**
  - evidence: rule_type은 다음 중 선택: possession, transformation, ghost, projection, superpower, body_deformation, time_period, costume, technology, other
  - why: The prompt defines a closed list of semantic categories for the LLM to classify open-world scenario phenomena. This creates a contract that must be manually synchronized with downstream code and limits the LLM's ability to describe novel visual phenomena not covered by these 10 buckets.
  - fix: Define these categories in a shared schema (e.g., JSON Schema or a central Enum) and reference them in the prompt, or allow the LLM to generate descriptive tags instead of a closed list.

- `52` **P2 / scenario_dependent_prompt**
  - evidence: All human characters are Korean unless stated otherwise.
  - why: This hardcodes a specific ethnicity bias into a base prompt, which may not apply to all scenarios and can lead to incorrect visual generation for non-Korean contexts without explicit overrides.
  - fix: Move project-specific defaults like ethnicity or nationality to a configuration variable or a project-specific prompt layer rather than the base system prompt.

## `prompts/_base/visual_world_rules/4.202604300936/rules_schema.json`

- `9` **P2 / schema_or_enum_drift**
  - evidence: rule_type: (possession, transformation, ghost, time_period, costume, technology 등)
  - why: Semantic categories are listed in the description but not enforced as a JSON enum. Downstream logic likely relies on these exact strings to handle specific visual rules (e.g., ghost transparency or possession effects), creating a brittle contract between the LLM and the pipeline.
  - fix: Define 'rule_type' as an enum containing the supported semantic categories to ensure strict validation and reliable downstream routing.

- `20` **P2 / scenario_dependent_prompt**
  - evidence: 예: A가 B의 몸을 소울라이드 중이면 A는 물리적 존재가 아님
  - why: The example uses a specific story mechanic ('soul-ride') to explain a general concept of physical presence. This introduces scenario-specific pollution into a base schema that could bias the LLM's reasoning in unrelated genres or stories.
  - fix: Replace the specific 'soul-ride' example with a generic one, such as 'Character A is a hologram or a reflection'.

## `prompts/_base/visual_world_rules/4.202604300936/system.md`

- `28` **P2 / llm_closed_list_instruction**
  - evidence: rule_type은 다음 중 선택: possession, transformation, ghost, projection, superpower, body_deformation, time_period, costume, technology, other
  - why: This forces the LLM to map arbitrary visual phenomena from a scenario into a fixed set of semantic categories. This classification is likely used for downstream routing or visual policy enforcement, but the closed list cannot capture the full range of open-world visual concepts (e.g., glitch effects, abstract entities).
  - fix: Allow the LLM to provide a descriptive tag or use a more extensible schema that does not rely on a hardcoded list of semantic buckets.

- `45-46` **P2 / scenario_dependent_prompt**
  - evidence: 작품 고유명사를 사용하되, 범용 규칙이 아닌 이 작품에서만 필요한 판단 기준을 작성하세요.
  - why: The prompt explicitly instructs the LLM to generate judgment criteria for physical presence that include scenario-specific proper nouns. This creates a brittle logic block that is tightly coupled to a specific story, making it difficult to audit or generalize across different episodes or series.
  - fix: Instruct the LLM to generate abstract physical presence rules based on entity roles or states rather than specific names, or move the logic to a centralized, scenario-agnostic validator.

- `64` **P2 / scenario_dependent_prompt**
  - evidence: All human characters are Korean unless stated otherwise.
  - why: This is a concrete cultural/ethnic bias provided as a primary example for the visual style summary. Providing such a specific example can bias the LLM to enforce this nationality even when the scenario text is neutral or implies a different context.
  - fix: Use a more abstract placeholder like '[Nationality/Race]' or provide multiple diverse examples to avoid biasing the model toward a single cultural trope.

## `prompts/_base/visual_world_rules/5.202605011300/rules_schema.json`

- `9` **P2 / schema_or_enum_drift**
  - evidence: rule_type": {"type": "string", "description": "규칙 유형 (possession, transformation, ghost, time_period, costume, technology 등)"}
  - why: The description defines a set of semantic categories (possession, ghost, etc.) that likely drive downstream logic, but they are not enforced as a JSON enum, creating a risk of drift and invalid values.
  - fix: Define 'rule_type' as an enum with the allowed values.

- `20` **P2 / scenario_dependent_prompt**
  - evidence: 예: A가 B의 몸을 소울라이드 중이면 A는 물리적 존재가 아님
  - why: The example uses 'soulride' (소울라이드), which is a specific plot concept from a particular story, polluting the base schema with scenario-specific logic.
  - fix: Use a generic example for non-physical presence, such as 'A is a ghost' or 'A is a reflection'.

## `prompts/_base/visual_world_rules/5.202605011300/system.md`

- `31-51` **P1 / llm_closed_list_instruction**
  - evidence: rule_type: possession, transformation, ghost, projection, superpower, body_deformation
  - why: The prompt forces the LLM to classify complex open-world scenario concepts into a closed list of semantic categories, each tied to hard-coded visual behaviors (e.g., always drawing the host's face for possession).
  - fix: Allow the LLM to describe visual requirements naturally or use a more flexible metadata structure that doesn't rely on a fixed semantic enum for visual routing.

- `68-72` **P1 / semantic_string_judgment**
  - evidence: 환각/현시 대상은 다른 인물이 등장하는 씬에서는 화면에서 제거한다
  - why: These instructions ask the LLM to generate semantic rules that determine entity visibility and membership based on scenario context (e.g., hallucinations). This creates a natural-language contract for visual routing that is brittle and difficult to validate.
  - fix: Replace natural-language visibility rules with structured entity-state flags (e.g., visibility: 'subjective_only') that can be processed by the pipeline without semantic interpretation.

- `98` **P2 / scenario_dependent_prompt**
  - evidence: All human characters are Korean unless stated otherwise.
  - why: This is a concrete scenario-specific bias (ethnicity/nationality) hard-coded into a base prompt, which may bias generation for non-Korean scenarios.
  - fix: Replace the concrete ethnicity with a placeholder like <default_ethnicity> or move this requirement to a scenario-specific configuration file.

## `prompts/_base/visual_world_rules/6.202605021400/rules_schema.json`

- `9` **P2 / schema_or_enum_drift**
  - evidence: rule_type: possession, transformation, ghost, time_period, costume, technology 등
  - why: The rule_type field uses a string type but lists specific semantic categories in the description. This creates a contract where the LLM is expected to classify rules into a closed set of types without schema enforcement, leading to potential drift or parsing errors in downstream logic.
  - fix: Change rule_type to an enum containing these categories to ensure structured classification and validation.

- `20` **P2 / scenario_dependent_prompt**
  - evidence: 예: A의 영혼이 B의 몸에 전이된 경우 A는 물리적 존재가 아님
  - why: The example provided for director_notes uses a highly specific supernatural scenario (soul transfer). While intended as an example, concrete scenario pollution in schema descriptions can bias the LLM's interpretation of physical presence rules toward specific tropes.
  - fix: Replace the specific soul-transfer example with a more abstract or generic logic example, such as 'if an entity is a hologram or a memory'.

## `prompts/_base/visual_world_rules/6.202605021400/system.md`

- `51` **P1 / llm_closed_list_instruction**
  - evidence: rule_type: possession, transformation, ghost, projection, superpower, body_deformation, time_period, costume, technology, other
  - why: This forces the LLM to map complex, open-world narrative tropes into a fixed set of semantic categories. These categories then trigger hardcoded visual logic (e.g., the possession rule in line 31), which is brittle when applied to diverse storytelling.
  - fix: Allow the LLM to describe the visual phenomenon naturally or use a more extensible schema that defines visual properties (transparency, facial identity, etc.) rather than narrative tropes.

- `57-73` **P1 / semantic_string_judgment**
  - evidence: director_notes (물리적 존재 여부를 판단할 때 혼동할 수 있는 유형적 원칙)
  - why: The prompt instructs the LLM to generate natural-language rules (e.g., 'hallucinations are not physical') to resolve ambiguity in physical presence. This delegates core pipeline routing and visibility logic to generated prose, which is difficult to validate and prone to drift.
  - fix: Define a structured 'visibility_policy' field with explicit flags (is_physical, is_visible_to_all, is_screen_only) rather than relying on generated 'notes' to guide the scene director.

- `98` **P2 / scenario_dependent_prompt**
  - evidence: All human characters are <region-derived demonym> unless stated otherwise.
  - why: This instruction forces a global demographic bias into the t2i_context based on a single extracted 'region' string. It assumes a monolithic ethnicity/nationality for the entire scenario, which can lead to incorrect visual generation for multi-cultural or international stories.
  - fix: Move demographic defaults to individual character metadata or allow the LLM to specify a distribution rather than a global override.

## `screenplay/extract_entities.py`

- `818-839` **P1 / semantic_string_judgment**
  - evidence: item["importance"] in {"major", "supporting"} and has_reference_value(item)
  - why: The code performs aggressive pruning of extracted entities based on hard-coded semantic labels ('importance', 'significance') and a heuristic trait count. This 'membership' decision can silently discard valid scenario data based on brittle LLM classifications or concise descriptions.
  - fix: Move pruning logic to a separate review step or allow the LLM to provide a confidence score instead of using hard-coded string filters.

- `886` **P1 / semantic_string_judgment**
  - evidence: if entity_identifiers(item) & entity_identifiers(existing_item):
  - why: Entity identity resolution across chunks is performed by checking for any overlap in normalized name or alias strings. This brittle matching fails to account for semantic similarity, spelling variations, or nicknames not explicitly listed as aliases, leading to duplicate entities in the final extraction.
  - fix: Use a cross-chunk coreference resolution step where the LLM is provided with existing entities and asked to map new mentions to them, or use vector embeddings for fuzzy identity matching.

- `973-975` **P1 / semantic_string_judgment**
  - evidence: canonical_name = entity_lookup.get((entity_type, normalize_name(entity_name))); if not canonical_name: continue
  - why: Relation participants are dropped if their names do not exactly match (after normalization) an entity name or alias extracted in the same or previous chunks. This brittle lookup causes loss of relational data due to minor naming inconsistencies in LLM output.
  - fix: Implement fuzzy name matching or a second-pass LLM resolution to link relation participants to the entity registry.

- `1026-1034` **P1 / semantic_string_judgment**
  - evidence: signature = "||".join([normalized["relation_family"], normalized["relation_type"], ...])
  - why: Relation deduplication relies on a signature that includes 'relation_type', which is a free-form string generated by the LLM. Semantically identical relations (e.g., 'is the father of' vs 'father') will result in different signatures and fail to merge, creating redundant graph edges.
  - fix: Normalize relation types to a closed vocabulary or use an LLM-based consolidation pass to merge semantically equivalent relations.

## `screenplay/extract_scene_stills.py`

- `450-480` **P1 / semantic_string_judgment**
  - evidence: similarity_score, left in right or right in left, visual_anchor_traits
  - why: The similarity_score function uses brittle substring checks and counts of overlapping natural-language traits to determine entity identity. This result directly controls visible-entity membership and entity_id assignment in the series memory, which in turn routes reference attachment and identity tags in the final image prompts.
  - fix: Use a more robust entity resolution strategy, such as LLM-based verification for ambiguous matches or a dedicated entity linking model that considers context beyond simple substring/token overlap.

- `701-712` **P1 / blind_string_mutation**
  - evidence: localize_cinematic_text, mapping.items(), localized.replace(english, translated)
  - why: The localization logic performs blind substring replacement on LLM-generated cinematic descriptions (camera and lighting blocks). This is brittle as it does not respect word boundaries and can lead to corrupted prose if technical terms overlap (e.g., 'Extreme' vs 'Extreme Close-Up') or appear as part of other words in the generated text.
  - fix: Replace blind string replacement with a structured approach where the LLM outputs canonical enums that are then mapped to localized strings, or use regex with word boundaries (\b) to ensure only whole terms are translated.

## `screenplay/prototype_episode_novel.py`

- `57-108` **P1 / scenario_dependent_code**
  - evidence: SPECIAL_ENTITY_GUARDRAILS = { "DR.NEX": { ... }, "한치호": { ... }, "은성": { ... }, "서현": { ... }, "오리엔티스": { ... } }
  - why: Hardcodes specific character names and visual guardrails into the pipeline logic. This biases the prototype builder toward a specific story and prevents it from being used for arbitrary scenarios without manual code modification.
  - fix: Move scenario-specific visual guardrails into a sidecar configuration file or include them in the entity metadata extracted from the screenplay.

- `418-420` **P2 / scenario_dependent_code**
  - evidence: cache_entity = SCRIPT_DIR / "srd_part_1_entities_v5.json"
  - why: Hardcodes paths to specific project data files ('srd part 1') for seeding analysis, which is scenario-specific behavior.
  - fix: Pass cache paths as arguments or configuration rather than hardcoding them in the analysis logic.

- `624-638` **P1 / semantic_string_judgment**
  - evidence: score += 6 if relation.get("relation_family") in DIRECT_RELATION_FAMILIES else 3
  - why: Uses a closed list of semantic relationship categories ('kinship', 'conflict', 'social', etc.) to calculate a priority score. This score determines which entities are prioritized for reference images and prompt inclusion, directly affecting visual output based on LLM-emitted semantic strings.
  - fix: Define relation families as a formal enum in the schema and use the enum values for scoring, or have the LLM emit a numerical priority score directly.

- `626` **P2 / schema_or_enum_drift**
  - evidence: {"critical": 8, "high": 5, "medium": 3, "low": 1}.get(entity_record.get("continuity_priority", "medium"), 3)
  - why: The code relies on exact string matches for a 'continuity_priority' field that is not enforced by a JSON enum in the schema, creating a brittle contract with the LLM output.
  - fix: Add 'continuity_priority' to the entity schema as an enum with these specific values.

- `861-875` **P1 / scenario_dependent_code**
  - evidence: if entity["name"] == "DR.NEX": return "철제 가면을 쓴 인간 리더..."
  - why: Contains hardcoded logic and natural-language descriptions for a specific character ('DR.NEX'), creating a direct dependency on a single story scenario.
  - fix: Use the 'description' field from the entity record or a generic template instead of hardcoding specific character names in the logic.

## `scripts/canary/g4_2_camera_wording.py`

- `48-54` **P1 / semantic_string_judgment**
  - evidence: CAMERA_WORDING_PATTERNS = [r"match.*reference.*(camera|framing|position)", ...]
  - why: The script uses brittle regex patterns to verify the presence of semantic camera-consistency instructions in generated T2I prompts. This result is used as a validation metric (degradation guard) for prompt engineering changes, making the pipeline's success dependent on specific phrasing rather than semantic intent.
  - fix: Instead of regex over generated prose, have the LLM emit a structured boolean or enum field indicating that camera consistency wording was applied, or use a more robust semantic similarity check.

## `scripts/canary/g4_2_close_forbidden.py`

- `33-47` **P1 / semantic_string_judgment**
  - evidence: CLOSE_FORBIDDEN_PATTERNS used in scan_scene_forbidden to trigger exit 1
  - why: The script performs semantic classification of generated t2i_prompt text using brittle regex patterns like 'from the reference' or 'preserving the same room perspective'. This match result directly controls a fail-fast validation gate (exit code 1), making the system's integrity dependent on specific natural-language phrasing.
  - fix: Transition from regex-based prose scanning to structured output validation where the LLM explicitly flags applied constraints, or use a semantic model to verify the absence of forbidden concepts.

## `scripts/canary/g4_3_body_part_focus.py`

- `55-244` **P1 / semantic_string_judgment**
  - evidence: BODY_PART_FOCUS_PATTERN = re.compile(r"\b(?:" + _TRIGGER_ALT + r")\s+C\d{2}(?:O\d{2})?'s\s+\w+", re.IGNORECASE) ... if args.role == "candidate" and body_part_focus_count > 0: return 1
  - why: The script classifies visual focus intent by matching natural-language trigger phrases (e.g., 'focus on', 'close on') followed by character IDs and body part words within the generated t2i_prompt. This match result directly causes the canary to fail (exit code 1), enforcing a semantic policy through brittle string matching over open-world prose.
  - fix: The prompt generation logic should output structured metadata indicating when a body-part focus is intended. The canary should then validate this structured field instead of parsing the final natural-language prompt string.

## `scripts/canary/g4_3_close_framing_face_forbidden.py`

- `63-270` **P1 / semantic_string_judgment**
  - evidence: find_forbidden_phrases uses _ID_CLOSE_FACE_FORBIDDEN_PHRASES to check t2i_prompt; if forbidden_total > 0: return 1
  - why: The script validates the semantic content of generated T2I prompts by checking for the presence of specific natural language phrases (e.g., 'his face fills the frame'). If any phrase is found, the canary fails. This is a brittle string-based classifier for open-world visual meaning that cannot handle semantic variations or context.
  - fix: Replace literal substring matching with a semantic classifier or LLM-based review that understands the visual intent of the prompt, or move the constraint enforcement into the structured schema validation if possible.

## `scripts/canary/g4_3_demographic_descriptor_present.py`

- `95-105` **P1 / semantic_string_judgment**
  - evidence: for ethnicity in _ID_ETHNICITY_COMPONENTS: if ethnicity.lower() in window: ... for age in _ID_AGE_BANDS: if age.lower() in window:
  - why: The script performs semantic classification of open-world natural language (T2I prompts) by searching for specific demographic keywords in a ±50 character window around character IDs. The result directly influences a canary ratio used to block candidate releases, making the validation process brittle and insensitive to context, synonyms, or complex phrasing that doesn't match the exact keyword list.
  - fix: Transition from post-hoc keyword searching to structured metadata tracking where demographic attributes are explicitly linked to character IDs during the prompt generation phase, or utilize an LLM-based evaluator for semantic verification.

## `scripts/canary/g4_3_reproduction_surface.py`

- `65-127` **P1 / semantic_string_judgment**
  - evidence: find_reproduction_violations(prompt) using _ID_REPRODUCTION_SURFACES
  - why: The function uses a list of natural-language keywords (e.g., mirror, screen) to infer the visual context of a generated T2I prompt. This result directly determines a validation pass/fail state (exit code 1 at line 324), making the pipeline's safety/policy enforcement dependent on brittle string matching over open-world prose.
  - fix: Instead of keyword matching on the final prompt, use structured metadata from the scene analysis phase or an LLM-based classifier to identify the presence of reproduction surfaces.

## `scripts/canary/g4_4_atmosphere_no_layout_import.py`

- `5-10` **P2 / schema_or_enum_drift**
  - evidence: Detects 7 furniture / wall / layout tokens (`furniture` / `wall position` / `room layout` / `same chair` / `same table` / `same wall` / `same window`)
  - why: The list of prohibited tokens is defined as a set of natural language strings that must be synchronized between the prompt instructions and this detector. This creates a contract based on exact string matches for visual concepts rather than a structured enum.
  - fix: Centralize these tokens into a formal enum shared by the prompt generator and the validator to prevent drift.

- `66-79` **P1 / semantic_string_judgment**
  - evidence: find_layout_imports(prompt) using _CONTINUITY_FURNITURE_LAYOUT_TOKENS
  - why: This function performs case-insensitive literal substring matches for phrases like 'room layout', 'same chair', and 'wall position' within the generated 't2i_prompt'. The result directly determines the script's exit code and validation status, making it a brittle semantic classifier that cannot distinguish between natural descriptive prose and intentional layout imports.
  - fix: Replace substring matching with a structured 'layout_preserved' boolean in the LLM output schema, or implement the LLM-based validator mentioned in the code's comments (Override O-17) to judge the prompt's intent.

## `scripts/canary/g4_4_double_description.py`

- `241-251` **P1 / semantic_string_judgment**
  - evidence: for noun in _CONTINUITY_GENERIC_PERSON_NOUNS: if noun.lower() in window: shot_count += 1
  - why: The script classifies a semantic violation ('double description') by searching for natural-language generic nouns within a character ID's proximity in the generated T2I prompt. This is brittle as it depends on an open-world list of nouns to enforce a visual/semantic constraint and directly impacts the validation pass/fail status.
  - fix: Move this check into the T2I generation logic where entity metadata is structured, or use an LLM-based semantic reviewer to identify redundant descriptions rather than relying on a brittle substring window check against a noun list.

## `scripts/canary/g4_4_view_mixing.py`

- `67-150` **P1 / semantic_string_judgment**
  - evidence: _VIEW_MIXING_FULL_BODY_VERBS, _BODY_PART_FOCUS_PATTERN, any(v in window for v in _VIEW_MIXING_FULL_BODY_VERBS)
  - why: The script classifies visual composition (view-mixing) by searching for specific natural-language verbs (stands, seated, etc.) and body-part focus patterns within generated T2I prompts. This brittle matching determines validation pass/fail and pipeline exit codes.
  - fix: Replace the regex-based proximity check with an LLM-based visual consistency validator or use structured shot-composition metadata to detect conflicting framing instructions.

## `scripts/canary/g4_5a_camera_frame_consistency.py`

- `78-160` **P1 / semantic_string_judgment**
  - evidence: _LOW_CONTRADICTION_TOKENS and _detect_violations_in_window scanning t2i_prompt
  - why: The script defines lists of natural-language keywords (e.g., 'chest', 'floor', 'ceiling', '가슴', '바닥') and uses them to perform semantic checks for spatial contradictions (Rule F) within a character window of the generated t2i_prompt. This brittle pattern-matching determines whether the validation passes or fails, which is prone to false positives/negatives in open-world scenarios.
  - fix: Replace the substring-based proximity check with an LLM-based semantic validator or a structured spatial verification step that does not rely on parsing generated natural language prose.

## `scripts/canary/g4_5a_fg_bg_shared_anchor.py`

- `183-189` **P1 / semantic_string_judgment**
  - evidence: _has_any_token(prompt, _SPATIAL_FG_BG_SEPARATION_TOKENS) ... _SPATIAL_INTERACTION_VERBS ... _SPATIAL_SHARED_ANCHOR_KEYWORDS
  - why: The script infers visual/spatial meaning (interaction, fg/bg separation, and shared anchors) from generated natural-language prompt prose using brittle substring checks. This classification determines whether a shot violates Rule G, directly affecting validation pass/fail behavior and the script's exit code.
  - fix: Replace the keyword-based heuristic with a structured LLM-based validator that understands the semantic context of the prompt, as suggested in the file's own comment at line 19.

## `scripts/canary/g4_5a_primary_framing.py`

- `70-326` **P1 / semantic_string_judgment**
  - evidence: _SPATIAL_FRAMING_CLOSE_KEYWORDS, _ID_BODY_PART_TRIGGERS, _FULL_BODY_KEYWORDS
  - why: The script uses brittle keyword lists (e.g., 'stands', '전신', 'focus on') to infer visual framing and body-part focus from natural language prompt text. This classification determines if a shot is in scope for Rule J and whether it contains a violation, directly causing the canary to fail (exit 1).
  - fix: Replace the keyword-based RO-8 algorithm with an LLM-based semantic judge (as suggested in the file's O-17 override comment) to evaluate framing conflicts in natural language prose.

## `scripts/canary/g4_5a_view_mixing_extension.py`

- `60-225` **P1 / semantic_string_judgment**
  - evidence: _VIEW_MIXING_FULL_BODY_VERBS, _FACE_CLOSE_UP_KEYWORDS, _detect_g4_4_view_mixing, _detect_two_face_close_up
  - why: The script infers visual semantics (framing conflicts and character focus) from generated natural-language prompts using brittle keyword lists and token-distance heuristics. This approach is prone to false negatives when prompts use synonyms or complex phrasing and requires manual synchronization with the prompt-generation logic. The code specifically notes that its face keyword list differs from the LLM-facing instructions, creating a drift risk.
  - fix: Replace keyword-based detection with an LLM-based validator (as suggested in line 28) or utilize structured metadata emitted during the prompt generation phase to verify rule compliance.

## `scripts/canary/g4_6_label_routing_face_substring_fix.py`

- `37-66` **P1 / semantic_string_judgment**
  - evidence: label = "previous shot at same location (SAME ROOM) — use this background as-is."; if "face framing" not in label.lower(); if not any("BACKGROUND from a previous shot (SAME ROOM)" in r for r in res.ref_roles)
  - why: The system uses natural language prose as a routing key to determine reference roles (BACKGROUND vs CHARACTER). This script specifically tests a regression where visual framing terminology ('face framing') within a background description caused incorrect semantic classification by the downstream router.
  - fix: Replace natural language routing labels with a structured enum or a dedicated classification field. The router should operate on formal identifiers rather than performing substring searches on descriptive prose.

## `scripts/regen_phase91_with_model.py`

- `233-241` **P1 / semantic_string_judgment**
  - evidence: _is_close_framing(camera_direction) ... _CLOSE_FRAMING_RE.search(camera_direction)
  - why: The function uses a regex pattern to classify visual framing from natural language 'camera_direction' strings. This classification result is used at lines 308-314 to decide whether to inject or skip background reference images ('chain_bg'). This makes the reference attachment logic brittle to variations in how framing is described in prose.
  - fix: Use a structured framing enum (e.g., CLOSE, MEDIUM, WIDE) in the shot manifest or database schema instead of performing regex searches on natural language descriptions.
