# `PREVIOUS STILL USAGE` 가 남의 관할을 말하던 것 (감사 1-E)

2026-08-27

## 실측이 가리킨 자리

절 사이 충돌 실측(120쌍): **동시 등장 57% 인데 실제 충돌은 16%**, 그리고
**충돌의 74% 가 이 절**이었다.

전역 우선순위 줄을 넣는 안은 **기각**했다 — 충돌 없는 84% 를 건드리면서
19건 중 14건만 닫는다.

## 뿌리 — 팩 안에서 자기모순

`prompts/_base/shot_ref_classify/4.*/prev_system.md`

| | 무엇을 말하나 |
|---|---|
| (a) prev 를 **고를 때** | 「인물의 의상·자세 일관성은 **별도 장치가 담당하므로 고려하지 마라**」 |
| (b) `usage_en` 을 **쓸 때** | 「TAKE: … **움직일 수 없는 인물의 자세·위치, 인물의 의상**」 |

그 「별도 장치」가 실제로 있다 — `still_recipe.build_prev_people_rule`:

    The clothing, hair and overall look of {shared_names} … are LOCKED
    to that photo.

즉 **같은 것을 두 곳이 말한다**(1-H 의 마감 이중 소유와 같은 모양).

## `usage_en` 실측 — 체크포인트 1,056 칸

| 축 | 비율 | 누가 소유해야 하나 |
|---|---|---|
| **인물**(자세·위치·의상) | **707 (66%)** | `prev_people_rule` 이 **이미** 담당 |
| **카메라**(각도·구도) | **253 (23%)** | staging 소유 — 저작 때 **못 본다** |
| 장소(룩·재질·조명) | 523 (49%) | 이어받아도 안전 |

표본이 못박는다:

    Exclude the prior full standing composition …
    Exclude the wide empty-room composition …
    Exclude the upward-looking …
    the young woman's continuing clothing and position …

★`shot_ref_classify` 의 `depends_on` 에 `shot_staging` 이 **없다.** 이 샷의
 촬영 계획을 못 본 채 「구도를 배제하라」고 쓰는 것은 **추측**이고, 그
 추측이 계획과 어긋나면 그림이 둘 중 하나를 버린다.

★낱말표는 **바닥값**이다 — 정확한 비율은 글자로 못 센다. 여기서 정한 것은
 「이 축이 실재하는가」다.

## 고친 법

### 저작 쪽 — 팩 v5

    TAKE      **장소와 사물만.** 벽·바닥·천장의 룩과 재질, 조명과 색감,
              붙박이, 그대로 남아 있는 상태물
    EXCLUDE   그대로 — 이 샷에 없어야 할 가구·인물·소품
    금지 ①    TAKE 에 사람에 관한 것을 쓰지 마라 (다른 장치가 정한다)
    금지 ②    TAKE·EXCLUDE 어디에도 카메라·구도·거리·각도를 쓰지 마라
              (지금 그 계획을 못 본다)

★**사람을 빼라는 말은 EXCLUDE 에 허용한다.** 그건 이 샷에 없어야 할 것을
 말하는 것이라 겹치지 않는다 — 실측 표본에서 유용했다
 (`Exclude the prior seated version of the young woman`).

★**금지만 쌓지 않았다.** 이어받을 재료(벽·바닥·재질·조명)를 남기고,
 무엇이 카메라 축인지 **예를 들어** 줬다(`wide composition`, `close-up`,
 `the prior framing`).

### 조립 쪽 — 팩 33 에 스템 신설

헤딩이 **코드에 박혀 있었다**(`still_recipe.py:1972`). 팩 해시가 안 잡으니
문안을 고쳐도 지문이 안 움직인다 — 나가는 글만 바뀌고 옛 그림이 남는다.

새 문안이 **관할을 못박는다**:

    it governs place and objects only, never who is in this shot or how
    the camera sees them

★이걸 조립 쪽에도 두는 이유: **옛 CP 의 `usage_en` 에는 인물·카메라 말이
 들어 있다.** 저작을 고쳐도 이미 저장된 값은 그대로이므로, 한 번 더
 한정해야 그 옛 값이 남의 것을 못 지시한다.

## 안 한 것 — `shot_staging` 을 `depends_on` 에 넣기

`shot_staging`(19.5)이 `shot_ref_classify`(21.9)보다 먼저 돌아 넣을 수는
있다. **안 넣었다:**

| | |
|---|---|
| 반대편에 열리는 것 | `depends_on` 변경 → 완주 CP 재실행 파장 |
| 필요한가 | 팩 v5 가 이미 「카메라를 쓰지 마라」로 닫는다 |
| 넣으면 방향이 | 「보고 **맞춰 써라**」 — **더 많은 지시**를 만든다 |

시험이 이 결정을 기록한다
(`test_staging_was_deliberately_not_added_as_a_dependency`) — 나중에 넣기로
하면 그 시험을 뒤집고 **재실행 비용을 같이 적는다.**

## 지출 — ★내가 처음에 틀리게 썼다

처음 이 절에 **「분석 콜만 다시 돈다, 이미지 아님」**이라고 썼다.
**틀렸다.** Codex 가 잡았고 코드로 확인했다.

### ① 「다시 돈다」가 아니라 **BLOCK 이다**

    step_runner.py:902  「config_hash mismatch 는 모든 step BLOCK
                         (사용자 의도 반영 — project_config 변경은
                          자동 재실행 시 의도와 다른 결과 위험)」

허용 목록(`_LEGACY_SCHEMA_BUMP_ALLOWLIST`)은 `schema_version` 에만 걸리고
거기 든 것은 `entity_t2i` 하나다. 완주한 스텝은 **스스로 다시 돌지 않고
멈춘다.**

### ② force 를 쓰면 **이미지를 다시 산다**

    analysis_dispatch_service.py:165
      「StepRunner.run() 의 force 동작이 invalidate_downstream(delete_cp=True)
       호출 → transitive downstream manifest 모두 delete」

`shot_ref_classify` 를 force 하면 하류가 통째로 지워지고 그 안에
`scene_image` 가 있다. **그림값이 든다.**

### ③ 옛 CP 를 지켜도 프롬프트는 바뀐다

조립 쪽만 고쳐도 prev 가 있는 샷의 문안이 달라진다 → 샷별 JIT 재검이
그것을 새 그림으로 본다. 「CP 를 안 건드리면 공짜」가 아니다.

## 그래서 이 판의 결정 — **새 주행에만 적용한다**

    · 스템 바이트를 `_config_hash_base()` 에 접는다
      (`recipe_prev_usage_pack` · `recipe_prev_usage_stem_content`)
    · 완주한 에피소드는 **BLOCK 으로 선다.** 그게 맞다 —
      문안이 바뀌었는데 옛 그림을 조용히 재사용하는 것보다 낫다
    · **옛 주행을 force 로 밀지 않는다.** 밀 이유가 생기면 그때
      샷 수 × 장당 값을 적고 따로 승인을 받는다

★**접지 않는 선택지는 없다.** 안 접으면 완주 스텝이 whole-step clean skip
 해서, 옛 그림을 지키려고 넣은 관할 한정이 정작 나가는 프롬프트까지
 못 내려간다 — **고친 것이 아무 데도 안 닿는다.**

### 재발 방지

`schema_version` 이 안 바뀐 것은 맞고 시험도 그대로다
(`test_only_the_prev_stem_changed`). 내가 틀린 것은 **`config_hash` 쪽
계약을 안 읽고 「스키마가 그대로니 안 막힌다」로 건너뛴 것**이다.
지문·재개 이야기를 쓸 때는 `step_runner._evaluate_contract_drift` 와
`analysis_dispatch_service` 를 열어 보고 쓴다.

## 도구

`backend/tools/prompt_measure/audit_prev_usage_scope.py` — 체크포인트에서
`usage_en` 을 전수로 읽어 세 축의 비율을 센다(무료).
