---
title: C2 — owned_object_usage[] echo schema v1 (fix-critical-1 Tier α #2, NEW area)
date: 2026-05-20+
status: closed (C2 v1 W1-W4 atomic execution 완료 2026-05-20+ — Codex per-wave APPROVED + W3 per-wave APPROVED_FOR_W4_ENTRY; §10 Closure 참조)
roadmap_ref: docs/superpowers/specs/2026-05-16-track-b-semantic-debt-roadmap-design.md (Track B Tier α #2 NEW area) + docs/fix-critical-1/index.html C2 section (locked persistent guide)
fix_critical_doc_ref: docs/fix-critical-1/index.html C2 section (lines 641-744)
prerequisites:
  - C1 perception_mode enum SOT v1 (closed 2026-05-20+, push range `67775ec..81abd24` + guide hotfix `eb3b807`) — HEAD anchor. C1 perception_mode helper + Area C directionality boundary 변경 0.
  - Area C (directionality_class enum SOT v1, closed 2026-05-12) — boundary preserve.
non_supersedes:
  - C3 detail_steps focus rewrite / C7 #12 shot_dependency_t2i drift / C6 #10 color_palette_intent / C9 L-7 body-light verb / C4 #8 background classifier / C5 #9 action segment SOT / C8 #7 잔여 sub-area split / C10 future structured carries.
---

# C2 — owned_object_usage[] echo schema v1

## 1. Purpose + Scope

### 1.1 Purpose

**audit 03 P0 (L-2)**: `scene_detail_owned_judge` LLM 이 redraw verb closed whitelist + anchor/reference phrase examples + 5-step priority closed list 로 owned 객체 redraw 여부 판정. verdict `redraw_violation` = **hard fail**. 새 verb 누락 silent miss / 의도외 verb over-trigger. 4-Gate 위반 (Prompt Closed-List Ban + open-world semantic 판단).

본 spec v1 = **producer-side `owned_object_usage[]` echo schema 신설** → judge 는 echo verify only (verb whitelist 폐기):
- **Producer (Layer 1+2)**: scene_detail v30 `t2i_variations[].owned_object_usage[]` LLM emit field 신설 + system.md echo instruction.
- **Consumer integration (Layer 4)**: 기존 owned sentinel/contract path 통합 (`_owned_helpers.py` sentinel v2 + `detail_steps.py` owned path + `_owned_judge.py`).
- **Judge (Layer 3)**: `scene_detail_owned_judge` v4 — redraw verb whitelist + anchor phrase examples + 5-step priority **폐기** → `owned_object_usage[]` echo vs t2i_prompt cross-check only.

### 1.2 In-scope

- **scene_detail v30 prompt-pack 신규 dir** (`prompts/_base/scene_detail/30.UTC_TIMESTAMP/`):
  - `detail_schema.json`: `t2i_variations[].owned_object_usage[]` field 신규 (required) — `array<{owned_token, usage_kind, source_phrase}>`.
  - `system.md`: copied from v29 + owned_object_usage echo instruction 신규 section.
- **scene_detail schema_version + version constant bump** (OQ-C2-3, output shape change):
  - `detail_steps.py` `SCENE_DETAIL_SCHEMA_VERSION` 11 → 12.
  - `detail_steps.py` `SCENE_DETAIL_PROMPT_VERSION` `29.*` → `30.UTC` (cp config_hash invalidation accepted).
  - `STEP_MANIFEST["scene_detail"]["schema_version"]` 11 → 12.
  - `version_registry.py` `scene_detail_composer` `1.29.0` → `1.30.0` + `prompt_dependency` `scene_detail/v29` → `scene_detail/v30`.
  - cp invalidation accepted (output shape change — schema_version/data-shape invalidation).
- **owned sentinel v2** (`_owned_helpers.py`, OQ-C2-2):
  - `OWNED_SENTINEL_SCHEMA_VERSION` 1 → 2.
  - `_REQUIRED_SENTINEL_FIELDS` 6 → 7 (`owned_usage_hash` 추가).
  - `build_owned_sentinel()` signature 에 `owned_object_usage` param 추가 + `owned_usage_hash` 계산 (full echo 중복 X, hash 만).
  - `assert_owned_sentinel_shape()` 7-field validation.
  - new helper `compute_owned_usage_hash()`.
- **detail_steps.py owned path 통합** (line 2943-3028):
  - `build_owned_sentinel()` 호출에 `owned_object_usage` (variation field) 전달.
  - judge 호출 분기에서 `owned_object_usage` echo cross-check.
- **`_owned_judge.py` echo cross-check** — `run_owned_judge()` 가 echo-verify-only judge 호출 (또는 echo cross-check helper).
- **scene_detail_owned_judge v4 prompt-pack 신규 dir** (`prompts/_base/scene_detail_owned_judge/4.UTC_TIMESTAMP/`):
  - `system.md`: redraw verb whitelist + anchor phrase examples + 5-step priority 폐기 → echo verify only.
  - `user_template.md`: `owned_object_usage` input 포함 (echo verify 가능).
  - `schema.json`: verdict enum shape 보존 시 byte-identical 가능 (verify only).
- **W3 integrated test 신설** + **W4 closure docs**.

### 1.3 Out-of-scope (Codex scope guard 흡수)

- **verdict enum `[redraw_violation, anchor_reference]` + `has_redraw_violation` semantics**: 보존 (Codex boundary).
- **t2i_prompt body shape**: 변경 0. owned_object_usage[] = sidecar structured evidence 추가, prompt prose mutation X.
- **C1 perception_mode helper + Area C directionality boundary**: 변경 0.
- **scene_detail_owned_judge version_registry entry**: 현재 없음 — invent X. prompt-loader/latest source proof 사용 (Codex OQ-C2-4).
- **parallel sentinel/contract path**: 신설 절대 X — 기존 owned sentinel path 통합 (Codex OQ-C2-2).
- **VLM / live LLM / semantic regex / standalone-token residue gates**: 모두 ban.
- **C3-C10**: 별도 area.

## 2. W0 Evidence Inventory (live, HEAD `eb3b807`)

### 2.1 Layer 1 — Producer schema (`scene_detail/29.../detail_schema.json`)

`t2i_variations[]` 현재 field 10개: `variant_label / camera_effect / t2i_prompt / outfit_assignments / source_facts / visual_inferences / creative_decisions / confidence / applied_frame_spatial_constraint_ids / reference_phrase_kinds`. **`owned_object_usage[]` 부재**.

### 2.2 Layer 3 — Judge prompt (`scene_detail_owned_judge/3.202605051746/system.md`)

- line 18-21: redraw 동사 closed whitelist (생성군 + 추가배치군 + 회피 표현 처리).
- line 23-32: redraw 예시 closed list.
- line 37-61: `anchor_reference` examples (명시적 reference / 공간·프레이밍 / 형용사·상태) + ambiguous default + 5-step 판정 우선순위.
- judge schema (`scene_detail_owned_judge/3.../schema.json`): `violations[] {owned_object, violating_phrase, reason, verdict enum [redraw_violation, anchor_reference]}`.

### 2.3 Layer 4 — Judge consumer

- `_owned_judge.py:30-116` `run_owned_judge()` — LLM judge 호출 (`call_structured_fn(step="scene_detail_owned_judge")`) + violations list shape 검증 (Wave 6 BLOCKING: silent `[]` fallback 차단).
- `_owned_helpers.py`:
  - `OWNED_SENTINEL_SCHEMA_VERSION = 1` (line 26).
  - `_REQUIRED_SENTINEL_FIELDS` 6개 (line 142-145): `schema_version / t2i_prompt_hash / owned_hash / camera_direction_hash / validator / violations`.
  - `build_owned_sentinel()` (line 149-174): 5 param (`owned / camera_direction / t2i_prompt / is_close_framing / violations`).
  - `assert_owned_sentinel_shape()` (line 177+): field/type/enum 검증.
  - `has_redraw_violation()` (line 278+).
  - `compute_owned_hash` / `compute_camera_direction_hash` / `compute_t2i_prompt_hash` / `refresh_t2i_prompt_hash`.
- `detail_steps.py:2943-3028` owned path — close skip / owned 부재 / judge 호출 3 분기 + sentinel attach (`:3023`) + contract_violation status marking (`:3025-3028`).

### 2.4 Boundary — C1 + Area C closed

- C1 perception_mode helper (`backend/app/core/perception_mode.py`) + scene_detail v29 perception_mode cross-reference 변경 0.
- Area C `_ALLOWED_DIRECTIONALITY_CLASSES` 등 변경 0.

## 3. OQ Resolutions (Codex scope guard 흡수)

### 3.1 OQ-C2 — echo 범위

**결정 = (a) full owned_list echo per variation** (Codex 권장):
- `owned_object_usage[]` = **required** field.
- normalized owned list 전체 cover (정확히 — set coverage deterministic).
- `usage_kind` enum `[redraw, anchor, absent]`.
- `source_phrase`: `absent` 일 때만 empty 허용 (redraw/anchor 는 non-empty).
- silent miss 회피 (전체 echo = deterministic set coverage).

### 3.2 OQ-C2-2 — sentinel 통합

**결정 = 기존 owned sentinel path 통합 + hash field 추가** (Codex 권장):
- `OWNED_SENTINEL_SCHEMA_VERSION` 1 → 2.
- `_REQUIRED_SENTINEL_FIELDS` 6 → 7 — `owned_usage_hash` 추가 (full echo 중복 X, hash 만).
- `build_owned_sentinel()` signature 에 `owned_object_usage` param 추가 → `compute_owned_usage_hash()` 로 hash 계산.
- verify path: current variation `owned_object_usage` vs sentinel `owned_usage_hash` 비교 — mismatch → AppError (tampered usage array detect).

**`compute_owned_usage_hash()` canonicalization (IMPORTANT 2)**:
1. coverage validate first (§4.1 — len/unique/set equality). 위반 시 AppError.
2. deterministic ordered representation: `sorted(owned_object_usage, key=lambda u: u["owned_token"])`.
3. hash payload per entry = `(owned_token, usage_kind, source_phrase)` — `source_phrase` = **exact post-schema string** (strip X, semantic normalization X).
4. sha256 of canonical JSON (sorted, no whitespace variance).
- parallel path 신설 절대 X.

### 3.3 OQ-C2-3 — scene_detail v30 + schema_version bump

**결정 = v30 mandatory + schema_version 11 → 12 + cp invalidation accepted** (Codex 권장, output shape change):
- `owned_object_usage[]` = 신규 output field → output shape change → schema_version/data-shape invalidation (C1 의 prompt-only preserve 정책 반복 X).
- `SCENE_DETAIL_PROMPT_VERSION` `29.*` → `30.UTC`.
- `SCENE_DETAIL_SCHEMA_VERSION` 11 → 12.
- `STEP_MANIFEST["scene_detail"]["schema_version"]` 11 → 12.
- `version_registry` `scene_detail_composer` `1.29.0` → `1.30.0` + `prompt_dependency` `scene_detail/v29` → `scene_detail/v30`.
- cp invalidation accepted.

### 3.4 OQ-C2-4 — scene_detail_owned_judge v4 prompt-pack

**결정 = v4 prompt-pack 신설 (version_registry entry invent X)** (Codex 권장):
- `scene_detail_owned_judge/4.UTC/`:
  - `system.md`: verb whitelist + anchor examples + 5-step priority 폐기 → echo verify only.
  - `user_template.md`: `owned_object_usage` input 포함 (echo verify 가능).
  - `schema.json`: verdict enum shape 보존 시 byte-identical 가능.
- `scene_detail_owned_judge` 는 version_registry entry 없음 — **invent X**. prompt-loader latest dir source proof 사용 (`load_prompt`/`load_schema` 가 latest dir resolve).

## 4. Invariants

### 4.1 owned_object_usage full coverage invariant (IMPORTANT 1 강화)

per variation `owned_object_usage[]` exact coverage:
- `len(owned_object_usage) == len(normalized_owned_list)` (exact cardinality, duplicate 금지).
- `owned_token` unique (no duplicate entry).
- `set(owned_token) == set(normalized_owned_list)` (no extra token, no missing token).
- **empty owned list 행동**: required field exists + equals `[]`.
- **close-framing path 행동** (`detail_steps.py:2950-2993` — owned 존재하나 close framing judge skip): 모든 normalized owned token echo with `usage_kind="absent"` + empty `source_phrase`.

### 4.2 usage_kind enum invariant

`owned_object_usage[].usage_kind ∈ {redraw, anchor, absent}`. `source_phrase` non-empty unless `usage_kind == absent`.

### 4.3 sentinel v2 invariant

`OWNED_SENTINEL_SCHEMA_VERSION == 2`. `_REQUIRED_SENTINEL_FIELDS` 7개 (`owned_usage_hash` 포함). `build_owned_sentinel` recomputes `owned_usage_hash` from `owned_object_usage`.

### 4.4 verdict enum preserve invariant

judge verdict enum `[redraw_violation, anchor_reference]` + `has_redraw_violation()` semantics 변경 0.

### 4.5 Judge no closed-list invariant

`scene_detail_owned_judge/v4/system.md` 안 known v3 redraw whitelist + redraw 예시 + anchor/default-priority residue phrases = 0 (residue gate — plan v1 안 marker-wrapped strict residue constants 로 catalog, stable count 표현 회피).

### 4.6 Boundary preserve invariant

C1 perception_mode helper + Area C directionality + t2i_prompt body shape 변경 0. parallel path 신설 0.

### 4.7 No silent fallback invariant

owned_object_usage[] missing / non-list / coverage mismatch → AppError fail-fast (Gate 4).

### 4.8 NO VLM invariant

본 spec 안 VLM 의존 0.

## 5. W1-W4 Implementation Plan

### 5.1 W1 — scene_detail v30 schema/prompt + version alignment

- scene_detail v30 prompt-pack 신설 (detail_schema.json `owned_object_usage[]` + system.md echo instruction).
- `SCENE_DETAIL_SCHEMA_VERSION` 11→12 + `SCENE_DETAIL_PROMPT_VERSION` 30.* + `STEP_MANIFEST` schema_version 12 + `version_registry` 1.30.0/v30.
- existing version-alignment test update (test_scene_detail_continuity_alignment / spatial_alignment / test_g4_5a / test_prompt_versions) — v29→v30 / 1.29.0→1.30.0 / schema_version 11→12.

### 5.2 W2 — sentinel v2 + detail_steps owned_object_usage read/validate (IMPORTANT 3 locked split)

- `_owned_helpers.py` sentinel v2 (`OWNED_SENTINEL_SCHEMA_VERSION` 2 + `owned_usage_hash` + `compute_owned_usage_hash` + `build_owned_sentinel` param + `assert_owned_sentinel_shape` 7-field).
- `detail_steps.py` owned path — variation `owned_object_usage` read + coverage validate (§4.1) + `build_owned_sentinel` 호출에 `owned_object_usage` 전달 **만**.
- **W2 boundary**: `_owned_judge.py` signature/call 변경 X (W3로). detail_steps `run_owned_judge()` 호출도 W2에서 변경 X.

### 5.3 W3 — owned_judge v4 prompt + _owned_judge plumbing + integrated test (IMPORTANT 3 locked split)

- `scene_detail_owned_judge/4.UTC/` prompt-pack (system.md echo verify only + user_template `owned_object_usage` input).
- `_owned_judge.py` signature/call update — `run_owned_judge(... owned_object_usage=...)` + echo cross-check.
- `detail_steps.py` `run_owned_judge()` 호출 site update (`owned_object_usage` 인자 전달) — **W3 same commit** (caller/template/signature sync, intermediate out-of-sync commit 회피).
- integrated test 신설 (G1-G7, no live LLM + NO VLM).

### 5.4 W4 — Closure docs atomic

- spec/plan status closed + roadmap §5.14 C2 entry + fix-critical-1 C2 closure marker + audit 03 closure section.

## 6. Boundary Preserve

| boundary | preserve 의무 |
|---|---|
| verdict enum `[redraw_violation, anchor_reference]` + `has_redraw_violation` | 변경 0 |
| t2i_prompt body shape | 변경 0 (sidecar evidence 추가만) |
| C1 perception_mode helper + scene_detail v29→v30 perception_mode cross-reference | preserve (v30 = v29 copy + owned 추가) |
| Area C directionality_class | 변경 0 |
| owned sentinel/contract path | 기존 path 통합, parallel 신설 0 |
| C3-C10 cross-cut | 본 spec 진입 X |

## 7. Test Gates (G1-G7)

- G1 producer schema `owned_object_usage[]` required + field shape (owned_token/usage_kind/source_phrase)
- G2 usage_kind enum `[redraw/anchor/absent]` strict
- G3 sentinel v2 (`OWNED_SENTINEL_SCHEMA_VERSION==2` + 7 required fields + `owned_usage_hash`)
- G4 judge v4 no closed-list residue (verb whitelist + anchor examples + 5-step priority 0)
- G5 verdict enum + has_redraw_violation preserve
- G6 boundary preserve (C1 helper + Area C + t2i_prompt body shape diff -u empty scoped)
- G7 NO VLM canary (AST-based) + no live LLM + no silent fallback (coverage mismatch → AppError)

## 8. Risk + Open Issues

- echo verify judge — owned_object_usage[] echo vs t2i_prompt cross-check 가 verb whitelist 없이 정확한지 (judge LLM 이 echo 와 prompt 일치 판정). plan v1 안 judge v4 prompt 정확 wording 결정.
- W1 schema_version 12 bump = cp invalidation (C1 N-exec-1 lesson 정합 — output shape change 이므로 정상).
- version constant bump cascade (C1 N-exec-3 lesson) — `grep -rn "29\.\|1.29.0\|schema_version.*11"` 전수.

## 9. Doctrine references

- [[feedback_llm_based_judgment]] — 4-Gate Boundary Doctrine
- [[feedback_no_vlm_dependency]] — NO VLM
- [[feedback_codex_mcp_discussion_workflow]] / [[feedback_codex_mcp_claude_mcp_response_trigger]]
- [[feedback_push_no_user_ask]] / [[feedback_session_50pct_codex_close_check]]
- [[project_fix_critical_1_persistent]] — persistent task source
- [[session_20260520_c1_perception_mode_enum_sot_v1_closure]] — C1 lesson carry (N-exec-1~5)

## 10. Closure (2026-05-20+)

### 10.1 W1-W4 commit chain

| Wave | commit | scope |
|---|---|---|
| W1 | `eb8343c` | scene_detail v30 schema/prompt + version alignment atomic — v30 prompt-pack (`detail_schema.json` `t2i_variations[].owned_object_usage[]` required field `{owned_token, usage_kind enum [redraw/anchor/absent], source_phrase}` + `system.md` OWNED OBJECT USAGE ECHO section) + `SCENE_DETAIL_SCHEMA_VERSION` 11→12 + `SCENE_DETAIL_PROMPT_VERSION` 30.* + `STEP_MANIFEST` schema_version 12 + `version_registry` scene_detail_composer 1.30.0/v30 + 5 existing version-alignment test (10 file: 2 new + 3 modify + 5 test) |
| W2 | `55f54ab` | sentinel v2 + detail_steps owned_object_usage echo read/validate — `OWNED_SENTINEL_SCHEMA_VERSION` 1→2 + `owned_usage_hash` 4th hash + `validate_owned_object_usage_coverage` / `compute_owned_usage_hash` / `assert_owned_usage_hash_matches` / `assert_close_framing_absent_echo` 신설 + `build_owned_sentinel` owned_object_usage param + detail_steps owned path echo read/validate (14 file: 2 prod + 12 test) |
| W3 | `bc05dc7` | owned_judge v4 prompt-pack + _owned_judge echo plumbing + integrated test — scene_detail_owned_judge v4 (`system.md` verb whitelist 폐기 echo-verify-only + `user_template.md` `{owned_object_usage}` placeholder + `schema.json` v3 byte-identical) + `run_owned_judge` required `owned_object_usage` kwarg + detail_steps call-site + `test_c2_owned_object_usage_echo.py` integrated G1-G7 26 test + run_owned_judge blast radius 13 call-site (8 file: 4 new + 4 modify) |
| W4 | W4 closure commit | closure docs atomic (path-limited 5 docs: 본 spec + plan + roadmap §5.14 + fix-critical-1 index.html C2 marker + audit 03 L-2 marker/§10) |

### 10.2 Gate result

- W3.1 C2 integrated test (`test_c2_owned_object_usage_echo.py`) — 26 PASS.
- W3.2 owned regression bundle — plan §5.5 5-file bundle + blast-radius 2 file (`test_scene_detail_owned_judge.py` + `test_g3_2_judge_step_extension.py`) 7-file run 158 PASS (Codex W3 per-wave 6-file re-verify 152 PASS — 차이 = `test_g3_2_judge_step_extension.py` 6 routing test).
- W3.3 judge v4 no closed-list residue PASS / W3.4 v4 prompt-loader latest source proof PASS.
- 전체 백엔드 4036 passed (5 pre-existing failure — `text_cleaner.clean_text` ImportError 등, `git stash` 후 clean HEAD `55f54ab` 재실행 5건 동일 실패 → W3 무관 확정).

### 10.3 OQ resolution 최종

- OQ-C2 = (a) full owned_list echo per variation — `owned_object_usage[]` required, `usage_kind` enum [redraw/anchor/absent], `source_phrase` absent 시만 empty.
- OQ-C2-2 = 기존 owned sentinel path 통합 + `owned_usage_hash` field (sentinel v2). parallel path 신설 0.
- OQ-C2-3 = scene_detail v30 + schema_version 11→12 + cp invalidation accepted (output shape change).
- OQ-C2-4 = scene_detail_owned_judge v4 prompt-pack (version_registry entry invent X — prompt-loader latest dir source).

### 10.4 Codex review trace

- spec v1 narrow re-review APPROVED_FOR_PLAN (3 IMPORTANT + 1 MINOR).
- plan v1 narrow re-review #3 APPROVED_FOR_EXECUTION (3 IMPORTANT + 2 MINOR + N-1 + N-2).
- W1 per-wave APPROVED_FOR_W2_ENTRY / W2 per-wave APPROVED_FOR_W3_ENTRY (close-framing N-1 narrow fix-up 흡수 후).
- W3 entry sanity APPROVED_FOR_W3_ENTRY_WITH_NARROW_PLAN_GAP_ABSORB (`test_scene_detail_owned_judge.py` blast radius plan §5.2 gap 흡수).
- W3 per-wave APPROVED_FOR_W4_ENTRY.

### 10.5 함정 / lesson learned

- **N-W2-1**: sentinel v2 signature/schema 변경 blast radius — `build_owned_sentinel` 직접호출 외 hand-built `owned_validation` dict 도 전수조사 의무 (plan §4.2 6 test → 실제 12 test).
- **N-W2-2**: 버전 constant bump 은 latest-activation canary (`test_area_7b_no_drift.py` NEW_DIR_EXPECTED) 도 cascade.
- **N-W2-3**: close-framing invariant = `usage_kind=='absent'` AND `source_phrase==''` 양쪽 검사 (Codex W2 per-wave N-1).
- **N-W3-1**: `run_owned_judge` signature blast radius — W3 entry sanity 는 `test_scene_detail_owned_judge.py` 만 식별, 실행 중 `grep run_owned_judge(` 전수조사로 `test_g3_2_consumer_wiring.py` 4 call-site 추가 발견 (총 13 call-site). signature 변경 시 직접호출 전수 grep 의무 (N-W2-1 정합).
- **N-W3-2**: NO VLM AST canary helper 이름 자체가 forbidden substring (`vlm`) 포함 시 canary self-trip — helper 명명에서 forbidden keyword 회피 (`_assert_no_vlm` → `_assert_no_forbidden_model_refs`).

### 10.6 carry priority post-C2

C3-C10 잔여 (fix-critical-1 index.html): **C3 detail_steps focus rewrite** (다음 진입) → C7 #12 shot_dependency_t2i drift → C6 #10 color_palette_intent → C9 L-7 body-light verb → C4 #8 background classifier → C5 #9 action segment SOT → C8 #7 잔여 sub-area split → C10 future structured carries.
