---
title: Area #6 — T2I Review Mutation Redesign (Track B Tier 2 #4)
date: 2026-05-18
status: closed (2026-05-18+, W1-W3 commits + W1 per-wave APPROVED + W1..W3c range review APPROVED + canary 5 PASS + residue gate 2 PASS)
roadmap_ref: docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-map.md §8 Area 5 (debt map naming) / 사용자 8-area memo §5.6 (Area #6)
audit_rows:
  - 01-code-side-regex-audit.md #10 (t2i_review blind substring `.replace()` mutation, line 186-190, 3 mutation site `:395 :402 :451`)
  - 02-prompt-side-hygiene-audit.md P-6 (synthetic placeholder example block, scene_system.md:45-78, boundary 본 area 일부 + Area #7 hygiene v2 carry)
  - 03-llm-side-heuristic-audit.md L-3 (6 issue type + target/suggestion mutation classifier instruction, line 73-79, fix direction line 165 verbatim)
prerequisites:
  - Patch A 4 helper (V3 patch I1 + AC-A1..A6, `_build_item_id_map` + `_refresh_scene_detail_sentinels` + `_capture_card_hash_state` + `_assert_card_hash_unchanged`) — production 잔존, 본 area 보존 의무
  - B1 patch (manifest fail-fast, `_save_checkpoint_data`, commit `23d63f5`) — silent skip 차단, 본 area 보존 의무
  - Area #5 W3 closure (commit `4853c7b`, `close_framing_existing_ref` 4.x → 5.x 폐기) — Area #6 복구 금지 boundary
non_supersedes:
  - Area #5 reference phrase phantom guard SOT (closed, commit `fe300bf..` Tier 2 #2) — `close_framing_existing_ref` 폐기는 Area #5 결과, 본 area 복구 0
  - Area #7 Prompt Hygiene v2 (active prompt closed-list cleanup, P-6 broader hygiene) — placeholder abstraction noun (`<frame-edge surface>`, `<character_id>`, `<shared support surface descriptor>`) 자체 cleanup 은 별도 area carry
  - Area #11 prompt_service `_classify_label` 11-enum (closed, Tier 2 #3) — label dispatch layer 별도 축
  - downstream cascade orchestration 신설 (`shot_dependency_t2i` / `scene_image_pipeline` 자동 force re-run) — 본 area v1 = signal only, 운영자 / 외부 orchestrator force 의무
---

# Area #6 — T2I Review Mutation Redesign (v1)

## 1. Purpose + Scope

### 1.1 Purpose

`backend/app/modules/pipeline/t2i_review.py:383-454` 의 `_apply_entity_fixes` (line 383-404) + `_apply_scene_fixes` (line 407-454) 가 LLM emit `target -> suggestion` 으로 `old.replace(target, suggestion)` blind substring mutation 으로 T2I prompt body 를 직접 변경. 3 mutation site (`:395` entity / `:402` entity completed / `:451` scene). `target` substring 이 prompt 내 다중 등장 시 의도 외 위치도 변조 (over-replace risk) — Patch A V3 patch I1 의 `item_id` fan-out 차단으로 inter-variation 모호성은 해소됐으나 intra-prompt substring 모호성은 본 area v1 의 fix scope.

본 area = `target/suggestion` mutation 완전 폐기 + LLM emit shape 를 `{id, scope, issue_code, action, hint_diagnostic}` **5 core fields** structured diagnostic 으로 재설계. t2i_review v1 은 **in-step regeneration 실행 0** — 외부 force signal 만 emit. cascade 정책 1-pass (`step_runner.py:1295-1308`) 보존, 재생성 orchestration 신설은 scope inflation 으로 v1 제외.

audit fix direction L-3 line 165 verbatim:
> `target.replace()` mutation 폐기 + LLM 이 `{item_id, issue_code, regenerate_required: bool, hint_diagnostic: str}` 만 emit → 코드는 regenerate trigger 만. span position / patch ID 도입 시 mutation 유지 가능. Codex P1-5 fix direction.

본 area = 위 fix direction 의 Option A' (regen-trigger / diagnostic-only) 채택. Option B (span position) + Option C (hybrid) 모두 reject — Option B 는 LLM span 정확도 신규 SOT risk, Option C 는 dual-path 복잡도 + low-risk issue 1-3 의 중복 substring 문제 해소 X.

### 1.2 In-scope

**Code (3 surface groups / 6 site)**:

> `HHMM` placeholders are implementation-time timestamp placeholders; W1 must replace them with the actual prompt directory timestamp before commit.

| Site | File | Lines | Action |
|---|---|---|---|
| Entity mutation 본체 | `backend/app/modules/pipeline/t2i_review.py` | 383-404 (`_apply_entity_fixes`) | 함수 폐기 (3 occurrence `target` + 2 `.replace()` + 2 `target in old`). diagnostic-only 변환: detected fixes 를 `diagnostics: list[dict]` 로 누적. |
| Scene mutation 본체 | `backend/app/modules/pipeline/t2i_review.py` | 407-454 (`_apply_scene_fixes`) | 함수 rewrite: `item_id_map` lookup + `applied_indices` 유지 (Patch A V3 patch I1 보존), 단 `old_prompt.replace(target, suggestion)` 폐기. `scene_applied_indices` 는 항상 `[]` return (canary contract). diagnostic 누적. |
| `run_t2i_review` orchestrator | `backend/app/modules/pipeline/t2i_review.py` | 38-99 | `_apply_*_fixes` call site → diagnostic 누적으로 변경. `entity_applied / scene_applied / scene_applied_indices` 모두 0/0/[] hard-coded canary (Patch A invariant 보존). 기존 `details: {entity, scene}` dict **폐기 + `diagnostics: list[dict]` array 로 대체** (Q9 결정 정합, "또는" wording 폐기). |
| Entity batch review | `backend/app/modules/pipeline/t2i_review.py` | 159-234 (`_review_entity_t2i`) | LLM emit shape 변경 — schema 가 `{id, scope: "entity", issue_code (enum3), action, hint_diagnostic}` **5 core fields** + optional alias `short_id` 로 재정의. fail-fast guard (B2 patch) 보존. log 의 `iss["target"] / iss["suggestion"]` 폐기, `iss["issue_code"] / iss["hint_diagnostic"]` 로 변경. |
| Scene batch review | `backend/app/modules/pipeline/t2i_review.py` | 241-376 (`_review_scene_detail`) | LLM emit shape 변경 — schema 가 `{id, scope: "scene", issue_code (enum5), action, hint_diagnostic}` **5 core fields** + optional alias `item_id`. result-level `id`/`item_id` schema-required (T5 stabilization v2 정합) 보존. fail-fast guard 보존. |
| Step orchestrator output | `backend/app/core/steps/t2i_review_step.py` | 53-117 (`_execute`) | `review_summary` shape 확장 — `entity_detected / scene_detected / entity_applied (=0) / scene_applied (=0) / regeneration_required: {entity, scene}` + 신규 `diagnostics: list[dict]`. backward-compat 유지. `applied_indices` empty 시 `_refresh_scene_detail_sentinels` + `_assert_card_hash_unchanged` not invoked (line 71 `if review_result["scene_applied"] > 0:` branch). 검증 canary 신설. |

**Prompt (4 stem / v6 pack 동시 신설)**:

| Stem | Current path (drift state) | New path | Action |
|---|---|---|---|
| scene_system.md | `prompts/_base/t2i_review/5.202605181528/scene_system.md` (5 issue type, target/suggestion + synthetic placeholder line 44-60) | `prompts/_base/t2i_review/6.20260518HHMM/scene_system.md` | (1) target/suggestion 규칙 (line 69-77) 폐기, `issue_code / hint_diagnostic` 작성 가이드 신설. (2) 5 issue type 본문 (line 14-66) 보존, 단 각 issue type 의 "target/suggestion 작성 방식" 하위 section 폐기 (regen diagnostic instruction 으로 대체). (3) line 44-60 synthetic placeholder 예시 block (`<frame-edge surface>` 등) 의 target/suggestion 형식 폐기 + hint_diagnostic 작성 원칙 5-7 lines 신설. abstraction noun 자체는 보존 (P-6 hygiene 영역 별도 closure). (4) ITEM_ID PROTOCOL section (line 78-83) 보존. |
| scene_schema.json | `prompts/_base/t2i_review/5.202605181528/scene_schema.json` (5 enum + target + suggestion) | `prompts/_base/t2i_review/6.20260518HHMM/scene_schema.json` | issue object shape: **5 core fields** `{id, scope: const "scene", issue_code: enum5 (missing_ethnicity / proper_noun_translated / awkward_translation / physical_inconsistency / unshared_fg_bg_actors), action: enum1 (regen_required), hint_diagnostic: str}` + optional debug alias `item_id` (= `id` value 동일) strict. `target / suggestion` field 폐기. `additionalProperties: false`. (Q8 정합) |
| entity_system.md | `prompts/_base/t2i_review/4.202605150957/entity_system.md` (v4 stem drift — v5 dir 미존재) | `prompts/_base/t2i_review/6.20260518HHMM/entity_system.md` | (1) target/suggestion 규칙 (line 21-23) 폐기, `issue_code / hint_diagnostic` 작성 가이드 신설. (2) 3 issue type 본문 (line 10-13) 보존, 단 각 issue type 의 target/suggestion 형식 폐기 (regen diagnostic instruction 으로 대체). (3) emit shape protocol section 추가 (`short_id` echo 의무). |
| entity_schema.json | `prompts/_base/t2i_review/4.202605150957/entity_schema.json` (v4 stem drift) | `prompts/_base/t2i_review/6.20260518HHMM/entity_schema.json` | issue object shape: **5 core fields** `{id, scope: const "entity", issue_code: enum3 (missing_ethnicity / proper_noun_translated / awkward_translation), action: enum1 (regen_required), hint_diagnostic: str}` + optional debug alias `short_id` (= `id` value 동일) strict. `target / suggestion` field 폐기. `additionalProperties: false`. (Q8 정합) |

**Version bump (cp invalidation + stem drift 해결)**:

| Constant / Path | From | To |
|---|---|---|
| `t2i_review` scene stem | `5.202605181528` | `6.20260518HHMM` |
| `t2i_review` entity stem | `4.202605150957` (v5 미존재 stem drift) | `6.20260518HHMM` (동시 신설) |
| `step_manifest.py` t2i_review row `schema_version` | (없음 — 미설정) | `1` 신규 — **W1 단일 atomic commit 안에 포함** (code + prompt + manifest 동시 변경 = 동일 commit, separate commit 금지) |

`schema_version` 신설 결정 (Codex Round 4 NEEDS_REVISION_MAJOR Finding 3 fix-up): output cp shape (`review_summary` shape 확장 + `diagnostics` array 신설) 변경되므로 step_runner `_check_cp_mismatch` 가 stale cp 감지 가능해야 함. v1 = 신규 schema 라 schema_version `1` 부여 (기존 cp = schema_version 미설정 → BLOCK + 운영자 명시 force 의무, D6 T5d 패턴). schema_version bump = code + prompt 와 동일 atomic commit (W1). W2/W3 중복 명시 폐기.

### 1.3 Out-of-scope (Non-claim, closure 미선언)

| Item | Reason | Carry destination |
|---|---|---|
| `close_framing_existing_ref` issue type 복구 | Area #5 W3 commit `4853c7b` 결과 — 5.x scene_system.md 에서 19 line block (line 31-49) 완전 삭제. Area #5 phantom guard SOT (scene_detail v26 `reference_phrase_kinds` sidecar) 가 producer-side 대체. **Area #6 복구 = Area #5 boundary 침범** | Area #5 결과 보존, 변경 0 |
| Active v6 prompt placeholder abstraction noun cleanup (`<frame-edge surface>`, `<character_id>`, `<shared support surface descriptor>` 등 broader P-6 hygiene) | placeholder noun 자체는 hint_diagnostic 가이드 예시로 보존 가치 (LLM 학습 anchor). 전체 P-6 hygiene closure 는 별도 area | **Area #7 Prompt Hygiene v2** carry |
| Archived prompt (2.x / 3.x / 4.x 4 dir) `target/suggestion` + `close_framing_existing_ref` residue | archived 보존 정책 (rollback path) | residue gate scope 외 |
| downstream cascade orchestration 신설 (`shot_dependency_t2i` / `scene_image_pipeline` 자동 force re-run) | editorial cascade 1-pass 정책 (`step_runner.py:1295-1308`) 보존. orchestration 신설 = scope inflation | 운영자 / 외부 orchestrator force 의무. 별도 area / 사후 area |
| `regenerate_required` consumer code 신설 | v1 = signal only emit. consumer (외부 orchestrator) 가 cp data 소비 책임 | 별도 area / 운영 reading |
| `hint_diagnostic` LLM regen path inject | v1 prompt injection 금지. audit log only + future regen path 가 별도 area 에서 inject 결정 | 별도 area carry |
| Patch A 4 helper + B1 `_save_checkpoint_data` 함수 폐기 | mutation=0 후에도 defensive regression guard 가치 (미래 mutation 재도입 시 invariant 자동 보호) | 함수 보존, canary 로 not-invoked 검증 |
| `_classify_label` 11-enum (Area #11) + `_classify_*_token` (Area #5) | 다른 축 (label dispatch / phantom guard) | Area #11 / Area #5 결과 보존 |

## 2. Audit Evidence

### 2.1 Debt map §8 Area 5 verbatim

```
Goal:
- Move from blind substring replacement to structured patch IDs/spans or
  regeneration diagnostics.
```

### 2.2 Audit row 01-code #10 verbatim (debt-audit/01-code-side-regex-audit.md:186-190)

```
### #10. `t2i_review` blind substring `.replace()` mutation
- file:line: modules/pipeline/t2i_review.py:383-403 `_apply_entity_fixes` + :407-454 `_apply_scene_fixes`
- 동작: LLM emit `target -> suggestion` 으로 blind `.replace()`.
- 위험: item_id fan-out 차단 (Patch A 완료), 그러나 target substring 다중 등장 시 의도 외 위치도 변조 가능. prompt-side `t2i_review/.../scene_system.md:87-90` dual sync 의무.
```

### 2.3 Audit row 03-llm L-3 fix direction verbatim (debt-audit/03-llm-side-heuristic-audit.md:165)

```
L-3 t2i_review | `target.replace()` mutation 폐기 + LLM 이 `{item_id, issue_code, regenerate_required: bool, hint_diagnostic: str}` 만 emit → 코드는 regenerate trigger 만. span position / patch ID 도입 시 mutation 유지 가능. Codex P1-5 fix direction.
```

### 2.4 4.x → 5.x diff (commit `4853c7b` Area #5 W3)

```
< ### 4. close_framing_existing_ref ★ 신규 — close framing 시 reference 가정 표현 누출
< shot의 camera_direction에 close-framing tag (`ECU`, `XCU`, `extreme close-up`, `MCU`, `medium close-up`, `close-up`, `CU`)가 ...
< (19 lines deleted)
---
> ### 4. physical_inconsistency ★ 신규 — 카메라 위치와 frame edge 요소의 물리 모순
```

`close_framing_existing_ref` issue type 은 Area #5 W3 W3 caller cascade 4-tuple + 4 prompt sync 결과로 완전 제거. Area #6 복구 금지.

## 3. Q1-Q10 Decision Table

각 Q 별 verdict + rationale + Codex iter 흡수.

### Q1 — Fix direction

**Decision**: Option A' (diagnostic / regen-trigger emit only, in-step regen 금지).

**Rationale**: audit L-3:165 fix direction verbatim. Option B (span position) = LLM span 정확도 신규 SOT risk. Option C (hybrid) = dual-path 복잡도 + low-risk issue 1-3 의 중복 substring 문제 해소 X.

**Codex iter**: Round 1 NEEDS_REVISION (entity path 누락) → Round 2 PASS_WITH_CLARIFICATIONS → Round 3 APPROVED.

### Q2 — issue_code enum scope

**Decision**: scene path = enum 5 (`missing_ethnicity / proper_noun_translated / awkward_translation / physical_inconsistency / unshared_fg_bg_actors`) + entity path = enum 3 (`missing_ethnicity / proper_noun_translated / awkward_translation`) **병렬**.

**Rationale**: entity context 에 physical_inconsistency / unshared_fg_bg_actors 의미 없음 (frame / fg-bg 인물 분리 X). enum 통일 시 LLM 혼동 risk. `close_framing_existing_ref` 복구 금지 (Area #5 W3 boundary 보존).

**Codex iter**: Round 1 권고 verbatim 수용 + Round 3 boundary cross-check `4853c7b` PASS.

### Q3 — regen trigger mechanism

**Decision**: external force signal only. t2i_review 가 `regeneration_required: {entity: N, scene: M}` count + `diagnostics` array 만 emit. cascade 정책 1-pass (`step_runner.py:1295-1308`) 보존. 재생성 orchestration 신설 = scope inflation 으로 v1 제외.

**Rationale**: editorial cascade 1-pass policy + manifest `step_type: "editorial"` 정합. 운영자 / 외부 orchestrator 가 cp data 소비 후 force re-run 의무.

**Codex iter**: Round 1 권고 verbatim + Round 3 cross-check `step_runner.py:1295-1308` PASS.

### Q4 — emit field `action`

**Decision**: `action: "regen_required"` enum. v1 = 단일 value. 미래 `audit_only / skip` 등 추가 가능 (enum extensibility).

**Rationale**: bool 보다 enum 우선 — v1 단일 value 면 bool 동등하지만 schema 미래 extension cost 0. Codex Round 1 권고.

**Codex iter**: Round 1 권고 + Round 2/3 confirmed.

### Q5 — `hint_diagnostic` 필드

**Decision**: required (non-empty string). v1 사용 범위 = production audit log only + future regeneration hint (별도 area). v1 prompt injection 금지 (MUST).

**Rationale**: data field 책임 분리. consumer (외부 orchestrator) 가 cp data 소비. v1 prompt injection 시 LLM regen path scope inflation.

**Codex iter**: Round 1 권고 + Round 2/3 confirmed.

### Q6 — closed boundary 보존 범위

**Decision**: 4 groups / 5 functions 전부 보존:

| Group | Function | Defense purpose |
|-------|----------|-----------------|
| Item ID map (Patch A V3 patch I1) | `_build_item_id_map` (`t2i_review.py:21-35`) | Inter-variation fan-out 차단. emit shape 변경 후에도 item_id echo 의무 — 보존 필수. |
| Sentinel refresh (Patch A AC-A1) | `_refresh_scene_detail_sentinels` (`t2i_review_step.py:184-214`) | mutation 후 owned hash sync. v1 mutation=0 시 branch not invoked (`if scene_applied > 0:` line 71). dead-code 아닌 defensive regression guard. |
| Card hash defense (Patch B V2 patch P2) | `_capture_card_hash_state` (`t2i_review_step.py:217-233`) + `_assert_card_hash_unchanged` (`t2i_review_step.py:236-258`) | t2i_review 가 card payload 변경 차단 (AC-A3). v1 mutation=0 시 trivially PASS. defensive guard. |
| Checkpoint save fail-fast (B1 patch) | `_save_checkpoint_data` (`t2i_review_step.py:119-174`) | manifest missing/unreadable fail-fast (silent skip 금지). v1 mutation=0 시 호출 안 됨 (`if review_result["entity_applied"] > 0:` / `if review_result["scene_applied"] > 0:` branch). 보존. |

**Canary contract** (mutation=0 invariant):
- `entity_applied == 0` (hard-coded)
- `scene_applied == 0` (hard-coded)
- `scene_applied_indices == []` (hard-coded)
- `_refresh_scene_detail_sentinels` not invoked (`if scene_applied > 0:` branch unreached)
- `_capture_card_hash_state` invoked (run 전 capture 의무, `t2i_review_step.py:51`) but `_assert_card_hash_unchanged` not invoked (same branch)
- `_save_checkpoint_data` not invoked (`if entity_applied / scene_applied > 0:` branch unreached)

**Codex iter**: Round 1 권고 + Round 2 정정 ("sentinel call 폐기" controller 추천 reject, "보존 + not-invoked 검증" verbatim) + Round 3 confirmed.

### Q7 — active prompt rewrite scope

**Decision**: active v6 prompt rewrite = target/suggestion 규칙 + line 44-60 예시 block 만 폐기, abstraction noun (`<frame-edge surface>` 등) 자체 보존. closure claim 좁힘 = "t2i_review active prompt target/suggestion 폐기". **P-6 전체 prompt hygiene closure 선언 금지**.

**Rationale**: placeholder abstraction noun 은 LLM hint_diagnostic 작성 가이드 anchor 로 보존 가치. broader P-6 hygiene (closed-list cleanup beyond Area #6 surfaces) 는 Area #7 carry.

**Codex iter**: Round 1 권고 + Round 2 정정 ("synthetic placeholder 제외" controller 추천 reject, "rewrite 포함 + P-6 closure 금지") + Round 3 confirmed.

### Q8 — schema shape

**Decision** (Codex Round 4 NEEDS_REVISION_MAJOR Finding 2 fix-up): **5 core fields + optional debug aliases** + enum 분리 + schema file 별도.

`4-field shape` wording 폐기 (controller spec v1 draft 의 잘못된 표현).

Core shape (5 required fields):
```json
{
  "id": "<string, unified ID — entity scope: short_id 와 동일, scene scope: item_id 와 동일>",
  "scope": "entity" | "scene",
  "issue_code": "<enum 3 (entity) or enum 5 (scene)>",
  "action": "regen_required",
  "hint_diagnostic": "<non-empty string, audit log + future regen hint>"
}
```

Optional debug aliases (consumer single-path + audit log legibility):
- entity_schema.json: 추가 `short_id` field (= `id` value 와 동일, 디버깅 legibility)
- scene_schema.json: 추가 `item_id` field (= `id` value 와 동일, 디버깅 legibility)

Entity emit (in `entity_schema.json`, total 6 fields):
- core 5: `id` (= short_id 값) / `scope: const "entity"` / `issue_code: enum (missing_ethnicity / proper_noun_translated / awkward_translation)` / `action: const "regen_required"` / `hint_diagnostic: non-empty string`
- alias: `short_id` (= `id` 동일 값, 디버깅 가독성)

Scene emit (in `scene_schema.json`, total 6 fields):
- core 5: `id` (= item_id 값, e.g., `S1_L0_V0`) / `scope: const "scene"` / `issue_code: enum (5 type)` / `action: const "regen_required"` / `hint_diagnostic: non-empty string`
- alias: `item_id` (= `id` 동일 값, 디버깅 가독성)

**Rationale**: shape 통일 = consumer (외부 orchestrator) 가 동일 5 core fields (+ optional aliases) consume. enum 분리 = entity context 의미 적용 가능 type 만. schema file 별도 = entity vs scene path natural disambiguation.

**Codex iter**: Round 1 권고 (`id, issue_code, action, hint_diagnostic` 통일 + scope field 추가) + Round 2 U9 정정 (보조 디버깅 field 동시 emit).

### Q9 — output checkpoint shape

**Decision**: `review_summary` 유지 (backward-compat) + `regeneration_required` + `diagnostics` 추가.

```json
{
  "review_summary": {
    "entity_detected": <int>,
    "scene_detected": <int>,
    "entity_applied": 0,
    "scene_applied": 0,
    "regeneration_required": {
      "entity": <int>,
      "scene": <int>
    }
  },
  "diagnostics": [
    {"scope": "entity", "id": "<short_id>", "short_id": "<short_id>", "issue_code": "<enum3>", "action": "regen_required", "hint_diagnostic": "<str>"},
    {"scope": "scene", "id": "<item_id>", "item_id": "<item_id>", "issue_code": "<enum5>", "action": "regen_required", "hint_diagnostic": "<str>"}
  ],
  "scene_applied_indices": []
}
```

기존 `details: {entity, scene}` dict 폐기 (mutation 사라지면 의미 없음). 신규 `diagnostics` array 가 단일 통합 consumer-facing shape.

**Rationale**: current `_execute()` output = `review_summary` (`t2i_review_step.py:110-117`). backward-compat 유지 + 확장. `entity_applied/scene_applied = 0` hard-coded canary.

**Codex iter**: Round 2 U8 권고 verbatim.

### Q10 — version-pack drift 처리

**Decision**: v6 pack 4 stem 동시 신설 W1 (`prompts/_base/t2i_review/6.20260518HHMM/`):
- `scene_system.md`
- `scene_schema.json`
- `entity_system.md` (entity 4.x stem drift 해소)
- `entity_schema.json`

v5 dir (scene 만), v4 dir (entity 만) 보존 (rollback path, archived 정책).

**Rationale**: 5.x = scene 만 / entity 는 4.x 잔존 = stem drift. v6 동시 신설 = producer contract 시작점. loader (`prompt_loader.py:231`) 가 stem 별 최신 version 찾아 fallback — entity 4.x → 6.x 자동 bump.

**Codex iter**: Round 1 권고 + Round 2 U10 ("W1 4 stem 동시 신설" verbatim) + Round 3 confirmed.

### Q-additional 10-14 (Codex Round 3 추가)

**Q10 (변경 wave timing)**: 위 통합.

**Q11 — Entity prompt/schema active drift closure**:
- v6 pack 에 entity_system + entity_schema 포함 (Q10 의 일부).
- residue gate = active v6 entity + scene 모두 `target/suggestion` 0 검증.

**Q12 — No mutation guard (residue gate strict)**:
- production code residue: `old.replace(target, suggestion)` / `.replace(target, suggestion)` / `target in old` / `target in old_prompt` 모두 0 hits (production scope, archived prompt 제외).
- active v6 prompt residue: `target/suggestion` **field syntax** 0 hits (scoped pattern: `"target":` / `"suggestion":` JSON + `- target:` / `- suggestion:` markdown protocol bullet). 일반 영어 단어 "target" / "suggestion" 본문 자유 사용 허용.

**Q13 — Editorial cascade non-change claim**:
- Area #6 v1 = downstream force re-run 실행 0. `regeneration_required` count + `diagnostics` array 만 emit. 운영자 / 외부 orchestrator force 의무.
- spec / commit body 에 verbatim 명시: "Area #6 v1 does not change editorial cascade policy (1-pass). downstream orchestration introduction = future area carry."

**Q14 — Archived prompt boundary**:
- archived 2.x / 3.x / 4.x 4 dir = residue gate 제외 (rollback path 보존).
- active v6 만 strict.

## 4. Architecture

### 4.1 Emit path (LLM → schema → diagnostic accumulator)

```
LLM (gpt) emit (per item)
  ↓
{id, scope, issue_code, action, hint_diagnostic, [short_id|item_id]}
  ↓
schema 검증 (entity_schema.json / scene_schema.json strict, additionalProperties: false)
  ↓
_review_entity_t2i / _review_scene_detail batch 결과 누적
  ↓
run_t2i_review 가 diagnostic list 통합 → diagnostics array
  ↓
_execute() output cp:
  review_summary: {entity_detected, scene_detected, entity_applied=0, scene_applied=0, regeneration_required: {entity, scene}}
  diagnostics: [...]
  scene_applied_indices: []  (canary contract)
```

### 4.2 No-mutation invariant

- `_apply_entity_fixes` 폐기 — entity_t2i_data 의 `t2i_prompt` 필드 변경 0.
- `_apply_scene_fixes` rewrite — scene_detail_data 의 `t2i_prompt` 필드 변경 0. `item_id_map` lookup + `applied_indices` empty list return.
- `_save_checkpoint_data` 호출 0 (`entity_applied / scene_applied = 0` branch unreached).
- `_refresh_scene_detail_sentinels` + `_assert_card_hash_unchanged` 호출 0 (`scene_applied > 0` branch unreached, `t2i_review_step.py:71`).
- `_capture_card_hash_state` invoked (run 전 capture 의무, `t2i_review_step.py:51`) — defensive baseline 보존.

### 4.3 Consumer contract (external orchestrator)

v1 = signal only. cp data 소비 consumer (별도 area 또는 운영자) 책임:
- `review_summary.regeneration_required.entity / .scene` > 0 → force re-run 의무
- `diagnostics` array iterate → 개별 issue 별 처리 (entity_t2i regen vs scene_detail regen 분기)
- consumer code 신설 = v1 scope 외

## 5. Closed Boundary

### 5.1 Patch A / B / B1 보존 invariant (Q6 정합)

위 §3 Q6 table verbatim.

### 5.2 Defensive guard rationale

mutation 폐기 후 5 functions 모두 trivially PASS (호출 안 됨 또는 trivially success). 그러나 미래 mutation 재도입 시:
- `_apply_*_fixes` 재구현 → `_refresh_scene_detail_sentinels` 자동 검증 (owned hash drift 차단)
- card payload 변경 시도 → `_assert_card_hash_unchanged` 자동 차단 (AC-A3)
- manifest missing / unreadable → `_save_checkpoint_data` fail-fast (B1)
- inter-variation fan-out → `_build_item_id_map` deterministic dispatch

dead code 아닌 **defensive regression guard** — Area #6 closure 시 spec wording 명시 의무.

### 5.3 Canary contract (Q6 invariant 검증)

W4 단위 test 신설 (또는 기존 `test_t2i_review_sentinel_refresh.py` 확장):

```python
def test_no_mutation_invariant():
    # mutation=0 path 검증
    result = run_t2i_review(...)
    assert result["entity_fixes"] >= 0  # detected count
    assert result["scene_fixes"] >= 0
    assert result["entity_applied"] == 0  # canary
    assert result["scene_applied"] == 0
    assert result["scene_applied_indices"] == []  # canary
    # diagnostic count = detected count (1:1 mapping)
    assert result["regeneration_required"]["entity"] == result["entity_fixes"]
    assert result["regeneration_required"]["scene"] == result["scene_fixes"]

def test_sentinel_branch_not_invoked():
    # _refresh_scene_detail_sentinels + _assert_card_hash_unchanged 호출 0 검증
    # mock 또는 spy 로 호출 횟수 0 assert
    ...

def test_w1_atomicity_invariant():
    """Codex Round 4 NEEDS_REVISION_MAJOR Finding 1 + Round 5 Canary pseudo-test fix-up.

    v6 schema active (5 core fields) 와 production code consumer (reader pattern) 정합 검증.
    Mixed state (v6 schema active + 옛 target/suggestion reader 잔존) 절대 0 — 주석만 아니라
    실제 assert 의무.
    """
    import re, pathlib
    from app.modules.prompt_loader import load_schema

    # (a) v6 active schema = 5 core fields strict
    for stem in ("scene_schema", "entity_schema"):
        schema = load_schema("t2i_review", stem)
        issue_obj_schema = schema["properties"]["results"]["items"]["properties"]["issues"]["items"]
        required = set(issue_obj_schema["required"])
        assert {"id", "scope", "issue_code", "action", "hint_diagnostic"}.issubset(required), (stem, required)
        assert "target" not in required and "suggestion" not in required, (stem, required)

    # (b) production code 가 동일 contract consumer — reader pattern 0 의무 (W1 atomicity)
    src = pathlib.Path("backend/app/modules/pipeline/t2i_review.py").read_text()
    forbidden_reader_patterns = [
        r'iss\["target"\]', r'iss\["suggestion"\]',
        r'iss\.get\(\s*["\']target["\']\s*\)', r'iss\.get\(\s*["\']suggestion["\']\s*\)',
        r'fix\["target"\]', r'fix\["suggestion"\]',
        r'fix\.get\(\s*["\']target["\']\s*\)', r'fix\.get\(\s*["\']suggestion["\']\s*\)',
    ]
    for pat in forbidden_reader_patterns:
        assert re.search(pat, src) is None, f"production reader pattern {pat!r} 잔존 (W1 atomicity 위반)"
```

## 6. Residue Gate (Q12 No-mutation guard)

Codex Round 4 NEEDS_REVISION_MAJOR Finding (residue gate fragility) fix-up: broad `grep -rE` 폐기, scoped Python/rg line-window 사용.

### 6.1 Production code residue (strict 0, scoped)

scope: `backend/app/modules/pipeline/t2i_review.py` mutation site (line 383-454) + caller (`backend/app/core/steps/t2i_review_step.py`).

```bash
# rg scoped to t2i_review production mutation sites only
rg -n --type py 'old\.replace\(target, suggestion\)|\.replace\(target, suggestion\)|target in old|target in old_prompt' \
    backend/app/modules/pipeline/t2i_review.py \
    backend/app/core/steps/t2i_review_step.py
# expected: 0 hits (production scope strict)
```

`backend/app/` 의 다른 incidental 한 `.replace(` 사용 (DB row formatting / path helper 등) 은 scope 외 — Codex audit 02 P2-6 정합.

### 6.2 Active v6 prompt residue (strict 0, scoped 4 file)

scope: `prompts/_base/t2i_review/6.*/` 4 file (scene_system / scene_schema / entity_system / entity_schema). archived 5.x / 4.x / 3.x / 2.x 제외.

```bash
# rg scoped to active v6 pack 4 file
rg -n 'target|suggestion' prompts/_base/t2i_review/6.*/
# expected: 0 hits for target/suggestion field syntax (manual rg, scoped test 가 strict 본체)
# 일반 영어 단어 "target" / "suggestion" 본문 자유 사용 허용 — closure claim = field syntax 0 (단일 wording)
```

scoped test 구현 (`backend/tests/unit/test_area_6_residue_gate.py` 또는 동급):
```python
import re, pathlib
PROMPT_DIR = pathlib.Path("prompts/_base/t2i_review")

def test_active_v6_no_target_suggestion_field():
    """v6 pack 4 file (scene + entity, .md + .json 모두) 안 target/suggestion field syntax 0.

    Codex Round 5 NEEDS_REVISION_MINOR Finding 3 fix-up: .md system prompt 도 검사 의무.
    .md 안 일반 영어 단어 false positive 회피 위해 schema field syntax pattern 만 검사.
    """
    v6_dirs = sorted(PROMPT_DIR.glob("6.*"))
    assert len(v6_dirs) == 1, f"single active v6 pack 의무, got {len(v6_dirs)}"
    v6 = v6_dirs[0]
    # 4 file 모두 검사 (entity_system.md + entity_schema.json + scene_system.md + scene_schema.json)
    files = sorted(v6.iterdir())
    assert {f.name for f in files} == {
        "entity_system.md", "entity_schema.json", "scene_system.md", "scene_schema.json"
    }, f"v6 pack 4 file 의무, got {[f.name for f in files]}"
    # JSON schema field syntax: "target" / "suggestion" (double-quoted)
    # Markdown protocol section syntax: - target: ... / - suggestion: ... (bullet field)
    forbidden_patterns = [
        r'"target"\s*:',           # JSON schema field
        r'"suggestion"\s*:',        # JSON schema field
        r'^\s*-\s*target\s*:',     # Markdown protocol bullet
        r'^\s*-\s*suggestion\s*:', # Markdown protocol bullet
    ]
    for fp in files:
        s = fp.read_text()
        for pat in forbidden_patterns:
            hits = re.findall(pat, s, re.MULTILINE)
            assert not hits, f"{fp.name} contains forbidden pattern {pat!r}: {hits[:3]}"

def test_production_no_blind_mutation():
    """t2i_review.py 안 mutation site + target/suggestion reader pattern 모두 0.

    Codex Round 5 NEEDS_REVISION_MINOR Finding 3 fix-up: reader pattern (iss["target"] 등)
    잔존 시 v6 schema 활성 후 KeyError 발생. mutation site grep 만으로는 W1 atomicity 보장 X.
    """
    src = pathlib.Path("backend/app/modules/pipeline/t2i_review.py").read_text()
    mutation_patterns = [
        r"old\.replace\(target,\s*suggestion\)",
        r"old_prompt\.replace\(target,\s*suggestion\)",
        r"\.replace\(target,\s*suggestion\)",
        r"target\s+in\s+old\b",
        r"target\s+in\s+old_prompt\b",
    ]
    reader_patterns = [
        r'iss\["target"\]',
        r'iss\["suggestion"\]',
        r'iss\.get\(\s*["\']target["\']\s*\)',
        r'iss\.get\(\s*["\']suggestion["\']\s*\)',
        r'fix\["target"\]',
        r'fix\["suggestion"\]',
        r'fix\.get\(\s*["\']target["\']\s*\)',
        r'fix\.get\(\s*["\']suggestion["\']\s*\)',
    ]
    for pat in mutation_patterns + reader_patterns:
        assert re.search(pat, src) is None, f"forbidden pattern {pat!r} found in t2i_review.py"
```

### 6.3 Archived prompt (residue scope 외)

- 2.x / 3.x / 4.x (4 dir) + 5.x = residue gate **제외**.
- rollback path 보존.

## 7. Schema_version invalidation policy (Q10 추가, Codex Round 4 Finding 3 fix-up)

**Decision**: `backend/app/core/step_manifest.py:758` t2i_review row 에 `schema_version: 1` 신규 부여 — **W1 단일 atomic commit 안에 포함** (code + prompt + manifest 동시 변경, separate commit 금지). 기존 cp (no schema_version) → `step_runner._check_cp_mismatch` BLOCK + 운영자 명시 force 의무 (D6 T5d 패턴 정합).

Rationale: schema_version bump 이 production cp shape 변경 / prompt active shape 변경 / code emit shape 변경 셋 모두와 동시 발생해야 atomicity 정합 (Codex Round 4 Finding 3). W2/W3 중복 명시는 spec v1 draft 의 결함 → 본 amend 에서 W1 일원화.

대안 비교 (참고):
- schema_version `1` 부여 (채택): stale cp 자동 BLOCK + 운영자 force. fail-fast 정합. 권장.
- explicit force_required: 운영자가 모든 cp 수동 force. fail-fast 강제 X. 운영 부담 증가. 폐기.

## 8. Wave Outline (3 wave, Codex Round 4 Finding 1+3 fix-up)

**Atomicity rationale**: v6 prompt pack 과 production code emit shape + manifest schema_version 모두 signature-breaking transition. loader (`prompt_loader.py:231`) 가 stem 별 최신 version auto-fallback → v6 신설 시 즉시 production runtime 활성화. code 가 옛 `target/suggestion` 의존 잔존 시 KeyError. → **W1 single atomic commit 의무** (Tier 1/2 carry lesson 정합).

### W1 — Atomic signature-breaking transition (v6 prompt pack + production code + manifest schema_version)

Single atomic commit:

**Prompt (4 file 신설, v6 pack)**:
- `prompts/_base/t2i_review/6.20260518HHMM/scene_system.md` 신설 (5 issue type 본문 보존, target/suggestion 작성 section 폐기, 5 core fields emit protocol section 명시, line 44-60 placeholder example → hint_diagnostic 작성 원칙 5-7 lines 대체, ITEM_ID PROTOCOL 보존)
- `prompts/_base/t2i_review/6.20260518HHMM/scene_schema.json` 신설 (5 enum + 5 core fields + `item_id` alias + additionalProperties: false)
- `prompts/_base/t2i_review/6.20260518HHMM/entity_system.md` 신설 (3 issue type 본문 보존, target/suggestion 작성 section 폐기, 5 core fields emit protocol + `short_id` echo section 신규)
- `prompts/_base/t2i_review/6.20260518HHMM/entity_schema.json` 신설 (3 enum + 5 core fields + `short_id` alias + additionalProperties: false)

**Production code 변경 (t2i_review.py + t2i_review_step.py)**:
- `t2i_review.py` `_review_entity_t2i` + `_review_scene_detail` result iter 변경 (`iss["target"]/iss["suggestion"]` → `iss["issue_code"]/iss["hint_diagnostic"]`)
- `t2i_review.py` `_apply_entity_fixes` 폐기 + entity diagnostic 누적 logic 신설
- `t2i_review.py` `_apply_scene_fixes` rewrite (item_id_map 보존, mutation 폐기, `applied_indices = []` return)
- `t2i_review.py` `run_t2i_review` orchestrator output dict 변경 (`details` 폐기, `diagnostics` array + `regeneration_required` 추가)
- `t2i_review_step.py` `_execute` output cp shape 변경 (`review_summary` shape 확장 + `diagnostics`)

**Manifest (step_manifest.py)**:
- `step_manifest.py:758` t2i_review row `schema_version: 1` 신규

W1 atomicity invariant (canary §5.3): v6 schema 활성 시 production code 가 5 core fields read 의무. Mixed window (v6 schema active + 옛 target/suggestion code) 절대 0.

### W2 — Docs + roadmap + cascade non-change claim

Atomic commit (docs only):
- `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-map.md` §8 Area 5 update (closure mark, Area #6 v1 결과 반영)
- `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/03-llm-side-heuristic-audit.md` L-3 update (fix direction 적용 결과)
- Closure non-claim memo: "Area #6 v1 does not change editorial cascade policy (1-pass). downstream orchestration introduction = future area carry."

### W3 — Closure cleanup + canary test 신설 + residue gate

Atomic commit:
- canary test 신설 (`backend/tests/unit/test_area_6_no_mutation.py` 또는 동급):
  - `test_no_mutation_invariant` (entity_applied=0 / scene_applied=0 / scene_applied_indices=[])
  - `test_sentinel_branch_not_invoked` (refresh + assert 호출 0)
  - `test_diagnostic_emit_shape` (5 core fields + aliases schema 검증)
  - `test_regeneration_required_count_matches_detected` (1:1 mapping)
  - `test_w1_atomicity_invariant` (v6 schema 5 core fields + production code 정합)
- residue gate 단위 test 신설 (`test_area_6_residue_gate.py`):
  - `test_active_v6_no_target_suggestion_field` (v6 prompt 4 file scoped)
  - `test_production_no_blind_mutation` (t2i_review.py mutation site scoped)
- 본 spec doc finalization + closure memo + roadmap mark closed
- Memory update (`session_20260518_area_6_t2i_review_mutation_redesign_v1_closure.md`)

## 9. Risks / Open Questions

### 9.1 Schema_version policy decision (Q10 추가) — CLOSED (Codex Round 4)

**결정 (W1 단일 atomic commit 안에 포함, separate commit 금지)**: Option α (schema_version `1` 부여 + step_runner BLOCK + 운영자 명시 force 의무). Option β (explicit force_required) 폐기.

기존 open question 은 spec §7 (Schema_version invalidation policy) 안 final decision 으로 closed.

### 9.2 `hint_diagnostic` empty string 허용 여부

v1 spec = required (non-empty). LLM 이 빈 string emit 시 schema 검증 fail. fail-fast 정합.

대안: empty string 허용 + run-time check → silent fallback risk (feedback_no_silent_fallback). reject.

### 9.3 Consumer code 책임 (v1 scope 외)

`regeneration_required` consumer code 신설 = 별도 area / 운영자 reading. v1 spec = signal only emit. consumer responsibility 명시는 commit body / closure memo.

### 9.4 `_capture_card_hash_state` invoked 보존 — CLOSED (Codex Round 4)

**결정**: invoke 자체 **보존** (defensive regression guard). `_capture_card_hash_state` 는 `_execute()` 진입 직후 (`t2i_review_step.py:51`) 호출 — `run_t2i_review()` 진입 전 baseline capture. v1 mutation=0 시 `_assert_card_hash_unchanged` 가 호출되지 않으나 capture 자체는 미래 mutation 재도입 시 자동 baseline 확보 가치.

## 10. NO VLM (Hard Constraint Inline)

본 area 의 모든 wave (W1-W3) 는 VLM (Vision Language Model) 기반 판단 / 검증 / 성능 전제 / 의존 구조 도입 0. fix-side mechanism = structured SOT (LLM emit 5 core fields) + schema enum + canary test + residue grep gate + audit log only.

[[feedback_no_vlm_dependency]] hard constraint 정합.

## 11. Codex Iter Summary

| Round | Verdict | Findings |
|-------|---------|----------|
| Q0-light Round 1 | NEEDS_REVISION (non-blocking) | entity path 누락 발견 (entity_system/schema v5 미존재 v4 stem drift). Q1-Q7 권고 + Q8-Q10 신규 추가 |
| Q0-light Round 2 | PASS_FOR_SPEC_DRAFTING_WITH_CLARIFICATIONS | Q1-Q10 outline confirmed. U8 review_summary 유지 / U9 diagnostics id 통합 / U10 v6 pack W1 / U11 placeholder rewrite + P-6 closure 금지 |
| Q0-light Round 3 (cross-analyze confirm) | PASS + APPROVED for spec drafting | controller cross-analyze (Area #5 W3 commit `4853c7b` boundary / Q3 cascade / Q9 review_summary / Q10 v6 stem) 모두 정합. 추가 의무 10-14 (schema_version / entity drift closure / no mutation guard / cascade non-change claim / archived boundary) |
| Spec Review Round 4 | NEEDS_REVISION_MAJOR | controller spec v1 draft `6035ae7` 의 3 Major finding: (1) W1 v6 pack 신설만 시 loader auto-fallback 으로 production runtime KeyError (atomicity 결함) — fix: W1+W2 atomic merge. (2) Q8 "4-field" wording 충돌 (실제 5 core fields + aliases) — fix: 5 core fields + optional debug aliases 명시. (3) schema_version 책임 W2/W3 중복 — fix: W1 일원화. + canary W1 atomicity invariant 추가 + residue gate scoped pattern. amend 1 commit `3eea676`. |
| Spec Review Round 5 | NEEDS_REVISION_MINOR | amend 1 `3eea676` 의 잔존 결함 3건: (1) "4-field" stale wording 잔존 (§1.1 line 29 / §1.2 line 47/48 / Q8 Rationale line 222) — fix: 모두 "5 core fields" 정정. (2) schema_version "W1 안 포함" wording 모호 ("안 포함" Korean 의미 의도 vs 반대 읽힘 risk, 4 곳) — fix: "W1 단일 atomic commit 안에 포함, separate commit 금지" 명시. (3) canary/residue test pseudo-check 결함 — fix: `test_active_v6_no_target_suggestion_field` 가 `.md` + `.json` 모두 검사 + scoped pattern (`"target":` JSON / `- target:` markdown), `test_production_no_blind_mutation` 에 reader pattern (`iss["target"]`, `iss.get("target")`, `fix["target"]` 등) 추가. amend 2 commit `4806014`. |
| Spec Review Round 5 추가 finding | NEEDS_REVISION_MINOR | Round 5 full 응답 안 추가 finding 2건 controller missed: (1) §1.2 line 46 `details: 폐기 또는 대체` wording (Q9 결정 = 폐기 + 대체 둘 다, "또는" 모호) — fix: "폐기 + diagnostics array 로 대체" 단일화. (2) `test_w1_atomicity_invariant` 본문 production code 정합 주석만 + 실제 assert 없음 — fix: production code reader pattern (`iss["target"]` 등) grep assert 추가. amend 3 commit `7328401`. |
| Spec Review Round 6 | NEEDS_REVISION_MINOR | amend 2/3 종합 narrow finding 2건: (1) §1.2 prompt table line 56/58 scene_schema/entity_schema row 가 Q8 shape (`{id, scope, ..., alias item_id\|short_id}`) 와 불일치 (`item_id` / `short_id` 만 명시, `id` core field 누락) — fix: row shape 정정 `{id, scope, ..., + optional debug alias}`. (2) residue gate closure claim wording 혼재 (`literal 0` line 280 + `literal field name 0` line 419 + `field syntax 0` line 432) — fix: 모두 `field syntax 0` 단일화 (scoped pattern only). amend 4 commit 진행. |

## 12. Function Boundary Cross-Check (Codex Round 3)

| Boundary | Function | File:Line | v1 Status |
|----------|----------|-----------|-----------|
| Patch A (V3 patch I1) | `_build_item_id_map` | `t2i_review.py:21-35` | invoked, deterministic id_map 유지 (item_id echo 의무) |
| Patch A (AC-A1) | `_refresh_scene_detail_sentinels` | `t2i_review_step.py:184-214` | not invoked (`if scene_applied > 0:` branch unreached) |
| Patch B (V2 patch P2, AC-A3) | `_capture_card_hash_state` | `t2i_review_step.py:217-233` | invoked (run 전 baseline 의무) |
| Patch B (V2 patch P2, AC-A3) | `_assert_card_hash_unchanged` | `t2i_review_step.py:236-258` | not invoked (`if scene_applied > 0:` branch unreached) |
| B1 patch (manifest fail-fast) | `_save_checkpoint_data` | `t2i_review_step.py:119-174` | not invoked (`if entity_applied / scene_applied > 0:` branch unreached) |

## 13. Closure Criteria

Area #6 v1 closure = 모두 다음 만족:

- W1-W3 모두 commit + push (W1 atomic signature-breaking transition + W2 docs + W3 closure cleanup)
- Codex per-wave review APPROVED (또는 NEEDS_REVISION_MINOR after fix-up APPROVED)
- residue gate (production scoped + active v6 scoped) strict 0
- canary test PASS (`test_no_mutation_invariant` + `test_sentinel_branch_not_invoked` + `test_diagnostic_emit_shape` + `test_regeneration_required_count_matches_detected` + `test_w1_atomicity_invariant`)
- residue gate test PASS (`test_active_v6_no_target_suggestion_field` + `test_production_no_blind_mutation`)
- Patch A / B / B1 boundary 5 functions 모두 production 잔존
- Editorial cascade 1-pass policy 변경 0 (`step_runner.py:1295-1308`)
- schema_version `1` 부여 (W1 단일 atomic commit 안에 포함, separate commit 금지, Option α)
- closure memo + roadmap mark closed + memory update

## 14. References

- audit row 03-llm L-3 (fix direction line 165): `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/03-llm-side-heuristic-audit.md`
- audit row 01-code #10: `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/01-code-side-regex-audit.md:186-190`
- debt map P1-5: `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-map.md:390-416`
- debt map §8 Area 5: `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-map.md:629-634`
- Area #5 W3 commit (close_framing_existing_ref 폐기): `4853c7b`
- Production code:
  - `backend/app/modules/pipeline/t2i_review.py`
  - `backend/app/core/steps/t2i_review_step.py`
  - `backend/app/core/step_manifest.py:758-770`
  - `backend/app/core/step_runner.py:1295-1308`
- Active prompt:
  - `prompts/_base/t2i_review/5.202605181528/` (scene only)
  - `prompts/_base/t2i_review/4.202605150957/` (entity stem drift)
- Hard constraint memo:
  - `[[feedback_no_vlm_dependency]]`
  - `[[feedback_codex_mcp_discussion_workflow]]`
  - `[[feedback_llm_based_judgment]]`

## 15. Closure Memo (2026-05-18+)

**Status**: CLOSED.

**Wave commits** (locally, push 보류 = Tier 2 carry policy):

- W1 atomic (signature-breaking transition): commit `8469511` — prompt v6 pack 4 file (`prompts/_base/t2i_review/6.202605181200/`) + `t2i_review.py` mutation 폐기 + `t2i_review_step.py` output cp 확장 + `step_manifest.py:758` `schema_version: 1` + 4 cascade test update (schema_v3 / apply_scene_fixes / run / evidence_consumer_wiring).
- W2 docs sync: commit `7e2b8cf` — debt-map §8 Area 5 + audit 03-llm L-3 row 모두 status: IN_PROGRESS (W1 production transition 적용 sync).
- W3a canary: commit `b9a64c7` — `test_area_6_no_mutation.py` 5 test PASS (no_mutation_invariant + sentinel_branch_not_invoked + diagnostic_emit_shape + regeneration_required_count_matches_detected + w1_atomicity_invariant).
- W3b residue gate: commit `85d2c0a` — `test_area_6_residue_gate.py` 2 test PASS (active_v6_no_target_suggestion_field + production_no_blind_mutation).
- W3c closure: 본 commit — 본 closure memo 추가 + spec status: design → closed + debt-map / audit row IN_PROGRESS → CLOSED 전환.

**Plan amend commits** (drift correction during execution):

- `6f118c2` plan amend 4 — W1 alias wording sync (`optional debug alias` → `required debug alias`, schema/code 정합, Codex W1 review Important #1 root cause).
- `df99f8c` plan amend 5 — W2 timing 정합 (`status: CLOSED` premature claim → `IN_PROGRESS` + W3c finalize transition).
- `256f6ee` plan amend 6 — W3a/W3b body path drift (`backend/app/...` hardcoded → BACKEND_ROOT = `parents[2]`).
- `b277e0e` plan amend 7 — W3b PROMPT_DIR path drift (`prompts/...` hardcoded → REPO_ROOT = `parents[3]`).

**Verdict per wave**:

- W1: Codex per-wave review NEEDS_REVISION_MINOR (Important #1 alias wording + Minor #1 mutation 전제 주석) → fix-up amend + plan amend 4 → narrow re-review APPROVED.
- W2: per-wave review 위임 안 함 (Codex W3 entry 의논 verdict: docs-only wave, W3 range review 에 묶음).
- W3a / W3b: per-wave review 위임 안 함 (controller direct execution, targeted pytest PASS evidence 보고).
- W3c (본 commit) + 전체 range review: 본 commit 후 Codex range review 위임 예정 (W1..W3c 5 wave + plan amend 4 commit).

**Residue gate** (scoped Python strict 본체, advisory rg 제외):

- Production: `backend/app/modules/pipeline/t2i_review.py` + `backend/app/core/steps/t2i_review_step.py` mutation site (5 pattern: `.replace(target, suggestion)` 등) + reader pattern (6 pattern: `iss["target"]` / `iss.get("target"...` 등, open-ended close paren 포함) 모두 0.
- Active v6 pack: `prompts/_base/t2i_review/6.202605181200/` 4 file (entity_system.md + scene_system.md + entity_schema.json + scene_schema.json) target/suggestion field syntax (JSON `"target":` + markdown `- target:`) 모두 0.
- Archived (2.x / 3.x / 4.x / 5.x): scope 외 (rollback path 보존 의무).

**Canary**:

- `entity_applied == 0` / `scene_applied == 0` / `scene_applied_indices == []` (hard-coded invariants).
- `_refresh_scene_detail_sentinels` 호출 0 / `_assert_card_hash_unchanged` 호출 0 (`if scene_applied > 0:` branch unreached, defensive).
- `_capture_card_hash_state` invoked (run 전 baseline) / `_save_checkpoint_data` 호출 0 (entity_applied/scene_applied > 0 branch unreached).
- W1 atomicity: v6 schema 5 core fields required strict (`id, scope, issue_code, action, hint_diagnostic` + required debug alias `short_id` / `item_id`) + production reader pattern 0 + mutation site 0 + `STEP_MANIFEST["t2i_review"]["schema_version"] == 1`.

**Carry**:

- Area #7 Prompt Hygiene v2 (placeholder abstraction noun broader cleanup, P-6 closure 미선언, t2i_review v6 placeholder example `<frame-edge surface>` 등 보존됨).
- 외부 orchestrator 의 `regeneration_required` consumer code 신설 (별도 area / 운영 reading).
- `hint_diagnostic` LLM regen path inject 결정 (별도 area / future regen path).
- shot_dependency_t2i_step `_normalize_scene_consistency_result` 부재 baseline FAIL (`TestShotDependencyT2iWiring::test_consistency_iter_calls_normalize`) — W1 scope 외 carry (shot_dependency_t2i residue, 별도 area / 추정 Area #12).

**Non-claim**:

- Editorial cascade 1-pass policy (`step_runner.py:1295-1308`) 변경 0. downstream orchestration 신설 = scope inflation 으로 v1 제외, 운영자 / 외부 orchestrator force 의무.
- Patch A/B/B1 5 functions 보존 (defensive regression guard, mutation 재도입 시 자동 보호).
- Area #5 W3 commit `4853c7b` 의 `close_framing_existing_ref` 폐기 boundary 보존 (복구 0).

**NO VLM** (`feedback_no_vlm_dependency` hard constraint 정합).
