# Semantic String Debt LLM Audit Findings

- result chunks: `20`
- findings: `25`

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

- `26-136` **P2 / schema_or_enum_drift**
  - evidence: STATE_CLASS_ENUM = frozenset({...}) ... LOCATION_SPACE_KEY_VOCAB = frozenset({...})
  - why: These constants define scenario-specific semantic categories (e.g., 'ransacked', 'blood_scene', 'kitchen', 'rooftop') that must be manually synchronized with LLM prompts. The code enforces these exact strings during validation (lines 51, 195), which can lead to fail-fast errors if the prompt and code drift apart. The docstring at line 126 explicitly acknowledges this manual synchronization requirement.
  - fix: Consolidate these vocabularies into a shared schema definition or registry that is used to both generate the LLM prompt and perform validation, reducing the risk of manual synchronization errors.

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

- `49-457` **P1 / semantic_string_judgment**
  - evidence: Keyword lists _CHARACTER_TOKENS (line 49) and _GENERIC_VERB_TOKENS (line 87) used by classify_from_the_reference (line 156) to drive fail-fast logic in validate_attached_refs (line 426).
  - why: The 'phantom guard' mechanism uses brittle string patterns and keyword proximity to infer the semantic meaning of 'from the reference' phrases in natural-language prompts. This inference directly controls whether the validator raises a RefContractError, which blocks image generation.
  - fix: Transition from natural-language keyword inference to structured reference markers. The LLM or prompt-building logic should provide explicit metadata or tags (e.g., <ref:character_id>) that the validator can check without heuristic parsing of prose.

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

- `65-80` **P1 / semantic_string_judgment**
  - evidence: _ELEMENT_ID_CLOSE_REGEX = re.compile(...) and _DESCRIPTION_CLOSE_KEYWORDS = (...)
  - why: The code uses regex patterns on element IDs and keyword matching on natural-language descriptions to classify visual framing (close-up vs. full-body). This classification is used to detect conflicts and trigger validation failures (STATUS_VALIDATOR_VIOLATIONS), directly affecting the pipeline's fail-fast and routing behavior based on brittle string heuristics.
  - fix: Update the LLM schema for fixed_elements to include an explicit 'framing' or 'visual_scope' enum field so the model declares its intent structurally rather than relying on downstream string inference.

- `355-356` **P1 / semantic_string_judgment**
  - evidence: if summary.startswith("분석 실패") or summary.startswith("분석 차단")
  - why: The logic for resuming or retrying scenes depends on checking specific Korean string prefixes within the 'analysis_summary' field, which is a natural-language output. This is brittle and couples the pipeline's execution state to the specific phrasing of LLM-generated text.
  - fix: Rely exclusively on the structured 'status' field for routing decisions. For backward compatibility with old checkpoints, perform a one-time migration to populate the status field based on the summary text.

- `748-752` **P2 / scenario_dependent_prompt**
  - evidence: - 사망/부상/의식불명 인물의 자세와 위치\n- 환경 상태 (깨진 창문, 열린 문, 혈흔 등)
  - why: The prompt contains concrete, scenario-specific examples of character states (death, injury, unconsciousness) and environmental props (broken windows, bloodstains). These specific tropes can bias the LLM's extraction logic toward dark or violent themes even when they are not present in the input scenario.
  - fix: Replace concrete tropes with abstract categories such as 'character physical posture', 'static environmental states', and 'fixed prop placement'.

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

- `139-161` **P1 / semantic_string_judgment**
  - evidence: _FACE_CLOSE_UP_PATTERNS and _is_face_close_up(prompt)
  - why: Uses a hardcoded list of English keywords (face, eye, gaze, expression) and regex patterns to classify visual framing from generated prompt prose. This classification directly controls whether character ID enforcement is mandatory or exempt, making the validation logic brittle to phrasing variations.
  - fix: Move visual framing classification (e.g., 'is_face_closeup') to a structured field in the shot metadata or render card produced by the LLM, rather than inferring it via regex in the validator.

- `214-230` **P1 / semantic_string_judgment**
  - evidence: t.lower() in prompt_lower for trigger_phrases
  - why: Uses a list of natural language phrases (from body_part_focus_rule.trigger_phrases) to detect a 'body part focus' state within the prompt text. This substring matching determines if the validator skips character ID enforcement, coupling validation logic to specific natural language tokens.
  - fix: Replace phrase-based triggers with a boolean flag or enum in the id_policy (e.g., 'is_body_part_focus') that explicitly signals the exemption.

- `544-572` **P1 / semantic_string_judgment**
  - evidence: pos = prompt_lower.find(name_lower, offset) and _entity_specific_id_in_window
  - why: Searches for natural-language character names (entity_canon.name) within the prompt to trigger a mandatory ID-proximity check. This couples validation success to the presence of specific name tokens and uses a brittle character-window heuristic (±60 chars) to enforce semantic correctness.
  - fix: Rely on the presence of IDs alone (Rule X-2) for character enforcement, or have the LLM emit a structured mapping of names to IDs if proximity validation is required.

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

- `199-210` **P1 / semantic_string_judgment**
  - evidence: item.encode("ascii") ... owned MUST be English canonical common nouns
  - why: The code uses a technical ASCII encoding check to enforce a semantic requirement that generated background objects must be English common nouns. This is a brittle pattern-based judgment that causes hard validation failures for valid semantic content that might include non-ASCII characters (like accented letters or smart quotes) or when the LLM fails to strictly adhere to the language constraint, rather than using a more robust semantic validation or allowing the downstream normalization to handle character sets.
  - fix: Remove the hard ASCII check and rely on prompt instructions for language control. If character set restriction is necessary for downstream systems, handle it during normalization (e.g., by stripping or transliterating) rather than failing the entire validation step.

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

- `37-304` **P1 / semantic_string_judgment**
  - evidence: _KOREAN_GAZE_STEMS, _KOREAN_FRAMING_NOUNS, detect_gaze_pattern_exclusions
  - why: The code uses a complex set of Korean lexicons and regex patterns to infer gaze targets and subjects from natural language shot descriptions. This result is used to mutate the visible entity list, making visibility logic dependent on brittle linguistic patterns.
  - fix: Deprecate natural language parsing in favor of structured LLM outputs for gaze targets and framing subjects (e.g., a dedicated 'gaze_target_id' field).

- `85-445` **P1 / semantic_string_judgment**
  - evidence: _OFFSCREEN_PHRASES, _PROXIMITY_PRE, detect_offscreen_drift
  - why: The drift detection logic uses regex for off-screen phrases combined with character-count proximity windows to identify characters mentioned as being off-camera. This heuristic-based classification of open-world text can trigger validation failures (VisibleStagingDriftError).
  - fix: Enforce structured 'is_offscreen' or 'visibility_status' flags in the character_angles schema and remove the proximity-based natural language fallback.

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

- `383-454` **P1 / blind_string_mutation**
  - evidence: old.replace(target, suggestion) / old_prompt.replace(target, suggestion)
  - why: The functions _apply_entity_fixes and _apply_scene_fixes perform blind substring replacement on generated T2I prompt text using LLM-provided 'target' and 'suggestion' strings. This is brittle as it can lead to unintended mutations if the target string appears multiple times or as part of another word, potentially corrupting the prompt.
  - fix: Instead of blind substring replacement, the LLM should return the full corrected prompt, or the system should use a more robust templating/token-based approach to update specific semantic components of the prompt.

## `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' + 신체부위) 패턴이 등장하면 얼굴·비얼굴 가리지 않고 C##O## 사용 금지
  - why: The prompt instructs the LLM to change its ID usage policy (routing) based on the presence of specific natural-language phrase patterns in the input description, which is a brittle semantic classifier.
  - fix: Pass a structured 'is_body_part_focus' boolean in the RenderPromptCard instead of relying on phrase matching over natural-language input.

- `119` **P1 / semantic_string_judgment**
  - evidence: fixed_elements[i].description 안 보통명사 인물 ("an adult figure" / "the seated person" 류) 이 ... 조건을 만족 시 해당 보통명사를 C##/C##O## 로 치환
  - why: This requires the LLM to perform semantic identity resolution by matching generic natural-language nouns to specific character IDs and then performing a blind string substitution.
  - fix: Provide explicit entity mapping in the structured input (e.g., fixed_elements[i].entity_id) rather than asking the LLM to infer identity from prose descriptions.

- `219-222` **P1 / semantic_string_judgment**
  - evidence: trait 가 "face fully obscured" / "no visible facial features" / "face hidden in shadow" 같은 face-obscured 표현을 포함하면, face / jaw / feature 묘사 표현 금지
  - why: The prompt uses a closed list of natural-language phrases within the 'stable_traits' field to trigger a behavioral change (forbidding facial descriptions). This is a brittle semantic classifier.
  - fix: Use a structured boolean flag or enum (e.g., visibility_state: 'obscured') in the entity traits schema instead of parsing prose strings.

- `369` **P1 / semantic_string_judgment**
  - evidence: running / riding / walking / moving / chasing / pedaling / rowing 류 ... 묘사하면, 그 상태의 mid-action 정지 ... 로 re-frame 가능
  - why: The prompt defines a list of motion verbs to classify the input scenario and trigger a 're-frame' strategy. This is a brittle string-based classifier for open-world motion semantics.
  - fix: Include a structured 'motion_type' or 'is_dynamic' flag in the shot staging data to drive re-framing logic.

- `511-516` **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-count windows and sentence boundaries to enforce semantic association between names and IDs in natural-language output.
  - fix: Use a structured output format where entities are explicitly linked to their descriptions (e.g., a JSON array of entity-description pairs) rather than relying on proximity in a flat string.

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

- `7` **P1 / semantic_string_judgment**
  - evidence: owned 어휘는 t2i_prompt 의 English token 과 정확히 매칭되어야 한다 (semantic gloss / 번역 매칭 금지).
  - why: This instruction explicitly forbids semantic understanding and forces brittle exact string matching between the canonical object list and the natural language prompt. This will cause false negatives when the prompt uses synonyms, plurals, or natural variations (e.g., 'doorway' vs 'door').
  - fix: Allow semantic matching or normalization so the LLM can correctly identify objects even when the prompt uses slightly different terminology.

- `18-21` **P1 / llm_closed_list_instruction**
  - evidence: redraw 동사 화이트리스트 (이 동사가 owned 객체를 직접 받을 때만 redraw): - 생성: create, render, draw, generate, paint, build, furnish - 추가/배치: add, place (a / a new), put, insert, hang, mount, install, set up
  - why: The prompt instructs the LLM to use a closed whitelist of verbs to determine if an object is being redrawn. This is a brittle semantic classifier that fails to account for the open-world variety of natural language expressions for 'creation' or 'modification' in T2I prompts.
  - fix: Allow the LLM to use general semantic reasoning to determine 'redraw' intent based on the context of the prompt rather than a hardcoded verb list.

- `42-45` **P1 / llm_closed_list_instruction**
  - evidence: leaning into the doorway... framed together between the tall shelves... center on the wallpaper... against the wall by the window
  - why: These spatial and framing phrases are used as a closed list of patterns to classify mentions as 'anchor_reference'. This restricts the LLM's ability to recognize other valid spatial relationships that imply referencing rather than redrawing, leading to brittle classification.
  - fix: Provide these as non-exhaustive examples of 'referencing' behavior rather than a definitive classification list.

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

- `31-49` **P1 / llm_closed_list_instruction**
  - evidence: 다음 패턴은 모두 off-camera 신호입니다: ... Gaze-target close-up 패턴 ... 명시적 off-camera/off-screen phrase ... 차단(blocking) 패턴 ... Reaction-only 패턴
  - why: The prompt defines specific linguistic templates (including regex-like Korean particles and verb stems) and keyword lists to classify whether an entity is 'off-camera'. This forces the LLM to act as a pattern-matcher rather than a semantic reasoner, leading to brittle visibility logic that fails if the input description uses synonymous but unlisted phrasing.
  - fix: Define the visibility rules using high-level physical and cinematic principles (e.g., 'exclude entities that are only mentioned as the target of a gaze in a close-up shot') rather than providing specific string patterns or keyword lists.

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

- `16-28` **P2 / schema_or_enum_drift**
  - evidence: "perspective": {"type": "string", ...}, "perception_mode": {"type": "string", ...}, "angle": {"type": "string", ...}
  - why: The fields 'perspective', 'perception_mode', and 'angle' list specific allowed values in their descriptions but are defined as open strings in the schema. This creates a drift between the documentation and the validation layer, risking invalid values reaching downstream consumers that expect exact matches for routing or visual treatment.
  - fix: Convert these fields to JSON enums to match the values listed in their descriptions, ensuring the schema enforces the contract.

- `30` **P1 / semantic_string_judgment**
  - evidence: "gaze_target": {"type": "string", "description": "Where the character's eyes are looking: ... 'unconscious', 'dead', 'severely_injured'"}
  - why: The gaze_target field is used as an overloaded semantic channel, mixing spatial targets (names, 'camera') with physical/medical states ('unconscious', 'dead', 'severely_injured'). This forces downstream logic to infer character status from a field intended for gaze direction, creating brittle dependencies where physical state is hidden inside a spatial attribute.
  - fix: Separate physical state into a dedicated field (e.g., 'physical_state') and keep 'gaze_target' for spatial coordinates or entities.

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

- `3-92` **P1 / blind_string_mutation**
  - evidence: target/suggestion 형태로 치환 정보를 제공하면 시스템이 자동으로 적용합니다. ... target: T2I 프롬프트 원문에서 정확히 찾을 수 있는 문자열 (sub-string 매치)
  - why: The prompt establishes a contract for automated, blind substring replacement of generated T2I prompt text. This is brittle as it relies on the LLM identifying and returning exact substrings for mutation without structural awareness of the prompt's composition.
  - fix: Instead of substring replacement, have the LLM return a structured list of semantic corrections or rewrite the entire prompt section using a template-based approach.

- `34-55` **P1 / semantic_string_judgment**
  - evidence: "the existing X" / "the reference X" / "low at ground/floor/quay level" + 묘사 "<surface> visible behind subject's hands"
  - why: The prompt instructs the LLM to use specific natural-language phrase patterns as triggers for semantic validation (framing and physical consistency). This relies on brittle string matching of open-world visual descriptions to decide if a prompt is physically or logically valid.
  - fix: Use structured metadata for camera height and object placement (e.g., Z-axis coordinates or relative depth enums) rather than searching for specific English phrases in the prompt text.
