# 2026-05-18 — Area #4: Scene Consistency Element Scope SOT v1 Design

**Status**: design draft (Q1-Q7 closed via Codex 의논, plan 진입 가능)
**Date**: 2026-05-18
**Track**: Track B — Semantic Debt Roadmap, Tier 2 (first wave), Area #4 (G2.2 element-level scope)
**Brainstorm closure memo**: 본 세션 (Q1-Q7 + §2 Decision Summary finalized)
**Roadmap reference**: `docs/superpowers/specs/2026-05-16-track-b-semantic-debt-roadmap-design.md` §5.4 (Area #4)
**Area #1 closure 참조 (pattern donor)**: `memory/session_20260516_area_1_id_outlook_reference_policy_sot_v1_closure.md`
**Area #2 closure 참조 (pattern donor)**: `memory/session_20260517_area_2_state_gaze_separation_closure.md`
**Area #3 closure 참조 (pattern donor)**: `memory/session_20260518_area_3_visibility_physical_presence_sot_v1_closure.md`
**framing_scale spec line 58 prerequisite**: `docs/superpowers/specs/2026-05-15-framing-scale-enum-sot-v1-design.md:58` ("element-level scope. shot-level framing_scale 로 대체 X. element_scope enum 별도 필요")

---

## §1. Overview / Scope / Non-goals

### §1.1 본질 — element-level close/full classifier (regex + keyword + classifier helper)

본 area v1 의 핵심 결함은 `scene_consistency_step.py:65-180` 의 3 표면이다:

1. **`_ELEMENT_ID_CLOSE_REGEX`** (line 65-72) — `_close_up|closeup|close|detail|wrist|hand|finger|...|toe` 등 12 단어 word-boundary regex 가 LLM emit `element_id` 의 접미사를 매칭해서 "close" framing 으로 분류. **Open-world semantic judgment on opaque ID string** — Gate 1 (Semantic Regex Ban) 위반.

2. **`_DESCRIPTION_CLOSE_KEYWORDS`** (line 73-80) — `close-up`, `tight on`, `macro shot`, `detail shot`, `focus on the` 등 10 phrase tuple 이 LLM emit `description` 자연어를 contains 매칭해서 "close" framing 분류. **Open-world prose semantic substring match** — Gate 1 위반.

3. **`_classify_framing(element)`** (line 103-120) — eid regex hit → "close" / desc kw hit → "close" / else "full". LLM-emit `element_id` + `description` 으로부터 framing scope 를 **code 가 추론**. LLM 이 framing intent 를 emit 한 적 없음 → fixed_elements schema 에 framing field 0.

### §1.2 Prompt SOT dual-sync (A037/A038)

LLM-side instruction 도 같은 문제 noun closed-list:

| Site | Pattern | Audit ID |
|---|---|---|
| `prompts/_base/scene_consistency/6.202605031033/system.md:30-35` | 전신형(full)/확대형(zoom) closed-list (Korean-language labels/examples) — Codex iter 2 M-1 fix | A037 |
| `prompts/_base/scene_consistency/6.202605031033/system.md:41` | `element_id 에 _close_up 등 접미사` LLM 의도 신호 instruction (code `_ELEMENT_ID_CLOSE_REGEX` 와 1:1 dual-sync) | A038 |

### §1.3 Production caller 현황 (1 helper + 1 consumer + 1 internal)

| Site | Function | Authority | v1 변경 |
|---|---|---|---|
| `backend/app/core/steps/scene_consistency_step.py:65-180` | `_ELEMENT_ID_CLOSE_REGEX` / `_DESCRIPTION_CLOSE_KEYWORDS` / `_classify_framing` / `_detect_framing_conflicts` | code-side inference (semantic regex) | W2 helper 폐기 + enum 직접 비교 |
| `backend/app/core/steps/scene_consistency_step.py:183-206` | `is_scene_result_consumer_safe` (consumer gate) | status + `_detect_framing_conflicts` re-check | W3 enum 비교로 변경, gate authority 유지 |
| `backend/app/core/steps/scene_consistency_step.py:451-470,625-635` | post-validator (`status=ok` 결과 일괄 `_detect_framing_conflicts` 검증 → `STATUS_VALIDATOR_VIOLATIONS` 격상) | producer-side post-validator | W3 enum 직접 비교 |
| `backend/app/core/steps/scene_context_loader.py:223,235` | `is_scene_result_consumer_safe` import + downstream gate (sole production consumer) | consumer-side defense | W3 import 보존, helper signature 보존 |
| `prompts/_base/scene_consistency/6.202605031033/system.md:30-35` | A037 closed-list 한국어 grammar example | prompt-side closed instruction | W1 prompt v7 rewrite |
| `prompts/_base/scene_consistency/6.202605031033/system.md:41` | A038 element_id 접미사 가이드 | prompt-side ID emit guide | W1 v7 폐기 (element_id opaque) |

### §1.4 4 Gate Policy Compliance ([[feedback_llm_based_judgment]])

본 spec 은 4 gate 모두 의무 적용:

- **Gate 1 (Semantic Regex Ban)**: open-world element-level scope 판단 = LLM SOT (`element_scope` enum emit). code regex = closed-world enum literal (`element_scope == "full"` / `== "close"`) 만 허용. `_ELEMENT_ID_CLOSE_REGEX` + `_DESCRIPTION_CLOSE_KEYWORDS` 권한 박탈.
- **Gate 2 (Prompt Closed-List Ban)**: active scene_consistency prompt v7 안 Korean grammar reasoning / closed-list noun example / element_id suffix guide 0. 추상 원칙 + structured emit instruction 만.
- **Gate 3 (Structured SOT Required)**: producer (scene_consistency v7) `fixed_elements[].element_scope` enum-only emit (`"full"` | `"close"`). schema required + additionalProperties strict.
- **Gate 4 (No Silent Fallback)**: code-side close/full inference 폐기 (silent SOT augmentation 차단). `element_scope` 가 schema required → 누락 시 jsonschema ValidationError → call_structured 자동 retry. element_id 는 opaque ID 로 격하 (의미 담지 X).

### §1.5 Non-goals (v1 명시 제외)

| Item | Reason | Disposition |
|---|---|---|
| P020 (`analysis_summary.startswith("분석 실패")` / `("분석 차단")` backward-compat shim 폐기 + status field strict) | 다른 축 (schema/status migration). Area #4 closure 와 별도 | follow-up area or §11 carry |
| P021 (system.md L9/L14/L17/L46 시나리오 의존 enumeration: `사망·부상·의식불명`, `깨진 창문/열린 문/혈흔` 등) | Area #7 (Prompt Hygiene v2) primary owner. v1 partial neutral 가능하나 "P021 closure" 선언 X | resolved by Carry-P021 W1-W4 — prompt-side hygiene only (content-only abstraction); Area #4 code-side classifier closure preserve |
| shot-level `framing_scale` 변경 | framing_scale enum SOT v1 closure 보존. element_scope 와 framing_scale 는 다른 차원 (element vs shot) | 변경 0 |
| Area #5 (`ref_contract_validator.py` token list / phantom guard) | independent area, scope 분리 | Area #5 별도 spec |
| body_part_focus / focus_scope 신설 (Area body_part_focus follow-up) | v1 close/full 2-value 으로 충분. body_part 차원은 Area #6 후속 | Area body_part_focus carry |
| schema additional close/full 외 enum 값 (`scene_wide`, `body_part_detail`, etc.) | v1 = current classifier output preservation. over-engineering 회피 | enum scope expansion 시 separate spec |
| multilingual support 검증 | 검증 데이터 부재 | non-goal |

---

## §2. Decision Summary (Q1-Q7 closure)

### §2.1 Q1 — Producer schema field

```
fixed_elements[i].element_scope: "full" | "close"
- required field
- additionalProperties: false on item
- LLM 이 emit (system.md v7 가 element_scope 결정 원칙 instruct)
- code 는 enum 직접 비교 (regex/keyword/classifier 0)
```

**근거**:
1. `element_scope` naming = audit doc 4 reference 매칭 (`01-code-side-regex-audit.md:204,353`, `00-index.md:202`, framing_scale spec line 58, roadmap §5.4).
2. `framing_scope` 는 `render_prompt_card.py:209` `_CONTINUITY_FRAMING_SCOPE_OPTIONS = ("third_person", "close_up")` (scene_detail view_consistency context) 와 cognitive collision 위험 — 같은 noun 다른 context.
3. v1 enum = 2 값 (`"full"` | `"close"`). 현재 `_classify_framing` 반환값 그대로. 3+ value 는 over-design (A2/A3/A4 옵션 모두 v1 에서 reject).

### §2.2 Q2 — P020 scope: Carry

P020 (`analysis_summary.startswith("분석 실패")` / `("분석 차단")` backward-compat shim) 는 Area #4 closure 외. status field backward-compat 축이고 element-scope 본체와 다른 결함 class. 같이 넣으면 schema/status migration area 로 cost 격상.

### §2.3 Q3 — P021 scope: Area #7 carry 원칙

P021 (`사망·부상·의식불명` / `깨진 창문, 열린 문, 혈흔` etc. system.md L9/L14/L17/L46 시나리오 의존 enumeration) 는 Area #7 (Prompt Hygiene v2) primary owner.

**v1 partial neutral 허용 범위** (W1 prompt v7 rewrite 시):
- A037/A038 rewrite 가 같은 section (system.md L24-L113) 을 건드림 → incidental cleanup 가능
- 시나리오 의존 noun (사망/부상/혈흔 etc.) 만 abstract phrasing 으로 변경 가능 (예: `"physical state described in scene text"`)
- **"P021 closure" 선언 X** — Area #7 가 primary owner 유지

**Post-update (2026-05-20+)**: Carry-P021 (prompt hygiene narrow) resolved by W1-W4 — scene_consistency v7 system.md hard-prime example abstraction (v8 prompt-pack `8.202605191744`). content-only abstraction, schema byte-identical, Area #4 code-side classifier preserve.

### §2.4 Q4 — Helper 폐기 design

**채택**: B (full opaque element_id + LLM enum emit + code enum 직접 비교).

- `_classify_framing` 폐기
- `_ELEMENT_ID_CLOSE_REGEX` 폐기
- `_DESCRIPTION_CLOSE_KEYWORDS` 폐기
- `element_id` 는 opaque ID 로 격하 (의미 담지 X, suffix guide A038 폐기)
- `_detect_framing_conflicts` 는 `element["element_scope"]` enum 직접 read 비교

### §2.5 Q5 — Consumer defense scope

**채택**: A (`is_scene_result_consumer_safe` 유지, `_detect_framing_conflicts` 만 enum 비교로 변경).

- consumer-side defense 자체 보존 (silent corruption 차단 layer)
- 변경 = inference (regex/keyword) 폐기 + enum 직접 비교만
- `scene_context_loader.py:223,235` import path 보존 → consumer 측 변경 0
- gate authority 유지 (`_detect_framing_conflicts` 위반 시 `False` 반환)

### §2.6 Q6 — Prompt v7 rewrite design

**채택**: B 변형 (원칙 기반 reasoning + closed list/Korean grammar/ID suffix guide 0).

A037 rewrite 핵심:
- active prompt v7 은 enum labels `full` / `close` 와 추상 원칙만 사용한다. `전신형` / `확대형` Korean labels 는 spec 설명 안에서만 허용하고, active prompt residue gate 대상에서는 0 hit 로 유지한다. (Codex iter 1 I5 fix — §8/§9 residue gate 충돌 회피)
- camera_direction/character_angles 기반 Korean-language closed-list reasoning **폐기**
- 핵심 instruction = "각 fixed_element 의 `element_scope` 필드에 `full` 또는 `close` 를 emit" (구체 wording 은 §6.2 verbatim)

A038 폐기:
- `element_id 에 _close_up 등 접미사` 가이드 제거
- element_id 는 opaque (LLM 자유 명명)
- 분류 의도는 `element_scope` 필드 에만 emit (element_id 로 암시 X)

### §2.7 Q7 — Closure verdict: version bump 기반 (monitoring 불요)

Area #3 식 open-ended monitoring (post-W2 audit log monitoring) **불필요**. 대신:

1. **Prompt/schema version bump** (6.202605031033 → 7.YYYYMMDDHHMM) → cp invalidation 자동 (manifest schema_version bump + checkpoint mismatch 시 강제 재실행)
2. **Schema strict**: `element_scope` required + additionalProperties: false
3. **Residue gates** (production code / active prompt / docs 분리):
   - production code: `_classify_framing` / `_ELEMENT_ID_CLOSE_REGEX` / `_DESCRIPTION_CLOSE_KEYWORDS` substring **0 occurrence**
   - active prompt v7: `_close_up` suffix guide / `_wrist`/`_eye` 등 신체 부위 closed-list / 전신형/확대형 closed-list reasoning **0**
   - docs/architecture: stale reference to old classifier **0** (audit doc 4 reference comment 만 historical OK)
4. **Canary fixtures** (3 시나리오 minimum):
   - (a) full + close overlap → conflict detected (validator raises)
   - (b) separated shots (no applies_to_shots overlap) → no conflict
   - (c) old cp (v6) → schema_version mismatch → 강제 v7 retry

---

## §3. Audit Evidence + Boundary

### §3.1 In-scope rows (Area #4 본체)

| ID | Prio | Loc | Pattern | v1 Fix |
|---|---|---|---|---|
| P019 | P1 CONFIRMED | `scene_consistency_step.py:65-180` | `_ELEMENT_ID_CLOSE_REGEX` (12-word regex) + `_DESCRIPTION_CLOSE_KEYWORDS` (10-phrase tuple) + `_classify_framing` (eid/desc → close/full) | W2 helper 폐기 + W3 `_detect_framing_conflicts` enum 직접 비교 |
| A037 | P1 CONFIRMED | `prompts/_base/scene_consistency/6.202605031033/system.md:30-35` | 전신형(full)/확대형(zoom) closed-list reasoning — Korean-language labels/examples (Codex iter 1 M1 fix — Korean grammar pattern 아닌 closed-list labels) | W1 v7 rewrite: 원칙 기반 reasoning + `element_scope` emit instruction |
| A038 | P2 CONFIRMED | `system.md:41` | `element_id` 접미사 `_close_up` LLM 의도 신호 instruction | W1 v7 폐기: element_id opaque, intent 는 `element_scope` 필드 emit |

### §3.2 Out-of-scope rows (carry)

| ID | Prio | Loc | Reason | Disposition |
|---|---|---|---|---|
| P020 | P2 LOW_SCHEMA | `scene_consistency_step.py:355` `summary.startswith("분석 실패") / ("분석 차단")` | status backward-compat shim (옛 v5 cp 호환). Area #4 element-scope 본체와 다른 축 (schema/status migration). | follow-up area or §11 carry |
| P021 | P2 CONFIRMED | `system.md:9,14,17,46` (audit ref `:749-751` 부분 이미 정리) — `사망/부상/의식불명`, `깨진 창문/열린 문/혈흔` 등 시나리오 의존 enumeration | Area #7 (Prompt Hygiene v2) primary owner. v1 W1 v7 rewrite 시 같은 section 시나리오 noun partial neutral 가능 (incidental cleanup) | resolved by Carry-P021 W1-W4 (2026-05-20+) — prompt-side hygiene only (v8 prompt-pack `8.202605191744`) |

---

## §4. Schema Design (`element_scope`)

### §4.1 v7 schema delta (scene_consistency/7.YYYYMMDDHHMM/schema.json)

```diff
 "fixed_elements": {
   "type": "array",
   "items": {
     "type": "object",
     "properties": {
       "element_id": {
         "type": "string",
-        "description": "고유 ID (snake_case, 보통명사 조합. 시나리오 고유명사 금지)"
+        "description": "고유 ID (snake_case, opaque identifier). 의미/intent 를 담지 말 것 — framing intent 는 element_scope 필드에만 기록."
       },
       "element_type": { "type": "string", "enum": ["character_state", "environment_state", "persistent_prop"] },
       "character_name": { ... },
       "description": { ... },
+      "element_scope": {
+        "type": "string",
+        "enum": ["full", "close"],
+        "description": "이 element 가 인물/객체의 전체적인 형태, 위치, 자세, 또는 외형을 유지해야 하면 'full', 전체 대상이 아니라 localized detail / sub-region 을 유지해야 하면 'close'. T2I 가 한 frame 에 full + close 를 중복 렌더링하지 않도록 producer 단계에서 결정. (Codex iter 2 M-2 fix — §6.2 abstract wording 과 정합)"
+      },
       "applies_to_shots": { ... },
       ...
     },
     "required": [
       "element_id", "element_type", "character_name", "description", "applies_to_shots",
+      "element_scope",
       "source_facts", "visual_inferences", "creative_decisions", "confidence"
     ],
     "additionalProperties": false
   }
 }
```

### §4.2 Schema version constants (Codex iter 1 I1 fix — registry structure 정합)

| Constant / registry field | Old | New |
|---|---|---|
| `SCENE_CONSISTENCY_SCHEMA_VERSION` (`scene_consistency_step.py:40`) | `2` | `3` |
| `step_manifest.STEP_MANIFEST["scene_consistency"]["schema_version"]` | `2` | `3` |
| prompt directory | `prompts/_base/scene_consistency/6.202605031033` | `prompts/_base/scene_consistency/7.YYYYMMDDHHMM` |
| `MODULE_VERSIONS["scene_consistency"]` (`version_registry.py:36`) | `"2.4.0"` | next semver, e.g. `"2.5.0"` |
| `_MODULE_INFO["scene_consistency"]["prompt_dependency"]` (`version_registry.py:129-131`) | `"scene_consistency/v6"` | `"scene_consistency/v7"` |
| `_MODULE_INFO["scene_consistency"]["updated_at"]` | `"2026-05-03"` | `"2026-05-18"` |

### §4.3 cp invalidation 메커니즘

- `step_runner.py` P0-3: manifest `schema_version` ↔ cp `schema_version` mismatch 시 resume reject → 강제 재실행
- 옛 v2 (v6 prompt) cp 는 v7 prompt 의 `element_scope` 필드 미포함 → schema mismatch detected → call_structured 재실행
- backward-compat fallback **0** (Gate 4 — silent fallback 차단)

---

## §5. Helper Removal + Consumer Migration

### §5.1 W2 Helper 폐기 list (scene_consistency_step.py)

**삭제** (substring 0 occurrence 의무):
- `_ELEMENT_ID_CLOSE_REGEX` (line 65-72)
- `_DESCRIPTION_CLOSE_KEYWORDS` (line 73-80)
- `_classify_framing` (line 103-120)

**보존** (signature 유지):
- `_normalize_applies_to_shots` (line 83-100) — applies_to_shots set normalization, scope 별개
- `_detect_framing_conflicts` (line 123-180) — body 만 enum 비교로 rewrite, signature/return shape 보존
- `is_scene_result_consumer_safe` (line 183-206) — body 변경 0, `_detect_framing_conflicts` 호출만 유지

### §5.2 `_detect_framing_conflicts` v7 body rewrite

```python
def _detect_framing_conflicts(scene_result: Dict[str, Any]) -> List[Dict[str, Any]]:
    """G2.2 v7: element_scope enum 직접 비교 — close/full overlap 위반 검출.

    LLM emit element_scope enum (schema required) 을 신뢰. element_id /
    description 의 inference 0 (W2 폐기).
    """
    fixed = scene_result.get("fixed_elements", []) or []
    if not fixed:
        return []

    by_char: Dict[str, List[Dict[str, Any]]] = {}
    for fe in fixed:
        if not isinstance(fe, dict):
            continue
        if fe.get("element_type") != "character_state":
            continue
        name = (fe.get("character_name") or "").strip()
        if not name:
            continue
        by_char.setdefault(name, []).append(fe)

    violations: List[Dict[str, Any]] = []
    for name, elements in by_char.items():
        if len(elements) < 2:
            continue
        for i in range(len(elements)):
            for j in range(i + 1, len(elements)):
                e1, e2 = elements[i], elements[j]
                shots1 = _normalize_applies_to_shots(e1.get("applies_to_shots", []))
                shots2 = _normalize_applies_to_shots(e2.get("applies_to_shots", []))
                overlap = shots1 & shots2
                if not overlap:
                    continue
                s1 = e1["element_scope"]  # required by v7 schema, KeyError = schema violation (Gate 4 fail-fast)
                s2 = e2["element_scope"]  # required by v7 schema, KeyError = schema violation (Gate 4 fail-fast)
                if s1 not in ("full", "close") or s2 not in ("full", "close"):
                    raise AppError(
                        code="step.contract_violation.scene_consistency.element_scope",
                        message=(
                            f"scene_consistency: invalid element_scope pair "
                            f"{s1!r}/{s2!r} for {name!r}"
                        ),
                    )
                if s1 == s2:
                    continue  # 같은 scope = 위반 아님
                for shot_idx in sorted(overlap):
                    violations.append({
                        "shot_index": shot_idx,
                        "character_name": name,
                        "elements": [e1.get("element_id", ""), e2.get("element_id", "")],
                        "framings": [s1, s2],  # legacy metadata key preserved; values are element_scope enum values
                    })
    return violations
```

**중요 차이** (v6 → v7):
- `_classify_framing` 호출 0 → element 의 `element_scope` 필드 직접 read
- return dict 의 metadata key `"framings"` 는 보존한다. 값만 v7 `element_scope` enum (`"full" | "close"`) 에서 온다. metadata key rename 은 scope creep 이며 test/cp cascade 비용만 증가시킨다. (Codex iter 1 I2 fix)
- `element_scope` 누락 / enum 범위 외 값은 `AppError(code="step.contract_violation.scene_consistency.element_scope")` 로 fail-fast (Gate 4). `from app.core.errors import AppError` 는 이미 `scene_consistency_step.py:8` 에 import 됨 (추가 import 불요). (Codex iter 1 C2 fix)

### §5.3 W3 Consumer migration

**Production consumer: `scene_context_loader.py:223,235`** — 변경 0 (import path 보존, `is_scene_result_consumer_safe(sc)` call site 동일).

**Internal consumer (scene_consistency_step.py 내부)**:
- L451-470: post-validator `_detect_framing_conflicts(r)` — body 만 enum 비교, signature 동일
- L625-635: existing_ok reuse 직전 검증 — 동일

**fixed_elements 광범위 reader** (element_scope pass-through, read 안 함):
- `detail_steps.py:369-2178`: `_derive_fixed_elements_for_shot` 가 fixed_elements list 통째로 shot context 에 inject. element_scope 새 필드는 pass-through (read 안 함, prompt 에 자동 포함).
- `render_prompt_card.py:1328-2123`: `build_continuity_elements_used` 가 fixed_elements list 통째로 dict 작성. element_scope pass-through.
- `semantic_contract_router.py:81-128`: `character_name` 만 read (Rule 2). element_scope pass-through.

**fixed_elements strict shape validator** (Codex iter 1 I3 fix — pass-through 만 아님):
- `render_prompt_card.py:2853-2858` `_FIXED_ELEMENT_REQUIRED_KEYS` — `element_scope` 를 추가하여 fixed_elements item contract 를 9-field → 10-field 로 갱신. `_assert_continuity_elements_used_shape` docstring (`render_prompt_card.py:2932`) 도 10-field 로 정정. This is not just pass-through; it is a strict shape validator.

→ **production consumer-side cascade**: scene_context_loader gate 변경 0 + render_prompt_card `_FIXED_ELEMENT_REQUIRED_KEYS` 10-field 갱신 (W3) + detail_steps / semantic_contract_router pass-through (W3 schema validation 통과 의무 — W1 schema add 와 동시).

---

## §6. Prompt v7 Design

### §6.1 system.md v7 rewrite scope

**유지** (Gate 2 compliant):
- 역할 / 고정 요소 유형 3 (character_state / environment_state / persistent_prop) 정의
- 추상 원칙 (인물 전체 ↔ 특정 부위 확대 동시 적용 시 T2I rendering 중복 위험)
- generic placeholder 예시 (C##, S## 등 synthetic ID)
- evidence/inference disclosure 4 field (source_facts / visual_inferences / creative_decisions / confidence)

**rewrite** (Gate 1/2 compliant):
- §"같은 인물의 전신 ↔ 확대 부위 중복 금지" section (L24-L92) → element_scope 결정 원칙 기반 reasoning
- 전신형(full)/확대형(zoom) closed-list (L30-35) → element_scope enum 의미 정의만 (camera_direction/character_angles 기반 Korean-language labels/examples 폐기) — Codex iter 2 M-1 fix
- element_id 접미사 가이드 (L41) → element_id opaque, intent 는 element_scope 필드 emit

**partial neutral** (Q3 P021 incidental cleanup):
- L9 state example list → `physical state explicitly described in the source text` (Codex iter 1 M2 fix — no examples)
- L17 `깨진 창문, 열린/닫힌 문, 벽 손상, 벽의 표식/낙서, 특정 조명 상태` → abstract category list (window/door/wall/lighting state) without scenario-specific noun enumeration
- L46 예시 시나리오 (사망 상태 인물) → generic synthetic 시나리오 (캐릭터 C## immobilized state)

### §6.2 v7 element_scope instruction 핵심 wording

**Codex iter 1 C1 fix**: v6 prompt 의 closed-list noun 결함 (`손/손목/이마/눈/입/목` 등 신체 부위 closed-list, `_close_up`/`_wrist` suffix 예시) 가 v7 instruction 에 그대로 들어가면 W1 이 A037/A038 을 고치는 동시에 같은 class 의 prompt pollution 을 재삽입함 → Gate 2 / residue gate 직접 위반. 아래 verbatim instruction 만 active prompt 에 박는다 (synthetic 신체 부위 closed-list 0, suffix example 0).

```md
## element_scope 결정 (필수 emit)

각 fixed_element 는 `element_scope: "full" | "close"` 둘 중 하나를 명시 emit 한다.

- `full`: 이 element 가 인물/객체의 전체적인 형태, 위치, 자세, 또는 외형을 유지해야 하는 continuity item 이다.
- `close`: 이 element 가 전체 대상이 아니라 특정 localized detail / sub-region 을 유지해야 하는 continuity item 이다.

같은 인물의 `character_state` element 가 한 씬에 둘 이상 있고 `applies_to_shots` 가 겹친다면,
`element_scope` 가 서로 다를 때 T2I 가 한 frame 에 전체 대상과 localized detail 을 동시에 렌더링할 수 있다.
그 경우 별도 항목으로 분리하고 `applies_to_shots` 가 겹치지 않도록 한다.

`element_id` 는 opaque snake_case 이름이다. scope / framing intent 를 `element_id` 안에 암시하지 말고,
그 의도는 오직 `element_scope` 필드에만 기록한다.
```

### §6.3 prompt version

`prompts/_base/scene_consistency/7.YYYYMMDDHHMM/`
- `system.md` v7 (P019/A037/A038 fix + P021 partial neutral)
- `schema.json` v7 (`element_scope` required field)

---

## §7. Canonical Principle Mapping Table

| Audit ID | Current Evidence | Problem Class | Canonical Clause | Schema + Prompt Wording | Regression Marker |
|---|---|---|---|---|---|
| P019 | `scene_consistency_step.py:65-180` `_ELEMENT_ID_CLOSE_REGEX` (12-word boundary regex) + `_DESCRIPTION_CLOSE_KEYWORDS` (10-phrase tuple) + `_classify_framing` (eid/desc → "close"/"full") | semantic_string_judgment on open-world LLM-emit strings | **Element-level framing scope is producer-emit structured enum (`element_scope`); code MUST NOT infer scope from element_id or description.** | Schema: `element_scope: enum ["full","close"]` required, additionalProperties:false. Prompt v7 §6.2: "element_scope 결정 (필수 emit)" instruction (3 paragraph) — closed-list 0, Korean grammar reasoning 0, suffix guide 0. | `test_no_classify_framing_helper` (helper substring 0), `test_no_element_id_close_regex` (regex constant 0), `test_no_description_close_keywords` (tuple 0), `test_detect_framing_conflicts_reads_element_scope` (enum 직접 비교 verify), `test_element_scope_enum_only` (enum 외 값 시 ValidationError) |
| A037 | `prompts/_base/scene_consistency/6.../system.md:30-35` 전신형(full)/확대형(zoom) closed-list — Korean-language labels/examples (Codex iter 1 M1 fix) | llm_closed_list_instruction | **Prompt MUST NOT enumerate scope decision criteria as a closed list of Korean-language labels/examples; emit element_scope enum based on abstract principle.** | Prompt v7 §6.2 verbatim (full/close 의미 정의 + 추상 원칙). camera_direction/character_angles 기반 reasoning 0. active prompt residue gate 에서 `전신형` / `확대형` 0 hit (Codex iter 1 I5 fix). | `test_prompt_v7_no_closed_framing_list` (활성 prompt 안 closed list signature substring 0), `test_prompt_v7_active_loader_matches_file` (active prompt = file), `test_prompt_versions_v7_registered` |
| A038 | `system.md:41` `element_id 에 _close_up 등 접미사` LLM 의도 신호 instruction | semantic_string_judgment + producer-side suffix convention | **element_id is an opaque identifier. Intent (scope) MUST be emitted in element_scope field only; element_id MUST NOT encode scope via suffix.** | Schema description: `"opaque identifier. ... framing intent 는 element_scope 필드에만 기록"`. Prompt v7 §6.2 끝: "element_id 는 opaque snake_case ... element_scope 를 element_id 접미사로 암시하지 말 것" verbatim. | `test_prompt_v7_no_element_id_suffix_guide` (`_close_up` substring 0 in active prompt), `test_schema_v7_element_id_description_says_opaque` |

### §7.1 Out-of-scope boundary table (carry — not v1 canonical)

| ID | Reason | Disposition | Carry Marker (if any) |
|---|---|---|---|
| P020 | status backward-compat shim, axis mismatch | follow-up area | regression test 0 (carry로 분리) |
| P021 | Area #7 primary owner. v1 incidental partial neutral 만 | resolved by Carry-P021 W3 G3 STRICT_RESIDUES marker-wrapped catalog (2026-05-20+) | resolved by Carry-P021 W3 G3 — 10 strict residue (R1-R6 + JS1/JS2a/JS2b/JS3) full-phrase membership absent in v8 system.md. `test_prompt_v7_no_scenario_specific_noun_in_l9_l17` carry marker superseded by `backend/tests/integration/test_carry_p021_scene_consistency_prompt_abstraction.py::test_gate_3_strict_residues_absent_in_v8_system_md` |
| framing_scale (shot-level) | 다른 차원 (element vs shot), framing_scale enum SOT v1 closure 보존 | 변경 0 | n/a |
| Area #5 (`ref_contract_validator.py` token list / phantom guard) | independent area | Area #5 spec | n/a |

---

## §8. Cascade Enumeration Table

| Surface | Current reads/writes | Planned change | Owner wave | Verification | Risk if missed |
|---|---|---|---|---|---|
| **Producer prompt+schema** | | | | | |
| `prompts/_base/scene_consistency/6.../system.md` | A037/A038 closed-list + suffix guide | v7 new dir, P019/A037/A038 fix + P021 partial neutral | W1 | `test_prompt_versions` + `test_prompt_v7_active_loader_matches_file` | active prompt 변경 안 되면 LLM 이 옛 closed-list 추론 → schema validation fail (element_scope 누락) → 무한 retry |
| `prompts/_base/scene_consistency/6.../schema.json` | element_scope 필드 없음, additionalProperties:false | v7 schema add element_scope required | W1 | `test_scene_consistency_schema_v7` (신규) | LLM 이 element_scope emit 해도 schema 미보유 시 strict 모드 reject 위험 |
| `version_registry.py` | `MODULE_VERSIONS["scene_consistency"] = "2.4.0"` + `_MODULE_INFO["scene_consistency"]["prompt_dependency"] = "scene_consistency/v6"` | next semver (e.g. `"2.5.0"`) + `prompt_dependency = "scene_consistency/v7"` + `updated_at = "2026-05-18"` | W1 | `test_scene_consistency_version_registry_v7` + sync test | registry drift → provenance/prompt_dependency metadata stale (Codex iter 2 I-2 fix) |
| `step_manifest.py` | scene_consistency v6 | scene_consistency v7 | W1 | `test_manifest_fields` | 동일 |
| **Helper/validator** | | | | | |
| `scene_consistency_step.py:65-180` | `_ELEMENT_ID_CLOSE_REGEX` + `_DESCRIPTION_CLOSE_KEYWORDS` + `_classify_framing` + `_detect_framing_conflicts` (close/full inference) | helper 3 삭제 + `_detect_framing_conflicts` body 만 enum 비교로 rewrite | W2 | `test_scene_consistency_validator.py` (cascade — `_classify_framing` 직접 호출 17 test 모두 삭제 or rewrite) | helper substring 잔존 시 residue gate fail |
| `scene_consistency_step.py:40` `SCENE_CONSISTENCY_SCHEMA_VERSION = 2` | cp invalidation 상수 | `= 3` | W1 | `test_g3_2_manifest_dag` | cp invalidation 안 됨 → 옛 v6 cp 결과 silent 통과 (Gate 4 위반) |
| `scene_consistency_step.py:183-206` `is_scene_result_consumer_safe` | status + `_detect_framing_conflicts` re-check | body 변경 0 (`_detect_framing_conflicts` 만 변경) | W2 (helper) + W3 (consumer-side defense 변경 0) | `test_consumer_verify_completion` | n/a (변경 0) |
| **Production consumers** | | | | | |
| `scene_context_loader.py:223,235` | `is_scene_result_consumer_safe(sc)` 호출 | 변경 0 | W3 | `test_subject_reference_policy_e2e` + `test_evidence_consumer_wiring` | n/a (signature 동일) |
| `detail_steps.py:369-2178` `_derive_fixed_elements_for_shot` | fixed_elements list 통째로 shot context 에 inject | element_scope pass-through (자동 포함) | W3 | `test_scene_detail_analyze_one` + `test_d6_scene_detail_chain_unchanged` | schema validation pass 라면 cascade 0 |
| `render_prompt_card.py:1328-1640,2853-2963` | `build_continuity_elements_used` 는 fixed_elements 를 deep-copy pass-through 하지만 `_FIXED_ELEMENT_REQUIRED_KEYS` 로 strict shape 검증도 수행 | `element_scope` pass-through + `_FIXED_ELEMENT_REQUIRED_KEYS` 10-field 갱신 + docstring 9→10 정정 | W3 | `test_render_prompt_card` + `_assert_continuity_elements_used_shape` coverage | key tuple 누락 시 v7 contract 를 downstream card layer가 검증하지 못함 (Codex iter 1 I3 fix) |
| `semantic_contract_router.py:81-128` | `character_name` 만 read (Rule 2) | element_scope pass-through | W3 | `test_semantic_contract_router` | n/a |
| **Tests** | | | | | |
| `tests/core/steps/test_scene_consistency_validator.py` | `_classify_framing` / `_detect_framing_conflicts` 17+ test | `_classify_framing` test 모두 삭제. `_detect_framing_conflicts` test 는 enum 비교로 rewrite + 추가 신규 enum-based test | W2 | `pytest backend/tests/core/steps/test_scene_consistency_validator.py` | helper 폐기 후 test ImportError (cascade fail) |
| `tests/core/steps/test_scene_consistency_status.py` | status field tests | 변경 0 (element_scope 와 별개) | n/a | n/a | n/a |
| `tests/unit/test_scene_consistency_schema_v6.py` | v6 schema fixture | **신규 `test_scene_consistency_schema_v7.py`** + v6 test 보존 (legacy reference) or rename to `_v7` | W1 | new file pass | v7 schema regression 미커버 |
| `tests/integration/test_subject_reference_policy_e2e.py` | Area #1 closure E2E (fixed_elements fixture) | element_scope 필드 fixture 추가 (각 fixed_element entry) | W3 | E2E pass | fixture migration 누락 시 schema validation fail in test |
| `tests/integration/test_evidence_consumer_wiring.py` | fixed_elements fixture | element_scope 추가 | W3 | pass | 동일 |
| `tests/unit/test_render_prompt_card.py` | 광범위 fixed_elements fixture | element_scope 추가 (필요한 fixture entries) | W3 | pass | 동일 |
| `tests/unit/test_g4_2_background_binding_lift.py` etc. (g4_2/g4_3/g4_4/g4_5a) | fixed_elements fixture | element_scope 추가 (필요한 fixture entries) | W3 | pass | 동일 |
| `tests/unit/test_evidence_normalize.py` | fixed_elements normalize | element_scope normalize confirm | W3 | pass | normalize 가 element_scope 보존하는지 verify |
| **Docs/spec** | | | | | |
| `docs/visual-reliability-audit/.../01-code-side-regex-audit.md:204,353` | element_scope enum 신설 권고 reference | W4 closure 시 closure 표시 (historical reference 유지) | W4 | manual diff | 무시 가능 (historical doc) |
| `docs/visual-reliability-audit/.../00-index.md:202` | 동일 | 동일 | W4 | 동일 | 동일 |
| `docs/superpowers/specs/2026-05-15-framing-scale-enum-sot-v1-design.md:58` | deferred row #17 | W4: line 58 row Disposition update ("✓ closed C-4" 표기) | W4 | manual diff | stale "deferred" 표기 유지 risk |
| `docs/superpowers/specs/2026-05-16-track-b-semantic-debt-roadmap-design.md` §5.4 | Area #4 row | W4 closure 표기 + Tier 2 #1 closure note | W4 | manual diff | roadmap 진행 status drift |
| **Residue gates** | | | | | |
| production code: `_classify_framing` / `_ELEMENT_ID_CLOSE_REGEX` / `_DESCRIPTION_CLOSE_KEYWORDS` substring | 현재 3 helper 정의 + cascade | strict 0 occurrence (production 코드 어디에도 없음) | W4 | (Codex iter 1 I4 fix — `rg -F` + `\|` 잘못된 사용 회피) (Codex iter 2 I-1 fix — no-hit 시 loop 최종 status 가 마지막 rg 의 exit 1 되어 false-fail 회피) `hits=0; for token in _classify_framing _ELEMENT_ID_CLOSE_REGEX _DESCRIPTION_CLOSE_KEYWORDS; do if rg -n -F "$token" backend/app; then hits=1; fi; done; test "$hits" -eq 0` → exit 0 (no output) | dead code 잔존 시 audit 재발 |
| active prompt v7: `_close_up` suffix / 전신형/확대형 closed-list reasoning | A037/A038 | strict 0 (active prompt 안 closed list 0, suffix guide 0) | W4 | `rg -n '_close_up|전신형.*확대형' prompts/_base/scene_consistency/7.*` → exit 1 (no match) | LLM closed-list 추론 회귀 |
| docs/architecture: outdated reference to old classifier | 일부 docs | W4 closure 표기 후 historical reference 만 OK | W4 | manual diff | stale 비교 risk |

---

## §9. Wave Outline (W0-W4)

### §9.1 W0 — Pre-W2 cascade baseline

**Goal**: production fixture / test surface 의 fixed_elements 의 현재 close/full classifier 결과 baseline 캡처 (W2 helper 폐기 후 비교 ground truth).

**Output**: `backend/tests/_audit_outputs/area_4_w0/classifier_baseline.jsonl`
- 각 scene_index, shot_index, element_id, current `_classify_framing(element)` 결과, eid/desc 매칭 표시
- production cp 안 fixed_elements 전수 (S* 모든 씬)

**Scope**: read-only instrumentation, no production write.

**Skip condition**: production cp 부재 시 W0 skip (W2 직접 진입), 단 spec §11 함정 #4 (W0 skip 시 regression baseline 부재 risk) 명시.

### §9.2 W1 — Producer schema + prompt v7

**Wave**:
- (a) `prompts/_base/scene_consistency/7.YYYYMMDDHHMM/` 신설
- (b) `schema.json` v7: `element_scope` required + description verbatim §4.1
- (c) `system.md` v7: §6.1 rewrite + §6.2 instruction verbatim + P021 partial neutral §6.1
- (d) `SCENE_CONSISTENCY_SCHEMA_VERSION = 3` (`scene_consistency_step.py:40`)
- (e) `version_registry.py` + `step_manifest.py` v7 entry
- (f) 신규 `tests/unit/test_scene_consistency_schema_v7.py` (v6 test 보존 or rename)

**Verify**: `test_prompt_versions` + `test_prompt_v7_active_loader_matches_file` + `test_step_manifest_v3` + `test_scene_consistency_schema_v7` 신규 pass.

**Commit**: 1 atomic — `feat(area-4-scene-consistency-element-scope-sot-v1): W1 — producer schema + prompt v7 (element_scope enum required + closed-list reasoning 폐기)`

### §9.3 W2 — Helper removal + validator rewrite

**Wave**:
- (a) `scene_consistency_step.py:65-72` `_ELEMENT_ID_CLOSE_REGEX` 삭제
- (b) `scene_consistency_step.py:73-80` `_DESCRIPTION_CLOSE_KEYWORDS` 삭제
- (c) `scene_consistency_step.py:103-120` `_classify_framing` 삭제
- (d) `scene_consistency_step.py:123-180` `_detect_framing_conflicts` body rewrite (§5.2)
- (e) `tests/core/steps/test_scene_consistency_validator.py`: `_classify_framing` test 17개 모두 삭제. `_detect_framing_conflicts` 6 test 는 enum 비교로 rewrite + 신규 enum-based test 5+ 추가 (close/full overlap detect / equal scope no conflict / missing scope ValidationError simulate / 다른 element_type 무시 / character_state 만 대상).

**Verify**: `pytest backend/tests/core/steps/test_scene_consistency_validator.py` PASS + helper substring grep strict 0 (Codex iter 1 I4 + iter 2 I-1 fix): `hits=0; for token in _classify_framing _ELEMENT_ID_CLOSE_REGEX _DESCRIPTION_CLOSE_KEYWORDS; do if rg -n -F "$token" backend/app; then hits=1; fi; done; test "$hits" -eq 0` → exit 0.

**Commit**: 1 atomic — `refactor(area-4-scene-consistency-element-scope-sot-v1): W2 — helper 폐기 + validator enum 직접 비교 rewrite`

### §9.4 W3 — Consumer migration + fixture cascade

**Wave**:
- (a) `is_scene_result_consumer_safe` (line 183-206) — 변경 0, signature 보존
- (b) `scene_context_loader.py:223,235` — 변경 0, import path 보존
- (c) Fixture cascade migration — fixed_elements element_scope 추가:
  - `tests/integration/test_subject_reference_policy_e2e.py`
  - `tests/integration/test_evidence_consumer_wiring.py`
  - `tests/unit/test_render_prompt_card.py`
  - `tests/unit/test_g4_2_background_binding_lift.py`, `test_g4_3_id_policy_lift.py`, `test_g4_4_continuity_lift.py`, `test_g4_5a_spatial_lift.py`
  - `tests/unit/test_evidence_normalize.py`
  - `tests/core/test_d6_scene_detail_chain_unchanged.py`
  - `tests/fixtures/_archive/g4_6_2026-05-16-area-1/*.json` — **변경 금지** (Codex iter 1 I6 fix — §11.3 함정 20 과 정합). archived fixture 는 v6 reproduction reference 로 보존한다. active test 가 v7 schema fixture 를 필요로 하면 archive 를 수정하지 말고 current test fixture/copy 를 별도로 만든다.

**Verify**: `pytest backend/tests/unit backend/tests/integration backend/tests/core` PASS (B1-B5 unrelated baseline 외).

**Commit**: 1 atomic — `test(area-4-scene-consistency-element-scope-sot-v1): W3 — fixture cascade migration (element_scope 필드 추가)`

### §9.5 W4 — Closure + canary + residue + roadmap update

**Wave**:
- (a) Residue gate strict (§8 마지막 3 row) — Codex iter 1 I4 fix (`rg -F` + `|` 잘못된 사용 회피):
  - production code (Codex iter 2 I-1 fix): `hits=0; for token in _classify_framing _ELEMENT_ID_CLOSE_REGEX _DESCRIPTION_CLOSE_KEYWORDS; do if rg -n -F "$token" backend/app; then hits=1; fi; done; test "$hits" -eq 0` → exit 0
  - active prompt suffix: `rg -n '_close_up' prompts/_base/scene_consistency/7.*` → exit 1 (no match)
  - active prompt Korean closed-list: `rg -n '전신형.*확대형|확대형.*전신형' prompts/_base/scene_consistency/7.*/system.md` → exit 1 (no match)
- (b) Canary fixture (`backend/tests/_audit_outputs/area_4_w4/canary_*.jsonl`):
  - (canary-1) full + close overlap → `_detect_framing_conflicts` returns non-empty
  - (canary-2) separated shots (no overlap) → returns empty
  - (canary-3) old v6 cp → schema_version mismatch → 강제 v7 retry verify (W0 baseline 과 비교)
- (c) Roadmap §5.4 closure update + framing_scale spec line 58 "✓ closed C-4" 표기
- (d) Closure memo write to memory (`session_20260518_area_4_scene_consistency_element_scope_sot_v1_closure.md`)

**Verify**: 4 closure criteria PASS:
- C1: schema v7 + cp invalidation 강제 v7 rerun
- C2: helper substring strict 0
- C3: prompt v7 closed-list reasoning + `_close_up` suffix guide 0
- C4: canary fixture 3 시나리오 PASS

**Commit**: 1 atomic — `docs(area-4-scene-consistency-element-scope-sot-v1): W4 — closure + canary + residue + roadmap §5.4 update`

---

## §10. Closure Conditions / Verdict Wording

### §10.1 Closure verdict (verbatim — Codex 권고)

```
Area #4 closure complete when scene_consistency v7 producer emits required
structured element_scope; code no longer infers close/full from element_id or
description; consumer defense remains active and compares element_scope directly;
active prompt contains no full/zoom closed phrase list or _close_up suffix guide;
cp invalidation/version bump forces v7 rerun; residue gates and canary fixtures
pass. No VLM-based validation used.
```

### §10.2 Non-claim (closure 미선언 범위 — 명시)

- **P020 status backward-compat shim** 미해결. Area #4 외, follow-up area or carry.
- **P021 broad prompt hygiene** resolved by Carry-P021 W1-W4 (2026-05-20+) — scene_consistency v7 system.md hard-prime examples abstracted (v8 prompt-pack `8.202605191744`). prompt-side hygiene only (content-only abstraction); Area #4 code-side classifier closure preserve (producer code `scene_consistency_step.py` 변경 0).
- **shot-level `framing_scale`** 변경 없음. framing_scale enum SOT v1 closure 보존.
- **Area #5 (`ref_contract_validator.py` token list / phantom guard)** 문제 미해결. independent area.

### §10.3 Monitoring trigger — 불요

Area #3 식 open-ended post-W2 audit log monitoring **불필요**. 본 area 의 closure 메커니즘 = deterministic:
1. schema required + additionalProperties:false → LLM emit 누락 시 call_structured 자동 retry (jsonschema ValidationError)
2. cp invalidation (schema_version 2 → 3) → 옛 v6 결과 silent 통과 차단
3. Residue gate strict 0 → 정적 검증

Long-tail monitoring 가 필요한 silent failure mode 없음.

---

## §11. No VLM + 4 Gate Compliance + 함정

### §11.1 No VLM rule inline

본 area 는 VLM (Vision Language Model) 기반 판단 / 검증 / 성능 전제 / 의존 0 ([[feedback_no_vlm_dependency]] hard constraint).

- producer = text-only LLM (gemini-3.1-pro-preview / gpt-5.5) `element_scope` emit
- validator = code structured field 직접 비교 (`_detect_framing_conflicts`)
- canary = code/test fixture 검증 (W4 fixture replay)
- prompt rewrite = text instruction
- 어떤 wave 도 VLM 호출 / VLM-as-judge / VLM-derived ground truth 사용 X

Production image generation pipeline (T2I) 의 정상 사용은 본 area 와 무관 — 본 area 의 의사 결정 / 검증 회로에 VLM 의존 부재.

### §11.2 4 Gate matrix

| Gate | Compliance | Evidence |
|---|---|---|
| Gate 1 Semantic Regex Ban | ✓ | `_ELEMENT_ID_CLOSE_REGEX` + `_DESCRIPTION_CLOSE_KEYWORDS` 폐기. code regex = enum literal 비교 (`element_scope == "full"`) 만. |
| Gate 2 Prompt Closed-List Ban | ✓ | A037 전신형/확대형 closed-list reasoning 폐기. v7 instruction = 추상 원칙 + synthetic 시나리오 예시. |
| Gate 3 Structured SOT Required | ✓ | `element_scope` schema required + enum-only. additionalProperties:false. |
| Gate 4 No Silent Fallback | ✓ | schema validation 실패 시 call_structured retry (자동). code inference fallback 0. cp invalidation 강제. |

### §11.3 함정 (Area #1/#2/#3 carry + Area #4 신규)

**Tier 1 carry 함정 요약** (Codex iter 1 M3 fix): top 8 are repeated inline; items 9-16 are inherited by reference from Area #3 closure memo ([[session_20260518_area_3_visibility_physical_presence_sot_v1_closure]]) and must be re-opened during plan review if touched by implementation scope.

1. Plan template cascade enumeration defect (W2 PD-1 + W3 cascade 2회 연속) → BLOCKING pre-step #1 강제 적용
2. Wording iteration cascade (BP guard 4 commits) → BLOCKING pre-step #2 강제
3. tmux_message + Enter 의무 (양방향 trigger)
4. 사용자 결정 ask 전 Codex 의논 의무 (memory rule 7a, 2026-05-18 strict 화 — push/scope inflation 포함 모든 일반 결정은 Codex+Claude 자체 결정)
5. VLM 절대 금지
6. Closure wording MAY/MUST NOT 분리 spec 의무
7. Push gate strict (Codex 의논 후 자체 결정)
8. Roadmap §5.X stale wording carry
9-16. Area #1/#2/#3 carry — see prior closure memos. plan review 시 implementation scope 가 해당 함정을 건드리면 inline 재 enumeration 의무.

**Area #4 신규 함정**:
17. **element_id naming convention 변경 risk** — element_id opaque 격하 시 fixed_elements 의 traceability 영향. v1 = LLM emit string preservation (opaque). element_id 자체 deterministic re-keying 시도 금지 (downstream caller 의존 가능성).
18. **W3 fixture cascade undercount risk** — fixed_elements 광범위 reader (8+ test file) fixture migration 누락 시 schema validation fail 광범위. BLOCKING pre-step #1 (cascade grep) §8 cascade table 전수 enumeration 의무.
19. **scene_context_loader import path drift** — `is_scene_result_consumer_safe` 함수 signature 보존 의무. helper 폐기 시 signature 변경 시 cascade 폭발.
20. **v6 schema fixture archived 보존 정책** — `tests/fixtures/_archive/g4_6_2026-05-16-area-1/*.json` 등 archived fixture 는 v6 reference 유지 (재현용). 변경 X. 단 시계열 confusion 방지 위해 closure memo 에 명시.
21. **canary 3 시나리오 deterministic 보장** — old cp fallback canary 가 cp file (sqlite or JSON) 의존 시 test isolation 위반. tmp file or in-memory fixture 사용 의무.
22. **render_contracts (Area B-min closed) boundary 보존** — element_scope 가 `attached_refs[]` / `required_refs[]` / `render_contracts` 와 충돌 X. element_scope 는 fixed_elements item-level, render_contracts 는 shot-level. cross-cut 0 verify 의무.

---

## §12. Lessons / Plan Handoff / Review Checklist

### §12.1 Tier 1 lessons 적용 (반드시)

본 spec 작성 + W1-W4 execution 시 Tier 1 lessons top 3 적용 의무 ([[next_session_area_4_scene_consistency_element_scope_brainstorm]] §"Tier 1 lessons top 3"):

1. **Cascade enumeration pre-step** (Tier 1 lesson #1): callee rename + import site + downstream tests + source-grep tests **plan 작성 전 grep 의무**. 본 spec §8 cascade table 이 baseline — plan 작성 시 확장 (Codex 권고 plan iter 1).
2. **Canonical wording mapping** (Tier 1 lesson #2): spec canonical clause → prompt clause → test marker **초기 1:1 매핑**. 본 spec §7 canonical mapping table 이 baseline.
3. **Workflow trigger hardening** (Tier 1 lesson #3): 사용자 decision ask 전 Codex 의논 의무 (memory rule 7a, strict 화). tmux_message + Enter 의무 양방향 trigger.

### §12.2 Plan 작성 handoff (다음 step)

본 spec closure 후 plan 작성 진입:

- **Plan filename**: `docs/superpowers/plans/2026-05-18-area-4-scene-consistency-element-scope-v1-implementation.md`
- **Plan 구조** (Area #3 plan pattern donor):
  1. Wave 5 (W0/W1/W2/W3/W4) per §9 outline
  2. Sub-task TDD outline (각 wave 별 test-first marker + green commit)
  3. Cascade enumeration table (§8 spec 의 확장 — production grep 완전화)
  4. Residue gate scope definition (§8 마지막 3 row 의 검증 절차)
  5. No VLM rule inline
  6. Commit message template (atomic 1 commit per wave)

### §12.3 Codex review checklist (spec iter 1)

본 spec Codex review 시 의무 check item:

- [ ] Q1-Q7 decision summary 모두 Codex 권고 verbatim 반영 (§2)
- [ ] Audit row P019/A037/A038 evidence + canonical mapping 1:1 (§7)
- [ ] Cascade enumeration 6 그룹 (Producer / Helper / Consumer / Tests / Docs / Residue) 모두 enumerated (§8)
- [ ] Wave outline W0-W4 5 wave 분리 + atomic commit 1 per wave (§9)
- [ ] Closure verdict verbatim Codex 권고 (§10.1) + Non-claim 4 항목 (§10.2) 명시
- [ ] No VLM rule inline (§11.1)
- [ ] 4 Gate compliance matrix (§11.2)
- [ ] 함정 carry 16 + 신규 6 (§11.3)
- [ ] Plan handoff 명시 (§12.2)

### §12.4 외부 review references

- Track B roadmap §5.4: `docs/superpowers/specs/2026-05-16-track-b-semantic-debt-roadmap-design.md:332-342`
- framing_scale spec prerequisite (✓ closed C-2): `docs/superpowers/specs/2026-05-15-framing-scale-enum-sot-v1-design.md:58`
- Audit doc 4 reference: `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/{00-index,01-code-side-regex-audit}.md`
- Area #1 closure (pattern donor): `memory/session_20260516_area_1_id_outlook_reference_policy_sot_v1_closure.md`
- Area #2 closure (pattern donor): `memory/session_20260517_area_2_state_gaze_separation_closure.md`
- Area #3 closure (pattern donor): `memory/session_20260518_area_3_visibility_physical_presence_sot_v1_closure.md`
