# Prompt Hygiene v1 — Spec

Date: 2026-05-15
Status: design approved (brainstorming closure)
Scope: A-small (3 module / 5 unique site / 6 P-N row)

## 1. Goal

Active prompt 안 시나리오 leak + over-specific example 의 generic placeholder 화. 코드 변경 최소 (`t2i_visual_converter.py` path bump 1 곳만). LLM-side classifier / mutation logic 일체 안 건드림.

P-1 = orphan 별도 cleanup area, 본 spec scope **외**.

## 2. Background + Input Sources

본 spec 는 다음 audit 의 결과로 작성:
- `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/02-prompt-side-hygiene-audit.md` — P-1~P-6 inventory + Codex absorption + 정정
- `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/04-db-row-verification.md` — module 별 active source 매트릭스 + Hygiene v1 적용 매트릭스
- `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/00-index.md` — first impl candidate decision (Hygiene v1 = (1) order)

사용자 결정 (2026-05-15 brainstorming):
- **P-1 orphan 분리**: `entity_extractor_legacy.py` import 0 → P-1 = 별도 cleanup area, Hygiene v1 외.
- **P-6 boundary**: `scene_system.md:45-78` 3 example blocks 만. line 31-43 / 49-59 / 65-74 / 87-90 = classifier behavior + target/suggestion 계약 → unchanged.
- **Module 3 hardcoded path bump 의무**: `t2i_visual_converter.py:9-12` path string `"v3"` → `"v4"`.
- **Module 2 / 4 = file fallback latest**: 새 dir 만으로 active, code 변경 0.

## 3. In Scope (5 unique sites / 6 P-N rows)

### 3.1 Module 2 — `scene_extractor_v2`

New dir: `prompts/_base/scene_extractor_v2/18.<TIMESTAMP>/` (full-pack copy from `17.202604101200/`)

| P-N | Source | Fix direction |
|-----|--------|---------------|
| P-2 | `17.202604101200/system.md:60` | `"동녘(강의원)"` → `"<visible_body_name>(<remote_identity_name>)"` placeholder. visual_world_rules `rule_type=possession` reference pointer 추가 (한 줄 — "본 분류는 visual_world_rules.rules[] 의 rule_type 따름"). |
| P-3 | `17.202604101200/system.md:63` | `"캡슐속 남자들"` → `"<container descriptor> 안의 인물들"` placeholder. |
| P-3b | `17.202604101200/turn_scene_detail.md:108` | `"캡슐속 남자들"이 헬기에 타고 있다면` → `"<container descriptor> 안의 인물들"이 <transport vehicle>에 타고 있다면` placeholder. |
| P-4 | `17.202604101200/turn_scene_detail.md:83-85` | `Korean police officer / Korean-style apartment / Korean convenience store / Joseon-era nobleman / tiled-roof wooden structure` → `<region-derived demonym> police officer / <region-style apartment> / <region-style convenience store> / <era-derived noble role> / <era-appropriate roofed wooden structure>` placeholder. 문화 cue 보존 (region/era derivation 의무). |

Code change: **없음** (file fallback latest).

### 3.2 Module 3 — `t2i_visual_converter`

New dir: `prompts/_base/t2i_visual_converter/v4/` (full-pack copy from `v3/`)

| P-N | Source | Fix direction |
|-----|--------|---------------|
| P-5 | `v3/system.md:19` | `"[주인공]이 투명 벽 너머로 남자를 올려다본다, 청록색 발광, 미디엄 숏"` → `"[primary character] looks toward [secondary visible target], <lighting cue>, <shot scale>"` placeholder. |

Code change: `backend/app/modules/t2i_visual_converter.py:9-12`
```python
# before:
PROMPT_DIR = PROMPTS_BASE / "t2i_visual_converter" / "v3"
# after:
PROMPT_DIR = PROMPTS_BASE / "t2i_visual_converter" / "v4"
```

### 3.3 Module 4 — `t2i_review`

New dir: `prompts/_base/t2i_review/4.<TIMESTAMP>/` (full-pack copy from `3.202605121200/`)

| P-N | Source | Fix direction |
|-----|--------|---------------|
| P-6 | `3.202605121200/scene_system.md:45-78` (3 example blocks) | concrete example (compact room / existing tabletop / wet floor planks / Figure A/B / shared bench) → `<existing background object>` / `<frame-edge surface>` / `<shared support surface>` / `<foreground actor>` / `<background actor>` placeholder. |

**Critical guard**: line 31-43 / 49-59 / 65-74 / 87-90 = classifier behavior + target/suggestion 계약 → **byte/text-level unchanged**. 자세는 §5.2.

Code change: **없음** (file fallback latest).

## 4. Out of Scope (사용자 명시 명문화)

- `t2i_review/scene_system.md:31-43, :49-59, :65-74` = 검출 패턴 / classifier behavior (unchanged)
- `t2i_review/scene_system.md:87-90` = target/suggestion 규칙 (`t2i_review.py:451` `target.replace()` 계약 — unchanged)
- `t2i_review/scene_system.md` 의 issue type 정의 (6 issue type)
- `t2i_review/scene_schema.json` schema
- `t2i_review/entity_system.md` + `entity_schema.json` (다른 stem — full-pack copy 만, fix 0)
- `backend/app/modules/pipeline/t2i_review.py` 치환 로직 (`.replace()` mutation)
- `entity_extraction/v7/chunk_system.md` (P-1 orphan — 별도 cleanup area)
- LLM-side classifier instruction redesign (L-1 ~ L-7)
- code-side regex / substring (#1 ~ #19)
- visual_world_rules SOT 일원화 (D-1 ~ D-5 + ADD-6 ~ ADD-11)
- framing_scale enum SOT (next first impl)
- DB row override / production source verification (PENDING 2)
- entity_extractor_v2 안 leak (active path 안 leak 0 확인됨)

## 5. Acceptance Criteria

### 5.1 Full-pack Copy (Acceptance, 선택 아님)

`backend/app/modules/prompt_loader.py:219` 가 stem-level latest 탐색 — 새 dir 에 stem 누락 시 이전 version dir 에서 가져옴 (stem-level fallback drift 위험).

→ **새 dir 은 기존 latest dir 의 모든 stem 을 full-pack copy 의무**.

| Module | New dir | Required stem (full-pack copy 의무) |
|--------|---------|--------------------------------------|
| 2 `scene_extractor_v2` | `18.<TIMESTAMP>/` | `system.md` + `turn_scene_detail.md` + `turn0_context.md` + `turn1_split_long.md` + `scene_detail_schema.json` (5 stem) |
| 3 `t2i_visual_converter` | `v4/` | `system.md` (1 stem) |
| 4 `t2i_review` | `4.<TIMESTAMP>/` | `entity_system.md` + `entity_schema.json` + `scene_system.md` + `scene_schema.json` (4 stem) |

검증 (file only — `find -maxdepth 1 -type f`, dir/junk 제외):
```bash
# Module 2 expected 5 files
test "$(find prompts/_base/scene_extractor_v2/18.<TIMESTAMP>/ -maxdepth 1 -type f | wc -l)" -eq 5
# Module 3 expected 1 file
test "$(find prompts/_base/t2i_visual_converter/v4/ -maxdepth 1 -type f | wc -l)" -eq 1
# Module 4 expected 4 files
test "$(find prompts/_base/t2i_review/4.<TIMESTAMP>/ -maxdepth 1 -type f | wc -l)" -eq 4
```

각 stem 의 fix-제외 부분 = 기존 latest 와 동일 (diff 0 outside fix scope).

### 5.2 P-6 Unchanged Guard (확장 4 region)

`t2i_review/4.<TIMESTAMP>/scene_system.md` 의 다음 line range = `3.202605121200/scene_system.md` 와 **byte/text-level unchanged**:

- line 31-43 (검출 패턴 — classifier behavior)
- line 49-59 (issue type 정의)
- line 65-74 (target/suggestion 작성 방식 — classifier behavior)
- line 87-90 (target/suggestion 규칙 — `t2i_review.py:451` 계약)

검증:
```bash
OLD=prompts/_base/t2i_review/3.202605121200/scene_system.md
NEW=prompts/_base/t2i_review/4.<TIMESTAMP>/scene_system.md
diff <(sed -n '31,43p;49,59p;65,74p;87,90p' "$OLD") \
     <(sed -n '31,43p;49,59p;65,74p;87,90p' "$NEW")
# expected: empty (no diff)
```

### 5.3 Residue Grep (Active New Dirs Only — module 별 scope 분리)

검증 scope = 새 active dirs **만**. legacy / 이전 version dir 의 hit 는 무시 (이전 version dir = file fallback latest 아님 → not active).

**중요 (review iter 2 fix)**: `t2i_review/scene_system.md` 는 line 65-74 unchanged guard region 안에 의도된 classifier instruction example 가 존재 (line 69 `Figure A/B` + line 74 `shared bench/shared table/the same X they both occupy`). 본 keyword 들은 fix-target line 76-78 의 same phrase 와 일치하지만 classifier behavior 의 일부 — fix 대상 아님. 따라서 `t2i_review` residue grep 은 **fix-target range only** (line 45-47 + 61-63 + 76-78).

검증 대상:
- `prompts/_base/scene_extractor_v2/18.<TIMESTAMP>/` — full new-dir grep
- `prompts/_base/t2i_visual_converter/v4/` — full new-dir grep
- `prompts/_base/t2i_review/4.<TIMESTAMP>/scene_system.md` — **fix-target range only** (line 45-47 / 61-63 / 76-78)

검증 keyword:
- scene_extractor_v2 + t2i_visual_converter full-dir: `은성` / `ZRBB` / `동녘` / `강의원` / `캡슐속` / `청록색` / `투명 벽` / `compact room` / `wet floor` / `Korean police` / `Joseon` / `tiled-roof`
- t2i_review fix-target range only: `compact room` / `wet floor` / `shared bench` / `Figure A` / `Figure B`

검증 명령:
```bash
# 1. scene_extractor_v2 + t2i_visual_converter — full new dir grep
for dir in scene_extractor_v2/18.* t2i_visual_converter/v4; do
  hits=$(grep -rn -E "은성|ZRBB|동녘|강의원|캡슐속|청록색|투명 벽|compact room|wet floor|Korean police|Joseon|tiled-roof" "prompts/_base/$dir" 2>/dev/null | wc -l | tr -d ' ')
  echo "$dir: $hits hits"
done

# 2. t2i_review — fix-target range only
T2I_NEW=$(ls -d prompts/_base/t2i_review/4.* | head -1)/scene_system.md
hits=$(sed -n '45,47p;61,63p;76,78p' "$T2I_NEW" | grep -n -E "compact room|wet floor|shared bench|Figure A|Figure B" | wc -l | tr -d ' ')
echo "$T2I_NEW (fix-target range): $hits hits"

# expected: 모두 0
```

**Important**:
- repo 전체 grep 0 요구 X (이전 version dir historical hit 는 정상).
- `t2i_review/4.<TS>/scene_system.md` 의 full-dir grep 시 line 69/74 의 의도된 classifier example/keyword hit 는 expected — 검증 대상 외.

### 5.4 Active Source Verification

각 module 의 새 dir 가 실제 load_prompt 결과로 active 인지 검증.

**Invocation 규칙**: package root 는 `backend/app` — `PYTHONPATH=backend` 의무. 프로젝트 검증 관례는 `.venv/bin/python` — system python 금지.

| Module | 검증 명령 | Expected |
|--------|-----------|----------|
| 2 | `PYTHONPATH=backend .venv/bin/python -c "from app.modules.prompt_loader import load_prompt; print(load_prompt('scene_extractor_v2', 'system')[:200])"` | 새 18.<TIMESTAMP>/system.md content prefix |
| 2 | `PYTHONPATH=backend .venv/bin/python -c "from app.modules.prompt_loader import load_prompt; print(load_prompt('scene_extractor_v2', 'turn_scene_detail')[:200])"` | 새 18.<TIMESTAMP>/turn_scene_detail.md content prefix |
| 3 | `PYTHONPATH=backend .venv/bin/python -c "from app.modules.t2i_visual_converter import PROMPT_DIR; print(PROMPT_DIR)"` | `.../t2i_visual_converter/v4` (path bump 검증) |
| 4 | `PYTHONPATH=backend .venv/bin/python -c "from app.modules.prompt_loader import load_prompt; print(load_prompt('t2i_review', 'scene_system')[:200])"` | 새 4.<TIMESTAMP>/scene_system.md content prefix |

대안 invocation (`cd backend` 후 상대 venv):
```bash
cd backend && ../.venv/bin/python -c "from app.modules.prompt_loader import load_prompt; print(load_prompt('scene_extractor_v2', 'system')[:200])"
```

### 5.5 Codex Fix Direction 정합

Replacement placeholder 가 Codex 권고 + audit `02-` §4 / §5 fix direction 와 정합:

- **P-2 placeholder** = visual_world_rules `rule_type=possession` reference pointer 한 줄 포함 (도메인 SOT 일원화 area 와 결합 시 충돌 없음).
- **P-4 placeholder** = region/era derivation cue 보존 (`<region-derived demonym>` / `<era-derived noble role>` — 문화 cue 제거 X).
- **P-6 placeholder** = abstract `<existing background object>` / `<frame-edge surface>` / `<shared support surface>` / `<foreground actor>` / `<background actor>` 사용 (Codex P1-3 fix direction).

## 6. Dependencies

- **Prerequisite**: 없음 (Hygiene v1 = First Implementation Candidate, 의존성 0)
- **Next after closure**: framing_scale enum SOT (`#1 + #2 + #16 + #17 + L-4 + L-5` atomic area)
- **Separate areas (carry)**: orphan cleanup (P-1) / visual_world_rules SOT 일원화 / shot_visibility drift-only / ref-contract phantom guard / representation_binding enum / t2i_review mutation redesign (L-3) / scene_detail_owned_judge schema echo (L-2)

## 7. Implementation Plan — 별도

본 spec 승인 후 별도 writing-plans 진입 (`docs/superpowers/plans/2026-05-15-prompt-hygiene-v1-plan.md` 예상).

Plan task breakdown (예상):
- **Task 0**: residue grep baseline 측정 (active old dirs hits 기록, 사후 비교용)
- **Task 1**: module 2 (`scene_extractor_v2`) — 새 `18.<TIMESTAMP>/` full-pack copy + 4 fix (P-2/P-3/P-3b/P-4)
- **Task 2**: module 3 (`t2i_visual_converter`) — 새 `v4/` full-pack copy + 1 fix (P-5) + `t2i_visual_converter.py:9-12` path bump
- **Task 3**: module 4 (`t2i_review`) — 새 `4.<TIMESTAMP>/` full-pack copy + 1 fix (P-6 scene_system.md:45-78 만)
- **Task 4**: P-6 unchanged guard 검증 (§5.2 diff 0)
- **Task 5**: residue grep 사후 측정 (active new dirs only, §5.3) + active source verification (§5.4)

## 8. Do Not / Guard

- **P-1 orphan area 흔들지 말 것** — Hygiene v1 에서 `entity_extraction/v8` 새 dir 또는 `entity_extractor_legacy.py:14` path bump **금지** (runtime 효과 0, 별도 orphan cleanup area).
- **t2i_review classifier redesign 금지** — line 31-43 / 49-59 / 65-74 / 87-90 byte/text-level unchanged (§5.2 acceptance).
- **`t2i_review.py:383-454` `.replace()` 치환 로직 안 건드림** — LLM-side L-3 별도 area.
- **이전 version dir 삭제 금지** — file fallback latest = new dir 이지만 historical 보존 의무.
- **새 dir 명명 규칙 (기존 패턴)**:
  - `scene_extractor_v2` / `t2i_review` = `<MAJOR>.<TIMESTAMP>` (e.g. `18.202605151200`)
  - `t2i_visual_converter` = `v<N>` (e.g. `v4`)
- **DB row 변경 금지** — Hygiene v1 affected module (2, 3, 4) 모두 DB row override 없음 (`entity_character_list` 만 db-aware, 본 affected 외). DB write 안 함.
- **entity_extractor_v2 안 건드림** — active path 안 leak 0 확인됨 (`02-` §2.2). 본 spec 영역 외.
- **schema 변경 금지** — `scene_detail_schema.json` / `entity_schema.json` / `scene_schema.json` 모두 full-pack copy 만, content 변경 0.

## 9. Risk + Mitigation

| Risk | Likelihood | Impact | Mitigation |
|------|-----------|--------|------------|
| Stem 누락 (full-pack copy 미준수) | medium | high (stem-level fallback drift) | §5.1 acceptance — file count + diff 검증 |
| t2i_review unchanged guard 위반 | low | high (`target.replace()` 계약 영향) | §5.2 acceptance — 4 region diff 0 검증 |
| Path bump 누락 (module 3) | medium | high (새 prompt active 안 됨) | §5.4 acceptance — `PROMPT_DIR` print 검증 |
| Residue grep scope 잘못 (repo 전체) | low | low (false positive) | §5.3 acceptance — active new dirs only 명시 |
| Production DB row override (PENDING) | unknown | unknown | 본 spec out of scope. Hygiene v1 affected module 모두 db-aware 0 — 영향 0. 단 production DB 별도 측정 의무 carry (`04-` §6 PENDING). |

## 10. Completion Criteria

본 Hygiene v1 patch 가 완료된 것으로 간주되는 조건:

- [ ] 3 module 의 새 dir 모두 생성 + full-pack copy (§5.1)
- [ ] 6 P-N fix 모두 적용 (§3)
- [ ] P-6 unchanged guard 통과 (§5.2 diff 0)
- [ ] Residue grep 0 hits in active new dirs (§5.3)
- [ ] Active source verification 4건 통과 (§5.4)
- [ ] Codex fix direction 정합 (§5.5)
- [ ] Code change 1 곳만 (`t2i_visual_converter.py:9-12`)
- [ ] DB row 변경 0
- [ ] schema 변경 0
- [ ] 이전 version dir 보존 (삭제 0)
