# Area #7b — Visual World Rules Downstream Prompt Cascade v1 Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Area #7a (closed `d0410eb`) 의 VWR v7 SOT 가 정합한 10-enum `rule_type` (`possession / transformation / ghost / projection / superpower / body_deformation / time_period / costume / technology / other`) 을 downstream 11-site cascade 의 9 modified prompt file 안에 **canonical VWR SOT reference clause** (audit §11.3 verbatim) 으로 단일화 — Group E (entity_all + entity_relation + entity_extractor_v2, 5 site / 4 modified file / 17 sibling byte-identical) + Group O (outlook_extractor, 2 site + line 24 / 2 modified file / 4 sibling) + Group S (scene_verify + scene_detail + shot_extract, 3 site / 3 modified file / 3 sibling). D-2 `entity_character_list` = no-change boundary preserve (owner taxonomy 5-element 분류, presence/visibility 결정 X). STEP_MANIFEST 변경 0 (Area #7a W1 신설 `visual_world_rules.schema_version=1` 만 active, 본 area = prompt text only change, cp invalidation 불필요). helper 신설 0. **W3 narrow exemption (Codex amend 8 + amend 9 + amend 10 OPTION_A expanded 흡수)**: scene_detail 4-point sync — `detail_steps.py:106` SCENE_DETAIL_PROMPT_VERSION + `version_registry.py:34`/`:126` MODULE_VERSIONS/_MODULE_INFO + **scene_detail-pinned tests 5 files** (continuity_alignment 4 assertion + spatial_alignment 5 assertion + prompt_versions 2 assertion + 1 function rename + g4_5a_spatial_integration 4 assertion + 1 function rename + area_5_residue_gate function rename + glob, schema_version == 11 보존). 다른 module production code 변경 0 doctrine 유지. v1 = **7 new prompt dirs + 9 modified prompt files + 24 byte-identical sibling files + 12 affected STEP_MANIFEST entries** (canonical wording: **12 affected STEP_MANIFEST entries = 10 modified-file-bound step entries + 2 sibling-only shared-module entries (`entity_all_location` / `entity_all_prop`)**; spec wording "10 STEP_MANIFEST entries" = modified-file-bound count metric, execution test = 12 entry presence + schema_version diff 0, Codex iter 1 F-1 reconciliation + iter 2 F-1 narrow sync). 4-Gate Boundary Doctrine inline (Semantic Regex Ban / Prompt Closed-List Ban / Structured SOT Required / No Silent Fallback) + closed-world exact residue phrase contract (fixed-string / glyph-exact membership, audit-verbatim + current-active-promoted inventory split, Generic Korean standalone ban 0). NO VLM hard constraint inline.

**Architecture:** signature-non-breaking transition (schema 변경 0, code 변경 0 [W3 narrow exemption — scene_detail 4-point sync 의무, Codex amend 8 OPTION_A 흡수], STEP_MANIFEST 변경 0). W0 = handoff session 안 inventory + line drift verify 완료 (spec §2.3 흡수, plan body 안 W0 Verification Contract 압축 표만 보관, execution wave commit 없음). W1 = atomic 단일 commit — entity_all `5.20260518HHMM/` + entity_relation `3.20260518HHMM/` + entity_extractor_v2 `10.20260518HHMM/` 3 new prompt dir + 4 file modified (character.md / system.md / system.md / turn0_style.md) + 17 sibling byte-identical copy (entity_all 6 + entity_relation 2 + entity_extractor_v2 9). W2 = atomic 단일 commit — outlook_extractor `12.20260518HHMM/` 1 new prompt dir + 2 file modified (phase1.md audit-verbatim line 16 + current-active-promoted line 24 + phase2.md line 8) + 4 sibling. W3 = atomic 단일 commit — scene_verify `2.20260518HHMM/` + scene_detail `27.20260518HHMM/` + shot_extract `12.20260518HHMM/` 3 new prompt dir + 3 file modified (system.md / system.md / user.md) + 3 sibling (verify_schema.json strict pack Codex F-1 흡수). **W3 line drift verify 의무** (audit 시점 scene_detail line 327 / shot_extract line 33 vs current latest line 473 / line 49). W4 = atomic 단일 commit — `test_area_7b_residue_gate.py` 신설 (Gate 1.1-1.9 exact residue phrase membership per modified file + Gate 2 canonical clause glyph-exact membership per 9 file + Gate 3 D-2 byte-identical sha256 + Gate 4 archive exclusion path glob). W5 = atomic 단일 commit — `test_area_7b_no_drift.py` 신설 (C1 prompt_loader latest activation 7 sub-canary + C2 sibling byte-identical 24 sub-canary + C3 STEP_MANIFEST 12 affected step entry presence verify (entry-existence contract, schema_version drift = C4 별도, W5 fix-up 1 narrow sync commit `fe7e55e`) + C4 schema_version 변경 0 + C5 D-2 DB override risk neutralized + C6 canonical clause membership 9 file). W6 = atomic 단일 commit — closure (spec status: closed + roadmap §5.7 mark + audit §13 Area #7b Closure append) + external memory closure memo + MEMORY.md index. Codex per-wave review boundary (W1-W6 each iter) + W1-W6 range review at W6 closure boundary. Push 보류 (APPROVED_FOR_PLAN ≠ APPROVED_FOR_PUSH, Area #7a 패턴 정합 spec + plan + execute closure atomic push at W6 range review APPROVED_FOR_PUSH 시점).

**Tech Stack:** Python 3.12 / pytest 9.0.2 / `pathlib.Path.read_text()` + `str.__contains__` (fixed-string membership 의무, regex 0 for phrase gates — Codex iter 0 strategy verdict Q7 정합), `hashlib.sha256` (byte-identical sibling verify — Codex Q6 정합 `cp -p src dest` + `shasum -a 256` equality check), `app.modules.prompt_loader.load_prompt` + `_list_module_versions(module)` (자체 numeric-desc sort 수행, latest version 자동 활성, file fallback default), `app.core.step_manifest.STEP_MANIFEST` (12 affected step entry presence verify per C3 entry-existence contract + schema_version 변경 0 verify per C4 별도, W5 fix-up 1 narrow sync commit `fe7e55e`). `cp -p src dest` for byte-identical sibling copy (preserve timestamp + permission). UTC timestamp via `date -u +%Y%m%d%H%M` (per wave entry mandatory — Codex Q5 정합, if UTC YYYYMMDD ≠ `20260518` narrow plan amend before mkdir).

**Spec reference:** `docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md` (commit `90a8cea` APPROVED_FOR_PLAN, Codex iter 7 verdict). 5 unpushed spec commit (9c1f7d6 spec v1 + feeb3b5 amend 1 4-Gate Doctrine + dc07ea7 amend 2 + 8fafd03 amend 3 + 90a8cea amend 4 iter 7 trace).

**Prerequisites:**
- Area #7a closed (push `d0410eb`, 12 commit range `8b5944d..d0410eb`): VWR v7 producer SOT (`rules_schema.json` rule_type 10-enum strict + director_notes description small fix + system.md 10-token canonical list) + STEP_MANIFEST `visual_world_rules.schema_version=1` + scene_director v9 system.md A047 3 site principle-only — 본 area 의 producer SOT.
- Area #3 closed (commit `97c4471`) boundary preserved: shot_director.py mutation 폐기 + Path 1/2 분리. 본 area = prompt-only cascade, shot_director 본체 변경 0.
- Area #5 closed (commit `fe300bf`) boundary preserved: `reference_phrase_kinds` sidecar. 본 area cross-cut 0.
- Hygiene v1 closed (commit `91d1dfd`) P-1 ~ P-6 fix 보존.

---

## File Structure

### Prompts — Create (W1 + W2 + W3, 7 new dirs / 33 files total = 9 modified + 24 byte-identical sibling)

> `HHMM` placeholders = per-wave commit 직전 UTC `date -u +%Y%m%d%H%M` 4-digit. **Codex iter 0 strategy Q5 정합**: full UTC timestamp 산출 의무, 만약 UTC YYYYMMDD ≠ `20260518` (예: UTC 가 2026-05-17 또는 2026-05-19 cross 시) 시 narrow plan/spec amend (placeholder `20260518` → 실제 UTC `YYYYMMDD`) 후 mkdir 진입. W1/W2/W3 각자 자체 timestamp 결정 (서로 다른 HHMM 가능, 단일 wave 안 file 들은 동일 timestamp).

**W1 (Group E — entity_*)** — 3 new prompt dir / 4 modified file / 17 byte-identical sibling copy:

| Module | New dir | Modified file | Byte-identical sibling copy (source = current latest dir) |
|---|---|---|---|
| `entity_all` | `prompts/_base/entity_all/5.20260518HHMM/` | `character.md` (audit-verbatim line 26 + 29 + 30 — site 1) | `location.md` / `prop.md` / `character_schema.json` / `location_schema.json` / `prop_schema.json` / `system.md` (6 file from `4.202603310100/`) |
| `entity_relation` | `prompts/_base/entity_relation/3.20260518HHMM/` | `system.md` (audit-verbatim line 11+12+13 + current-active-promoted line 30 — site 3) | `analyze.md` / `analyze_schema.json` (2 file from `2.202603301800/`, Codex iter 4 F-1 흡수 — production `entity_relation.py:93-95` strict pack 의무) |
| `entity_extractor_v2` | `prompts/_base/entity_extractor_v2/10.20260518HHMM/` | `system.md` (line 22 + line 32 — site 6) + `turn0_style.md` (line 13 — site 7) | `turn_entity_detail.md` / `turn0_style_schema.json` / `turn1_7_detail_batch_schema.json` / `turn1_7_detail_batch.md` / `turn1_review_schema.json` / `turn1.md` / `turn2.md` / `turn3.md` / `turn4.md` (9 file from `9.202605130226/`) |

**W2 (Group O — outlook_*)** — 1 new prompt dir / 2 modified file / 4 byte-identical sibling copy:

| Module | New dir | Modified file | Byte-identical sibling copy (source = current latest dir) |
|---|---|---|---|
| `outlook_extractor` | `prompts/_base/outlook_extractor/12.20260518HHMM/` | `phase1.md` (audit-verbatim line 16 + current-active-promoted line 24 — site 4) + `phase2.md` (audit-verbatim line 8 — site 5) | `phase1_schema.json` / `phase2_schema.json` / `phase3_schema.json` / `phase3.md` (4 file from `11.202603311724/`) |

**W3 (Group S — scene_*)** — 3 new prompt dir / 3 modified file / 3 byte-identical sibling copy — **line drift verify 의무**:

| Module | New dir | Modified file | Byte-identical sibling copy (source = current latest dir) |
|---|---|---|---|
| `scene_verify` | `prompts/_base/scene_verify/2.20260518HHMM/` | `system.md` (audit-verbatim line 7 — site 9) | `verify_schema.json` (1 file from `1.202603231200/`, Codex iter 4 F-1 흡수 — production `detail_steps.py:3088-3089` strict pack 의무) |
| `scene_detail` | `prompts/_base/scene_detail/27.20260518HHMM/` | `system.md` (audit-verbatim line 473 — site 10, audit 시점 line 327 line drift, controller verify 2026-05-19 결과 line 473 정합) | `detail_schema.json` (1 file from `26.202605181435/`) |
| `shot_extract` | `prompts/_base/shot_extract/12.20260518HHMM/` | `user.md` (audit-verbatim line 49 — site 11, audit 시점 line 33 line drift, controller verify 2026-05-19 결과 line 49 정합) | `system.md` (1 file from `11.202604201230/`) |

**D-2 carve-out (변경 0 boundary preserve)** — new dir 신설 0:

| Module | 현재 latest (불변) | 변경 사유 |
|---|---|---|
| `entity_character_list` | `prompts/_base/entity_character_list/2.202605011057/system.md` (line 10 owner taxonomy 5-element 분류 `인간, 요괴, 동물, 로봇, 외계인 등`) | 사용자 명시 + audit §11.3 line 264-265 verbatim 정합 + Codex iter 2 verdict Q3. owner taxonomy = 인물 정의 boundary (presence/visibility 결정 X). VWR rule_type SOT 와 다른 축. `db=`-aware caller 존재 (audit §11.4) 이지만 변경 0 이므로 DB row 영향 0. |

### Production code — 변경 0 (W1/W2/W4/W5/W6) — W3 narrow exemption: scene_detail 4-point sync (Codex amend 8 + amend 9 + amend 10 verdict OPTION_A expanded 흡수, scene_detail-pinned tests 5 files plural)

- `backend/app/core/step_manifest.py` — 변경 0 (Area #7a W1 신설 `visual_world_rules.schema_version=1` 보존, 본 area = prompt text only change, schema_version bump 0, prompt_version field 신설 0 per Area #7a W0 S8 verdict 정합).
- `backend/app/modules/prompt_loader.py` — 변경 0 (numeric-desc latest version 자동 활성 보존).
- `backend/app/core/version_registry.py` — **W3 narrow exemption**: `MODULE_VERSIONS["scene_detail_composer"]` `"1.26.0"` → `"1.27.0"` (line 34) + `_MODULE_INFO["scene_detail_composer"]["prompt_dependency"]` `"scene_detail/v26"` → `"scene_detail/v27"` (line 126) + `updated_at` `"2026-05-18"` → `"2026-05-19"` (Area #5 W1 4-point sync row 3+4 정합 의무). 다른 module entry 변경 0.
- `backend/app/core/steps/detail_steps.py` — **W3 narrow exemption**: `SCENE_DETAIL_PROMPT_VERSION` `"26.202605181435"` → `"27.20260518HHMM"` (W3 actual UTC HHMM substitute, line 106, Area #5 W1 4-point sync row 2 정합 의무). `SCENE_DETAIL_SCHEMA_VERSION = 11` **유지** (schema 변경 0 doctrine, Codex amend 8 verdict — 본 area = prompt text only, schema bump 0).
- 그 외 production code — 변경 0 (helper 신설 0).

### 4-point sync narrow exemption rationale (Codex amend 8 + amend 9 + amend 10 흡수)

scene_detail 에만 hard-pinned defensive guards **scene_detail-pinned tests 5 files** (repo-wide grep gate via `assert.*"1\.26\.0"|"scene_detail/v26"|startswith\("26\."\)|latest_major.*"26"`):

1. `backend/tests/prompts/test_scene_detail_continuity_alignment.py` (Area #5 W1 4-point sync) — 4 assertion.
2. `backend/tests/prompts/test_scene_detail_spatial_alignment.py` (Area #5 W1 자매 4-point sync) — 5 assertion.
3. `backend/tests/test_prompt_versions.py` (Group E generic prompt version pin) — 2 assertion + 1 function rename (`test_version_registry_scene_detail_composer_1_26_0` → `_1_27_0`).
4. `backend/tests/integration/test_g4_5a_spatial_integration.py` (G4.5a spatial 4-way sync) — 4 assertion + 1 function rename (`test_4_way_alignment_post_g4_5a_bump` → `test_4_way_alignment_post_area7b_w3_bump`).
5. `backend/tests/integration/test_area_5_residue_gate.py` (Area #5 W3 active prompt residue) — 1 function rename (`test_active_prompt_residue_scene_detail_v26_no_closed_phrase_examples` → `_v27_*`) + glob `26.*/` → `27.*/` (active prompt 가 v27 로 이동했으므로 canary scope 도 v27).

다른 module (entity_*/outlook_*/scene_verify/shot_extract) 비교 결과 ALL absent (`grep -rnE "(ENTITY|OUTLOOK|SCENE_VERIFY|SHOT_EXTRACT)_PROMPT.*VERSION" backend/app/` 0 hit). 다른 scene_detail test (`test_scene_detail_id_policy_alignment.py` + `test_scene_detail_v21_grep_gate.py` + `test_scene_detail_v21_rule_x2_semantic.py`) 4-point sync hardcoded assertion 0 (prompt body content gate only). 새 prompt directory `scene_detail/27.*` 추가 만 으로는 5 file 14+ assertion 중 11+ trip (schema_version 11 유지 + non-blocking residue gate 1 stale meaning) → W3 atomic commit 동기화 필수. 본 narrow exemption boundary = scene_detail 4-point sync 만 (다른 module production code 변경 0 doctrine 보존, helper 신설 0 doctrine 보존, STEP_MANIFEST 변경 0 doctrine 보존).

**Repo-wide grep gate doctrine (Codex amend 10 함정 학습)** — 다음 prompt new-dir area Q0/W0 grep gate 확장 의무: `backend/tests/prompts/test_*_alignment.py` plural 만이 아니라 **repo-wide** `grep -rnE 'assert.*"1\.<MAJOR>\.0"|scene_detail/v<MAJOR>|SCENE_DETAIL_PROMPT_VERSION.*startswith\("<MAJOR>\."|latest_major.*"<MAJOR>"' backend/ --include='*.py'` + **function name AST-level scan** (test_*_<module>_*_1_<MAJOR>_0 / test_*_post_*_<MAJOR>_bump / test_*_<module>_v<MAJOR>_* etc., singular grep 으로 함정 missed).

### Tests — Modify (W3 narrow exemption, 5 files — Codex amend 10 OPTION_A expanded plural)

- Modify (W3 narrow exemption): `backend/tests/prompts/test_scene_detail_continuity_alignment.py` — 4 assertion 갱신:
  - Line 69 `MODULE_VERSIONS["scene_detail_composer"] == "1.26.0"` → `"1.27.0"`.
  - Line 103 `info["prompt_dependency"] == "scene_detail/v26"` → `"scene_detail/v27"`.
  - Line 120 `SCENE_DETAIL_PROMPT_VERSION.startswith("26.")` → `startswith("27.")`.
  - Line 196 `latest_major == "26"` → `"27"`.
  - **Line 168 `SCENE_DETAIL_SCHEMA_VERSION == 11` 보존** (Codex amend 8 verdict — schema 변경 0).
  - Line 188 `latest == SCENE_DETAIL_PROMPT_VERSION` 변경 0 (compare 자체, constant 양쪽 모두 갱신되어 정합).
- Modify (W3 narrow exemption): `backend/tests/prompts/test_scene_detail_spatial_alignment.py` — 5 assertion 갱신 (Codex amend 9 흡수):
  - Line 72 `version == "1.26.0"` → `"1.27.0"`.
  - Line 106 `pdep == "scene_detail/v26"` → `"scene_detail/v27"`.
  - Line 127 `SCENE_DETAIL_PROMPT_VERSION.startswith("26.")` → `startswith("27.")`.
  - Line 132 `SCENE_DETAIL_PROMPT_VERSION.startswith("26.")` → `startswith("27.")` (duplicate sub-test).
  - Line 207 `latest_major == "26"` → `"27"`.
- Modify (W3 narrow exemption): `backend/tests/test_prompt_versions.py` — 2 assertion + 1 function rename (Codex amend 10 흡수):
  - Line 211 `SCENE_DETAIL_PROMPT_VERSION.startswith("26.")` → `startswith("27.")`.
  - Line 219 `MODULE_VERSIONS["scene_detail_composer"] == "1.26.0"` → `"1.27.0"`.
  - Line 214 function rename `test_version_registry_scene_detail_composer_1_26_0` → `test_version_registry_scene_detail_composer_1_27_0`.
  - Line 209 + 218 history comment `v25 → v26` / `1.25.0 → 1.26.0` 갱신 (`v26 → v27` / `1.26.0 → 1.27.0` Area #7b W3 추가).
- Modify (W3 narrow exemption): `backend/tests/integration/test_g4_5a_spatial_integration.py` — 4 assertion + 1 function rename (Codex amend 10 흡수):
  - Line 591 `SCENE_DETAIL_PROMPT_VERSION.startswith("26.")` → `startswith("27.")`.
  - Line 598 `MODULE_VERSIONS["scene_detail_composer"] == "1.26.0"` → `"1.27.0"`.
  - Line 607 `info["prompt_dependency"] == "scene_detail/v26"` → `"scene_detail/v27"`.
  - Line 769 `current.startswith("26.")` (config_hash test) → `startswith("27.")`.
  - Line 561 function rename `test_4_way_alignment_post_g4_5a_bump` → `test_4_way_alignment_post_area7b_w3_bump`.
  - Line 562-574 docstring `v26 / 1.26.0 / scene_detail/v26` references + 593/600/609/770 error message narrow sync.
- Modify (W3 narrow exemption): `backend/tests/integration/test_area_5_residue_gate.py` — 1 function rename + glob (Codex amend 10 흡수, non-blocking 단 stale meaning carry 차단):
  - Line 172 function rename `test_active_prompt_residue_scene_detail_v26_no_closed_phrase_examples` → `test_active_prompt_residue_scene_detail_v27_no_closed_phrase_examples`.
  - Line 178 glob `prompts/_base/scene_detail/26.*/` → `prompts/_base/scene_detail/27.*/` (active prompt 가 v27 로 이동, canary scope 도 v27 fresh).
  - Line 184 print message `"FOUND scene_detail v26 forbidden literal: ..."` → `v27`.
  - Line 173-176 docstring history `v26` → `v27` narrow sync.
- Error message + docstring wording `26.*` / `v26` / `1.26.0` references 도 narrow sync (controller 자체 wording sync, 의미 보존).

### Tests — Create (W4 + W5, 2 file)

- Create: `backend/tests/integration/test_area_7b_residue_gate.py` (Gate 1.1-1.9 (9) + Gate 2 parametrize (9) + Gate 3 (1) + Gate 4 (1) + Sanity (1) = **21 test target**, Codex iter 1 F-4 fix-up).
- Create: `backend/tests/integration/test_area_7b_no_drift.py` (C1 7-sub-canary + C2 24-sub-canary + C3 + C4 + C5 + C6 9-sub-canary, no live LLM + NO VLM).

### Closure — Modify (W6, repo-local, 3 file)

- Modify: `docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md` (frontmatter `status: drafting` → `status: closed` + body 끝 §11 Closure section append).
- Modify: `docs/superpowers/specs/2026-05-16-track-b-semantic-debt-roadmap-design.md` §5.7 Sub-area (b) closed mark + carry table 갱신.
- Modify: `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/02-prompt-side-hygiene-audit.md` (§13 Area #7b Closure section append + audit §11.2 row 9 site 모두 `**Status: closed (Area #7b, 2026-05-19+)**` mark).

### External (W6, repo 밖 — git stage 절대 금지, 2 file)

- Create (non-git write only): `/Users/manta/.claude/projects/-Users-manta-Documents-Projects-TheRoad-I1/memory/session_20260519_area_7b_v1_closure.md`.
- Modify (non-git write only): `/Users/manta/.claude/projects/-Users-manta-Documents-Projects-TheRoad-I1/memory/MEMORY.md`.

본 2 external memory file 은 controller 의 `~/.claude/...` 영역 — repo (`/Users/manta/Documents/Projects/TheRoad-I1`) 외부. `git add` 절대 불가 — write-only + filesystem 정상 작성 확인 step 만. W6 commit content = repo-local docs 3 file 만.

---

## Atomicity Doctrine

**W0 = no commit.** spec §2.3 inventory + 9 file line drift verify (본 plan body Task 1 W0 Verification Contract 압축 표 안 보관 + per-wave entry 시 controller `grep -n` verify 의무).

**W1 = 1 task = 1 atomic commit (signature-non-breaking).** Group E 3 module new dir + 4 modified file + 17 sibling byte-identical copy 모두 single atomic commit. signature-non-breaking — schema 변경 0 + cp invalidation 불필요. 단 prompt text 변경 동시 multiple module 이므로 atomic boundary 의무 (mixed window 시 partial cascade — 예: entity_all `5.*` active 인데 entity_extractor_v2 `9.*` 잔존 → LLM 한쪽만 canonical clause 받아서 cross-consumer drift).

**W2 = 1 task = 1 atomic commit.** Group O 1 module new dir + 2 modified file + 4 sibling. single new dir, single revertable surface.

**W3 = 1 task = 1 atomic commit.** Group S 3 module new dir + 3 modified file + 3 sibling. **W3 entry 시 line drift narrow verify 의무** (scene_detail line 473 + shot_extract line 49 controller `grep -n` 재확인, audit 시점 line 327 / 33 와 다른 line drift). 만약 W3 entry 시점 prompt version bump 가 또 발생하면 narrow plan amend (latest version dir + 정확 line number 정정) 후 W3 진입.

**W4 = 1 task = 1 atomic commit.** residue gate test 1 file 신설.

**W5 = 1 task = 1 atomic commit.** canary test 1 file 신설.

**W6 = 1 task = 1 atomic commit (closure cleanup).** repo-local docs 3 file modify. external memory 2 file 은 git stage 절대 금지 (별도 step, write-only).

**deferred decision 없음** — Area #7a W0 S8 verdict (`prompt_version` field 신설 안함, STEP_MANIFEST entry-level 영향 0) 정합 적용. 본 area = prompt text only change, schema_version 변경 0, prompt_version 변경 0 모두 explicit.

---

## Pre-Commit Verification Doctrine

각 wave commit 직전 controller 자체 verify 의무. 실패 1 항목이라도 있으면 commit 절대 금지 → 본문 fix → verify 재실행.

**모든 grep/membership check = fixed-string membership only (regex 0 for phrase gates, Codex iter 0 strategy verdict Q7 정합)**. shell 에서 `grep -F` (fixed-string) flag 의무, Python 에서 `str.__contains__` 또는 `in` operator 만.

### W1 (Group E) pre-commit verify (8 종)

1. **UTC timestamp 결정 + date drift check** — `date -u +%Y%m%d%H%M` 결과 첫 8 digit = `20260518` 확인. 다른 날짜 (`20260517` / `20260519` etc) 시 narrow plan/spec amend (placeholder `20260518` → 실제 `YYYYMMDD`) 후 mkdir.
2. **Canonical VWR clause membership per 4 modified file** — 4 modified file (entity_all character.md / entity_relation system.md / entity_extractor_v2 system.md / entity_extractor_v2 turn0_style.md) 안 canonical clause 본문 (`본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.`) fixed-string membership 1+ (`grep -Fc` ≥1).
3. **W1 exact residue phrase inventory hit 0** — **15 phrase total: entity_all 8 + entity_relation 4 + entity_extractor_v2 3** (Codex iter 1 F-5 wording fix-up). Breakdown:
   - entity_all 8 audit-verbatim (line 26+29+30): `인간↔요괴` / `인간↔괴물` / `본체↔변신체` / `빙의/합체: 다른 존재가 몸을 빌리거나 합체하여 외형이 변하는 경우` full phrase (line 29 audit-verbatim full bullet, generic heading `빙의/합체` 단독 substring ban 0 / 4-Gate Boundary Doctrine + spec §3.1 line 239 Generic Korean standalone ban 0 정합) / `이무기` / `구미호` / `요괴화` / `뱀파이어`.
   - entity_relation 3 audit-verbatim (line 11+12+13): `요괴/괴물 형태` / `유령/망령 형태` / `갑옷 착용 형태`. + 1 current-active-promoted (line 30 full phrase): `요괴로 변해도 원래 인물의 흔적이 있음 → true` = 4 phrase total.
   - entity_extractor_v2 system.md 2 audit-verbatim (line 22 + line 32): `평상복 → 전신 갑옷` + `### 빙의/정신 전환/몸을 빌리는 설정이 있는 경우`. + turn0_style.md 1 audit-verbatim (line 13): `원격 접속/조종/빙의/텔레파시` = 3 phrase total.
   4 modified file 안 각 phrase `grep -Fc` = 0.
4. **17 byte-identical sibling copy verify** — entity_all 6 sibling + entity_relation 2 sibling + entity_extractor_v2 9 sibling 각자 source = current latest dir file vs new dir file `shasum -a 256` equality check. 17 / 17 PASS 의무.
5. **D-2 byte-identical verify** — `entity_character_list/2.202605011057/system.md` sha256 = Area #7a closure (`d0410eb`) 시점과 동일. 변경 0 verify.
6. **prompt_loader latest activation verify (entity_all + entity_relation + entity_extractor_v2)** — Python REPL: `from app.modules.prompt_loader import _list_module_versions; print(_list_module_versions('entity_all')[0])` → `5.20260518HHMM` (자체 timestamp substitute) 확인. 3 module 모두. `_list_module_versions(module)` 가 numeric-desc sort 자체 수행 (backend/app/modules/prompt_loader.py:167-180).
7. **STEP_MANIFEST schema_version 변경 0 verify** — `backend/.venv/bin/python -c "from app.core.step_manifest import STEP_MANIFEST; assert STEP_MANIFEST['visual_world_rules']['schema_version'] == 1, STEP_MANIFEST['visual_world_rules']"` (Area #7a 신설 `1` 보존, Codex iter 1 F-6 fix-up — `python` not on PATH, use venv).
8. **Smoke pytest (existing entity test 통과)** — `backend/.venv/bin/pytest backend/tests -k "entity_all or entity_relation or entity_extractor" -x --no-header 2>&1 | tail -10` baseline (known-baseline failure 만 허용, 본 area 신규 failure 0).

8 종 모두 PASS 시에만 W1 commit 진행. (Note: Step 3 안 8+4+3=15 phrase = entity_all 8 phrase 분리 listing 정합, fix-up.)

### W2 (Group O) pre-commit verify (5 종)

1. **UTC timestamp + date drift check** (W1 동일 pattern).
2. **Canonical VWR clause membership per 2 modified file** — phase1.md + phase2.md 안 canonical clause fixed-string membership 1+.
3. **W2 exact residue phrase inventory hit 0** — 3 phrase (phase1.md 1 audit-verbatim: `메카, 파워드슈트, 강화복, 갑옷 로봇` line 16 single contiguous phrase; phase1.md 1 current-active-promoted: `인간형 요괴/괴물, 뱀파이어, 좀비` line 24 single contiguous phrase; phase2.md 1 audit-verbatim: `원격접속/빙의:` line 8 = single colon-terminated phrase) `grep -Fc` = 0 each.
4. **4 byte-identical sibling copy verify** — phase1_schema.json / phase2_schema.json / phase3_schema.json / phase3.md 각자 sha256 equality vs current latest (`11.202603311724/`).
5. **Smoke pytest (existing outlook test 통과)** — `backend/.venv/bin/pytest backend/tests -k "outlook" -x --no-header 2>&1 | tail -10`.

5 종 모두 PASS 시에만 W2 commit 진행.

### W3 (Group S) pre-commit verify (8 종) — line drift verify 의무 + 4-point sync narrow exemption (Codex amend 8 흡수)

1. **UTC timestamp + date drift check**.
2. **Line drift verify (W3 entry 시 controller 재확인 의무)** — scene_detail `26.202605181435/system.md` line 473 = `- 원격 조종/접속 인물 제외 (조종자 몸이 다른 장소에 있음)` 정합 + shot_extract `11.202604201230/user.md` line 49 = `- 얼굴이 크게 달라지는 변화: 나이 변화, 변장/성형 전후, 빙의로 얼굴이 바뀜` 정합. `grep -nF` 으로 정확 line number 재확인. 만약 line drift 발견 (audit 시점 327 / 33 → current latest 473 / 49 와 또 다른 결과) 시 narrow plan/spec amend 후 W3 진입.
3. **Canonical VWR clause membership per 3 modified file** — scene_verify system.md + scene_detail system.md + shot_extract user.md 안 canonical clause fixed-string membership 1+.
4. **W3 exact residue phrase inventory hit 0** — 3 phrase (scene_verify 1 audit-verbatim: `3. **빙의/영혼 상태**: 다른 인물의 몸에 들어간 경우, 원래 몸은 visible=false, 빙의된 몸은 visible=true. reason에 상태를 명시` line 7 full sentence; scene_detail 1 audit-verbatim: `- 원격 조종/접속 인물 제외 (조종자 몸이 다른 장소에 있음)` line 473 full sentence; shot_extract 1 audit-verbatim: `빙의로 얼굴이 바뀜` line 49 parenthetical) `grep -Fc` = 0 each.
5. **3 byte-identical sibling copy verify** — scene_verify verify_schema.json + scene_detail detail_schema.json + shot_extract system.md 각자 sha256 equality vs current latest.
6. **Smoke pytest (existing scene_verify / scene_detail / shot_extract test 통과)** — `backend/.venv/bin/pytest backend/tests -k "scene_verify or scene_detail or shot_extract" -x --no-header 2>&1 | tail -10`. **단 Codex amend 8 narrow exemption** — 본 verify 실행 전 verify 7 (4-point sync narrow exemption) production code + test 갱신 commit 동시 stage 의무. atomic single commit boundary 안 verify 6 실행 시 4-point sync test 5 assertion 모두 PASS.
7. **scene_detail 4-point sync narrow exemption verify (Codex amend 8 흡수)** — controller 자체 fixed-string membership verify:
   - `grep -nF 'SCENE_DETAIL_PROMPT_VERSION = "27.20260518HHMM"' backend/app/core/steps/detail_steps.py` (line 106, W3 actual HHMM substitute) 1 hit.
   - `grep -nF '"scene_detail_composer": "1.27.0"' backend/app/core/version_registry.py` (line 34) 1 hit.
   - `grep -nF '"prompt_dependency": "scene_detail/v27"' backend/app/core/version_registry.py` (line 126) 1 hit.
   - `grep -nF 'SCENE_DETAIL_SCHEMA_VERSION = 11' backend/app/core/steps/detail_steps.py` (line 105) 1 hit 보존 (schema 변경 0 doctrine).
8. **scene_detail-pinned tests 5 files PASS verify** — `backend/.venv/bin/pytest backend/tests/prompts/test_scene_detail_continuity_alignment.py backend/tests/prompts/test_scene_detail_spatial_alignment.py backend/tests/test_prompt_versions.py backend/tests/integration/test_g4_5a_spatial_integration.py backend/tests/integration/test_area_5_residue_gate.py -v --no-header 2>&1 | tail -40` 모두 PASS (Codex amend 10 verdict — 14+ assertion 갱신 + 3 function rename + schema_version 보존).

8 종 모두 PASS 시에만 W3 commit 진행.

### W4 (Residue Gate) pre-commit verify (3 종)

1. **pytest residue gate test PASS** — `backend/.venv/bin/pytest backend/tests/integration/test_area_7b_residue_gate.py -v` 모든 test PASS.
2. **fixed-string membership only verify** — `grep -nE "re\.compile|re\.search|re\.match" backend/tests/integration/test_area_7b_residue_gate.py` = 0 hit (phrase gate regex 0, Codex Q7 정합). path glob (Gate 4 archive exclusion) 만 closed-world regex 허용 — 단 phrase 검사는 절대 0.
3. **Test count 정합** — Gate 1.1-1.9 = 9 test + Gate 2 (per 9 file membership) = 9 test (또는 1 parametrize) + Gate 3 = 1 test + Gate 4 = 1+ test. 총 ≥ 12 test.

### W5 (Canary) pre-commit verify (3 종)

1. **pytest canary PASS** — `backend/.venv/bin/pytest backend/tests/integration/test_area_7b_no_drift.py -v` 모든 test PASS.
2. **No live LLM verify** — `grep -nE "openai|gemini|llm_client|call_structured|completion" backend/tests/integration/test_area_7b_no_drift.py` = 0 hit (production LLM module import 0).
3. **No VLM verify** — `grep -nE "vision_language|image_validation|vlm_client|run_vlm|call_vlm" backend/tests/integration/test_area_7b_no_drift.py` = 0 hit (Codex iter 1 F-3 fix-up — `VLM|vlm` literal token 은 doctrine wording "NO VLM hard constraint" 안에 잔존하므로 grep self-hit 회피, narrow forbidden import/call token 만 verify). NO VLM hard constraint inline.

### W6 (Closure) pre-commit verify (4 종)

1. **Spec status 정합** — spec frontmatter `status: closed (Codex iter X APPROVED_FOR_EXECUTION + W1-W6 atomic execution + Codex per-wave + range review APPROVED_FOR_PUSH + push 완료)` substring 확인.
2. **Roadmap §5.7 mark 정합** — roadmap `§5.7 Sub-area (b) ... Area #7b ... closed (2026-05-19+, commit <range>)` substring 확인.
3. **Audit §13 append 정합** — audit `02-` file 안 `§13 Area #7b Closure` 또는 `Status: closed (Area #7b, 2026-05-19+)` substring 9 site (audit §11.2 row 1+3+4+5+6+7+9+10+11) 정합.
4. **path-limited git add scope** — `git status` 결과 modified = 3 file (spec + roadmap + audit) only, external memory file 은 `git status` 결과에 absent (`~/.claude/...` repo 밖). `git add -A` / `git add .` 절대 금지.

4 종 모두 PASS 시에만 W6 commit 진행.

---

## Task 1: W0 — Verification Contract (spec-absorbed, no execution commit)

**Files:**
- Read only (verify at wave entry): `prompts/_base/entity_all/4.202603310100/character.md` + `prompts/_base/entity_relation/2.202603301800/system.md` + `prompts/_base/entity_extractor_v2/9.202605130226/system.md` + `prompts/_base/entity_extractor_v2/9.202605130226/turn0_style.md` + `prompts/_base/outlook_extractor/11.202603311724/phase1.md` + `prompts/_base/outlook_extractor/11.202603311724/phase2.md` + `prompts/_base/scene_verify/1.202603231200/system.md` + `prompts/_base/scene_detail/26.202605181435/system.md` + `prompts/_base/shot_extract/11.202604201230/user.md`
- Read only (verify): `backend/app/core/step_manifest.py` (12 affected step entry mapping per Contract 3)
- Read only (verify): `backend/app/modules/prompt_loader.py:130-180, :219-235, :259-266` (strict pack mode)
- Read only (verify): `backend/app/modules/pipeline/entity_relation.py:93-95` (entity_relation 3 file strict pack)
- Read only (verify): `backend/app/core/steps/detail_steps.py:3088-3089` (scene_verify load_schema strict pack)

**Status**: W0 = handoff session (2026-05-19 Area #7a closure 후 brainstorming + spec drafting session) 안 inventory + Codex 7-iter spec quality review APPROVED_FOR_PLAN 완료. 본 plan body 안 W0 execution wave commit **0**. 본 plan body Task 1 = **W0 Verification Contract 압축 표** + **per-wave entry 시 controller `grep -n` 재확인 의무 명시** 만.

### W0 Verification Contract (압축 표, Codex iter 0 strategy Q2 정합)

#### Contract 1 — Latest version dir (8 module + D-2 carve-out)

| Module | Current latest dir | New dir target (W1/W2/W3) | wave |
|---|---|---|---|
| `entity_all` | `4.202603310100` | `5.20260518HHMM` | W1 |
| `entity_relation` | `2.202603301800` | `3.20260518HHMM` | W1 |
| `entity_extractor_v2` | `9.202605130226` | `10.20260518HHMM` | W1 |
| `outlook_extractor` | `11.202603311724` | `12.20260518HHMM` | W2 |
| `scene_verify` | `1.202603231200` | `2.20260518HHMM` | W3 |
| `scene_detail` | `26.202605181435` | `27.20260518HHMM` | W3 |
| `shot_extract` | `11.202604201230` | `12.20260518HHMM` | W3 |
| `entity_character_list` (D-2 carve-out) | `2.202605011057` | **변경 0** (no new dir) | — |

**per-wave entry verify obligation** — W1/W2/W3 entry 시 controller `ls prompts/_base/<module>/` 결과가 위 latest dir 와 정합 확인 의무. 만약 latest dir 가 또 bump 되었으면 narrow plan amend (latest dir + new dir version 정정) 후 wave 진입.

#### Contract 2 — 9-file line drift (audit 시점 vs current latest)

| Site | File | Audit 시점 line | Current latest line (controller verify 2026-05-19) | drift? |
|---|---|---|---|---|
| 1 | `entity_all/4.202603310100/character.md` | 26-30 | 26 + 29 + 30 (정합) | no drift |
| 3 | `entity_relation/2.202603301800/system.md` | 11-13, 30 | 11 + 12 + 13 + 30 (정합) | no drift |
| 6 | `entity_extractor_v2/9.202605130226/system.md` | 22, 32 | 22 + 32 (정합) | no drift |
| 7 | `entity_extractor_v2/9.202605130226/turn0_style.md` | 13 | 13 (정합) | no drift |
| 4 | `outlook_extractor/11.202603311724/phase1.md` | 16 | 16 (정합) + line 24 current-active-promoted (audit verbatim 아님, Codex iter 4 F-3 흡수) | no drift |
| 5 | `outlook_extractor/11.202603311724/phase2.md` | 8 | 8 (정합) | no drift |
| 9 | `scene_verify/1.202603231200/system.md` | 7 | 7 (정합) | no drift |
| 10 | `scene_detail/26.202605181435/system.md` | 327 | **473** (controller verify, scene_detail 26 version 매우 active, audit 시점 이후 21 version bump) | **drift confirmed** |
| 11 | `shot_extract/11.202604201230/user.md` | 33 | **49** (controller verify, shot_extract 11 version, audit 시점 이후 2 version bump) | **drift confirmed** |

**W3 entry verify obligation** — scene_detail line 473 + shot_extract line 49 controller `grep -nF` 으로 정확 line + phrase 재확인 의무. 만약 W3 entry 시점 또 다른 prompt version bump 발생 → narrow plan amend (latest version dir + 정확 line number 정정) 후 W3 진입.

#### Contract 3 — STEP_MANIFEST entry mapping (12 affected STEP entry, Codex iter 1 F-1 fix-up)

**Naming reconciliation (Codex iter 1 F-1 흡수 + iter 2 F-1 narrow sync)**: spec wording = "10 STEP_MANIFEST entries" (modified-file-bound count). Live `STEP_MANIFEST` literal = **12 affected keys**. Plan canonical wording (execution-test) = **12 affected STEP_MANIFEST entries = 10 modified-file-bound step entries + 2 sibling-only shared-module entries (`entity_all_location` / `entity_all_prop`)**. spec terminology "10" 보존 = modified-file-bound count only metric (audit §11.2 site mapping 정합), execution test = 12 entry presence + schema_version diff 0.

| Step entry (STEP_MANIFEST key) | Prompt module | Site (audit §11.2) | Action class |
|---|---|---|---|
| `entity_all_character` | `entity_all` | site 1 (character.md modified) | modified-file surface |
| `entity_all_location` | `entity_all` | (shared module, location.md byte-identical sibling) | shared-module sibling |
| `entity_all_prop` | `entity_all` | (shared module, prop.md byte-identical sibling) | shared-module sibling |
| `entity_relation` | `entity_relation` | site 3 (system.md modified + analyze.md/analyze_schema.json strict pack 의무) | modified-file surface |
| `entity_extract_character` | `entity_extractor_v2` | site 6 + 7 (system.md + turn0_style.md modified) | modified-file surface |
| `entity_extract_location` | `entity_extractor_v2` | (shared module, system.md + turn0_style.md modified — 동일 prompt module) | modified-file surface (shared) |
| `entity_extract_prop` | `entity_extractor_v2` | (shared module, system.md + turn0_style.md modified — 동일 prompt module) | modified-file surface (shared) |
| `outlook_phase1` | `outlook_extractor` | site 4 + line 24 (phase1.md modified) | modified-file surface |
| `outlook_phase2` | `outlook_extractor` | site 5 (phase2.md modified) | modified-file surface |
| `scene_verify` | `scene_verify` | site 9 (system.md modified + verify_schema.json strict pack 의무) | modified-file surface |
| `scene_detail` | `scene_detail` | site 10 (system.md modified) | modified-file surface |
| `shot_extract` | `shot_extract` | site 11 (user.md modified) | modified-file surface |

**Canonical breakdown (Codex iter 2 F-1 narrow sync)** — **12 affected STEP_MANIFEST entries = 10 modified-file-bound step entries + 2 sibling-only shared-module entries (`entity_all_location` / `entity_all_prop`)**.

- **10 modified-file-bound step entries** (binding to 9 modified prompt files):
  - `entity_all_character` (character.md modified, site 1).
  - `entity_relation` (system.md modified, site 3).
  - `entity_extract_character` + `entity_extract_location` + `entity_extract_prop` (3 step entries sharing entity_extractor_v2 modified system.md + turn0_style.md, site 6 + 7).
  - `outlook_phase1` (phase1.md modified, site 4 + line 24).
  - `outlook_phase2` (phase2.md modified, site 5).
  - `scene_verify` (system.md modified, site 9).
  - `scene_detail` (system.md modified, site 10).
  - `shot_extract` (user.md modified, site 11).
- **2 sibling-only shared-module entries** (binding to new dir `entity_all/5.*` via byte-identical sibling copy):
  - `entity_all_location` (location.md byte-identical sibling).
  - `entity_all_prop` (prop.md byte-identical sibling).

D-2 `entity_character_list` = boundary preserve (변경 0, 표 외).

**W5 C3 step entry presence verify scope (W5 fix-up 1 narrow sync commit `fe7e55e`)** = all 12 affected step entry present in `STEP_MANIFEST` (entry-existence contract — `for entry in expected_entries: assert entry in STEP_MANIFEST`). schema_version drift = C4 별도 verify (snapshot field-level diff 0 은 C3 scope 외).

#### Contract 4 — DB / code constant pin risk (audit §11.4 grep)

| Module | `db=`-aware caller | code constant pin | Risk in this area |
|---|---|---|---|
| `entity_character_list` (D-2 carve-out) | **존재** (audit §11.4) | 0 | **변경 0** 으로 DB row 영향 0 |
| 7 new-dir module (entity_all / entity_relation / entity_extractor_v2 / outlook_extractor / scene_verify / scene_detail / shot_extract) | absent (file fallback only) | 0 | new dir 신설 자동 active |

**W5 canary obligation** — C5 D-2 DB override risk neutralized: entity_character_list 본문 sha256 변경 0 verify (Gate 3 W4 정합) + production loader `db=` parameter path snapshot verify (변경 0).

#### Contract 5 — Sibling byte-identical copy inventory (24 total, Codex iter 0 strategy Q6 정합)

| Wave | Module | Sibling file 수 | 정합 source dir | Strict pack obligation? |
|---|---|---|---|---|
| W1 | `entity_all` | 6 (location.md / prop.md / character_schema.json / location_schema.json / prop_schema.json / system.md) | `4.202603310100/` | no |
| W1 | `entity_relation` | 2 (analyze.md / analyze_schema.json) | `2.202603301800/` | **yes** (production `entity_relation.py:93-95` 3 file strict pack, Codex iter 4 F-1 흡수) |
| W1 | `entity_extractor_v2` | 9 (turn_entity_detail.md / turn0_style_schema.json / turn1_7_detail_batch_schema.json / turn1_7_detail_batch.md / turn1_review_schema.json / turn1.md / turn2.md / turn3.md / turn4.md) | `9.202605130226/` | no |
| W2 | `outlook_extractor` | 4 (phase1_schema.json / phase2_schema.json / phase3_schema.json / phase3.md) | `11.202603311724/` | no |
| W3 | `scene_verify` | 1 (verify_schema.json) | `1.202603231200/` | **yes** (production `detail_steps.py:3088-3089` `load_schema("scene_verify", "verify_schema")`, Codex iter 4 F-1 흡수) |
| W3 | `scene_detail` | 1 (detail_schema.json) | `26.202605181435/` | no (단 `prompt_loader._resolve_stem_in_pack:259-266` strict pack mode 안 missing stem raise 의무 정합) |
| W3 | `shot_extract` | 1 (system.md) | `11.202604201230/` | no |
| | **Total** | **24** | | |

**Codex Q6 정합 copy pattern**: `cp -p src dest` (preserve timestamp + permission) per sibling pair + `shasum -a 256 src dest` equality check per sibling (controller verify, W4 canary C2 24-sub-canary 정합).

### W0 Conclusion + per-wave entry obligation

- spec §2.3 inventory + 본 Verification Contract 5 = W0 inventory baseline. 별도 W0 memo file 신설 0 (Area #7a W0 memo 5.5kb 보다 작은 inventory, plan body 안 흡수).
- **per-wave entry verify**: W1/W2/W3 entry 시 controller `ls prompts/_base/<module>/` (Contract 1) + `grep -nF "<exact phrase>" <file>` (Contract 2 line drift) 정합 의무. drift 발견 시 narrow plan/spec amend 후 wave 진입.
- W0 execution wave commit **0**.

---

## Task 2: W1 — Group E (entity_*) Cascade Atomic (single commit)

**Files:**
- Create dir: `prompts/_base/entity_all/5.20260518HHMM/` (7 file: 1 modified character.md + 6 sibling byte-identical)
- Create dir: `prompts/_base/entity_relation/3.20260518HHMM/` (3 file: 1 modified system.md + 2 sibling byte-identical strict pack)
- Create dir: `prompts/_base/entity_extractor_v2/10.20260518HHMM/` (11 file: 2 modified system.md + turn0_style.md + 9 sibling byte-identical)

**Atomic single commit** — 3 module new dir + 4 modified file + 17 sibling byte-identical copy 모두 single atomic commit. signature-non-breaking — schema 변경 0 + cp invalidation 불필요. 단 multiple module cascade 의 LLM cross-consumer drift 차단 위해 atomic 의무.

### S1 — Determine W1 UTC timestamp + date drift check

- [ ] **Step 1.1: UTC 현재 시각 12-digit YYYYMMDDHHMM 결정**

```bash
date -u +%Y%m%d%H%M
```

Output example: `202605181900` (UTC 2026-05-18 19:00). 이 값을 W1 모든 placeholder substitute (단일 commit 안 동일 timestamp).

- [ ] **Step 1.2: date drift check**

만약 Step 1.1 결과 첫 8 digit ≠ `20260518` (예: `20260517` UTC pre-midnight 또는 `20260519` UTC post-midnight cross):
1. Halt W1 진입.
2. narrow plan/spec amend — `20260518` placeholder substitute → 실제 UTC `YYYYMMDD`. 본 plan body 안 W1 (Task 2) + W2 (Task 3) + W3 (Task 4) 모든 `20260518HHMM` 정정 + spec `2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md` §1.2 표 안 `N.20260518HHMM` 정정. 별도 narrow amend commit.
3. amend 후 Step 1.1 재실행 후 W1 진입.

**rationale (Codex iter 0 strategy verdict Q5 정합)**: 본 area #7b plan amend 3 narrow (UTC date drift fix-up, 2026-05-18 UTC) 후 placeholder = `20260518HHMM`. 실 execution 이 UTC 다른 날짜로 cross 하면 directory naming = UTC 정합 (Area #7a 정합 보존, `7.202605181540` = UTC 2026-05-18 15:40 KST 2026-05-19 00:40).

### S2 — Create entity_all 5.20260518HHMM directory (W1 site 1)

- [ ] **Step 2.1: directory 신설**

```bash
mkdir -p prompts/_base/entity_all/5.20260518HHMM
```

(`HHMM` = Step 1.1 결과 substitute, 예: `prompts/_base/entity_all/5.202605181900`.)

- [ ] **Step 2.2: byte-identical sibling copy (6 file)**

```bash
cp -p prompts/_base/entity_all/4.202603310100/location.md prompts/_base/entity_all/5.20260518HHMM/location.md
cp -p prompts/_base/entity_all/4.202603310100/prop.md prompts/_base/entity_all/5.20260518HHMM/prop.md
cp -p prompts/_base/entity_all/4.202603310100/character_schema.json prompts/_base/entity_all/5.20260518HHMM/character_schema.json
cp -p prompts/_base/entity_all/4.202603310100/location_schema.json prompts/_base/entity_all/5.20260518HHMM/location_schema.json
cp -p prompts/_base/entity_all/4.202603310100/prop_schema.json prompts/_base/entity_all/5.20260518HHMM/prop_schema.json
cp -p prompts/_base/entity_all/4.202603310100/system.md prompts/_base/entity_all/5.20260518HHMM/system.md
```

- [ ] **Step 2.3: byte-identical sibling sha256 verify**

```bash
for f in location.md prop.md character_schema.json location_schema.json prop_schema.json system.md; do
  src=$(shasum -a 256 prompts/_base/entity_all/4.202603310100/$f | awk '{print $1}')
  dst=$(shasum -a 256 prompts/_base/entity_all/5.20260518HHMM/$f | awk '{print $1}')
  if [ "$src" != "$dst" ]; then echo "FAIL: $f sha256 mismatch"; exit 1; else echo "PASS: $f"; fi
done
```

Expected: 6 PASS.

- [ ] **Step 2.4: character.md modified — base copy + amend**

base copy (Step 2.2 와 동일 pattern):
```bash
cp -p prompts/_base/entity_all/4.202603310100/character.md prompts/_base/entity_all/5.20260518HHMM/character.md
```

그 후 본문 amend (controller Edit tool 사용, surgical edit):

**Site 1 (line 26 + 29 + 30 audit-verbatim residue 폐기 + canonical clause 삽입)**:

Before (line 24-32):
```markdown
## 분리 기준 — 외형이 달라지면 반드시 별도 인물로 분리
캐릭터가 일반적인 사람이 아니거나, 특정 상태에 따라 외형이 변하면 **반드시 분리 추출**한다:
- 변신/변형: 인간↔요괴, 인간↔괴물, 본체↔변신체 등 외형이 달라지는 경우
- 나이 변화: 어린 시절↔성인↔노인 등 얼굴이 크게 달라지는 경우
- 성형/변장: 수술 전후, 변장 전후로 얼굴이 달라지는 경우
- 빙의/합체: 다른 존재가 몸을 빌리거나 합체하여 외형이 변하는 경우
- **수식어 기반 분리**: 인물/물체 이름 앞에 외형적 변형을 나타내는 수식어(이무기, 구미호, 요괴화, 뱀파이어 등)가 붙어있고 그 모습이 원래와 매우 다르면 반드시 분리
- 핵심: 같은 인물이라도 **이미지로 그렸을 때 다른 사람처럼 보이면** 무조건 분리
```

After (canonical clause + generic principle wording):
```markdown
## 분리 기준 — 외형이 달라지면 반드시 별도 인물로 분리
캐릭터가 일반적인 사람이 아니거나, 특정 상태에 따라 외형이 변하면 **반드시 분리 추출**한다:

본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.

- 변신/변형: 외형이 달라지는 경우 (VWR rule_type 정합)
- 나이 변화: 어린 시절↔성인↔노인 등 얼굴이 크게 달라지는 경우
- 성형/변장: 수술 전후, 변장 전후로 얼굴이 달라지는 경우
- 비물리/매개 상태: VWR rules[] 의 rule_type 및 director_notes 에 정의된 외형 변화 기준을 따른다.
- **수식어 기반 분리**: 인물/물체 이름 앞에 외형적 변형을 나타내는 수식어가 붙어있고 그 모습이 원래와 매우 다르면 반드시 분리 (VWR rule_type 정합)
- 핵심: 같은 인물이라도 **이미지로 그렸을 때 다른 사람처럼 보이면** 무조건 분리
```

**Amend boundary 의무 (Codex Q3=Hybrid 정합)**:
- canonical clause (audit §11.3 verbatim) **글자-단위 정확 동일** (W2 Site 1 paraphrase 격분 trigger 재발 차단, [[session_20260519_area_7a_w0_w2_execution_closure]] 함정 7 정합).
- audit-verbatim residue 8 phrase (`인간↔요괴` / `인간↔괴물` / `본체↔변신체` / `빙의/합체: 다른 존재가 몸을 빌리거나 합체하여 외형이 변하는 경우` full phrase / `이무기` / `구미호` / `요괴화` / `뱀파이어`) 본체 폐기 — generic principle wording (`변신/변형` heading 자체 같은 일반 단어) 보존. **Audit-verbatim 8 phrase 의 specific 도메인-specific term 만 폐기** (`인간↔요괴` 등 specific arrow + `이무기, 구미호, 요괴화, 뱀파이어` enumeration + `빙의/합체` 의 audit verbatim full bullet 본문 line 29 full phrase). **Generic heading "빙의/합체" alone is not forbidden; forbidden exact residue phrase is "빙의/합체: 다른 존재가 몸을 빌리거나 합체하여 외형이 변하는 경우" anchored to entity_all/4.202603310100/character.md line 29** (4-Gate Boundary Doctrine Gate 2 + spec §3.1 line 239 Generic Korean standalone ban 0 정합). controller 가 heading 자체도 generic 추상화 결정 (예: `- 비물리/매개 상태` 같은 wording) 권장 — full legacy phrase substring hit 차단 안전.
- 8 audit-verbatim phrase exact `grep -Fc` = 0 verify obligation (Step S6 W1 pre-commit verify Step 3 정합).

### S3 — Create entity_relation 3.20260518HHMM directory (W1 site 3, strict pack 의무)

- [ ] **Step 3.1: directory 신설**

```bash
mkdir -p prompts/_base/entity_relation/3.20260518HHMM
```

- [ ] **Step 3.2: byte-identical sibling copy (2 file, strict pack 의무)**

```bash
cp -p prompts/_base/entity_relation/2.202603301800/analyze.md prompts/_base/entity_relation/3.20260518HHMM/analyze.md
cp -p prompts/_base/entity_relation/2.202603301800/analyze_schema.json prompts/_base/entity_relation/3.20260518HHMM/analyze_schema.json
```

**rationale**: production `entity_relation.py:93-95` 가 system.md + analyze.md + analyze_schema.json 3 file 모두 load. `prompt_loader._resolve_stem_in_pack:259-266` strict mode 안 latest pack stem miss 시 raise. sibling byte-identical copy 누락 시 production crash trigger (Codex iter 4 F-1 흡수).

- [ ] **Step 3.3: sibling sha256 verify**

```bash
for f in analyze.md analyze_schema.json; do
  src=$(shasum -a 256 prompts/_base/entity_relation/2.202603301800/$f | awk '{print $1}')
  dst=$(shasum -a 256 prompts/_base/entity_relation/3.20260518HHMM/$f | awk '{print $1}')
  if [ "$src" != "$dst" ]; then echo "FAIL: $f sha256 mismatch"; exit 1; else echo "PASS: $f"; fi
done
```

Expected: 2 PASS.

- [ ] **Step 3.4: system.md modified — base copy + amend**

```bash
cp -p prompts/_base/entity_relation/2.202603301800/system.md prompts/_base/entity_relation/3.20260518HHMM/system.md
```

**Site 3 amend — line 11+12+13 audit-verbatim 3 bullet + line 30 current-active-promoted full phrase**:

Before (line 9-13 인물 예시 + line 28-32 소품 예시):
```markdown
### 인물 예시
- 사람 → 늙은 모습 (노화)
- 사람 → 요괴/괴물 형태 (변신)
- 사람 → 유령/망령 형태 (사후)
- 영웅 → 갑옷 착용 형태 (변장/장비)

### 소품 예시
- **true**: 원래 형태의 시각적 특징이 남아있음 (참조 이미지 생성 시 원본을 참고해야 함)
  - 사람이 늙어도 얼굴 특징은 유지됨 → true
  - 요괴로 변해도 원래 인물의 흔적이 있음 → true
  - 검이 빛나는 형태로 변해도 기본 형태는 같음 → true
  - 마을이 폐허가 되어도 같은 장소임 → true
```

After (canonical clause + generic principle wording + generic placeholder):
```markdown
### 인물 예시

본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.

- 사람 → 늙은 모습 (노화)
- 사람 → 외형이 달라진 형태 (변신, VWR rule_type 정합)
- 사람 → 사후 형태 (사후, VWR rule_type 정합)
- 영웅 → 장비 착용 형태 (변장/장비)

### 소품 예시
- **true**: 원래 형태의 시각적 특징이 남아있음 (참조 이미지 생성 시 원본을 참고해야 함)
  - 사람이 늙어도 얼굴 특징은 유지됨 → true
  - 이미지 형태가 달라져도 원래 인물의 흔적이 있음 → true
  - 검이 빛나는 형태로 변해도 기본 형태는 같음 → true
  - 마을이 폐허가 되어도 같은 장소임 → true
```

**Amend boundary**:
- 3 audit-verbatim phrase (`요괴/괴물 형태` / `유령/망령 형태` / `갑옷 착용 형태`) generic 추상화 + canonical clause 삽입.
- 1 current-active-promoted phrase (`요괴로 변해도 원래 인물의 흔적이 있음 → true` full phrase) → generic placeholder (`이미지 형태가 달라져도 원래 인물의 흔적이 있음 → true`).
- audit-verbatim 3 phrase + current-active-promoted 1 phrase 모두 `grep -Fc` = 0 verify obligation.
- canonical clause **글자-단위 정확 동일**.

### S4 — Create entity_extractor_v2 10.20260518HHMM directory (W1 site 6 + 7)

- [ ] **Step 4.1: directory 신설**

```bash
mkdir -p prompts/_base/entity_extractor_v2/10.20260518HHMM
```

- [ ] **Step 4.2: byte-identical sibling copy (9 file)**

```bash
for f in turn_entity_detail.md turn0_style_schema.json turn1_7_detail_batch_schema.json turn1_7_detail_batch.md turn1_review_schema.json turn1.md turn2.md turn3.md turn4.md; do
  cp -p prompts/_base/entity_extractor_v2/9.202605130226/$f prompts/_base/entity_extractor_v2/10.20260518HHMM/$f
done
```

- [ ] **Step 4.3: 9-file sibling sha256 verify**

```bash
for f in turn_entity_detail.md turn0_style_schema.json turn1_7_detail_batch_schema.json turn1_7_detail_batch.md turn1_review_schema.json turn1.md turn2.md turn3.md turn4.md; do
  src=$(shasum -a 256 prompts/_base/entity_extractor_v2/9.202605130226/$f | awk '{print $1}')
  dst=$(shasum -a 256 prompts/_base/entity_extractor_v2/10.20260518HHMM/$f | awk '{print $1}')
  if [ "$src" != "$dst" ]; then echo "FAIL: $f sha256 mismatch"; exit 1; else echo "PASS: $f"; fi
done
```

Expected: 9 PASS.

- [ ] **Step 4.4: system.md modified — base copy + amend (site 6 line 22 + line 32)**

```bash
cp -p prompts/_base/entity_extractor_v2/9.202605130226/system.md prompts/_base/entity_extractor_v2/10.20260518HHMM/system.md
```

**Site 6 amend (line 22 + line 32)**:

Before (line 20-34):
```markdown
허용되는 변형 예시:
- 20대 → 60대 (나이가 크게 달라짐)
- 평상복 → 전신 갑옷 (완전히 다른 실루엣)
- 변장으로 다른 사람처럼 보이는 경우

금지되는 변형 (씬 T2I 프롬프트로 처리 가능):
- "전투 준비 상태" — 프롬프트에 "무장한" 추가하면 됨
- "결박된 상태" — 프롬프트에 "묶인" 추가하면 됨
- "부상 상태", "두 동강 난 상태" — 참조 이미지 불필요
- "기억 속 모습" — 기억은 시각적 요소가 아님
- 같은 사람의 소소한 의상 변화

### 빙의/정신 전환/몸을 빌리는 설정이 있는 경우

- 중요한 건 육체의 외형이지, 정신/영혼의 주인이 아님
```

After (canonical clause + generic placeholder + section header rewrite):
```markdown
허용되는 변형 예시:
- 20대 → 60대 (나이가 크게 달라짐)
- 의상이 완전히 다른 실루엣으로 변하는 경우 (VWR rule_type=costume / technology 정합)
- 변장으로 다른 사람처럼 보이는 경우

금지되는 변형 (씬 T2I 프롬프트로 처리 가능):
- "전투 준비 상태" — 프롬프트에 "무장한" 추가하면 됨
- "결박된 상태" — 프롬프트에 "묶인" 추가하면 됨
- "부상 상태", "두 동강 난 상태" — 참조 이미지 불필요
- "기억 속 모습" — 기억은 시각적 요소가 아님
- 같은 사람의 소소한 의상 변화

### 비물리 / 매개 상태 처리

본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.

- 중요한 건 육체의 외형이지, 정신/영혼의 주인이 아님
```

**Amend boundary**:
- line 22 audit-verbatim (`평상복 → 전신 갑옷`) 폐기 → generic placeholder (`의상이 완전히 다른 실루엣으로 변하는 경우`).
- line 32 audit-verbatim section header (`### 빙의/정신 전환/몸을 빌리는 설정이 있는 경우`) 폐기 → generic section header (`### 비물리 / 매개 상태 처리`) + canonical clause 삽입.
- 2 audit-verbatim phrase exact `grep -Fc` = 0 verify obligation.
- principle wording (`중요한 건 육체의 외형이지, 정신/영혼의 주인이 아님`) 보존.

- [ ] **Step 4.5: turn0_style.md modified — base copy + amend (site 7 line 13)**

```bash
cp -p prompts/_base/entity_extractor_v2/9.202605130226/turn0_style.md prompts/_base/entity_extractor_v2/10.20260518HHMM/turn0_style.md
```

**Site 7 amend (line 13)**:

Before (line 11-15):
```markdown
- visual_world_rules: "이 인물이 이 장소에 물리적으로 존재하는가?"를 판단하는 핵심 규칙만 (2~5개).
  반드시 포함:
  - 원격 접속/조종/빙의/텔레파시 등 기술이 있다면: 접속자의 물리적 몸이 현장에 있는지 없는지
  - 몽타주/교차편집에서 다른 장소 인물이 보이는 것이 물리적 존재인지 편집 기법인지
  불필요한 것: 장비 외형 디테일, 색감, 공간 분위기 (다른 필드에서 다룸)
```

After (canonical clause + generic instruction):
```markdown
- visual_world_rules: "이 인물이 이 장소에 물리적으로 존재하는가?"를 판단하는 핵심 규칙만 (2~5개).

  본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.

  반드시 포함:
  - rule_type=projection / possession 등 비물리 매개 상태 인물: 접속자의 물리적 몸이 현장에 있는지 없는지
  - 몽타주/교차편집에서 다른 장소 인물이 보이는 것이 물리적 존재인지 편집 기법인지
  불필요한 것: 장비 외형 디테일, 색감, 공간 분위기 (다른 필드에서 다룸)
```

**Amend boundary**:
- line 13 audit-verbatim (`원격 접속/조종/빙의/텔레파시`) 폐기 → generic wording (`rule_type=projection / possession 등 비물리 매개 상태`) + canonical clause 삽입 (line 11 직후).
- 1 audit-verbatim phrase exact `grep -Fc` = 0 verify obligation.
- visual_world_rules section 의 본 turn0_style 자체 사용 의도 (LLM 이 VWR 정의 시 무엇을 emit 해야 하는지 instruction) 보존.

### S5 — W1 pre-commit verification (8 종)

- [ ] **Step 5.1: 8 종 verify 실행**

Pre-Commit Verification Doctrine W1 본문 8 종 (UTC date drift / Canonical clause membership / W1 exact residue phrase inventory 15 phrase hit 0 / 17 sibling sha256 / D-2 byte-identical / prompt_loader latest activation / STEP_MANIFEST schema_version=1 / Smoke pytest entity_*) 모두 PASS 확인.

실패 1 종 있을 시 commit 절대 금지 → 본문 fix → 8 종 재실행.

**residue phrase grep command (fixed-string membership, regex 0)**:

```bash
# entity_all character.md — 8 audit-verbatim phrase
for phrase in "인간↔요괴" "인간↔괴물" "본체↔변신체" "빙의/합체: 다른 존재가 몸을 빌리거나 합체하여 외형이 변하는 경우" "이무기" "구미호" "요괴화" "뱀파이어"; do
  hit=$(grep -Fc "$phrase" prompts/_base/entity_all/5.20260518HHMM/character.md)
  if [ "$hit" -ne 0 ]; then echo "FAIL: entity_all/character.md residue: $phrase ($hit hits)"; exit 1; else echo "PASS: $phrase"; fi
done

# entity_relation system.md — 3 audit-verbatim + 1 current-active-promoted
for phrase in "요괴/괴물 형태" "유령/망령 형태" "갑옷 착용 형태" "요괴로 변해도 원래 인물의 흔적이 있음 → true"; do
  hit=$(grep -Fc "$phrase" prompts/_base/entity_relation/3.20260518HHMM/system.md)
  if [ "$hit" -ne 0 ]; then echo "FAIL: entity_relation/system.md residue: $phrase ($hit hits)"; exit 1; else echo "PASS: $phrase"; fi
done

# entity_extractor_v2 system.md — 2 audit-verbatim
for phrase in "평상복 → 전신 갑옷" "### 빙의/정신 전환/몸을 빌리는 설정이 있는 경우"; do
  hit=$(grep -Fc "$phrase" prompts/_base/entity_extractor_v2/10.20260518HHMM/system.md)
  if [ "$hit" -ne 0 ]; then echo "FAIL: entity_extractor_v2/system.md residue: $phrase ($hit hits)"; exit 1; else echo "PASS: $phrase"; fi
done

# entity_extractor_v2 turn0_style.md — 1 audit-verbatim
hit=$(grep -Fc "원격 접속/조종/빙의/텔레파시" prompts/_base/entity_extractor_v2/10.20260518HHMM/turn0_style.md)
if [ "$hit" -ne 0 ]; then echo "FAIL: turn0_style.md residue"; exit 1; else echo "PASS"; fi
```

Expected: 15 PASS (8 entity_all + 4 entity_relation + 2 entity_extractor_v2 system + 1 turn0_style).

**Canonical clause membership grep command (fixed-string, regex 0)**:

```bash
canonical='본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.'

for f in prompts/_base/entity_all/5.20260518HHMM/character.md prompts/_base/entity_relation/3.20260518HHMM/system.md prompts/_base/entity_extractor_v2/10.20260518HHMM/system.md prompts/_base/entity_extractor_v2/10.20260518HHMM/turn0_style.md; do
  hit=$(grep -Fc "$canonical" "$f")
  if [ "$hit" -lt 1 ]; then echo "FAIL: $f missing canonical clause"; exit 1; else echo "PASS: $f ($hit hits)"; fi
done
```

Expected: 4 PASS.

### S6 — W1 atomic commit

- [ ] **Step 6.1: git status 확인**

```bash
git status
```

확인: untracked = `prompts/_base/entity_all/5.20260518HHMM/` (7 file) + `prompts/_base/entity_relation/3.20260518HHMM/` (3 file) + `prompts/_base/entity_extractor_v2/10.20260518HHMM/` (11 file) = **21 untracked file total**. modified = 0.

- [ ] **Step 6.2: path-limited git add**

```bash
git add prompts/_base/entity_all/5.20260518HHMM/ \
        prompts/_base/entity_relation/3.20260518HHMM/ \
        prompts/_base/entity_extractor_v2/10.20260518HHMM/
```

**절대 금지**: `git add -A` / `git add .` / sensitive file (DB / env / credentials) 자동 stage.

- [ ] **Step 6.3: W1 atomic commit**

```bash
git commit -m "$(cat <<'EOF'
feat(area-7b-vwr-cascade-downstream-v1): W1 producer atomic — Group E entity_all + entity_relation + entity_extractor_v2 canonical VWR SOT clause cascade (5 site / 4 modified file / 17 sibling)

Group E (entity_*) — 3 module new prompt dir + 4 modified file + 17 byte-identical sibling copy 모두 single atomic commit. signature-non-breaking
(schema 변경 0, cp invalidation 불필요).

entity_all 5.20260518HHMM/ (site 1 character.md modified + 6 sibling
byte-identical): line 26 + 29 + 30 8 audit-verbatim phrase (인간↔요괴 / 인간↔
괴물 / 본체↔변신체 / 빙의/합체 / 이무기 / 구미호 / 요괴화 / 뱀파이어)
domain-specific term 본체 폐기 → canonical VWR SOT clause + generic principle.

entity_relation 3.20260518HHMM/ (site 3 system.md modified + 2 sibling
strict pack): line 11+12+13 3 audit-verbatim phrase (요괴/괴물 형태 /
유령/망령 형태 / 갑옷 착용 형태) 폐기 + line 30 current-active-promoted
phrase (요괴로 변해도 원래 인물의 흔적이 있음 → true full phrase) generic
추상화 → canonical clause + generic placeholder. analyze.md + analyze_schema.json
byte-identical sibling copy (Codex iter 4 F-1 흡수, production entity_relation.py:
93-95 strict pack 의무).

entity_extractor_v2 10.20260518HHMM/ (site 6+7, system.md + turn0_style.md
modified + 9 sibling byte-identical): system.md line 22 audit-verbatim
(평상복 → 전신 갑옷) + line 32 audit-verbatim section header (### 빙의/정신
전환/몸을 빌리는 설정이 있는 경우) 폐기 → canonical clause + generic section
header (### 비물리 / 매개 상태 처리). turn0_style.md line 13 audit-verbatim
(원격 접속/조종/빙의/텔레파시) 폐기 → canonical clause + generic wording
(rule_type=projection / possession 등 비물리 매개 상태).

Canonical clause (audit §11.3 verbatim, 4 modified file 모두 글자-단위 정확
동일 의무): 본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.
rules[] 의 rule_type ∈ {possession, transformation, ghost, projection,
superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의
되어 있지 않으면 일반 인물로 처리.

4-Gate Boundary Doctrine 정합 (사용자 격분 흡수 2026-05-19):
- Semantic Regex Ban (open-world semantic 판단 regex 0)
- Prompt Closed-List Ban (LLM-instructed closed-list domain term enumeration 0)
- Structured SOT Required (open-world semantic 판단 = LLM-produced structured emit)
- No Silent Fallback (invalid input = explicit reject + typed error)

Pre-commit verify 8 종 PASS: UTC date drift / canonical clause membership 4 file /
W1 exact residue phrase inventory 15 phrase hit 0 / 17 sibling sha256 PASS /
D-2 byte-identical / prompt_loader latest activation 3 module / STEP_MANIFEST
schema_version=1 보존 / Smoke pytest entity_*.

STEP_MANIFEST 변경 0 (Area #7a W1 신설 visual_world_rules.schema_version=1
보존, 본 area prompt text only change).

D-2 entity_character_list = 변경 0 boundary preserve (owner taxonomy 5-element
분류, presence/visibility 결정 X, db-aware caller but out of scope unchanged).

NO VLM hard constraint inline.

Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md
Plan: docs/superpowers/plans/2026-05-19-area-7b-vwr-cascade-downstream-v1-implementation.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```

- [ ] **Step 6.4: commit 확인**

```bash
git log -1 --stat
```

확인: 1 commit + 21 file created (entity_all 7 + entity_relation 3 + entity_extractor_v2 11).

### S7 — W1 Codex review 의뢰 (per-wave external)

- [ ] **Step 7.1: Codex pane %0 read guard**

```bash
# tmux_read %0 (50 lines) — read guard 의무
```

- [ ] **Step 7.2: W1 commit Codex review 의뢰**

tmux_type %0 (single message, 본 task 직후 fresh):

```
Area #7b W1 commit review 의뢰.

Commit: <W1 commit hash>
Wave: W1 producer atomic (Group E — entity_all + entity_relation + entity_extractor_v2 canonical VWR SOT clause cascade, 5 site / 4 modified file / 17 sibling byte-identical).
Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md (commit 90a8cea).
Plan: docs/superpowers/plans/2026-05-19-area-7b-vwr-cascade-downstream-v1-implementation.md.

검토 항목:
1. canonical clause 4 modified file 모두 글자-단위 정확 동일 (audit §11.3 verbatim).
2. W1 exact residue phrase inventory 15 phrase hit 0 (entity_all 8 audit-verbatim + entity_relation 3 audit-verbatim + 1 current-active-promoted + entity_extractor_v2 system 2 audit-verbatim + turn0_style 1 audit-verbatim).
3. 17 sibling byte-identical sha256 PASS (entity_all 6 + entity_relation 2 strict pack + entity_extractor_v2 9).
4. principle wording 보존 (변신/변형 heading 자체, 비물리/매개 상태 generic heading, 중요한 건 육체의 외형 등; legacy full phrase "빙의/합체: 다른 존재가 몸을 빌리거나 합체하여 외형이 변하는 경우" hit 0).
5. atomic single commit (W2 / W3 cascade 0).
6. D-2 entity_character_list 변경 0 boundary preserve.
7. STEP_MANIFEST schema_version 변경 0 (Area #7a 신설 1 보존).
8. 4-Gate Boundary Doctrine 정합 (Semantic Regex Ban / Prompt Closed-List Ban / Structured SOT Required / No Silent Fallback).
9. NO VLM hard constraint.

verdict: APPROVED / NEEDS_REVISION_MINOR / NEEDS_REVISION_MAJOR. minor finding 시 fix-up amend (또는 별도 narrow amend commit). major 시 W1 redo.

완료되면 끝났다고 claude mcp 호출해줘!
```

- [ ] **Step 7.3: tmux_keys Enter + tmux_read polling**

verdict 도착 후 controller cross-analyze ([[feedback_codex_mcp_discussion_workflow]] rule 7b — verdict verbatim 받아쓰지 말 것, controller cross-analyze 의무). NEEDS_REVISION 시 fix-up amend, APPROVED 시 W2 진입.

---

## Task 3: W2 — Group O (outlook_*) Cascade Atomic (single commit)

**Files:**
- Create dir: `prompts/_base/outlook_extractor/12.20260518HHMM/` (6 file: 2 modified phase1.md + phase2.md + 4 sibling byte-identical)

**Atomic single commit** — 1 module new dir + 2 modified file + 4 sibling byte-identical copy single atomic commit.

### S1 — Determine W2 UTC timestamp + date drift check

- [ ] **Step 1.1: UTC 현재 시각 12-digit YYYYMMDDHHMM 결정 + date drift check**

```bash
date -u +%Y%m%d%H%M
```

(W2 자체 timestamp — W1 timestamp 과 다를 수 있음.)

date drift check (W1 Task 2 S1.2 pattern 정합): 첫 8 digit ≠ `20260518` 시 narrow plan/spec amend.

### S2 — Create outlook_extractor 12.20260518HHMM directory (W2 site 4 + 5)

- [ ] **Step 2.1: directory 신설**

```bash
mkdir -p prompts/_base/outlook_extractor/12.20260518HHMM
```

- [ ] **Step 2.2: byte-identical sibling copy (4 file)**

```bash
for f in phase1_schema.json phase2_schema.json phase3_schema.json phase3.md; do
  cp -p prompts/_base/outlook_extractor/11.202603311724/$f prompts/_base/outlook_extractor/12.20260518HHMM/$f
done
```

- [ ] **Step 2.3: 4-file sibling sha256 verify**

```bash
for f in phase1_schema.json phase2_schema.json phase3_schema.json phase3.md; do
  src=$(shasum -a 256 prompts/_base/outlook_extractor/11.202603311724/$f | awk '{print $1}')
  dst=$(shasum -a 256 prompts/_base/outlook_extractor/12.20260518HHMM/$f | awk '{print $1}')
  if [ "$src" != "$dst" ]; then echo "FAIL: $f sha256 mismatch"; exit 1; else echo "PASS: $f"; fi
done
```

Expected: 4 PASS.

- [ ] **Step 2.4: phase1.md modified — base copy + amend (site 4 line 16 audit-verbatim + line 24 current-active-promoted)**

```bash
cp -p prompts/_base/outlook_extractor/11.202603311724/phase1.md prompts/_base/outlook_extractor/12.20260518HHMM/phase1.md
```

**Site 4 amend (line 16 audit-verbatim)**:

Before (line 14-18):
```markdown
6. 시나리오에 복장 묘사가 없어도 장면 상황으로 추론하여 구체적으로 지정
7. 아웃룩은 의상 자체만 — 같은 옷이 더러워져도 동일 아웃룩, 일시적 장식은 별도 아웃룩이 아님
8. 사람이 탑승하거나 착용하는 인간형 기계장치(메카, 파워드슈트, 강화복, 갑옷 로봇 등)도 아웃룩으로 추출 — 해당 캐릭터의 외형을 결정하므로 의상과 동일 취급
```

After (canonical clause + generic wording):
```markdown
6. 시나리오에 복장 묘사가 없어도 장면 상황으로 추론하여 구체적으로 지정
7. 아웃룩은 의상 자체만 — 같은 옷이 더러워져도 동일 아웃룩, 일시적 장식은 별도 아웃룩이 아님

본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리. 특히 costume / technology rule_type 의 wear/ride 형태 (실루엣을 결정하는 wearable/ridable 외형) 는 아웃룩 으로 처리.

8. 사람이 탑승하거나 착용하는 인간형 기계장치도 아웃룩으로 추출 — 해당 캐릭터의 외형을 결정하므로 의상과 동일 취급 (VWR costume / technology rule_type 정합)
```

**Site 4 line 24 amend (current-active-promoted residue, Codex iter 4 F-3 흡수)**:

Before (line 22-26):
```markdown
## 비인간형 캐릭터 판별

아웃룩 추출과 함께, 사람 형상이 아닌 캐릭터를 non_humanoid_characters에 넣으세요.
- 사람 형상이 아닌 캐릭터: 동물, 뱀, 곤충 떼, 박쥐 떼, 물체, 차량 등
- 사람 형상인 캐릭터: 인간, 인간형 요괴/괴물, 뱀파이어, 좀비 등 (아웃룩 대상)
```

After (canonical clause reference + generic wording):
```markdown
## 비인간형 캐릭터 판별

아웃룩 추출과 함께, 사람 형상이 아닌 캐릭터를 non_humanoid_characters에 넣으세요.
- 사람 형상이 아닌 캐릭터: 동물, 뱀, 곤충 떼, 박쥐 떼, 물체, 차량 등
- 사람 형상인 캐릭터: 인간 + VWR rules[] 의 rule_type 이 humanoid 변형으로 가리키는 인물 (아웃룩 대상)
```

**Amend boundary**:
- line 16 audit-verbatim phrase (`메카, 파워드슈트, 강화복, 갑옷 로봇` single contiguous parenthetical) 본체 폐기 → canonical clause + generic wording (`costume / technology rule_type 의 wear/ride 형태`).
- line 24 current-active-promoted phrase (`인간형 요괴/괴물, 뱀파이어, 좀비` single contiguous parenthetical, controller verify 2026-05-19, audit §11.2 verbatim 아님, Codex iter 4 F-3 흡수) 본체 폐기 → generic wording (`VWR rules[] humanoid 변형`).
- 2 phrase 모두 `grep -Fc` = 0 verify obligation.
- principle wording (사람이 탑승하거나 착용하는 인간형 기계장치 의무 / 사람 형상인 캐릭터 헤딩 등) 보존.

- [ ] **Step 2.5: phase2.md modified — base copy + amend (site 5 line 8 audit-verbatim)**

```bash
cp -p prompts/_base/outlook_extractor/11.202603311724/phase2.md prompts/_base/outlook_extractor/12.20260518HHMM/phase2.md
```

**Site 5 amend (line 8)**:

Before (line 6-10):
```markdown
1. 씬에 물리적으로 존재하는 인물만 배정
   - 몽타주/교차편집: 각 인물은 자기가 실제로 있는 장소의 씬에만 배정
   - 원격접속/빙의: 접속당한 몸이 있는 장소에만 배정
   - V.O./회상/이름만 언급: 배정 안 함
2. 의상 연속성: 명시적 환복 언급이 없으면 직전 씬과 동일 아웃룩 유지
```

After (canonical clause + generic wording):
```markdown
1. 씬에 물리적으로 존재하는 인물만 배정

본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.

   - 몽타주/교차편집: 각 인물은 자기가 실제로 있는 장소의 씬에만 배정
   - VWR rule_type=possession / projection 등 비물리 매개 상태: 접속당한 몸이 있는 장소에만 배정
   - V.O./회상/이름만 언급: 배정 안 함
2. 의상 연속성: 명시적 환복 언급이 없으면 직전 씬과 동일 아웃룩 유지
```

**Amend boundary**:
- line 8 audit-verbatim phrase (`원격접속/빙의:` colon-terminated heading parenthetical) 본체 폐기 → canonical clause + generic wording (`VWR rule_type=possession / projection 등 비물리 매개 상태`).
- 1 phrase exact `grep -Fc` = 0 verify obligation.
- principle wording (`접속당한 몸이 있는 장소에만 배정`) 보존.

### S3 — W2 pre-commit verification (5 종)

- [ ] **Step 3.1: 5 종 verify 실행**

Pre-Commit Verification Doctrine W2 본문 5 종 (UTC date drift / Canonical clause membership 2 file / W2 exact residue phrase inventory 3 phrase hit 0 / 4 sibling sha256 / Smoke pytest outlook) 모두 PASS.

**residue phrase grep command**:

```bash
# phase1.md — 1 audit-verbatim + 1 current-active-promoted
for phrase in "메카, 파워드슈트, 강화복, 갑옷 로봇" "인간형 요괴/괴물, 뱀파이어, 좀비"; do
  hit=$(grep -Fc "$phrase" prompts/_base/outlook_extractor/12.20260518HHMM/phase1.md)
  if [ "$hit" -ne 0 ]; then echo "FAIL: phase1.md residue: $phrase"; exit 1; else echo "PASS: $phrase"; fi
done

# phase2.md — 1 audit-verbatim
hit=$(grep -Fc "원격접속/빙의:" prompts/_base/outlook_extractor/12.20260518HHMM/phase2.md)
if [ "$hit" -ne 0 ]; then echo "FAIL: phase2.md residue"; exit 1; else echo "PASS"; fi
```

Expected: 3 PASS.

**Canonical clause membership grep command**:

```bash
canonical='본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.'

for f in prompts/_base/outlook_extractor/12.20260518HHMM/phase1.md prompts/_base/outlook_extractor/12.20260518HHMM/phase2.md; do
  hit=$(grep -Fc "$canonical" "$f")
  if [ "$hit" -lt 1 ]; then echo "FAIL: $f missing canonical clause"; exit 1; else echo "PASS: $f"; fi
done
```

Expected: 2 PASS.

### S4 — W2 atomic commit

- [ ] **Step 4.1: git status + path-limited git add**

```bash
git status
git add prompts/_base/outlook_extractor/12.20260518HHMM/
```

확인: untracked = `prompts/_base/outlook_extractor/12.20260518HHMM/` (6 file).

- [ ] **Step 4.2: W2 atomic commit**

```bash
git commit -m "$(cat <<'EOF'
feat(area-7b-vwr-cascade-downstream-v1): W2 consumer atomic — Group O outlook_extractor canonical VWR SOT clause cascade (2 site + line 24 / 2 modified file / 4 sibling)

Group O (outlook_*) — 1 module new prompt dir + 2 modified file + 4 byte-identical
sibling copy single atomic commit.

outlook_extractor 12.20260518HHMM/ (site 4 + 5):
- phase1.md line 16 audit-verbatim phrase (메카, 파워드슈트, 강화복, 갑옷 로봇
  single contiguous parenthetical) 본체 폐기 → canonical clause + generic
  wording (costume / technology rule_type 의 wear/ride 형태).
- phase1.md line 24 current-active-promoted phrase (인간형 요괴/괴물, 뱀파이어,
  좀비 single contiguous parenthetical, controller verify 2026-05-19, audit
  §11.2 verbatim 아님, Codex iter 4 F-3 흡수) 본체 폐기 → generic wording
  (VWR rules[] humanoid 변형).
- phase2.md line 8 audit-verbatim phrase (원격접속/빙의: colon-terminated
  heading parenthetical) 본체 폐기 → canonical clause + generic wording
  (VWR rule_type=possession / projection 등 비물리 매개 상태).
- phase1_schema.json + phase2_schema.json + phase3_schema.json + phase3.md
  byte-identical sibling copy (4 file).

Canonical clause (audit §11.3 verbatim, 2 modified file 모두 글자-단위 정확
동일 의무).

4-Gate Boundary Doctrine 정합.

Pre-commit verify 5 종 PASS: UTC date drift / canonical clause membership
2 file / W2 exact residue phrase inventory 3 phrase hit 0 / 4 sibling sha256
PASS / Smoke pytest outlook.

NO VLM hard constraint inline.

Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md
Plan: docs/superpowers/plans/2026-05-19-area-7b-vwr-cascade-downstream-v1-implementation.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```

- [ ] **Step 4.3: commit 확인**

```bash
git log -1 --stat
```

확인: 1 commit + 6 file created.

### S5 — W2 Codex review 의뢰 (per-wave external)

- [ ] **Step 5.1: Codex pane %0 read + W2 commit review 의뢰**

tmux_type %0 (fresh):

```
Area #7b W2 commit review 의뢰.

Commit: <W2 commit hash>
Wave: W2 consumer atomic (Group O — outlook_extractor canonical VWR SOT clause cascade, 2 site + line 24 / 2 modified file / 4 sibling).
Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md (commit 90a8cea).

검토 항목:
1. canonical clause 2 modified file 모두 글자-단위 정확 동일.
2. W2 exact residue phrase inventory 3 phrase hit 0 (phase1 audit-verbatim 메카/파워드슈트/강화복/갑옷 로봇 + phase1 current-active-promoted 인간형 요괴/괴물/뱀파이어/좀비 + phase2 audit-verbatim 원격접속/빙의:).
3. 4 sibling byte-identical sha256 PASS.
4. principle wording 보존 (사람 형상 캐릭터 헤딩 / 접속당한 몸이 있는 장소 등).
5. atomic single commit.
6. 4-Gate Boundary Doctrine 정합.
7. NO VLM.

verdict: APPROVED / NEEDS_REVISION_MINOR / NEEDS_REVISION_MAJOR.

완료되면 끝났다고 claude mcp 호출해줘!
```

verdict 도착 후 controller cross-analyze. APPROVED 시 W3 진입.

---

## Task 4: W3 — Group S (scene_*) Cascade Atomic (single commit) — line drift verify 의무

**Files:**
- Create dir: `prompts/_base/scene_verify/2.20260518HHMM/` (2 file: 1 modified system.md + 1 sibling verify_schema.json strict pack)
- Create dir: `prompts/_base/scene_detail/27.20260518HHMM/` (2 file: 1 modified system.md + 1 sibling detail_schema.json)
- Create dir: `prompts/_base/shot_extract/12.20260518HHMM/` (2 file: 1 modified user.md + 1 sibling system.md)

**Atomic single commit** — 3 module new dir + 3 modified file + 3 sibling byte-identical copy single atomic commit. **line drift verify 의무**: scene_detail line 473 + shot_extract line 49 controller `grep -nF` 재확인.

### S1 — Determine W3 UTC timestamp + date drift check + line drift verify

- [ ] **Step 1.1: UTC timestamp 결정 + date drift check** (W1/W2 동일 pattern)

```bash
date -u +%Y%m%d%H%M
```

date drift check: 첫 8 digit ≠ `20260518` 시 narrow plan/spec amend.

- [ ] **Step 1.2: line drift verify (W3 entry 시 controller 재확인 의무)**

```bash
# scene_detail 현재 latest version 확인
ls prompts/_base/scene_detail/ | sort -V | tail -1
# Expected: 26.202605181435

# scene_detail line 473 정합 verify
grep -nF "원격 조종/접속 인물 제외 (조종자 몸이 다른 장소에 있음)" prompts/_base/scene_detail/26.202605181435/system.md
# Expected: 473:- 원격 조종/접속 인물 제외 (조종자 몸이 다른 장소에 있음)

# shot_extract 현재 latest version 확인
ls prompts/_base/shot_extract/ | sort -V | tail -1
# Expected: 11.202604201230

# shot_extract line 49 정합 verify
grep -nF "빙의로 얼굴이 바뀜" prompts/_base/shot_extract/11.202604201230/user.md
# Expected: 49:- 얼굴이 크게 달라지는 변화: 나이 변화, 변장/성형 전후, 빙의로 얼굴이 바뀜
```

만약 line 또는 latest version dir 가 또 drift (audit 시점 327→473 / 33→49 와 또 다른 결과) 발생:
1. Halt W3 진입.
2. narrow plan/spec amend (latest version dir + 정확 line number 정정).
3. amend 후 Step 1.1 + 1.2 재실행 후 W3 진입.

### S2 — Create scene_verify 2.20260518HHMM directory (W3 site 9, strict pack 의무)

- [ ] **Step 2.1: directory 신설**

```bash
mkdir -p prompts/_base/scene_verify/2.20260518HHMM
```

- [ ] **Step 2.2: byte-identical sibling copy (1 file, strict pack 의무)**

```bash
cp -p prompts/_base/scene_verify/1.202603231200/verify_schema.json prompts/_base/scene_verify/2.20260518HHMM/verify_schema.json
```

**rationale**: production `detail_steps.py:3088-3089` 가 `load_schema("scene_verify", "verify_schema")` 호출. `prompt_loader._resolve_stem_in_pack:259-266` strict mode 안 latest pack 의 verify_schema stem miss 시 raise. sibling byte-identical copy 의무 (Codex iter 4 F-1 흡수).

- [ ] **Step 2.3: sibling sha256 verify**

```bash
src=$(shasum -a 256 prompts/_base/scene_verify/1.202603231200/verify_schema.json | awk '{print $1}')
dst=$(shasum -a 256 prompts/_base/scene_verify/2.20260518HHMM/verify_schema.json | awk '{print $1}')
if [ "$src" != "$dst" ]; then echo "FAIL: verify_schema.json sha256 mismatch"; exit 1; else echo "PASS"; fi
```

Expected: PASS.

- [ ] **Step 2.4: system.md modified — base copy + amend (site 9 line 7 audit-verbatim)**

```bash
cp -p prompts/_base/scene_verify/1.202603231200/system.md prompts/_base/scene_verify/2.20260518HHMM/system.md
```

**Site 9 amend (line 7 audit-verbatim full sentence)**:

Before (line 5-9):
```markdown
1. **물리적 존재만 인정**: 해당 씬의 공간에 실제로 있는 대상만 physically_visible = true
2. **언급만으로는 불충분**: 대화 중 이름이 나오더라도 해당 공간에 없으면 false
3. **빙의/영혼 상태**: 다른 인물의 몸에 들어간 경우, 원래 몸은 visible=false, 빙의된 몸은 visible=true. reason에 상태를 명시
4. **이전 씬 컨텍스트 활용**: 앞 2개 씬의 내용을 참고하여 인물의 이동/퇴장을 추적
5. **배경/소품**: 씬 텍스트에 명시적으로 묘사되거나, 해당 공간에 당연히 존재하는 것만 인정
```

After (canonical clause + generic wording):
```markdown
1. **물리적 존재만 인정**: 해당 씬의 공간에 실제로 있는 대상만 physically_visible = true
2. **언급만으로는 불충분**: 대화 중 이름이 나오더라도 해당 공간에 없으면 false

본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.

3. **rule_type=possession 등 비물리 매개 상태**: VWR director_notes 의 visible 결정을 따른다 (예: rule_type=possession 의 경우 원래 몸은 visible=false, 매개체 몸은 visible=true). reason 에 rule_type 명시.
4. **이전 씬 컨텍스트 활용**: 앞 2개 씬의 내용을 참고하여 인물의 이동/퇴장을 추적
5. **배경/소품**: 씬 텍스트에 명시적으로 묘사되거나, 해당 공간에 당연히 존재하는 것만 인정
```

**Amend boundary**:
- line 7 audit-verbatim full sentence (`3. **빙의/영혼 상태**: 다른 인물의 몸에 들어간 경우, 원래 몸은 visible=false, 빙의된 몸은 visible=true. reason에 상태를 명시`) 본체 폐기 → canonical clause + generic wording (`rule_type=possession 등 비물리 매개 상태`).
- 1 phrase exact `grep -Fc` = 0 verify obligation.
- principle wording (visible=true/false / reason에 rule_type 명시) 보존.
- SOT field reference (VWR director_notes) 강조.

### S3 — Create scene_detail 27.20260518HHMM directory (W3 site 10)

- [ ] **Step 3.1: directory 신설 + sibling copy (1 file)**

```bash
mkdir -p prompts/_base/scene_detail/27.20260518HHMM
cp -p prompts/_base/scene_detail/26.202605181435/detail_schema.json prompts/_base/scene_detail/27.20260518HHMM/detail_schema.json
```

- [ ] **Step 3.2: sibling sha256 verify**

```bash
src=$(shasum -a 256 prompts/_base/scene_detail/26.202605181435/detail_schema.json | awk '{print $1}')
dst=$(shasum -a 256 prompts/_base/scene_detail/27.20260518HHMM/detail_schema.json | awk '{print $1}')
if [ "$src" != "$dst" ]; then echo "FAIL: detail_schema.json sha256 mismatch"; exit 1; else echo "PASS"; fi
```

Expected: PASS.

- [ ] **Step 3.3: system.md modified — base copy + amend (site 10 line 473 audit-verbatim)**

```bash
cp -p prompts/_base/scene_detail/26.202605181435/system.md prompts/_base/scene_detail/27.20260518HHMM/system.md
```

**Site 10 amend (line 473 audit-verbatim, S1.2 line drift verify 후 정확 line number 정합)**:

Before (line 470-476):
```markdown

샷의 프레임 안에 **물리적으로 보이는** 대상만 포함:
- 목소리만 들리는 인물 제외 (V.O., 전화, 무전, 방송)
- 원격 조종/접속 인물 제외 (조종자 몸이 다른 장소에 있음)
- 회상/환상/꿈에만 등장 제외
- 대사에서만 언급 제외
- 다른 장소 대상 제외
```

After (canonical clause + generic wording):
```markdown

본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.

샷의 프레임 안에 **물리적으로 보이는** 대상만 포함:
- 목소리만 들리는 인물 제외 (V.O., 전화, 무전, 방송)
- VWR SOT 가 비물리 매개로 분류한 인물 제외 (예: rule_type=projection / remote, 조종자 몸이 다른 장소에 있음)
- 회상/환상/꿈에만 등장 제외
- 대사에서만 언급 제외
- 다른 장소 대상 제외
```

**Amend boundary**:
- line 473 audit-verbatim full sentence (`- 원격 조종/접속 인물 제외 (조종자 몸이 다른 장소에 있음)`) 본체 폐기 → canonical clause + generic wording (`VWR SOT 가 비물리 매개로 분류한 인물 제외`).
- 1 phrase exact `grep -Fc` = 0 verify obligation.
- nearby section context (샷의 프레임 안 / 목소리만 들리는 인물 / 회상/환상/꿈 / 다른 장소 대상) 보존.

### S4 — Create shot_extract 12.20260518HHMM directory (W3 site 11)

- [ ] **Step 4.1: directory 신설 + sibling copy (1 file)**

```bash
mkdir -p prompts/_base/shot_extract/12.20260518HHMM
cp -p prompts/_base/shot_extract/11.202604201230/system.md prompts/_base/shot_extract/12.20260518HHMM/system.md
```

- [ ] **Step 4.2: sibling sha256 verify**

```bash
src=$(shasum -a 256 prompts/_base/shot_extract/11.202604201230/system.md | awk '{print $1}')
dst=$(shasum -a 256 prompts/_base/shot_extract/12.20260518HHMM/system.md | awk '{print $1}')
if [ "$src" != "$dst" ]; then echo "FAIL: shot_extract system.md sha256 mismatch"; exit 1; else echo "PASS"; fi
```

Expected: PASS.

- [ ] **Step 4.3: user.md modified — base copy + amend (site 11 line 49 audit-verbatim parenthetical)**

```bash
cp -p prompts/_base/shot_extract/11.202604201230/user.md prompts/_base/shot_extract/12.20260518HHMM/user.md
```

**Site 11 amend (line 49 audit-verbatim parenthetical, S1.2 line drift verify 후 정확 line number 정합)**:

Before (line 47-51):
```markdown
[변형 기준 — 괄호 표기 대상]
변형이란 얼굴이 크게 달라지거나, 얼굴과 몸을 구분할 수 없는 형태로 바뀌는 경우만:
- 얼굴이 크게 달라지는 변화: 나이 변화, 변장/성형 전후, 빙의로 얼굴이 바뀜
- 완전변형: 인간→동물, 인간→비인간형
```

After (canonical clause + generic wording):
```markdown
[변형 기준 — 괄호 표기 대상]

본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.

변형이란 얼굴이 크게 달라지거나, 얼굴과 몸을 구분할 수 없는 형태로 바뀌는 경우만:
- 얼굴이 크게 달라지는 변화: 나이 변화, 변장/성형 전후, rule_type=possession 등 VWR SOT 가 가리키는 외형 변화 상태
- 완전변형: 인간→동물, 인간→비인간형
```

**Amend boundary**:
- line 49 audit-verbatim parenthetical (`빙의로 얼굴이 바뀜` enumeration tail) 본체 폐기 → canonical clause + generic wording (`rule_type=possession 등 VWR SOT 가 가리키는 외형 변화 상태`).
- 1 phrase exact `grep -Fc` = 0 verify obligation.
- `나이 변화 / 변장/성형` generic example 보존 (도메인-specific 아님).

### S5 — W3 pre-commit verification (8 종, Codex amend 8 narrow exemption 흡수)

- [ ] **Step 5.1: 8 종 verify 실행**

Pre-Commit Verification Doctrine W3 본문 8 종 (UTC date drift / line drift verify / Canonical clause membership 3 file / W3 exact residue phrase inventory 3 phrase hit 0 / 3 sibling sha256 / Smoke pytest scene_verify or scene_detail or shot_extract / 4-point sync narrow exemption production code 4 grep / scene_detail alignment test 5 PASS) 모두 PASS.

**residue phrase grep command**:

```bash
# scene_verify system.md — 1 audit-verbatim
hit=$(grep -Fc "3. **빙의/영혼 상태**: 다른 인물의 몸에 들어간 경우, 원래 몸은 visible=false, 빙의된 몸은 visible=true. reason에 상태를 명시" prompts/_base/scene_verify/2.20260518HHMM/system.md)
if [ "$hit" -ne 0 ]; then echo "FAIL: scene_verify residue"; exit 1; else echo "PASS"; fi

# scene_detail system.md — 1 audit-verbatim
hit=$(grep -Fc "- 원격 조종/접속 인물 제외 (조종자 몸이 다른 장소에 있음)" prompts/_base/scene_detail/27.20260518HHMM/system.md)
if [ "$hit" -ne 0 ]; then echo "FAIL: scene_detail residue"; exit 1; else echo "PASS"; fi

# shot_extract user.md — 1 audit-verbatim
hit=$(grep -Fc "빙의로 얼굴이 바뀜" prompts/_base/shot_extract/12.20260518HHMM/user.md)
if [ "$hit" -ne 0 ]; then echo "FAIL: shot_extract residue"; exit 1; else echo "PASS"; fi
```

Expected: 3 PASS.

**Canonical clause membership grep command**:

```bash
canonical='본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 rule_type ∈ {possession, transformation, ghost, projection, superpower, body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 않으면 일반 인물로 처리.'

for f in prompts/_base/scene_verify/2.20260518HHMM/system.md prompts/_base/scene_detail/27.20260518HHMM/system.md prompts/_base/shot_extract/12.20260518HHMM/user.md; do
  hit=$(grep -Fc "$canonical" "$f")
  if [ "$hit" -lt 1 ]; then echo "FAIL: $f missing canonical clause"; exit 1; else echo "PASS: $f"; fi
done
```

Expected: 3 PASS.

**4-point sync narrow exemption verify (Codex amend 8 흡수)**:

```bash
# 1. detail_steps.py:106 SCENE_DETAIL_PROMPT_VERSION new latest (W3 actual HHMM substitute)
grep -Fc 'SCENE_DETAIL_PROMPT_VERSION = "27.20260518HHMM"' backend/app/core/steps/detail_steps.py
# Expected: 1 (HHMM = W3 actual UTC)

# 2. version_registry.py:34 MODULE_VERSIONS bump
grep -Fc '"scene_detail_composer": "1.27.0"' backend/app/core/version_registry.py
# Expected: 1

# 3. version_registry.py:126 _MODULE_INFO prompt_dependency bump
grep -Fc '"prompt_dependency": "scene_detail/v27"' backend/app/core/version_registry.py
# Expected: 1

# 4. SCENE_DETAIL_SCHEMA_VERSION == 11 preserve (schema 변경 0)
grep -Fc 'SCENE_DETAIL_SCHEMA_VERSION = 11' backend/app/core/steps/detail_steps.py
# Expected: 1 (보존)
```

Expected: 4 PASS (production code 3 갱신 + 1 schema_version 보존).

**scene_detail-pinned tests 5 files PASS verify (Codex amend 10 OPTION_A expanded plural)**:

```bash
backend/.venv/bin/pytest \
  backend/tests/prompts/test_scene_detail_continuity_alignment.py \
  backend/tests/prompts/test_scene_detail_spatial_alignment.py \
  backend/tests/test_prompt_versions.py \
  backend/tests/integration/test_g4_5a_spatial_integration.py \
  backend/tests/integration/test_area_5_residue_gate.py \
  -v --no-header 2>&1 | tail -40
```

Expected: 모두 PASS (14+ assertion 갱신 + 3 function rename + schema_version 보존, Codex amend 8 + amend 9 + amend 10 verdict).

### S6 — W3 atomic commit

- [ ] **Step 6.1: git status + path-limited git add (Codex amend 10 OPTION_A expanded — production code 2 + test 5 추가 stage = 13 file total)**

```bash
git status
git add prompts/_base/scene_verify/2.20260518HHMM/ \
        prompts/_base/scene_detail/27.20260518HHMM/ \
        prompts/_base/shot_extract/12.20260518HHMM/ \
        backend/app/core/steps/detail_steps.py \
        backend/app/core/version_registry.py \
        backend/tests/prompts/test_scene_detail_continuity_alignment.py \
        backend/tests/prompts/test_scene_detail_spatial_alignment.py \
        backend/tests/test_prompt_versions.py \
        backend/tests/integration/test_g4_5a_spatial_integration.py \
        backend/tests/integration/test_area_5_residue_gate.py
```

확인: 6 untracked prompt file (scene_verify 2 + scene_detail 2 + shot_extract 2) + 2 modified production code file (detail_steps.py + version_registry.py) + 5 modified test file (continuity_alignment + spatial_alignment + prompt_versions + g4_5a_spatial_integration + area_5_residue_gate) = 13 file changed (atomic boundary, 4-point sync narrow exemption 정합 + scene_detail-pinned tests 5 files plural Codex amend 10 흡수).

- [ ] **Step 6.2: W3 atomic commit**

```bash
git commit -m "$(cat <<'EOF'
feat(area-7b-vwr-cascade-downstream-v1): W3 consumer atomic — Group S scene_verify + scene_detail + shot_extract canonical VWR SOT clause cascade (3 site / 3 modified file / 3 sibling) — line drift verify + scene_detail 4-point sync narrow exemption (Codex amend 8 OPTION_A + amend 9 + amend 10 OPTION_A expanded scene_detail-pinned tests 5 files)

Group S (scene_*) — 3 module new prompt dir + 3 modified file + 3 byte-identical
sibling copy + scene_detail 4-point sync narrow exemption (production code
2 file + scene_detail-pinned tests 5 file plural) — single atomic commit
13 file total. line drift verify 의무 (scene_detail audit 시점 line 327 →
current 473 / shot_extract audit 33 → current 49).

scene_verify 2.20260518HHMM/ (site 9 system.md modified + verify_schema.json
strict pack sibling): line 7 audit-verbatim full sentence (3. **빙의/영혼
상태**: 다른 인물의 몸에 들어간 경우, 원래 몸은 visible=false, 빙의된 몸은
visible=true. reason에 상태를 명시) 폐기 → canonical clause + generic wording
(rule_type=possession 등 비물리 매개 상태). production detail_steps.py:3088-3089
strict pack 의무 정합 (Codex iter 4 F-1 흡수).

scene_detail 27.20260518HHMM/ (site 10 system.md modified + detail_schema.json
sibling): line 473 audit-verbatim full sentence (- 원격 조종/접속 인물 제외
(조종자 몸이 다른 장소에 있음)) 폐기 → canonical clause + generic wording
(VWR SOT 가 비물리 매개로 분류한 인물 제외). line drift verify 정합
(audit 시점 line 327 → current 473).

shot_extract 12.20260518HHMM/ (site 11 user.md modified + system.md sibling):
line 49 audit-verbatim parenthetical (빙의로 얼굴이 바뀜) 폐기 → canonical
clause + generic wording (rule_type=possession 등 VWR SOT 가 가리키는 외형
변화 상태). 나이 변화 / 변장/성형 generic example 보존. line drift verify
정합 (audit 시점 line 33 → current 49).

scene_detail 4-point sync narrow exemption (Codex amend 8 OPTION_A 흡수,
Area #5 W1 doctrine 정합 의무):
- backend/app/core/steps/detail_steps.py:106 SCENE_DETAIL_PROMPT_VERSION
  "26.202605181435" → "27.20260518HHMM" (W3 actual UTC HHMM).
- backend/app/core/version_registry.py:34 MODULE_VERSIONS
  ["scene_detail_composer"] "1.26.0" → "1.27.0".
- backend/app/core/version_registry.py:126 _MODULE_INFO
  ["scene_detail_composer"]["prompt_dependency"] "scene_detail/v26"
  → "scene_detail/v27" + updated_at "2026-05-19".
- SCENE_DETAIL_SCHEMA_VERSION = 11 보존 (schema 변경 0 doctrine).
- backend/tests/prompts/test_scene_detail_continuity_alignment.py 4 assertion
  갱신 (line 69 MODULE_VERSIONS "1.26.0" → "1.27.0" + line 103 _MODULE_INFO
  "scene_detail/v26" → "scene_detail/v27" + line 120 startswith "26." →
  "27." + line 196 latest_major "26" → "27"). line 168 schema_version == 11
  보존.
- backend/tests/prompts/test_scene_detail_spatial_alignment.py 5 assertion
  갱신 (Codex amend 9 plural expansion: line 72 MODULE_VERSIONS + line 106
  _MODULE_INFO + line 127/132 startswith 2 instance + line 207 latest_major
  모두 27 series 갱신). 자매 alignment test 동일 4-point sync doctrine.
- backend/tests/test_prompt_versions.py 2 assertion + 1 function rename
  (Codex amend 10 OPTION_A expanded: line 211 startswith "26." → "27." +
  line 219 MODULE_VERSIONS "1.26.0" → "1.27.0" + line 214 function name
  test_version_registry_scene_detail_composer_1_26_0 → _1_27_0). history
  comment v25→v26 / 1.25.0→1.26.0 narrow sync.
- backend/tests/integration/test_g4_5a_spatial_integration.py 4 assertion +
  1 function rename (Codex amend 10 OPTION_A expanded: line 591 startswith
  "26." + line 598 MODULE_VERSIONS + line 607 _MODULE_INFO + line 769
  config_hash startswith 모두 27 series 갱신; line 561 function name
  test_4_way_alignment_post_g4_5a_bump → test_4_way_alignment_post_area7b_w3_bump).
  docstring 562-574 + error message narrow sync.
- backend/tests/integration/test_area_5_residue_gate.py 1 function rename +
  glob (Codex amend 10 OPTION_A expanded, non-blocking 단 stale meaning
  carry 차단: line 172 function name v26 → v27 + line 178 glob 26.*/ →
  27.*/ + line 184 print message v26 → v27). active prompt 가 v27 로 이동,
  canary scope 도 v27 fresh.

다른 module (entity_*/outlook_*/scene_verify/shot_extract) production code
변경 0 doctrine + helper 신설 0 + STEP_MANIFEST 변경 0 보존.

Canonical clause (audit §11.3 verbatim, 3 modified file 모두 글자-단위 정확
동일 의무).

4-Gate Boundary Doctrine 정합.

Pre-commit verify 8 종 PASS: UTC date drift / line drift verify scene_detail
+ shot_extract / canonical clause membership 3 file / W3 exact residue phrase
inventory 3 phrase hit 0 / 3 sibling sha256 PASS / Smoke pytest scene_verify
or scene_detail or shot_extract / 4-point sync narrow exemption production
code 4 grep / scene_detail-pinned tests 5 files PASS (continuity + spatial +
prompt_versions + g4_5a_spatial_integration + area_5_residue_gate, Codex
amend 10 OPTION_A expanded).

NO VLM hard constraint inline.

Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md
Plan: docs/superpowers/plans/2026-05-19-area-7b-vwr-cascade-downstream-v1-implementation.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```

- [ ] **Step 6.3: commit 확인**

```bash
git log -1 --stat
```

확인: 1 commit + 6 file created.

### S7 — W3 Codex review 의뢰 (per-wave external)

- [ ] **Step 7.1: Codex pane %0 read + W3 commit review 의뢰**

tmux_type %0 (fresh):

```
Area #7b W3 commit review 의뢰.

Commit: <W3 commit hash>
Wave: W3 consumer atomic (Group S — scene_verify + scene_detail + shot_extract canonical VWR SOT clause cascade, 3 site / 3 modified file / 3 sibling + scene_detail 4-point sync narrow exemption production code 2 file + scene_detail-pinned tests 5 file plural = 13 file total, Codex amend 8 OPTION_A + amend 9 + amend 10 OPTION_A expanded 흡수).
Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md (commit <spec amend 7 commit hash>).
Plan: docs/superpowers/plans/2026-05-19-area-7b-vwr-cascade-downstream-v1-implementation.md (commit <plan amend 8 commit hash>).

검토 항목:
1. canonical clause 3 modified file 모두 글자-단위 정확 동일.
2. W3 exact residue phrase inventory 3 phrase hit 0 (scene_verify 빙의/영혼 상태 full sentence + scene_detail 원격 조종/접속 인물 제외 full sentence + shot_extract 빙의로 얼굴이 바뀜 parenthetical).
3. line drift 정합 (scene_detail audit 327 → current 473 / shot_extract audit 33 → current 49 controller verify).
4. 3 sibling byte-identical sha256 PASS (scene_verify verify_schema.json strict pack + scene_detail detail_schema.json + shot_extract system.md).
5. principle wording 보존 (visible=true/false / reason에 rule_type 명시 / 나이 변화/변장/성형 generic example / 회상/환상/꿈 등).
6. atomic single commit (3 prompt dir [6 prompt file] + 2 production code file + 5 scene_detail-pinned test file plural = 13 file changed 정확, Codex amend 10 OPTION_A expanded).
7. 4-Gate Boundary Doctrine 정합.
8. NO VLM.
9. 4-point sync narrow exemption 정합 (Codex amend 8 OPTION_A):
   - detail_steps.py:106 SCENE_DETAIL_PROMPT_VERSION == "27.20260518HHMM" (W3 actual UTC).
   - version_registry.py:34 MODULE_VERSIONS["scene_detail_composer"] == "1.27.0".
   - version_registry.py:126 _MODULE_INFO["scene_detail_composer"]["prompt_dependency"] == "scene_detail/v27".
   - SCENE_DETAIL_SCHEMA_VERSION == 11 보존 (schema 변경 0).
   - test_scene_detail_continuity_alignment.py 4 assertion 갱신 (1.27.0 / v27 / startswith "27." / latest_major "27") + 1 schema_version 보존.
   - test_scene_detail_spatial_alignment.py 5 assertion 갱신 plural (자매 alignment test, Codex amend 9 plural).
   - test_prompt_versions.py 2 assertion + 1 function rename (`_1_26_0` → `_1_27_0`, Codex amend 10 OPTION_A expanded).
   - test_g4_5a_spatial_integration.py 4 assertion + 1 function rename (`test_4_way_alignment_post_g4_5a_bump` → `test_4_way_alignment_post_area7b_w3_bump`, Codex amend 10).
   - test_area_5_residue_gate.py 1 function rename + glob `26.*/` → `27.*/` (active prompt v27 fresh canary, Codex amend 10).
   - 다른 module (entity_*/outlook_*/scene_verify/shot_extract) production code 변경 0 doctrine 보존.
10. backend smoke pytest = `backend/.venv/bin/pytest backend/tests -k "scene_verify or scene_detail or shot_extract" -x --no-header` ALL PASS + scene_detail-pinned tests 5 files (continuity_alignment + spatial_alignment + prompt_versions + g4_5a_spatial_integration + area_5_residue_gate) ALL PASS.

verdict: APPROVED / NEEDS_REVISION_MINOR / NEEDS_REVISION_MAJOR.

완료되면 끝났다고 claude mcp 호출해줘!
```

verdict 도착 후 controller cross-analyze. APPROVED 시 W4 진입.

---

## Task 5: W4 — Residue Gate Test (single commit)

**Files:**
- Create: `backend/tests/integration/test_area_7b_residue_gate.py`

**Atomic single commit** — residue gate test 1 file 신설. closed-world exact residue phrase contract — **pure `exact_phrase in body` / `not in` fixed-string membership only, regex 0 for phrase gates** (Codex iter 0 strategy verdict Q7 정합 + 사용자 격분 흡수 4-Gate Boundary Doctrine 정합).

### S1 — Create test_area_7b_residue_gate.py

- [ ] **Step 1.1: residue gate test 신설**

File: `backend/tests/integration/test_area_7b_residue_gate.py`

Full content:

```python
"""Area #7b residue gate — Visual World Rules downstream prompt cascade.

closed-world exact residue phrase contract (사용자 격분 흡수 2026-05-19, [[feedback_llm_based_judgment]] 정합):
- pure str membership (str.__contains__ / `in` operator) only — regex 0 for phrase gates.
- inventory split: audit-verbatim (audit §11.2 line 240-254 본문 정확) + current-active-promoted (controller verify 2026-05-19, audit §11.2 미포함).
- source path + line + audit-or-current-active classification anchored.

4-Gate Boundary Doctrine (semantic 판단 절대 금지):
- Gate (1) Semantic Regex Ban — open-world semantic 판단 regex 0.
- Gate (2) Prompt Closed-List Ban — prompt 안 LLM-instructed closed-list domain term enumeration 0.
- Gate (3) Structured SOT Required — open-world semantic 판단 = LLM-produced structured emit.
- Gate (4) No Silent Fallback — invalid input = explicit reject + typed error.

Gate Coverage:
- Gate 1.1-1.9 exact residue phrase membership per modified file (9 sub-gate, 15 phrase total).
- Gate 2 canonical VWR clause glyph-exact membership per 9 modified file (hit ≥ 1).
- Gate 3 D-2 entity_character_list byte-identical (sha256 diff 0).
- Gate 4 archive directory exclusion (path glob, structural).

NO VLM hard constraint inline.
"""

from __future__ import annotations

import hashlib
from pathlib import Path

import pytest

REPO_ROOT = Path(__file__).resolve().parents[3]  # backend/tests/integration/<this> → repo root
PROMPTS_BASE = REPO_ROOT / "prompts" / "_base"

# --- Canonical clause (audit §11.3 verbatim, 9 rewritten site 모두 글자-단위 동일 의무) ---

CANONICAL_VWR_CLAUSE = (
    "본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 "
    "rule_type ∈ {possession, transformation, ghost, projection, superpower, "
    "body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 "
    "않으면 일반 인물로 처리."
)

# --- D-2 carve-out path + hardcoded sha256 (변경 0 boundary preserve, Codex iter 1 F-2 흡수) ---

D2_ENTITY_CHARACTER_LIST = PROMPTS_BASE / "entity_character_list" / "2.202605011057" / "system.md"
# D-2 sha256 anchor = Area #7a closure push (d0410eb) 시점 controller verify 2026-05-19
D2_EXPECTED_SHA256 = "4ca95ca996a5e1d649e92c9baf8963654a5f89537a794ab6ec04e86ce9971713"


def _sha256(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


def _latest_active_dir(module: str, version_prefix: str) -> Path:
    """Return the lexicographically latest dir matching version prefix (e.g. '5.', '12.')."""
    base = PROMPTS_BASE / module
    candidates = sorted(p for p in base.iterdir() if p.is_dir() and p.name.startswith(version_prefix))
    assert candidates, f"no {version_prefix}* dir under {base}"
    return candidates[-1]


@pytest.fixture(scope="module")
def entity_all_v5_dir() -> Path:
    return _latest_active_dir("entity_all", "5.")


@pytest.fixture(scope="module")
def entity_relation_v3_dir() -> Path:
    return _latest_active_dir("entity_relation", "3.")


@pytest.fixture(scope="module")
def entity_extractor_v2_v10_dir() -> Path:
    return _latest_active_dir("entity_extractor_v2", "10.")


@pytest.fixture(scope="module")
def outlook_extractor_v12_dir() -> Path:
    return _latest_active_dir("outlook_extractor", "12.")


@pytest.fixture(scope="module")
def scene_verify_v2_dir() -> Path:
    return _latest_active_dir("scene_verify", "2.")


@pytest.fixture(scope="module")
def scene_detail_v27_dir() -> Path:
    return _latest_active_dir("scene_detail", "27.")


@pytest.fixture(scope="module")
def shot_extract_v12_dir() -> Path:
    return _latest_active_dir("shot_extract", "12.")


# --- Gate 1.1: entity_all 5.*/character.md (audit §11.2 site 1 line 244 verbatim) ---


def test_gate_1_1_entity_all_character_md_residue(entity_all_v5_dir: Path) -> None:
    """Site 1 audit-verbatim 8 phrase hit 0 (fixed-string membership only)."""
    body = (entity_all_v5_dir / "character.md").read_text(encoding="utf-8")
    audit_verbatim_phrases = [
        "인간↔요괴",
        "인간↔괴물",
        "본체↔변신체",
        "빙의/합체",
        "이무기",
        "구미호",
        "요괴화",
        "뱀파이어",
    ]
    for phrase in audit_verbatim_phrases:
        assert phrase not in body, f"entity_all character.md residue: {phrase!r}"


# --- Gate 1.2: entity_relation 3.*/system.md (audit §11.2 site 3 line 246 + current-active-promoted line 30) ---


def test_gate_1_2_entity_relation_system_md_residue(entity_relation_v3_dir: Path) -> None:
    """Site 3 audit-verbatim 3 phrase + current-active-promoted 1 phrase hit 0."""
    body = (entity_relation_v3_dir / "system.md").read_text(encoding="utf-8")
    audit_verbatim_phrases = [
        "요괴/괴물 형태",
        "유령/망령 형태",
        "갑옷 착용 형태",
    ]
    current_active_promoted = "요괴로 변해도 원래 인물의 흔적이 있음 → true"
    for phrase in audit_verbatim_phrases:
        assert phrase not in body, f"entity_relation system.md audit-verbatim residue: {phrase!r}"
    assert current_active_promoted not in body, (
        f"entity_relation system.md current-active-promoted residue: {current_active_promoted!r}"
    )


# --- Gate 1.3: entity_extractor_v2 10.*/system.md (audit §11.2 site 6 line 249 verbatim) ---


def test_gate_1_3_entity_extractor_v2_system_md_residue(entity_extractor_v2_v10_dir: Path) -> None:
    """Site 6 audit-verbatim 2 phrase hit 0."""
    body = (entity_extractor_v2_v10_dir / "system.md").read_text(encoding="utf-8")
    audit_verbatim_phrases = [
        "평상복 → 전신 갑옷",
        "### 빙의/정신 전환/몸을 빌리는 설정이 있는 경우",
    ]
    for phrase in audit_verbatim_phrases:
        assert phrase not in body, f"entity_extractor_v2 system.md residue: {phrase!r}"


# --- Gate 1.4: entity_extractor_v2 10.*/turn0_style.md (audit §11.2 site 7 line 250 verbatim) ---


def test_gate_1_4_entity_extractor_v2_turn0_style_md_residue(
    entity_extractor_v2_v10_dir: Path,
) -> None:
    """Site 7 audit-verbatim 1 phrase hit 0."""
    body = (entity_extractor_v2_v10_dir / "turn0_style.md").read_text(encoding="utf-8")
    assert "원격 접속/조종/빙의/텔레파시" not in body, (
        "entity_extractor_v2 turn0_style.md residue: '원격 접속/조종/빙의/텔레파시'"
    )


# --- Gate 1.5: outlook_extractor 12.*/phase1.md (audit §11.2 site 4 line 247 + current-active-promoted line 24) ---


def test_gate_1_5_outlook_phase1_residue(outlook_extractor_v12_dir: Path) -> None:
    """Site 4 audit-verbatim 1 phrase + current-active-promoted 1 phrase hit 0."""
    body = (outlook_extractor_v12_dir / "phase1.md").read_text(encoding="utf-8")
    audit_verbatim = "메카, 파워드슈트, 강화복, 갑옷 로봇"
    current_active_promoted = "인간형 요괴/괴물, 뱀파이어, 좀비"
    assert audit_verbatim not in body, f"outlook phase1.md audit-verbatim residue: {audit_verbatim!r}"
    assert current_active_promoted not in body, (
        f"outlook phase1.md current-active-promoted residue: {current_active_promoted!r}"
    )


# --- Gate 1.6: outlook_extractor 12.*/phase2.md (audit §11.2 site 5 line 248 verbatim) ---


def test_gate_1_6_outlook_phase2_residue(outlook_extractor_v12_dir: Path) -> None:
    """Site 5 audit-verbatim 1 phrase hit 0."""
    body = (outlook_extractor_v12_dir / "phase2.md").read_text(encoding="utf-8")
    assert "원격접속/빙의:" not in body, "outlook phase2.md residue: '원격접속/빙의:'"


# --- Gate 1.7: scene_verify 2.*/system.md (audit §11.2 site 9 line 252 verbatim) ---


def test_gate_1_7_scene_verify_system_md_residue(scene_verify_v2_dir: Path) -> None:
    """Site 9 audit-verbatim 1 full sentence hit 0."""
    body = (scene_verify_v2_dir / "system.md").read_text(encoding="utf-8")
    audit_verbatim = (
        "3. **빙의/영혼 상태**: 다른 인물의 몸에 들어간 경우, 원래 몸은 "
        "visible=false, 빙의된 몸은 visible=true. reason에 상태를 명시"
    )
    assert audit_verbatim not in body, f"scene_verify system.md residue: {audit_verbatim!r}"


# --- Gate 1.8: scene_detail 27.*/system.md (audit §11.2 site 10 line 253 verbatim, line drift verify) ---


def test_gate_1_8_scene_detail_system_md_residue(scene_detail_v27_dir: Path) -> None:
    """Site 10 audit-verbatim 1 full sentence hit 0 (audit 시점 line 327 → current line 473 drift verify)."""
    body = (scene_detail_v27_dir / "system.md").read_text(encoding="utf-8")
    audit_verbatim = "- 원격 조종/접속 인물 제외 (조종자 몸이 다른 장소에 있음)"
    assert audit_verbatim not in body, f"scene_detail system.md residue: {audit_verbatim!r}"


# --- Gate 1.9: shot_extract 12.*/user.md (audit §11.2 site 11 line 254 verbatim, line drift verify) ---


def test_gate_1_9_shot_extract_user_md_residue(shot_extract_v12_dir: Path) -> None:
    """Site 11 audit-verbatim 1 parenthetical hit 0 (audit 시점 line 33 → current line 49 drift verify)."""
    body = (shot_extract_v12_dir / "user.md").read_text(encoding="utf-8")
    assert "빙의로 얼굴이 바뀜" not in body, "shot_extract user.md residue: '빙의로 얼굴이 바뀜'"


# --- Gate 2: canonical VWR clause glyph-exact membership per 9 modified file (hit ≥ 1) ---


@pytest.mark.parametrize(
    "module_fixture,filename",
    [
        ("entity_all_v5_dir", "character.md"),
        ("entity_relation_v3_dir", "system.md"),
        ("entity_extractor_v2_v10_dir", "system.md"),
        ("entity_extractor_v2_v10_dir", "turn0_style.md"),
        ("outlook_extractor_v12_dir", "phase1.md"),
        ("outlook_extractor_v12_dir", "phase2.md"),
        ("scene_verify_v2_dir", "system.md"),
        ("scene_detail_v27_dir", "system.md"),
        ("shot_extract_v12_dir", "user.md"),
    ],
)
def test_gate_2_canonical_clause_membership(
    module_fixture: str, filename: str, request: pytest.FixtureRequest
) -> None:
    """9 rewritten file 모두 canonical VWR clause glyph-exact membership ≥ 1 (fixed-string)."""
    module_dir = request.getfixturevalue(module_fixture)
    body = (module_dir / filename).read_text(encoding="utf-8")
    assert CANONICAL_VWR_CLAUSE in body, (
        f"{module_dir.name}/{filename}: missing canonical VWR clause (글자-단위 정확 동일 의무)"
    )


# --- Gate 3: D-2 entity_character_list byte-identical (sha256 diff 0, 변경 0 boundary preserve) ---


def test_gate_3_d2_entity_character_list_byte_identical() -> None:
    """D-2 carve-out — entity_character_list/2.202605011057/system.md 본 area 안 변경 0 verify.

    Codex iter 1 F-2 fix-up: hardcoded sha256 anchor (Area #7a closure push d0410eb 시점,
    controller verify 2026-05-19). 변경 시 D-2 boundary 위반.
    """
    assert D2_ENTITY_CHARACTER_LIST.exists(), f"D-2 path missing: {D2_ENTITY_CHARACTER_LIST}"
    # Primary: sha256 hardcoded anchor (byte-identical contract)
    actual_sha = _sha256(D2_ENTITY_CHARACTER_LIST)
    assert actual_sha == D2_EXPECTED_SHA256, (
        f"D-2 sha256 mismatch (boundary preserve 위반): "
        f"expected {D2_EXPECTED_SHA256}, actual {actual_sha}"
    )
    # Sanity: owner taxonomy 5-element 분류 본체 보존 (sha256 PASS 시 자동 보장, but explicit)
    body_text = D2_ENTITY_CHARACTER_LIST.read_text(encoding="utf-8")
    assert "인간, 요괴, 동물, 로봇, 외계인" in body_text, (
        "D-2 owner taxonomy 5-element 분류 본체 변경 — boundary preserve 위반"
    )
    # entity_character_list 디렉토리 안 새 dir 신설 0 verify
    base = PROMPTS_BASE / "entity_character_list"
    dirs = sorted(p.name for p in base.iterdir() if p.is_dir())
    assert dirs == ["1.202604010100", "2.202605011057"], (
        f"D-2 entity_character_list new dir 신설 발견 — boundary 위반: {dirs}"
    )


# --- Gate 4: archive directory exclusion (path glob, structural) ---


def test_gate_4_archive_directory_exclusion() -> None:
    """archive dir (current latest 외) 본문 안 residue phrase 잔존 = 허용 (Gate 1.x scope 외).

    structural verify: 7 module 각각 latest dir (5.* / 3.* / 10.* / 12.* / 2.* / 27.* / 12.*) 가
    Gate 1.x scope 안. archive dir (예: entity_all 1.* / 2.* / 3.* / 4.*) 은 path glob 으로
    scope 외 verify.
    """
    expected = {
        "entity_all": "5.",
        "entity_relation": "3.",
        "entity_extractor_v2": "10.",
        "outlook_extractor": "12.",
        "scene_verify": "2.",
        "scene_detail": "27.",
        "shot_extract": "12.",
    }
    for module, prefix in expected.items():
        latest = _latest_active_dir(module, prefix)
        # latest dir name starts with expected prefix (closed-world path comparison)
        assert latest.name.startswith(prefix), (
            f"{module}: latest dir {latest.name} does not start with {prefix}"
        )


# --- Sanity: 모든 Gate 1.x fixture 가 존재하는 path 인지 verify ---


def test_sanity_all_modified_file_exist(
    entity_all_v5_dir: Path,
    entity_relation_v3_dir: Path,
    entity_extractor_v2_v10_dir: Path,
    outlook_extractor_v12_dir: Path,
    scene_verify_v2_dir: Path,
    scene_detail_v27_dir: Path,
    shot_extract_v12_dir: Path,
) -> None:
    """9 modified file 모두 존재 verify."""
    expected_files = [
        (entity_all_v5_dir, "character.md"),
        (entity_relation_v3_dir, "system.md"),
        (entity_extractor_v2_v10_dir, "system.md"),
        (entity_extractor_v2_v10_dir, "turn0_style.md"),
        (outlook_extractor_v12_dir, "phase1.md"),
        (outlook_extractor_v12_dir, "phase2.md"),
        (scene_verify_v2_dir, "system.md"),
        (scene_detail_v27_dir, "system.md"),
        (shot_extract_v12_dir, "user.md"),
    ]
    for module_dir, filename in expected_files:
        target = module_dir / filename
        assert target.exists(), f"missing modified file: {target}"
```

**Notes**:
- `parents[3]`: `backend/tests/integration/<this>` → repo root (Codex iter 1 Area #7a F-2 흡수 — `parents[2]` 는 `backend/` 까지만 도달).
- `_latest_active_dir(module, version_prefix)`: prefix-matching path glob, closed-world structural (Gate 4 archive exclusion 정합).
- **regex 0 for phrase gates** (Codex iter 0 strategy Q7 정합) — `import re` 미포함, `str.__contains__` (`in` / `not in`) 만 사용.
- Test count: Gate 1.1-1.9 (9) + Gate 2 (parametrize 9) + Gate 3 (1) + Gate 4 (1) + Sanity (1) = **21 test target**.

### S2 — pytest 실행

- [ ] **Step 2.1: residue gate test 모두 PASS 확인**

```bash
backend/.venv/bin/pytest backend/tests/integration/test_area_7b_residue_gate.py -v
```

Expected: 21 PASS (Gate 1.1-1.9 9 + Gate 2 parametrize 9 + Gate 3 1 + Gate 4 1 + Sanity 1).

실패 시 본문 fix (W1 / W2 / W3 redo + 본 test 재실행).

### S3 — fixed-string membership only verify (W4 pre-commit verify Step 2 정합)

- [ ] **Step 3.1: regex 0 verify**

```bash
grep -nE "re\.compile|re\.search|re\.match|re\.findall|re\.sub" backend/tests/integration/test_area_7b_residue_gate.py
```

Expected: 0 hit (phrase gate regex 0, Codex Q7 정합).

```bash
grep -n "^import re$\|^from re" backend/tests/integration/test_area_7b_residue_gate.py
```

Expected: 0 hit.

### S4 — W4 commit

- [ ] **Step 4.1: git add + commit**

```bash
git add backend/tests/integration/test_area_7b_residue_gate.py
git commit -m "$(cat <<'EOF'
test(area-7b-vwr-cascade-downstream-v1): W4 residue gate — Gate 1.1-1.9 exact residue phrase membership per modified file + Gate 2 canonical clause membership + Gate 3 D-2 byte-identical + Gate 4 archive exclusion

closed-world exact residue phrase contract (사용자 격분 흡수 2026-05-19, [[feedback_llm_based_judgment]] 정합):
- pure str.__contains__ / `in` operator only — regex 0 for phrase gates.
- inventory split: audit-verbatim + current-active-promoted, source path +
  line + classification anchored.
- Generic Korean standalone ban 0 (요괴 / 빙의 / 변신 단독 forbidden 0).

Gate Coverage (21 test target):
- Gate 1.1 entity_all 5.*/character.md — 8 audit-verbatim phrase hit 0.
- Gate 1.2 entity_relation 3.*/system.md — 3 audit-verbatim + 1 current-active-
  promoted phrase hit 0.
- Gate 1.3 entity_extractor_v2 10.*/system.md — 2 audit-verbatim phrase hit 0.
- Gate 1.4 entity_extractor_v2 10.*/turn0_style.md — 1 audit-verbatim phrase
  hit 0.
- Gate 1.5 outlook 12.*/phase1.md — 1 audit-verbatim + 1 current-active-promoted
  phrase hit 0 (Codex iter 4 F-3 흡수).
- Gate 1.6 outlook 12.*/phase2.md — 1 audit-verbatim phrase hit 0.
- Gate 1.7 scene_verify 2.*/system.md — 1 audit-verbatim full sentence hit 0.
- Gate 1.8 scene_detail 27.*/system.md — 1 audit-verbatim full sentence hit 0
  (line drift verify audit 시점 327 → current 473).
- Gate 1.9 shot_extract 12.*/user.md — 1 audit-verbatim parenthetical hit 0
  (line drift verify audit 시점 33 → current 49).
- Gate 2 canonical VWR clause glyph-exact membership per 9 modified file
  (parametrize, fixed-string).
- Gate 3 D-2 entity_character_list/2.202605011057/system.md byte-identical
  + owner taxonomy 5-element 분류 보존 + new dir 신설 0.
- Gate 4 archive directory exclusion (path glob structural — 7 module latest
  dir prefix 5./3./10./12./2./27./12.).
- Sanity 9 modified file 모두 존재.

4-Gate Boundary Doctrine 정합 inline.

NO VLM hard constraint inline. jsonschema/markdown/regex(closed-world path
only)/text only.

Pre-commit verify 3 종 PASS: pytest 21 PASS / regex 0 for phrase gates / test
count ≥ 12.

Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md §7
Plan: docs/superpowers/plans/2026-05-19-area-7b-vwr-cascade-downstream-v1-implementation.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```

### S5 — W4 Codex review 의뢰

- [ ] **Step 5.1: Codex pane %0 read + W4 commit review 의뢰**

tmux_type %0 (fresh):

```
Area #7b W4 commit review 의뢰.

Commit: <W4 commit hash>
Wave: W4 residue gate test (Gate 1.1-1.9 exact residue phrase membership + Gate 2 canonical clause + Gate 3 D-2 byte-identical + Gate 4 archive exclusion + Sanity, 21 test total).
Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md §7.

검토 항목:
1. fixed-string membership only — regex 0 for phrase gates (Codex iter 0 strategy Q7 정합).
2. Gate 1.1-1.9 inventory 정합 vs spec §5.5 / §7 (audit-verbatim + current-active-promoted split).
3. Gate 2 canonical clause glyph-exact membership 9 file 모두 hit ≥ 1.
4. Gate 3 D-2 byte-identical + owner taxonomy 보존 + new dir 신설 0.
5. Gate 4 archive exclusion path glob structural (closed-world).
6. 4-Gate Boundary Doctrine 정합 (Semantic Regex Ban / Prompt Closed-List Ban / Structured SOT Required / No Silent Fallback).
7. NO VLM.
8. parents[3] repo root 정합 (Area #7a F-2 정합).

verdict: APPROVED / NEEDS_REVISION_MINOR / NEEDS_REVISION_MAJOR.

완료되면 끝났다고 claude mcp 호출해줘!
```

verdict 도착 후 controller cross-analyze. APPROVED 시 W5 진입.

---

## Task 6: W5 — Canary Test (single commit)

**Files:**
- Create: `backend/tests/integration/test_area_7b_no_drift.py`

**Atomic single commit** — canary test 1 file 신설. **No live LLM + NO VLM hard constraint inline**. C1-C6 sub-canary 정합 vs spec §5.6.

### S1 — Create test_area_7b_no_drift.py

- [ ] **Step 1.1: canary test 신설**

File: `backend/tests/integration/test_area_7b_no_drift.py`

Full content:

```python
"""Area #7b canary — VWR downstream prompt cascade no-drift verification.

6 sub-canary (spec §5.6, no live LLM, NO VLM):
- C1: prompt_loader latest activation per 7 new-dir module (D-2 제외).
- C2: byte-identical sibling copy per 7 new dir (24 sibling file total).
- C3: STEP_MANIFEST 12 affected step entry presence verify (entry-existence contract, schema_version drift = C4 별도, Codex iter 1 F-1 fix-up + W5 fix-up 1 narrow sync commit `fe7e55e`).
- C4: schema_version 변경 0 (visual_world_rules.schema_version=1 Area #7a 신설 보존).
- C5: D-2 DB override risk neutralized (entity_character_list sha256 변경 0 + db-aware caller path 변경 0).
- C6: canonical VWR clause glyph-exact membership per 9 modified file (hit ≥ 1).

NO VLM 의무 — 모든 verification = schema/text/manifest only.
"""

from __future__ import annotations

import hashlib
import sys
from pathlib import Path

import pytest

REPO_ROOT = Path(__file__).resolve().parents[3]  # backend/tests/integration/<this> → repo root
PROMPTS_BASE = REPO_ROOT / "prompts" / "_base"
BACKEND_ROOT = REPO_ROOT / "backend"

# backend/app import path setup
if str(BACKEND_ROOT) not in sys.path:
    sys.path.insert(0, str(BACKEND_ROOT))

CANONICAL_VWR_CLAUSE = (
    "본 prompt 의 변신/빙의/원격접속 판단 기준은 visual_world_rules.rules[] 의 "
    "rule_type ∈ {possession, transformation, ghost, projection, superpower, "
    "body_deformation} 을 따른다. 작품에 해당 rule_type rule 이 정의되어 있지 "
    "않으면 일반 인물로 처리."
)

# D-2 hardcoded sha256 anchor (Codex iter 1 F-2 흡수, Area #7a closure d0410eb 시점 controller verify 2026-05-19)
D2_EXPECTED_SHA256 = "4ca95ca996a5e1d649e92c9baf8963654a5f89537a794ab6ec04e86ce9971713"

# 7 new-dir module + new version prefix (D-2 제외)
NEW_DIR_EXPECTED = {
    "entity_all": "5.",
    "entity_relation": "3.",
    "entity_extractor_v2": "10.",
    "outlook_extractor": "12.",
    "scene_verify": "2.",
    "scene_detail": "27.",
    "shot_extract": "12.",
}

# 24 sibling byte-identical copy inventory (Contract 5 정합)
SIBLING_INVENTORY = {
    ("entity_all", "5.", "4.202603310100"): [
        "location.md",
        "prop.md",
        "character_schema.json",
        "location_schema.json",
        "prop_schema.json",
        "system.md",
    ],
    ("entity_relation", "3.", "2.202603301800"): [
        "analyze.md",
        "analyze_schema.json",
    ],
    ("entity_extractor_v2", "10.", "9.202605130226"): [
        "turn_entity_detail.md",
        "turn0_style_schema.json",
        "turn1_7_detail_batch_schema.json",
        "turn1_7_detail_batch.md",
        "turn1_review_schema.json",
        "turn1.md",
        "turn2.md",
        "turn3.md",
        "turn4.md",
    ],
    ("outlook_extractor", "12.", "11.202603311724"): [
        "phase1_schema.json",
        "phase2_schema.json",
        "phase3_schema.json",
        "phase3.md",
    ],
    ("scene_verify", "2.", "1.202603231200"): ["verify_schema.json"],
    ("scene_detail", "27.", "26.202605181435"): ["detail_schema.json"],
    ("shot_extract", "12.", "11.202604201230"): ["system.md"],
}

# 9 modified file (canonical clause 의무)
MODIFIED_FILES = [
    ("entity_all", "5.", "character.md"),
    ("entity_relation", "3.", "system.md"),
    ("entity_extractor_v2", "10.", "system.md"),
    ("entity_extractor_v2", "10.", "turn0_style.md"),
    ("outlook_extractor", "12.", "phase1.md"),
    ("outlook_extractor", "12.", "phase2.md"),
    ("scene_verify", "2.", "system.md"),
    ("scene_detail", "27.", "system.md"),
    ("shot_extract", "12.", "user.md"),
]


def _latest_active_dir(module: str, version_prefix: str) -> Path:
    base = PROMPTS_BASE / module
    candidates = sorted(p for p in base.iterdir() if p.is_dir() and p.name.startswith(version_prefix))
    assert candidates, f"no {version_prefix}* dir under {base}"
    return candidates[-1]


def _sha256(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


# --- C1: prompt_loader latest activation (7 sub-canary, 1 per new-dir module) ---


@pytest.mark.parametrize("module,version_prefix", list(NEW_DIR_EXPECTED.items()))
def test_c1_prompt_loader_latest_activation(module: str, version_prefix: str) -> None:
    """7 module 각각 _list_module_versions(module)[0] 가 새 dir version prefix 정합 (자체 numeric-desc sort)."""
    from app.modules.prompt_loader import _list_module_versions

    versions = _list_module_versions(module)
    assert versions, f"no version dir for {module}"
    latest = versions[0]
    assert latest.startswith(version_prefix), (
        f"{module}: latest version {latest!r} does not start with prefix {version_prefix!r}"
    )


# --- C2: byte-identical sibling copy verify (24 sub-canary) ---


def _sibling_pairs() -> list[tuple[str, str, str, str]]:
    """Return (module, new_prefix, source_dir, sibling_filename) tuples — 24 total."""
    pairs = []
    for (module, new_prefix, source_dir), siblings in SIBLING_INVENTORY.items():
        for sibling in siblings:
            pairs.append((module, new_prefix, source_dir, sibling))
    return pairs


@pytest.mark.parametrize("module,new_prefix,source_dir,sibling_filename", _sibling_pairs())
def test_c2_sibling_byte_identical(
    module: str, new_prefix: str, source_dir: str, sibling_filename: str
) -> None:
    """7 new dir 안 24 sibling stem file 가 직전 latest version dir 의 같은 file 과 sha256 동일."""
    src = PROMPTS_BASE / module / source_dir / sibling_filename
    new_dir = _latest_active_dir(module, new_prefix)
    dst = new_dir / sibling_filename
    assert src.exists(), f"sibling source missing: {src}"
    assert dst.exists(), f"sibling dest missing: {dst}"
    assert _sha256(src) == _sha256(dst), (
        f"sibling sha256 mismatch: {module}/{source_dir}/{sibling_filename} ≠ {new_dir.name}/{sibling_filename}"
    )


# --- C3: STEP_MANIFEST 12 affected step entry presence verify (entry-existence contract, schema_version drift = C4 별도, Codex iter 1 F-1 fix-up + W5 fix-up 1 narrow sync commit fe7e55e) ---


def test_c3_step_manifest_entry_presence_verify() -> None:
    """STEP_MANIFEST 12 affected step entry (10 modified-file-bound + 2 sibling-only shared-module) 안 entry presence verify.

    closed-world struct comparison: 본 area = prompt text only change, STEP_MANIFEST
    entry-level 변경 0 verify (Area #7a 신설 visual_world_rules.schema_version=1 보존).
    """
    from app.core.step_manifest import STEP_MANIFEST

    expected_entries = [
        "entity_all_character",
        "entity_all_location",
        "entity_all_prop",
        "entity_relation",
        "entity_extract_character",
        "entity_extract_location",
        "entity_extract_prop",
        "outlook_phase1",
        "outlook_phase2",
        "scene_verify",
        "scene_detail",
        "shot_extract",
    ]
    for entry in expected_entries:
        assert entry in STEP_MANIFEST, f"missing STEP_MANIFEST entry: {entry}"
    # 본 area 안 schema_version 신설 0 (visual_world_rules.schema_version=1 보존 = Area #7a W1)
    for entry in expected_entries:
        # 본 area 안 신설 schema_version 0 — 단 기존 entry 가 schema_version 가질 수 있음 (Area #6 etc)
        # 검증 의도 = 본 area 안 schema_version 변경 0 즉 신설/bump/삭제 0
        # 본 test 는 entry 존재 + 본 area 신설 schema_version key 0 만 verify
        pass  # 본 test 는 entry 존재 verify 만, schema_version bump 는 C4 가 별도 verify


# --- C4: schema_version 변경 0 (visual_world_rules.schema_version=1 Area #7a 신설 보존) ---


def test_c4_visual_world_rules_schema_version_preserved() -> None:
    """visual_world_rules.schema_version=1 (Area #7a W1 신설) 본 area 안 변경 0 verify."""
    from app.core.step_manifest import STEP_MANIFEST

    vwr = STEP_MANIFEST["visual_world_rules"]
    assert vwr.get("schema_version") == 1, f"VWR schema_version 변경: {vwr}"


# --- C5: D-2 DB override risk neutralized ---


def test_c5_d2_entity_character_list_unchanged() -> None:
    """D-2 carve-out — entity_character_list 본문 sha256 변경 0 + new dir 신설 0.

    Codex iter 1 F-2 fix-up: hardcoded sha256 anchor (Area #7a closure push d0410eb 시점,
    controller verify 2026-05-19). db-aware caller (audit §11.4) 존재 이지만 본 area 변경 0
    으로 DB row 영향 0.
    """
    d2_path = PROMPTS_BASE / "entity_character_list" / "2.202605011057" / "system.md"
    assert d2_path.exists(), f"D-2 path missing: {d2_path}"
    # Primary: sha256 hardcoded anchor (byte-identical contract, W4 Gate 3 helper 와 동일)
    actual_sha = _sha256(d2_path)
    assert actual_sha == D2_EXPECTED_SHA256, (
        f"D-2 sha256 mismatch (boundary preserve 위반): "
        f"expected {D2_EXPECTED_SHA256}, actual {actual_sha}"
    )
    # Sanity: Owner taxonomy 5-element 분류 보존 (sha256 PASS 시 자동 보장, but explicit)
    body = d2_path.read_text(encoding="utf-8")
    assert "인간, 요괴, 동물, 로봇, 외계인" in body, "D-2 owner taxonomy 변경"
    # new dir 신설 0 verify
    base = PROMPTS_BASE / "entity_character_list"
    dirs = sorted(p.name for p in base.iterdir() if p.is_dir())
    assert dirs == ["1.202604010100", "2.202605011057"], f"D-2 new dir 신설 발견: {dirs}"


def test_c5_d2_prompt_loader_path_unchanged() -> None:
    """D-2 production loader path 보존 — entity_character_list module 의 latest version 가 변경 0."""
    from app.modules.prompt_loader import _list_module_versions

    versions = _list_module_versions("entity_character_list")
    assert versions, "entity_character_list no version dir"
    latest = versions[0]
    assert latest == "2.202605011057", f"D-2 latest version 변경: {latest}"


# --- C6: canonical VWR clause glyph-exact membership per 9 modified file (hit ≥ 1) ---


@pytest.mark.parametrize("module,version_prefix,filename", MODIFIED_FILES)
def test_c6_canonical_clause_membership(module: str, version_prefix: str, filename: str) -> None:
    """9 rewritten file 모두 canonical VWR clause glyph-exact membership ≥ 1 (fixed-string)."""
    module_dir = _latest_active_dir(module, version_prefix)
    body = (module_dir / filename).read_text(encoding="utf-8")
    assert CANONICAL_VWR_CLAUSE in body, (
        f"{module_dir.name}/{filename}: missing canonical VWR clause"
    )
```

**Notes**:
- C1 parametrize 7 sub-canary (entity_all / entity_relation / entity_extractor_v2 / outlook_extractor / scene_verify / scene_detail / shot_extract — D-2 제외).
- C2 parametrize 24 sub-canary (Contract 5 정합 — entity_all 6 + entity_relation 2 + entity_extractor_v2 9 + outlook_extractor 4 + scene_verify 1 + scene_detail 1 + shot_extract 1).
- C3 STEP_MANIFEST entry 12 row presence verify (entry 존재 + 본 area 안 schema_version 신설 0 — C4 가 별도 verify).
- C4 visual_world_rules.schema_version=1 보존 (Area #7a W1 신설).
- C5 D-2 sha256 변경 0 + new dir 신설 0 + production loader path 보존.
- C6 parametrize 9 sub-canary (9 modified file canonical clause membership).
- **NO live LLM, NO VLM** — `openai` / `gemini` / `llm_client` / `vlm` / `image_validation` import 0.
- Test count: C1 (parametrize 7) + C2 (parametrize 24) + C3 (1) + C4 (1) + C5 (2) + C6 (parametrize 9) = **44 test target**.

### S2 — pytest 실행

- [ ] **Step 2.1: canary test 모두 PASS 확인**

```bash
backend/.venv/bin/pytest backend/tests/integration/test_area_7b_no_drift.py -v
```

Expected: 44 PASS (C1 7 + C2 24 + C3 1 + C4 1 + C5 2 + C6 9).

### S3 — No live LLM + NO VLM verify (W5 pre-commit verify 정합)

- [ ] **Step 3.1: live LLM import 0 verify**

```bash
grep -nE "openai|gemini|llm_client|call_structured|completion" backend/tests/integration/test_area_7b_no_drift.py
```

Expected: 0 hit.

- [ ] **Step 3.2: NO VLM verify** (Codex iter 1 F-3 fix-up — narrow forbidden token only, `VLM|vlm` literal 회피)

```bash
grep -nE "vision_language|image_validation|vlm_client|run_vlm|call_vlm" backend/tests/integration/test_area_7b_no_drift.py
```

Expected: 0 hit. (doctrine wording `NO VLM hard constraint` 안 `VLM` literal token 잔존 = legitimate docstring, grep self-hit 회피 의무.)

### S4 — W5 commit

- [ ] **Step 4.1: git add + commit**

> **Historical audit trail (W5 fix-up 1 narrow `fe7e55e` 후 sync 적용 cascade, Codex W1-W6 range review narrow 흡수)**: 아래 commit message body (`git commit -m` HEREDOC) 는 W5 atomic commit `531e67f` published wording verbatim. C3 sub-canary description 안 `STEP_MANIFEST snapshot` + `snapshot diff 0` 단순화 form 은 W5 fix-up 1 narrow commit `fe7e55e` 후 본 test file (`test_area_7b_no_drift.py`) 의 module docstring + section header + function name (`test_c3_step_manifest_snapshot_diff_zero` → `test_c3_step_manifest_entry_presence_verify`) + test docstring 4 site 안 `12 affected step entry presence verify (entry-existence contract, schema_version drift = C4 별도)` 으로 sync. Plan body 안 본 quoted commit message body = published commit history 정합 보존 (commit body mutation 불가, plan body audit trail preserve).

```bash
git add backend/tests/integration/test_area_7b_no_drift.py
git commit -m "$(cat <<'EOF'
test(area-7b-vwr-cascade-downstream-v1): W5 canary — prompt_loader latest 7 + sibling byte-identical 24 + STEP_MANIFEST snapshot + schema_version 보존 + D-2 neutralized + canonical clause 9

6 sub-canary (spec §5.6, no live LLM, NO VLM):
- C1 prompt_loader latest activation per 7 new-dir module (entity_all 5./
  entity_relation 3./entity_extractor_v2 10./outlook_extractor 12./scene_verify
  2./scene_detail 27./shot_extract 12.).
- C2 byte-identical sibling copy verify per 7 new dir (24 sibling sha256 equality
  vs source latest dir).
- C3 STEP_MANIFEST snapshot diff 0 (12 affected step entry presence verify, Codex iter 1 F-1 fix-up).
- C4 visual_world_rules.schema_version=1 보존 (Area #7a W1 신설, 본 area 안 변경 0).
- C5 D-2 entity_character_list/2.202605011057/system.md sha256 변경 0 + owner
  taxonomy 5-element 분류 보존 + new dir 신설 0 + production loader path 보존.
- C6 canonical VWR clause glyph-exact membership per 9 modified file (fixed-
  string, hit ≥ 1).

NO live LLM (openai / gemini / llm_client import 0).
NO VLM hard constraint inline (vision_language / image_validation 0).

Pre-commit verify 3 종 PASS: pytest 44 PASS / live LLM import 0 / NO VLM.

Test count: C1 7 + C2 24 + C3 1 + C4 1 + C5 2 + C6 9 = 44 total.

Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md §5.6
Plan: docs/superpowers/plans/2026-05-19-area-7b-vwr-cascade-downstream-v1-implementation.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```

### S5 — W5 Codex review 의뢰

- [ ] **Step 5.1: Codex pane %0 read + W5 commit review 의뢰**

> **Historical audit trail (W5 fix-up 1 narrow `fe7e55e` 후 sync 적용 cascade, Codex W1-W6 range review narrow 흡수)**: 아래 review 의뢰 prompt body 는 W5 commit review 시 published wording verbatim. C3 `STEP_MANIFEST snapshot` 단순화 form 은 W5 fix-up 1 narrow commit `fe7e55e` 후 test file 안 `12 affected step entry presence verify (entry-existence contract, schema_version drift = C4 별도)` 으로 sync. Plan body 안 본 quoted review prompt 는 published audit trail preserve.

tmux_type %0 (fresh):

```
Area #7b W5 commit review 의뢰.

Commit: <W5 commit hash>
Wave: W5 canary test (C1 prompt_loader latest 7 + C2 sibling byte-identical 24 + C3 STEP_MANIFEST snapshot + C4 schema_version 보존 + C5 D-2 neutralized + C6 canonical clause 9, 44 test total, no live LLM + NO VLM).
Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md §5.6.

검토 항목:
1. C1 7 sub-canary parametrize 정합 (D-2 제외).
2. C2 24 sub-canary parametrize 정합 (Contract 5 sibling inventory).
3. C3 STEP_MANIFEST 12 affected step entry verify (entity_all_character/location/prop + entity_relation + entity_extract_character/location/prop + outlook_phase1/2 + scene_verify + scene_detail + shot_extract — **canonical wording: 10 modified-file-bound step entries + 2 sibling-only shared-module entries (entity_all_location / entity_all_prop)**; Codex iter 2 F-1 narrow sync).
4. C4 visual_world_rules.schema_version=1 보존.
5. C5 D-2 sha256 + owner taxonomy 보존 + new dir 0 + production loader path.
6. C6 canonical clause membership 9 file parametrize.
7. No live LLM + NO VLM 정합 (grep verify).
8. parents[3] repo root 정합.

verdict: APPROVED / NEEDS_REVISION_MINOR / NEEDS_REVISION_MAJOR.

완료되면 끝났다고 claude mcp 호출해줘!
```

verdict 도착 후 controller cross-analyze. APPROVED 시 W6 진입.

---

## Task 7: W6 — Closure (single commit + external memory + range review + push)

**Files (repo-local, single commit)**:
- Modify: `docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md` (frontmatter `status: drafting` → `status: closed` + body 끝 §11 Closure section append).
- Modify: `docs/superpowers/specs/2026-05-16-track-b-semantic-debt-roadmap-design.md` §5.7 Sub-area (b) closed mark + carry table 갱신.
- Modify: `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/02-prompt-side-hygiene-audit.md` (§13 Area #7b Closure section append + audit §11.2 row 9 site `**Status: closed (Area #7b, 2026-05-19+)**` mark).

**Files (external, repo 밖 — git stage 절대 금지)**:
- Create (non-git write only): `/Users/manta/.claude/projects/-Users-manta-Documents-Projects-TheRoad-I1/memory/session_20260519_area_7b_v1_closure.md`.
- Modify (non-git write only): `/Users/manta/.claude/projects/-Users-manta-Documents-Projects-TheRoad-I1/memory/MEMORY.md`.

### S1 — Spec status close

- [ ] **Step 1.1: spec frontmatter status 갱신**

File: `docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md`

Frontmatter (line 4) edit:

Before:
```yaml
status: drafting (Q0+Q1-Q7 brainstorming closed in handoff session, Codex 2-round APPROVED outline; spec drafting iter pending)
```

After:
```yaml
status: closed (Codex iter X APPROVED_FOR_EXECUTION + W1-W6 atomic execution + Codex per-wave + range review APPROVED_FOR_PUSH + push 완료)
```

(`X` = plan drafting Codex iter round count + 1, controller fill-in.)

- [ ] **Step 1.2: spec body 끝 §11 Closure section append**

File 끝 append (after §10 Codex Iter Trace):

```markdown
## 11. Closure (2026-05-19+)

**Status**: closed (Codex iter X APPROVED_FOR_EXECUTION + W1-W6 atomic execution + Codex per-wave + range review APPROVED_FOR_PUSH + push 완료).

**Wave commits**:
- W1 (`<hash>`): Group E entity_all + entity_relation + entity_extractor_v2 canonical VWR SOT clause cascade atomic (5 site / 4 modified file / 17 sibling).
- W2 (`<hash>`): Group O outlook_extractor canonical VWR SOT clause cascade atomic (2 site + line 24 / 2 modified file / 4 sibling).
- W3 (`<hash>`): Group S scene_verify + scene_detail + shot_extract canonical VWR SOT clause cascade atomic (3 site / 3 modified file / 3 sibling, line drift verify 정합).
- W4 (`<hash>`): Residue gate test (Gate 1.1-1.9 + Gate 2 + Gate 3 + Gate 4 + Sanity, 21 test).
- W5 (`<hash>`): Canary test (C1 7 + C2 24 + C3 1 + C4 1 + C5 2 + C6 9, 44 test, no live LLM + NO VLM).
- W6 (`<hash>`): Closure cleanup (본 section + roadmap §5.7 + audit §13 + audit row status mark).

**Closure verdict** (Q7 verbatim, Codex iter 2 fixed):
> Area #7b closes when the VWR downstream prompt cascade is converted from prompt-owned scenario/domain term lists to canonical visual_world_rules.rules[].rule_type SOT references across the rewritten entity/outlook/scene prompt sites; entity_character_list D-2 remains explicitly preserved as a generic owner-taxonomy boundary; active prompt residue gates verify site-specific exact residue phrases 0 (fixed-string / glyph-exact membership, audit-verbatim + current-active-promoted inventory split, no semantic judgment) and canonical VWR SOT references present in every rewritten site; canaries verify prompt_loader latest activation, STEP_MANIFEST schema_version unchanged, DB override risk neutralized, and no VLM validation is used.

**In-scope closed** (audit §11.2 row, 9 site):
- D-1 entity_all character.md (site 1).
- D-3 entity_relation system.md (site 3).
- D-4 entity_extractor_v2 system.md (site 6).
- ADD-6 entity_extractor_v2 turn0_style.md (site 7).
- ADD-8 outlook_extractor phase1.md (site 4 + line 24 current-active-promoted).
- ADD-9 outlook_extractor phase2.md (site 5).
- ADD-10 scene_verify system.md (site 9).
- ADD-11 scene_detail system.md (site 10, line drift 327 → 473).
- audit §11.2 row 11 shot_extract user.md (site 11, line drift 33 → 49).

**D-2 carve-out**: entity_character_list (site 2) = 변경 0 boundary preserve (owner taxonomy 5-element 분류, presence/visibility 결정 X).

**Carry (non-claim, follow-up)**:
- Area #7c (t2i_review v6 placeholder example abstraction — Track B Tier 3 #3 후속).
- Area #7d (cinematography closed-list SOT dual-site — Track B Tier 3 #4 후속).
- Carry-A099 (VWR system.md director_notes prose redesign V8+).
- Carry-A100 (VWR system.md t2i_context demonym redesign V8+).
- Carry-P021 (scene_consistency 7 enumeration broad, source unresolved low-priority).
```

### S2 — Roadmap §5.7 update

- [ ] **Step 2.1: roadmap §5.7 Sub-area (b) closed mark**

File: `docs/superpowers/specs/2026-05-16-track-b-semantic-debt-roadmap-design.md`

§5.7 Sub-area (b) 본문 안 본 area `closed` mark 추가 또는 update:

```markdown
- **Sub-area (b) — Area #7b (visual_world_rules downstream prompt cascade)**: **closed (2026-05-19+, commit <range>)**. In-scope = 9 site (D-1 / D-3 / D-4 / ADD-6 / ADD-8 / ADD-9 / ADD-10 / ADD-11 / audit §11.2 site 11). D-2 entity_character_list = 변경 0 boundary preserve. Carry follow-up = Area #7c (t2i_review placeholder) + Area #7d (cinematography dual-site) + Carry-A099 / A100 / P021.
```

### S3 — Audit `02-` §13 Area #7b Closure append + row status mark

- [ ] **Step 3.1: §13 Area #7b Closure section append**

File: `docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/02-prompt-side-hygiene-audit.md`

§12 Area #7a Closure section 다음에 §13 신설:

```markdown
## §13 Area #7b Closure (2026-05-19+)

**Status**: closed (commit `<range>` push).

**In-scope 9 site closed mapping**:
| Site (audit §11.2) | Module / file | Action |
|---|---|---|
| 1 (D-1) | entity_all/5.*/character.md | line 26+29+30 audit-verbatim 8 phrase 폐기 + canonical clause |
| 3 (D-3) | entity_relation/3.*/system.md | line 11-13 audit-verbatim 3 + line 30 current-active-promoted 1 phrase 폐기 + canonical clause |
| 6 (D-4) | entity_extractor_v2/10.*/system.md | line 22 + 32 audit-verbatim 2 phrase 폐기 + canonical clause + section header rewrite |
| 7 (ADD-6) | entity_extractor_v2/10.*/turn0_style.md | line 13 audit-verbatim 1 phrase 폐기 + canonical clause |
| 4 (ADD-8) | outlook_extractor/12.*/phase1.md | line 16 audit-verbatim + line 24 current-active-promoted 2 phrase 폐기 + canonical clause |
| 5 (ADD-9) | outlook_extractor/12.*/phase2.md | line 8 audit-verbatim 1 phrase 폐기 + canonical clause |
| 9 (ADD-10) | scene_verify/2.*/system.md | line 7 audit-verbatim 1 full sentence 폐기 + canonical clause |
| 10 (ADD-11) | scene_detail/27.*/system.md | line 473 audit-verbatim 1 full sentence 폐기 + canonical clause (line drift 327 → 473) |
| 11 | shot_extract/12.*/user.md | line 49 audit-verbatim 1 parenthetical 폐기 + canonical clause (line drift 33 → 49) |

**D-2 carve-out**: entity_character_list (site 2) = **변경 0 boundary preserve**. owner taxonomy 5-element 분류 = 인물 정의 boundary, presence/visibility 결정 X.

**4-Gate Boundary Doctrine 적용 (사용자 격분 흡수 2026-05-19)**: closed-world exact residue phrase contract (fixed-string / glyph-exact membership, audit-verbatim + current-active-promoted inventory split, source path + line + classification anchored, Generic Korean standalone ban 0).

**NO VLM hard constraint** — residue gate + canary 모두 schema/text/manifest verification only.

**Carry follow-up**: Area #7c (t2i_review placeholder) + Area #7d (cinematography dual-site) + Carry-A099 (director_notes prose) + Carry-A100 (t2i_context demonym) + Carry-P021 (scene_consistency, source unresolved).
```

- [ ] **Step 3.2: audit §11.2 row 9 site `**Status: closed (Area #7b, 2026-05-19+)**` mark**

audit §11.2 line 240-254 표 안 row 1 / 3 / 4 / 5 / 6 / 7 / 9 / 10 / 11 의 본문 끝 `**Status: closed (Area #7b, 2026-05-19+)**` line 추가. row 2 (D-2 entity_character_list) = `**Status: D-2 carve-out (변경 0 boundary preserve)**`. row 8 (scene_director, Area #7a closed) = 변경 0 (Area #7a closure 시 이미 mark).

(controller 해당 row 위치 grep 후 surgical edit.)

### S4 — External memory file 작성 (repo 밖 — git stage 절대 금지)

- [ ] **Step 4.1: closure 종합 memo 작성**

File (repo 밖): `/Users/manta/.claude/projects/-Users-manta-Documents-Projects-TheRoad-I1/memory/session_20260519_area_7b_v1_closure.md`

Body skeleton:

```markdown
---
name: session-20260519-area-7b-v1-closure
description: "2026-05-19+ Area #7b (VWR downstream prompt cascade) v1 closure 종합 — W1-W6 atomic execution + Codex per-wave + range review APPROVED_FOR_PUSH + push 완료."
metadata:
  node_type: memory
  type: project
---

**2026-05-19+ Area #7b v1 closure 종합 (Track B Tier 3 #2)**

## Final state
- push 완료 (`<range>` N commits since `d0410eb`).
- 6 execution wave (W1 Group E entity / W2 Group O outlook / W3 Group S scene line drift verify / W4 residue gate / W5 canary / W6 closure).
- Codex iter X round APPROVED.

## Wave commits
- W1: `<hash>` Group E atomic (entity_all + entity_relation + entity_extractor_v2 / 5 site / 4 modified file / 17 sibling).
- W2: `<hash>` Group O atomic (outlook_extractor / 2 site + line 24 / 2 modified file / 4 sibling).
- W3: `<hash>` Group S atomic (scene_verify + scene_detail + shot_extract / 3 site / 3 modified file / 3 sibling, line drift 정합).
- W4: `<hash>` residue gate (Gate 1.1-1.9 + Gate 2 + Gate 3 + Gate 4 + Sanity, 21 test).
- W5: `<hash>` canary (C1 7 + C2 24 + C3 1 + C4 1 + C5 2 + C6 9 = 44 test, no live LLM + NO VLM).
- W6: `<hash>` closure cleanup (spec status + roadmap §5.7 + audit §13 + audit row status).

## Architecture (production + carry table 정합)
(spec §1.2 In-scope + §1.3 Out-of-scope + §6 Carry Table verbatim)

## Closed boundary (in-scope vs carry)
- In-scope: 9 site (D-1 + D-3 + D-4 + ADD-6 + ADD-8 + ADD-9 + ADD-10 + ADD-11 + site 11).
- D-2 carve-out: entity_character_list 변경 0 boundary preserve.
- Carry: Area #7c + Area #7d + Carry-A099 + Carry-A100 + Carry-P021.

## Codex iter trace (full session)
- spec iter 1-7 (handoff session → 본 session) APPROVED_FOR_PLAN.
- plan drafting iter 0 strategy APPROVED + iter X plan quality APPROVED_FOR_EXECUTION.
- execution per-wave W1/W2/W3/W4/W5/W6 each APPROVED.
- W1-W6 range review APPROVED_FOR_PUSH.

## 함정 (본 session 신규 학습)
(controller verify 후 N 항목)

## 다음 area candidate
(Area #7c / Area #7d / Carry-A099 / Carry-A100 / Carry-P021)

## References
(spec + roadmap + audit + production code path)

## 관련 memo
(이전 진입점 해소 + Area #7a 정합)
```

- [ ] **Step 4.2: MEMORY.md index 갱신**

File (repo 밖): `/Users/manta/.claude/projects/-Users-manta-Documents-Projects-TheRoad-I1/memory/MEMORY.md`

추가 1 line (semantic 위치):

```markdown
- [session_20260519_area_7b_v1_closure.md](session_20260519_area_7b_v1_closure.md) — **2026-05-19+ Area #7b (VWR downstream prompt cascade) v1 closure 종합 (Track B Tier 3 #2, push 완료)** — ...
```

해소 표시 (이전 진입점):
- `[next_session_area_7b_plan_drafting.md]` description 앞에 `**(해소됨 2026-05-19+, 결과 session_20260519_area_7b_v1_closure.md 참조)**` 추가.

### S5 — git status 확인 (path-limited)

- [ ] **Step 5.1: stage scope verify**

```bash
git status
```

확인: modified = 3 file (spec + roadmap + audit 02-) only. external memory file 은 `git status` 결과에 absent (`~/.claude/...` repo 밖).

- [ ] **Step 5.2: path-limited git add**

```bash
git add docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md \
        docs/superpowers/specs/2026-05-16-track-b-semantic-debt-roadmap-design.md \
        docs/visual-reliability-audit/2026-05-14-semantic-string-routing-debt-audit/02-prompt-side-hygiene-audit.md
```

### S6 — W6 commit

- [ ] **Step 6.1: W6 commit**

```bash
git commit -m "$(cat <<'EOF'
docs(area-7b-vwr-cascade-downstream-v1): W6 closure — spec status closed + roadmap §5.7 Sub-area (b) Area #7b closed mark + audit §13 Area #7b Closure + audit §11.2 9 site status mark

W1-W5 atomic execution 완료 + Codex per-wave APPROVED.

Closure verdict (Q7 verbatim, Codex iter 2 fixed):
> "Area #7b closes when the VWR downstream prompt cascade is converted from
> prompt-owned scenario/domain term lists to canonical visual_world_rules.
> rules[].rule_type SOT references across the rewritten entity/outlook/scene
> prompt sites; entity_character_list D-2 remains explicitly preserved as a
> generic owner-taxonomy boundary; active prompt residue gates verify
> site-specific exact residue phrases 0 (fixed-string / glyph-exact
> membership, audit-verbatim + current-active-promoted inventory split, no
> semantic judgment) and canonical VWR SOT references present in every
> rewritten site; canaries verify prompt_loader latest activation,
> STEP_MANIFEST schema_version unchanged, DB override risk neutralized, and
> no VLM validation is used."

In-scope 9 site closed: D-1 entity_all/character.md + D-3 entity_relation/
system.md + D-4 entity_extractor_v2/system.md + ADD-6 entity_extractor_v2/
turn0_style.md + ADD-8 outlook/phase1.md (line 16 audit-verbatim + line 24
current-active-promoted) + ADD-9 outlook/phase2.md + ADD-10 scene_verify/
system.md + ADD-11 scene_detail/system.md (line drift 327 → 473) + audit
§11.2 site 11 shot_extract/user.md (line drift 33 → 49).

D-2 carve-out: entity_character_list/2.202605011057/system.md (site 2 owner
taxonomy 5-element 분류) = 변경 0 boundary preserve.

Carry follow-up: Area #7c (t2i_review placeholder) + Area #7d (cinematography
dual-site) + Carry-A099 (director_notes prose) + Carry-A100 (t2i_context
demonym) + Carry-P021 (scene_consistency, source unresolved).

4-Gate Boundary Doctrine 적용 inline (사용자 격분 흡수 2026-05-19).

NO VLM hard constraint.

Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md (status closed)
Roadmap: docs/superpowers/specs/2026-05-16-track-b-semantic-debt-roadmap-design.md §5.7

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```

- [ ] **Step 6.2: W6 commit 확인**

```bash
git log -1 --stat
```

확인: 1 commit + 3 file modified (docs only).

### S7 — Codex W1-W6 range review 의뢰

- [ ] **Step 7.1: Codex pane %0 read + W1-W6 range review 의뢰**

tmux_type %0 (fresh):

```
Area #7b W1-W6 range review 의뢰.

Range: <W1 commit>..<W6 commit> (6 commits — W1 Group E / W2 Group O / W3 Group S / W4 residue gate / W5 canary / W6 closure).
Spec: docs/superpowers/specs/2026-05-19-area-7b-vwr-cascade-downstream-v1-design.md (commit 90a8cea, APPROVED_FOR_PLAN).
Plan: docs/superpowers/plans/2026-05-19-area-7b-vwr-cascade-downstream-v1-implementation.md.
Unpushed: 5 spec commit + plan v1 commit + plan amend N + 6 execution commit = 13+ commit since d0410eb.

검토 항목:
1. W1-W6 atomic boundary 정합 (W1/W2/W3/W4/W5/W6 each single commit, no cross-wave bleeding).
2. 9 modified file 모두 canonical clause 글자-단위 동일 (audit §11.3 verbatim).
3. W1+W2+W3 exact residue phrase inventory 15+3+3 = 21 phrase 모두 hit 0 (audit-verbatim + current-active-promoted split).
4. 24 sibling byte-identical sha256 PASS (W1 17 + W2 4 + W3 3).
5. D-2 entity_character_list 변경 0 boundary preserve (sha256 + new dir 0 + owner taxonomy 보존).
6. Residue gate (W4) 21 test 정합 vs spec §7 (fixed-string membership only, regex 0 for phrase gates).
7. Canary (W5) 44 test 정합 vs spec §5.6 (C1 7 + C2 24 + C3 1 + C4 1 + C5 2 + C6 9, no live LLM + NO VLM).
8. Closure (W6) verdict verbatim + roadmap §5.7 mark + audit §13 + audit row 9 site status mark.
9. 4-Gate Boundary Doctrine 정합 (Semantic Regex Ban / Prompt Closed-List Ban / Structured SOT Required / No Silent Fallback).
10. STEP_MANIFEST 변경 0 (visual_world_rules.schema_version=1 Area #7a 신설 보존).
11. line drift verify (scene_detail 327→473 / shot_extract 33→49).
12. NO VLM hard constraint inline.
13. unrelated drift 0 (path-limited git add 정합).

verdict: APPROVED_FOR_PUSH / NEEDS_REVISION_MINOR / NEEDS_REVISION_MAJOR.

완료되면 끝났다고 claude mcp 호출해줘!
```

- [ ] **Step 7.2: APPROVED_FOR_PUSH 시 즉시 push (사용자 ask 0)**

[[feedback_push_no_user_ask]] 정합 — Codex APPROVED_FOR_PUSH verdict 받으면 사용자 명시 승인 ask 금지, 즉시 push:

```bash
git push origin main
```

확인: `git log origin/main..HEAD` 결과 0 commits (모두 push).

만약 Codex NEEDS_REVISION 시 narrow amend (path-limited git add scope) 후 narrow re-review 의뢰. APPROVED_FOR_PUSH 도달 시까지 반복.

- [ ] **Step 7.3: Closure 종합 memo + 다음 진입점 memo 완료**

External memory (Task 7 S4 본문) — commit hash + push range 채워 fix-up.

다음 진입점 memo (Area #7c 후속 또는 다음 Tier 3 area) 작성:

```
File (repo 밖): /Users/manta/.claude/projects/-Users-manta-Documents-Projects-TheRoad-I1/memory/next_session_area_7c_or_next_tier3.md
Body: Area #7b closed 후 follow-up Tier 3 area 진입점 — Area #7c (t2i_review placeholder) / Area #7d (cinematography dual-site) / Carry-A099-A100-P021 candidate 정합.
```

MEMORY.md index 추가.

---

## Self-Review (Plan author)

작성 후 controller self-review (subagent dispatch 금지, 단순 checklist — writing-plans skill 정합):

1. **Spec coverage**:
   - §1.1 Purpose + §1.2 In-scope (3 surface group: Group E entity_* / Group O outlook_* / Group S scene_*) → Task 2 (W1) + Task 3 (W2) + Task 4 (W3) 매핑 ✓.
   - §1.3 Out-of-scope (D-2 carve-out + Area #7c/d + Carry-A099/A100/P021 + helper 신설 0 + STEP_MANIFEST schema_version bump 0) → Task 1 W0 Verification Contract Contract 4 + Task 7 W6 §11 Closure section 명시 ✓.
   - §2 Audit Evidence (roadmap §5.7 + audit §11 본문) → Task 1 W0 Verification Contract 2 + Task 7 W6 S3 audit row status mark 매핑 ✓.
   - §3 N-Layer Architecture (canonical VWR SOT clause + Group E + Group O + Group S + D-2 carve-out) → Task 2/3/4 cascade 매핑 ✓.
   - §4 Q1-Q7 Brainstorming Closure (Q1 D-2 carve-out / Q2 entity_extractor_v2 single dir / Q3 Hybrid canonical clause + local prefix/suffix / Q4 schema_version 변경 0 / Q5 residue gate scope / Q6 canary scope / Q7 closure verdict) → Task 2/3/4/5/6/7 매핑 ✓.
   - §5 Wave Outline (W0/W1/W2/W3/W4/W5/W6) → Task 1/2/3/4/5/6/7 매핑 ✓.
   - §6 Carry Table (D-2 + Area #7c + Area #7d + Carry-A099/A100/P021) → Task 7 W6 §11 Closure + S2 roadmap + S3 audit 매핑 ✓.
   - §7 Residue Gate (closed-world exact residue phrase contract + 4 Gate doctrine) → Task 5 W4 본문 ✓.
   - §8 Closure Verdict (Q7 verbatim) → Task 7 W6 S6 commit body + S1.2 §11 Closure verbatim ✓.

2. **Placeholder scan**:
   - `HHMM` placeholder = per-wave entry 시 substitute (Codex Q5 정합, plan body 안 explicit instruction) ✓.
   - `<W1 commit hash>` / `<W2 commit hash>` / ... = wave commit 후 controller fill-in (Codex review prompt 안) ✓.
   - `<range>` = W6 push 후 controller fill-in (closure section + memo) ✓.
   - `<hash>` (closure section) = wave commit hash, W6 S1.2 controller fill-in ✓.
   - 다른 TBD / TODO / "implement later" / "fill in details" / "Similar to Task N" / "Add appropriate error handling" 패턴 = 0 ✓.

3. **Type consistency**:
   - `CANONICAL_VWR_CLAUSE` Python literal = W4 + W5 동일 (residue gate Gate 2 + canary C6 동일 문자열) ✓.
   - `NEW_DIR_EXPECTED` dict = W5 C1 + W4 Gate 4 동일 prefix mapping ✓.
   - `SIBLING_INVENTORY` dict = W5 C2 + W1/W2/W3 cp -p command 동일 source/dest pair ✓.
   - `_latest_active_dir(module, version_prefix)` helper signature = W4 + W5 동일 ✓.
   - HHMM placeholder substitute timing = W1 / W2 / W3 각각 (서로 다를 수 있음, full UTC `date -u +%Y%m%d%H%M`) ✓.
   - `parents[3]` (repo root) = W4 + W5 동일 (Area #7a F-2 정합) ✓.

4. **Spec/plan boundary**:
   - spec = decision-level (3 group 분리 / canonical clause verbatim / D-2 carve-out / 4-Gate Boundary Doctrine / residue gate scope / canary scope).
   - plan = task-level (commit count / pytest command / commit message verbatim / pre-commit verify per-wave 종 / sibling sha256 verify command / line drift verify command).
   - boundary 흐림 시 Codex iter 1 plan quality review 흡수.

5. **Codex MCP workflow**:
   - W1 commit → Codex per-wave review (Task 2 S7).
   - W2 commit → Codex per-wave review (Task 3 S5).
   - W3 commit → Codex per-wave review (Task 4 S7).
   - W4 commit → Codex per-wave review (Task 5 S5).
   - W5 commit → Codex per-wave review (Task 6 S5).
   - W6 commit + W1-W6 range review → Codex (Task 7 S7).
   - 모든 review 의뢰 prompt 끝 `완료되면 끝났다고 claude mcp 호출해줘!` 의무 ([[feedback_codex_mcp_discussion_workflow]] rule 7a).
   - verdict 도착 후 controller cross-analyze 의무 (verbatim 받아쓰지 말 것, rule 7b).

6. **NO VLM hard constraint**:
   - residue gate (Task 5 W4) = JSON parse + markdown parse + path glob (closed-world structural) + str.__contains__ only.
   - canary (Task 6 W5) = jsonschema + path glob + sha256 + STEP_MANIFEST struct only.
   - live router completion / VLM 의존 0 (W5 S3 grep verify).

7. **사용자 ask 0**:
   - W1/W2/W3/W4/W5/W6 진입 = controller 자체 결정.
   - W3 line drift verify drift 발견 시 narrow plan amend = controller 자체 결정 (Codex 의논 후).
   - W1-W6 range push = APPROVED_FOR_PUSH 후 즉시 push (Task 7 S7.2, [[feedback_push_no_user_ask]] 정합).
   - 사용자 ask = 심각 버그 only (예: production crash + Codex 도 fix 불가).

8. **4-Gate Boundary Doctrine inline**:
   - Gate (1) Semantic Regex Ban = W4 residue gate Python pattern (regex 0 for phrase gates) ✓.
   - Gate (2) Prompt Closed-List Ban = Canonical clause (VWR rules_schema enum reference, 새 closed-list 아님) ✓.
   - Gate (3) Structured SOT Required = VWR producer SOT 의 LLM-structured emit 활용 ✓.
   - Gate (4) No Silent Fallback = sibling sha256 mismatch / canonical clause missing / residue hit 발견 시 explicit reject + assert ✓.

9. **closed-world exact residue phrase contract**:
   - fixed-string / glyph-exact membership ✓.
   - inventory split: audit-verbatim (audit §11.2 line 240-254) + current-active-promoted (controller verify 2026-05-19, Codex iter 4 F-3 흡수) ✓.
   - source path + line + classification anchored ✓.
   - Generic Korean standalone ban 0 (단어 단독 검사 0) ✓.

---

## Codex Iter Trace (plan drafting)

- **iter 0 (본 session, plan drafting 전 strategy 의논)**: APPROVED_STRATEGY. 8 결정점 verdict — Q1 plan v1 single atomic commit / Q2 W0 spec-absorbed + Verification Contract 압축 표 / Q3 per-wave + range review / Q4 1300-1700 line target / Q5 full UTC `date -u +%Y%m%d%H%M` + narrow amend if date drift / Q6 cp -p + shasum -a 256 equality / Q7 pure str membership regex 0 / Q8 push hold until W6 APPROVED_FOR_PUSH. scope_creep_risk = LOW. execution complexity = MEDIUM. 예상 amend cycle = 2-3 round. NO VLM hard constraint 의무.
- **iter 1+ (plan v1 commit 후 plan quality review)**: pending. (controller fill-in 후 plan amend N → iter 2 narrow → ... → APPROVED_FOR_EXECUTION.)
- **execution per-wave review**: pending (W1/W2/W3/W4/W5/W6 each Codex iter, controller fill-in).
- **W1-W6 range review**: pending (W6 closure 후, controller fill-in 전 APPROVED_FOR_PUSH 도달 시 push).
