# Area D-next-min — Implementation plan (clean rebuild on origin/main=479c368)

**Date**: 2026-05-15
**Spec**: `docs/superpowers/specs/2026-05-15-area-d-next-min-keep-elements-environment-static-prop-only.md`
**Strategy**: Salvage + Boundary Reset — archive 보존 + main 깨끗하게 재구성

---

## §1. Commit sequence (clean rebuild stack + closure wording fix)

### Commit 1 — Spec + Plan docs
```
docs(area-d-next-min): spec + plan — keep_elements environment/static_prop only
```

**Files**:
- `docs/superpowers/specs/2026-05-15-area-d-next-min-keep-elements-environment-static-prop-only.md` (이 spec)
- `docs/superpowers/plans/2026-05-15-area-d-next-min-implementation.md` (본 plan)

archive narrative 명시: `archive/area-d-next-immobilized-attempt` + `archive/area-d-next-min-iteration` 보존.

### Commit 2 — Atomic producer + KEEP_ELEMENT_KINDS helper

```
feat(area-d-next-min): atomic producer v7 — prompt + step + manifest + registry + helper module
```

**Production**:
- `prompts/_base/shot_dependency_t2i/7.202605151200/system.md` (신규)
- `prompts/_base/shot_dependency_t2i/7.202605151200/schema.json` (신규)
- `backend/app/core/keep_elements.py` (신규 — 2-enum frozenset + validate helpers)
- `backend/app/core/steps/shot_dependency_t2i_step.py` — `_immobile_hints` + `scene_consistency` 의존 완전 제거 + `_process_llm_result` post-validation enum 2종
- `backend/app/core/step_manifest.py` — shot_dependency_t2i.schema_version = 3
- `backend/app/core/version_registry.py` — MODULE_VERSIONS 1.4.0 + v7 + 2026-05-15

**Tests**:
- `backend/tests/services/test_area_d_next_shot_dependency_t2i.py` (신규) — B1-B7 atomic test

### Commit 3 — L2/L3 loader fail-fast

```
feat(area-d-next-min): L2 + L3 loader fail-fast — legacy v5/v6 cp + shape validation
```

**Production**:
- `backend/app/services/scene_checkpoint_loaders.py` — `load_shot_dependency_map` 의 keep_elements shape validation + `except AppError: raise`
- `backend/app/core/steps/scene_context_loader.py` — `_load_dependencies` 의 schema_v != 3 + keep_elements 검증

**Tests**:
- `backend/tests/services/test_scene_checkpoint_loaders.py` — c4 (valid 2-enum) + c4b 신규 (legacy v6 immobilized_character reject) + c5 (broad except)
- `backend/tests/unit/test_scene_context_loader_load_dependencies.py` (신규) — v7 valid / v5 legacy / v6 schema_version=2 legacy / shape 위반 / immobilized_character kind reject

### Commit 4 — Consumer (label-only + defense-in-depth + C8 regex 폐기 완성)

```
feat(area-d-next-min): consumer cascade — scene_reference_service / detail_steps / render_prompt_card + tests
```

**Production**:
- `backend/app/services/scene_reference_service.py` — `_KEEP_ELEMENT_PERSON_TOKENS` regex 완전 폐기 (C8 원래 목적) + `validate_keep_elements` defense-in-depth + label concat only
- `backend/app/core/steps/detail_steps.py` — `_compute_forward_zoom_targets` dict-only cascade + `forward_zoom_targets` inject `k["label"]`
- `backend/app/core/steps/render_prompt_card.py` — `forward_zoom_targets[].keep_elements` raw list 보존 (CLAUDE.md 무절단)

**Tests**:
- `backend/tests/services/test_scene_reference_service.py` — d3 (zoom_in_detail 2-enum) + d4/d5/d5b (shape validation) + d6_legacy (immobilized_character reject)
- `backend/tests/services/test_phase4_iter7_stabilization.py` — `_KEEP_ELEMENT_PERSON_TOKENS` 폐기 검증
- `backend/tests/services/test_prompt_service_label_routing.py` — 정합
- `backend/tests/integration/test_g4_1_card_consumer_wiring.py` — render_prompt_card cascade
- `backend/tests/unit/test_render_prompt_card.py` — render_prompt_card cascade
- `backend/tests/core/test_detail_steps_keep_elements.py` (신규) — e1/e2/e3 forward_zoom_targets cascade
- `backend/tests/core/test_forward_zoom_targets.py` — 정합
- `backend/tests/fixtures/g4_6/s1_shot3_shot4_dependency.json` — 2-enum
- `backend/tests/fixtures/g4_6/s1_shot5_dependency.json` — 2-enum

---

## §2. Canary procedure (commits 후)

### Step A — F1 force re-run

```bash
curl -sS -b /tmp/theroad_session.cookie -X POST \
  "http://localhost:8000/api/v1/projects/02829fe8-af47-4dda-9cfe-af9457a4cd5b/episodes/fc38cf03-3863-4cdb-936a-3ef99438242c/steps/shot_dependency_t2i?mode=force"
```

검증 (cp 파일 직접 read):
```python
schema_version == 3
all keep_elements entries kind ∈ {"environment", "static_prop"}
immobilized_character entry count == 0
person-token (man/woman/character/body/figure/detective/prisoner/child) label count == 0
```

### Step B — F3 force re-run (scene_detail consumer)

```bash
curl -sS -b /tmp/theroad_session.cookie -X POST \
  ".../steps/scene_detail?mode=force"
```

검증:
- 57 shots completed
- forward_zoom_targets keep_elements 이 environment/static_prop 만 prompt 로 cascade
- 회귀 0

### Step C — F1b shot_dependency_t2i 재실행 (양방향 정합)

```bash
curl -sS -b /tmp/theroad_session.cookie -X POST \
  ".../steps/shot_dependency_t2i?mode=force"
```

검증:
- F1 동일 (kind 2종, person 0)
- 새 scene_detail 기준으로 deps 재정렬 정상

### Step D — scene_image_pipeline force 보류

D-next-min 의 본질은 keep_elements routing/validation 이지 PNG 품질 아님. PNG regen 은 별도 Area 로 진행.

---

## §3. Verification checklist

### 3.1 Unit tests (clean rebuild 후)

```bash
backend/.venv/bin/python -m pytest \
  backend/tests/services/test_area_d_next_shot_dependency_t2i.py \
  backend/tests/services/test_scene_checkpoint_loaders.py \
  backend/tests/services/test_scene_reference_service.py \
  backend/tests/services/test_phase4_iter7_stabilization.py \
  backend/tests/services/test_prompt_service_label_routing.py \
  backend/tests/unit/test_scene_context_loader_load_dependencies.py \
  backend/tests/unit/test_render_prompt_card.py \
  backend/tests/integration/test_g4_1_card_consumer_wiring.py \
  backend/tests/core/test_detail_steps_keep_elements.py \
  backend/tests/core/test_forward_zoom_targets.py \
  -q
```

Expected: ~170+ PASS, 0 fail.

### 3.2 Broader regression

```bash
backend/.venv/bin/python -m pytest \
  backend/tests/unit/test_scene_context_owned_loader.py \
  backend/tests/unit/test_g3_2_close_skip_sentinel_drift.py \
  backend/tests/unit/test_scene_detail_verify_origin.py \
  backend/tests/unit/test_t2i_review_sentinel_refresh.py \
  backend/tests/unit/test_legacy_schema_bump_allowlist.py \
  backend/tests/core/test_scene_analysis_dto.py \
  backend/tests/core/test_chain_bg_guide.py \
  backend/tests/core/test_phase9_1_camera_consistency.py \
  backend/tests/core/test_scene_detail_analyze_one.py \
  backend/tests/core/test_consumes_downstream_integration.py \
  backend/tests/unit/test_g3_2_manifest_dag.py \
  backend/tests/core/steps/test_scene_consistency_status.py \
  backend/tests/core/steps/test_scene_consistency_validator.py \
  -q
```

Expected: ~140 PASS, 0 new fail.

### 3.3 Stale wording 검증

```bash
# v6 의미적 잔재 (없어야 함 — 역사적 reference 만 허용)
grep -rn "schema v6\|schema_version=2 (immobilized\|immobilized_character.*kind" backend/app/ --include="*.py" | grep -v "Area D-next-min" | grep -v "polled negation" | grep -v __pycache__
```

Expected: 0 hits (역사적 reference 는 의도적 narrative 유지).

---

## §4. Codex closure review prep

본 commits + canary 후 manual paste prompt 작성:
1. clean rebuild 결정 narrative (archive 보존 + main 깨끗하게)
2. spec §10 acceptance criteria 13 항목 PASS evidence
3. F1/F3/F1b canary 결과 (immobilized_character 0, person-like label 0, scene_detail cascade 정상)
4. broader regression 회귀 0

`/tmp/codex_closure_review_area_d_next_min.md` self-contained prompt 작성 → 사용자 별도 Codex tmux session 에 paste.

---

## §5. Push (closure review APPROVED 후)

```bash
git push origin main
```

archive branches:
- `archive/area-d-next-immobilized-attempt` @ 9e2e377 (origin/main 직전 D-next 시도)
- `archive/area-d-next-min-iteration` @ 3161e9e (Patch A/B/C+D iteration)

→ remote push 안 함 (local archive 만). 필요 시 별도 push 가능 (`git push origin archive/area-d-next-immobilized-attempt`).

---

## §6. Lesson (carry to MEMORY.md)

1. **LLM-side classification 의 한계**: open-world semantic 판단 (active vs immobilized character) 은 prompt wording 강화로 해결 불가. spec narrowing 후에도 LLM 분류 정확도 60% (Fix 1 결과).

2. **책임 경계 진단 의무**: 새 enum / SOT 도입 전 기존 layer 의 책임 census 필수. 4층 architecture (World State / Frame State / Render Contract / Reference Composition) + Visual Routing Matrix 활용.

3. **Consumer-side dispatch 가 없으면 enum 자체가 over-engineering**: Area B 의 `required_refs[].kind` 와 Area C 의 `reproduction_surface_rule.applies` 는 consumer 가 분기 → 의미 있는 enum. D-next 3-kind 는 consumer label-only → 의미 0.

4. **Cross-layer leak 차단**: producer 가 다른 layer 의 SOT (scene_consistency.character_state) 를 user_prompt 에 inject 하면서 LLM 에게 재분류 요청 = architectural smell.

5. **Clean rebuild 가치**: failed attempt commits 가 main 에 남으면 다음 Area 의 closure review 비용 증가. archive 보존 + main 재구성이 closure review narrative 깔끔.

6. **Salvage + Boundary Reset 패턴**: 전부 폐기 아니라 valid work (C8 regex 폐기, validation 로직, refactor, fixture, cleanup) 는 살리고 책임 경계 오류만 좁힘. 자율 판단보다 사용자 review 후 진행.

7. **양방향 canary (F1 → F3 → F1b)**: producer 변경 후 producer 만 force re-run 하면 downstream consumer 가 새 cp consume 검증 안 됨. F3 (consumer force) + F1b (양방향 정합) 까지 closure narrative 완성.
