# 인수인계 — GROUNDING-V2 (2026-09-02, 모델 교체용)

> 읽는 순서: **§4 경계**부터 보고, 그다음 §5 다음 진입점.
> 이 문서 하나로 이어받을 수 있게 적었다. 모르는 것은 「모른다」로 적었다.

---

## 1. 지금 어디

| | |
|---|---|
| 브랜치 | `tools/carried-name-ab` |
| HEAD | `2d35d2e4` — `fix(#GV2): shot_director 가 location_part 를 후보로 받지도 못했다` |
| worktree | **깨끗하다**(미커밋 0). worktree 안 씀 |
| 이번 판 commit | `d992a611..HEAD` **38개** |
| 원본 DB | `theroad` · alembic `011` · 새 표 **0** — **한 글자도 안 건드렸다** |
| canary DB | `theroad_canary_69e821758f3d` · alembic `012` · 판정 5행 |

### 이번 판에 도입한 계약 판

```
grounding_ref_brief pack        3.202609020400
acquisition projection          2.202609020700
bundle projection               4.202609020800
sidecar writer                  2.202609020800
reference bundle                2.202609020800
fidelity 축                     1.202609020700
review(사람 판정)               1.202609020900
payload probe                   1.202609021000
shot_director schema            4          ← 스텝 상수 **와** manifest 둘 다
alembic head                    012_grounding_fidelity_review  (≤32자 필수)
```

---

## 2. 끝낸 것 · 부분 · 미검증

### 끝냈다 (Codex APPROVE 받음)

- **canary ① 유료 주행 2회.** 중앙 조사가 실제로 돌았다 — 검색 10/10 ·
  받기 38장(25MB) · 최종 이미지 **0**.
- **재판정**(받아 둔 사진으로 판정만 다시) — 새 검색 0 · 새 받기 0 · VLM 10.
  결과 **selected 5 · no_match 5 · retryable 2**(검색 승인을 다 써서 후보를
  한 장도 못 받은 둘: `L01#context` · `rs_ed64…`).
- **사람 고증 판정** — 사용자가 실제로 화면에서 5장을 보고 눌렀다.
  `P01·LP01·LP03·LP05` 맞다 / **`LP04` 아니다**
  (사유: 「이발소 안의 벽이 아니야, 가격은 없어, 메뉴는 있지만 간판에」).
- **판정이 production 사슬을 실제로 바꾼다** —
  배경 sidecar `['LP01','LP03','LP05']` · 정책 lane `['P01']` ·
  `LP04` 안 붙음 · 두 lane 중복 0.
- **두 lane 회계** — acquisition 12 / replay 10 / 겹침 0 / 원 줄 16 보존.
- **`shot_director` 가 `location_part` 를 갈래로 읽는다** — producer 좌표가
  있는 씬만 후보. 실물에서 씬1 `LP01·LP02` / 씬2 `LP03·LP04` /
  씬3 `LP05·LP04` / 씬4 `LP02`.

### 부분 — 지었지만 **아직 안 돌렸다**

- **canary ② 측정 도구** `tools/grounding_audit/canary_payload_probe.py`.
  production 함수만 지난다(`central_cp_with_reviews` → `write_for_shot` →
  `attach_from_rpc`). 이미지 provider 는 **인자로도 안 받는다**.
  ★가시성 SOT(`shot_director` CP)가 없으면 **선다** — 지금 그 CP 가 없어서
  **아직 실물로 못 돌렸다**.

### 아직 검증 안 됨 — **이렇게 적어야 한다**

- `location` 갈래: 후보 **0장**(검색 승인 소진). `reference_unavailable`.
- `character_outlook`: verified **0**. 무료 positive control 로만 있고
  **실물 통과라고 쓰면 안 된다**.
- `character`: 실물 참조 없음.
- **최종 이미지 생성: 0회.** 한 번도 안 했다.

---

## 3. 마지막으로 실제 확인한 시험

```
tests/grounding      3897 passed · 5 skipped · 실패 0   (netprobe 바깥 호출 0건)
전체 판(tests)       13486 passed · 실패 109
                     = 기준선과 **같은 109개**(양방향 차집합 공집합)
```

- 기준선 명령: `pytest tests -q -p no:randomly` (pytest.ini 의
  `addopts = -m "not pg"` 로 50 deselected). 기준선 산출은
  `scratchpad/wide_base.txt`. ★**같은 명령으로만** 견준다 — 수가 아니라
  **집합**을 양방향 차집합으로 본다.
- netprobe 가 세는 144건은 **기준선에도 있는** 것이고 전부 **막힌** 시도다.
- 중단·미완 시험: 없다. 마지막 wide 는 완주했다.
- ★**시험 도중에 파일을 고치지 마라** — 없는 실패 4개를 봤다(두 번 겪음).

---

## 4. 경계 — 여기를 넘지 마라

| 문 | 지금 | 누가 연다 |
|---|---|---|
| 글/VLM 전송 | **누계 80 / 승인 93 · 남은 13** | Codex 재승인 |
| 새 이미지 검색 | **0** (10/10 소진) | Codex — 지금 **닫힘** |
| 새 다운로드 | **0** | Codex — 지금 **닫힘** |
| 참조 판정 VLM | **0** | Codex — 지금 **닫힘** |
| **최종 이미지 생성** | **0** | **별도 승인 단계** — canary ② 통과 뒤 |

- canary run_id **`69e821758f3d`** · 열린 attempt **0**.
- 코드 사슬: `d992a611 → 4f3f279c → f3031fff → 397fea99 → d88a1c53 →
  1204c335 → 2d0cf2a2 → ed97b080 → c9fc9177`.
  재개하려면 **현재 tip 으로 오는 전이를 먼저 적어야** 한다
  (`canary_run.record_code_transition`). 트리가 더러우면 선다.
- ★**남은 13은 「논리 13」이 아니라 run 전체의 실제 전송 정지선**이다.
  키 슬롯 2 계약에서 논리 11 의 물리 최악은 22 다 — 「11 ≤ 13」은 완주
  증명이 **아니다**. 다음 승인 때는 transport hard cap 13 안에서만 시도하고,
  거절·미완이면 **자동 확대·재실행 없이 inconclusive 로 선다**.

---

## 5. 다음 진입점 — 순서대로

★2026-09-02 저녁 갱신: ①②③ 끝남(아래 각 절 머리에 적음). 남은 것은 ④ 와 Codex 재리뷰. commit e0540bcd · 8374cc33 · 97970e45.

### ① ✅ 끝남 2026-09-02 — `shot_selection` + `shot_director` 실주행

attempt `85771cc56d07` completed · 논리 8 · 실제 전송 9/13(shot_director 에 429 → secondary failover 1회) · Opik 성공 8 · 누계 89/93 · CP 둘 completed · `llm_called_scenes` 4 · 검색/받기/이미지 0. LP01·LP03·LP02 가 샷에 보이고 LP05 는 후보였으나 안 뽑힘(억지로 안 붙임).

원래 계획(참고):

canary ② 는 샷별 가시성이 있어야 잰다. 지금 그 CP 가 없다.

1. **호출 수를 다시 산출한다** — 논리 상한이 아니라 **물리 전송 최악**으로.
   `canary_cost_table` 의 caps × 키 슬롯 2 로 계산하고, 13 을 넘으면 안 연다.
2. Codex 재리뷰 → 승인.
3. `canary_run.py --live --run-id 69e821758f3d --mode v2_chunk
   --fixture period_episode --target shot_director` 로 **그 두 스텝만**
   (`reopen` 갈래를 쓰거나 target 을 옮긴다).
   검색·받기·이미지 승인은 **0** 으로 잠근다.
4. Opik · `transport_used.jsonl` · attempt 장부 셋으로 대조한다.

### ② ✅ 끝남 2026-09-02 — canary ② 실측

다섯 축 통과 · provider 0 · exit 0 · `artifact/20260902_canary2/payload_probe.json`. sidecar [LP01, LP03] · 정책 [P01] · 미확인 0 · 겹침 0 · sha 누수 0 · declared sha == 실린 bytes sha. ★probe 결함 둘을 고쳤다(e0540bcd): final_id 키 덮어쓰기(subject 키로) · 첫 축 기대를 「확인됨 ∩ 보임」으로. 정책 감사에 `fidelity_rejected` 칸(8374cc33).

원래 계획(참고):

```
python tools/grounding_audit/canary_payload_probe.py \
  --project-id 8e2e65b7-e910-4b12-b081-c23de0affab5 \
  --episode-id 9e64c302-82e6-4407-b560-8c70c2ab7192 \
  --database-url postgresql://theroad:theroad_dev_2026@localhost/theroad_canary_69e821758f3d \
  --projects-dir <artifact/canary_69e821758f3d/projects> \
  --out artifact/20260902_canary2
```

받아야 할 축(도구가 `verdicts` 로 낸다):
확인된 배경이 sidecar 에 실린다 · 확인 안 된 것은 **0** ·
prop 은 정책 lane 으로만 · 두 lane 중복 **0** ·
같은 bytes 를 쓰는 거절/미확인이 **안 샌다**.

### ③ ✅ 끝남 2026-09-02 (무료) — 현대 배경 고증 축

v2_chunk 활성 경로에 시대를 요구하는 자리 0(코드 확인). production 변경 0. fixture `modern_episode`(ERA "" · REGION 만) + 시험 32(97970e45). 자세한 것은 docs/TASKS.md 「현대·지역 고증 축」 줄. Codex 재리뷰 대기 · 유료 현대 canary 는 별도 승인.

### ③-b ✅ 끝남 2026-09-02 16:16 — 1단계 canary(배경 off · world_guide 까지 글만) 완주

attempt e02db4801500 completed · 누계 135/150 · 사이드카 LP01(씬1샷1)·LP03(씬2샷4) 이 production scene_detail 카드에 identity·sha·파일 좌표로 결속 · 못 구한 줄 9 는 부착 0. 오늘 서고 고친 다섯(docs/TASKS.md 「1단계 canary」 줄) — 전부 Codex 재리뷰. 무료 exit probe 는 readiness 문(`gate.incomplete_references` · 참조 이미지 14개 미생성)에서 섬(전송 0).

★이어받는 사람이 알아야 할 것: ①`BACKGROUND_MODE=off` 로 process 를 띄워야 한다(`--background off` 는 선언·대조만) ②canary CLI 는 env 를 settings 보다 먼저 박고 `app.core.config`/`database` 미로드를 fail-closed 로 확인한다 — 모듈 import 때 settings 를 읽는 호출을 넣지 마라 ③계측 단위는 `METERING_UNITS`(읽어 확인한 것만) × `CALLS_PER_UNIT`(hard) · 정상 예상은 단위당 1 ④partial 은 cap 0 되쓰기가 아니다 ⑤사이드카 sha·좌표는 `grounding_sidecar_writer.row_content_sha256`/`row_file_coordinate` 한 곳(좌표 둘 대조).

### ④ 2단계 — 이미지 (**별도 승인 · 안 열었다**)

최종 씬 이미지 1장은 구조상 불가(앞에 ref_image_gen 11 · composite 4 · variant · scene 14). 정직한 단위는 ≈30장의 「이미지 canary」. `APPROVED_IMAGE_CALLS=0` 상수는 2단계 승인표와 원자적으로 바꾼다. 2단계 상한엔 scene LVM 검증·재생성 갈래도 각각 명시해야 한다(Codex). exit probe 의 HTTP 직전 캡처는 그 뒤에만 닿는다.


---

### ④-c ✅ 2026-09-02 19:43 — modern_episode canary **한 attempt 완주** · A/B 갤러리 · 둘 다 **사람 판정 대기**

- A/B: `artifact/canary_69e821758f3d/gallery_ab/index.html`(정답표 `ab_key.json` 페이지 밖). clone DB
  `theroad_canary_69e821758f3daa` / `…bb` 는 실험 사본(원본 아님).
- modern: run `be17560a08d0`(코드 175c2b6c). 16 대상 · 사진 9 · 씬 6/6(고증 사진 없이). 판정 backend 8942
  (`DATABASE_URL=…theroad_canary_be17560a08d0` · `PROJECTS_DIR=artifact/canary_be17560a08d0/projects`) — TASKS 표의 URL.
  판정 뒤 순서: `canary_ab_arms.reproject_sidecar` 식으로 씬1샷1 카드 재투영(LLM 0) → 씬 이미지 재생성(이미지 문 80 안) → 사람 비교.
- 도구 변경: 중앙 조사 대상 = `AXIS_BASIS.hard`(뜻) · 앞단 18 스텝 계측(period 실측 대조) · 새 run 은 dry→live 로 바로 갔다.

### ④-b ✅ 2026-09-02 18:52 — stage2a **유료 완주** (이미지 19 · 글 171 · 코드 3e2debb1)

- 사용자 지시(Codex 전달): **속도 우선 · 소액 재승인 왕복 금지** → 글 240 · 이미지 80(범위 결속). 다섯 attempt 에서
  서고 고친 것 다섯(위 TASKS 표) — 전부 유료 0 에서 fail-closed 로 섰다. 씬 7/7 · exit probe 에 사이드카 sha 실림.
- 갤러리 `artifact/canary_69e821758f3d/gallery_stage2a/index.html` — 판정은 사람만(§5·§6).
- **다음**: A/B arm B — 별도 run_id · canary DB·artifact clone · clone 에서 LP01/LP03 두 판정만 무효화(원본 표 불변) ·
  production helper 로 사이드카 재투영(LLM 재호출 0) · 두 샷 × 2~3회 ≤12장 · 사람이 순서 가려 판정. 그 다음 현대
  배경 fixture(`modern_episode`) canary · merge 전 정리(pg lane 옛 fake · xdist 워커 DB 안전문 · wide 한 번).
- ★live 명령: env 여섯 + `--live --run-id 69e821758f3d --mode v2_chunk --fixture period_episode --target scene_image_pipeline
  --background off --still-recipe off --outdoor off`. 코드가 바뀌면 전이(`record_transition_stage2.py` 식으로
  `record_code_transition`)를 먼저 적어야 잇는다.

### ④-a ✅ 2026-09-02 저녁 — 2단계 무료 준비 전부 끝 (유료 0) · **사용자 승인 대기**

- Codex BLOCK 셋 닫음: ①LP 집행자 하나(`canonical_ref_owner_types` · db78acea) ②verified C/P 사진이
  canonical ref 생성 입력에 실림(`grounding_canonical_ref_inputs` · db78acea) ③재개 신선도 = 입력 지문
  (자산+CP 행 둘 다 · `is_fresh` · v2_chunk 직접 API fail-closed · step 지문 · f60ad840).
  gpt-image 문 구멍 여섯 + AST 래칫(db78acea). Codex 는 셋 다 APPROVE.
- canary 도구: lane 축 셋(background·still_recipe·outdoor · f93e7448) · fixture `HAS_OUTLOOKS` ·
  run 신원 대조(`assert_scenario_matches_run`) · 이미지 스텝 넷 계측 + 이미지 표 + fixture 상한 둘 +
  대조 문 둘 + CP 에서 읽은 실제 수(a9f40478).
- **dry 표(산출 #35 · 전이 677a9a1d554f)**: unknown 0 · unverified 0 · 실제 이미지 **31**(참조 9 · 합성 8 ·
  씬 14) · hard 253 · LVM 글 34/68. 제안 정지선: 글 counted 150→**210** · `APPROVED_IMAGE_CALLS` 0→**40**.
- Codex 비용 상한 BLOCK 둘도 닫음(d543fa1b): 이미지 cap run 전체 누계 · 이미지 승인 scope 결속(`APPROVED_IMAGES_BY_SCOPE`).
- **다음 사람이 할 일**: ①사용자 승인(210/40) → `APPROVED_BY_MODE["v2_chunk"]["counted"]` 150→210 과
  `APPROVED_IMAGES_BY_SCOPE[("v2_chunk","period_episode","scene_image_pipeline","off","off","off")] = 40` 을 그 표와 **원자적으로** 고쳐 커밋 → 전이 기록 → live
  (`--live --target scene_image_pipeline --background off --still-recipe off --outdoor off`, env 여섯 개를
  process 앞에) ②끝나면 exit probe(HTTP 직전 캡처 · 사이드카 sha 실림) ③A/B arm B 는 별도 run_id · clone
  에서 LP01/LP03 두 판정만 무효화 · 사람이 순서 가려 판정 ④merge 전 정리: pg lane
  `test_form_reference_lineage_pg` 의 옛 fake(`pick_structure_desc`).
- ★환경 변수 여섯을 **process 시작 전에** 줘야 한다 — 안 주면 `scenario()` 가 선언과 실제가 다르다고 선다:
  `BACKGROUND_MODE=off STILL_RECIPE_MODE=off OUTDOOR_LANE_PLAN_ENABLED=false OUTDOOR_LANE_PIPE_ENABLED=false
  OUTDOOR_DIRECT_COMPOSE_ENABLED=false OUTDOOR_MAP_CONTI_ENABLED=false`.

## 6. 사용자 요구 — 현대 배경도 고증한다

> 「너 잊지말고 이것 구현후에 꼭 "주유소", 한국식 "편의점 + 앞쪽 벤치" 등
> 현대 배경이라도 고증이 필요한 경우는 되도록 진행해야해」 (2026-09-02)

- **시대가 기준이 아니다.** 판별은 두 축뿐이다 —
  「모델이 근거 없이 그리면 **겉모습을 틀릴 만한가**」 ·
  「틀렸을 때 **그곳 사정을 아는 사람이 알아채는가**」.
- 주유소·편의점·약국·개찰구는 나라마다 간판·구조·기계가 다르고 모델이
  모른다. 그래서 **현대여도 두 축에 걸린다.**
- ★★★그 낱말들은 **사례일 뿐이다.** production 코드·프롬프트에 장소명·
  나라명·상표명·명사 목록·정규식 분기를 **넣지 마라**. 입력 시나리오나
  fixture 원고에만 나온다. 넣는 순간 그것이 하드코딩이다.
- 할 일: **현대 원고 fixture**(시대 선언 **없음** · 지역만)를 새로 만들고,
  `docs/TASKS.md` 의 「현대·지역 고증 축」 무료 acceptance **일곱**을 그
  원고로 통과시킨다. 특히 ①시대 없이 지역만 있는 현대 장소가 두 축으로
  target 이 되는가 ②같은 배경의 쉬운 대상은 **음성 대조로 비대상**인가.
- 이미 서 있는 문: `assert_coordinates_carried` 가 **지역만 선언되면
  지역을 의무**로 보고, **시대가 없으면 만들지도 요구하지도 않는다**.

---

## 7. 이어받는 사람이 꼭 알아야 할 것

### 오늘 가장 많이 낸 결함 — 「끝났다」와 「못 봤다」를 안 가름

하루에 **다섯 자리**에서 났다. 한 칸이 두 뜻이면 읽는 쪽이 **유리하게**
읽는다 — 「없다」로 읽으면 지나가고, 「못 봤다」로 읽으면 또 산다.
그리고 셋 다 **초록으로 보인다**.
→ `~/.claude/.../memory/feedback-nothing-found-vs-never-looked.md`

### 이 판에서 반복해서 데인 것

- **같은 값을 두 곳에 적으면 한쪽만 고쳐진다.** 오늘도 났다
  (`shot_director` 스텝 상수만 올리고 manifest 를 안 올려 기준선 밖 새
  실패 1). 판·규칙을 더할 땐 **그 값을 복사하는 줄**을 먼저 찾아라.
- **조립 자리에서 재지 마라.** 「붙는 것 0」이라 보고했는데 집행자 **둘 중
  하나만** 쟀다. 소비자가 몇인지 먼저 세라.
- **계약만 있고 내는/읽는 곳이 0곳.** `apply_reviews` 를 만들어 놓고
  production 호출자가 없었다. 만들었으면 **부르는 줄**을 찾아라.
- **글자로 금지를 막지 마라** — 그 금지를 적은 주석·제 함수 이름·
  `hashlib.update` 가 걸렸다. AST 로 보고 docstring 을 벗겨라.
- **fixture 가 결함을 숨긴다.** 이제 `verified` 는 **DB 에 행이 있어야**
  성립한다(줄에 손으로 적은 값은 투영이 덮는다). 대역 session 을 끼우면
  판정이 통째로 안 보인다.
- **빈손은 모든 축을 지나간다.** 「없다」를 세기 전에 **있는지** 먼저 봐라.

### 도구 자리

```
tools/grounding_audit/canary_run.py            canary 입구(재개 문·전이 기록)
tools/grounding_audit/canary_payload_probe.py  canary ② 측정(provider 안 부름)
tools/grounding_audit/fidelity_review_page.py  판정 갤러리 생성(정적)
app/api/v1/grounding_fidelity.py               판정 받는 **유일한 문** + 화면
app/modules/pipeline/grounding_fidelity_review.py  DB→CP 투영 · 지문
```

판정 화면을 다시 띄우려면 canary 범위 backend 를 별도 포트로:

```
DATABASE_URL=postgresql://theroad:theroad_dev_2026@localhost/theroad_canary_69e821758f3d \
PROJECTS_DIR=<artifact/canary_69e821758f3d/projects> \
python -m uvicorn app.main:app --host 0.0.0.0 --port 8941
# → /api/v1/grounding-fidelity/login?next=…  (admin / admin123)
```

★**원본 DB·원본 projects 에는 쓰지 않는다.**

### ④-d 2026-09-02 밤 — 장소 신원의 진짜 원인 · Codex BLOCK 다섯 · run 45075f79441e 재개

- **오진 하나를 바로잡았다.** 「이발소·국밥집·골목이 L01 하나」는 판독기 지시문이 아니라 **격리**였다.
  판독기(팩 v6)는 장소 넷을 냈고, 「씬 밖 샷 결속 하나」로 셋이 **행째** 격리됐다(옛 run 12행 · 새 run 9행 —
  이발사·미닫이문·교복 윗도리도 함께). `grounding_chunk/manifest.json` 의 `grounding_quarantined` 에 다 적혀 있었다.
  → `resolve_rows` 는 이제 **검증된 자리만 남기고 뺀 것을 `salvage_problems` 로 적는다**. 지어낸 인용은 여전히 한
  자리도 못 받고, 검증된 언급 0 · 지어낸 근거 문장은 행째 격리 그대로. manifest 에 `grounding_salvaged`.
  멈춘 run 의 저장된 응답을 새 코드로 무료 재처리하면 31행 0 격리 · location 4(이발소 앞·안 분리) · 이발사 C02.
- **끝점 검사기** `tools/grounding_audit/location_identity_check.py --run-id RID --fixture period_episode` —
  좌표로만 잇는다. 옛 run 에 대면 ✗5.
- **Codex BLOCK 다섯**: ①2차 pass 상한(`_cap` = 대상 × pass) ③좌표 선언 production 입구(`PUT /projects/{id}/grounding-coordinates`)
  ⑤팩 5(고정 명사 예시 제거) 수용 · ②VLM 거친 선택 ④아웃룩 이중 구매는 근거로 거부(TASKS 표 참조).
- **run 45075f79441e**: 조사 단계 직전(글 45 · 이미지 0)에 멈춰 세웠다. 재개 = transition 기록 → `resume_period2.sh --dry` → `--live`.
  `grounding_chunk` 은 처리 계약이 바뀌어 다시 돌지만 판독기 응답 2건은 journal 재사용(재구매 0) — 하류는 무효화되어 다시 돈다.
- 다음: 재개 완주 → 검사기 → 두 샷 A/B 재생성(별도 clone) → 사람 판정.

### ④-e 2026-09-02 밤 늦게 — 재개 다섯 번 서고 고침 · Codex BLOCK ①②③ 닫음 · 일곱 번째 attempt 진행

- **재개가 옛 CP 로 지나갔었다.** runner 의 drift BLOCK(409) 을 `run_steps_batch` 가 삼키고 canary 는 completed 로 되읽었다.
  이제 `canary_pipeline.contract_drift_of`(runner 의 `_check_cp_mismatch`) → `plan_reentry` 표(어긋남+승인 전이 → force).
  근본: `grounding_chunk_step` 이 제 지문을 CP 에 안 적어 재개마다 drift 였다(이제 적는다).
- 그 뒤 유료 0 으로 넷 더: git_tip dict/str · not_applicable drift · journal 상한(자리 수 `slot`) · `grounding_salvaged` NameError.
  → [[feedback-my-fake-was-a-str-the-real-thing-was-a-dict]]
- **일곱 번째 attempt 21c47e1b**: grounding_chunk CP = processing 4.202609022340 · location 4 · salvaged 9 · quarantined 0. 하류 진행 중.
- Codex BLOCK ①(근거 씬 결속: 다른 씬 근거는 그 문장만 빼고 기록) ②(좌표 PUT 쓰기 문 `deps.require_project_write`) ③(후보별 사람 검토:
  `review_inputs_for` 행×후보 · `apply_reviews` 가 verified 후보를 chosen 으로 승격) 전부 코드+시험. 12cb56a1 은 Codex APPROVE.
- 완주 뒤 acceptance 표: chunk CP config_hash == `_config_hash()` · processing 4 · salvaged 존재 · `location_identity_check` 4 locations/LP parents/cross-ref 0.

### ④-f 2026-09-03 새벽 — HITL 0 · 자동 획득 5단계 · 대상 병렬 · 야외 보충 · 조사 재실행 완주

- **야외 ON 유료 canary 1판 `4398a55dc0bb` (04:26~04:43 · exit 0 · 글 63)** — ③④⑤ **미확정**. 실제 수: 실외 그룹 1 · unique loc 1.
  manifest 에 `outdoor_structure_form_reference → reference_acquisition` 의존이 없어 중앙 CP 없이 돌았고 `acquisition_owner` 가
  legacy 구매로 내려갔다(제공자 4회 · 보충 CP 0). 수리 셋(side worktree `feat/grounding-parallel-acquire`): `918e1fbb` 의존 +
  사는 모드 front 없으면 422 · `93dd009a` 소유권 전환을 config hash 에 결속(Codex BLOCK) · `e3d6a104` producer 그룹 상한 문 + 언어 문.
  다음: 병합 → 같은 run 에 transition+dry 먼저 → 거절 사유가 scope 계약일 때만 fresh `f7cc45c576c0`. 자세히 설계 문서 §8 정정 둘.
- **2판(같은 run 재개, 05:04~05:13) acceptance ①~⑦ ✅** · 3판 재개 provider 0. Codex 긴급 BLOCK(중앙 상한 계획 때 수) → provider 앞 문 `faf70a87`/`00f02dc1` ·
  정지 요청이 검색 실패로 접히던 것 `cd210f76`. main tip `cd210f76`. 자세히 설계 문서 §8 정정 셋.
- **배경 사슬 네 스텝 계측 단위** `295ff202`·`d0ff43dc` — 통합 canary(배경 on → scene_detail) 의 unverified 0.
- **통합 canary `f7cc45c576c0`(배경 on + outdoor on → scene_detail) 통과** — 5 attempt · 누계 228/480 · 이미지 1. 서고 고친 다섯(큐 신원 · 팩 버전 · sync 동명 ·
  렌더 스텝 문 · policy 지문 불일치) + 재개 idempotency 연속 3회 0 + outbound 소비자 문. 한 run 야외 통합은 미측정(닫힘 밖). 설계 §8 정정 다섯.
- **취소 = 자동 재시도 빚**(Codex BLOCK 05:30) `fe428dae`·`3ebd32dc`·`85617c9c` — 봉인된 CP 를 plain resume 이 RERUN_SELF 로 연다.
  live 4판(빚 재개) 05:52 시작. main tip `85617c9c`.
- **live 4판 끝(06:00) acceptance 1~6 실측 통과** — 7 재구매 0 · 9 만 구매(다 selected) · 최종 CP pending 0 · projection 동일 · 직후 plain resume provider 0. 누계 126/480.

**최상위 불변식(사용자 재지시 · TASKS 머리)**: 실서비스는 사람 없이 끝까지 간다. 사람 판정/선택 행이 0건이어도
자동 선택 한 장이 참조로 붙는다. 검토 화면·판정 표는 canary·A/B·사후 평가 도구다. 검토 75건 뒤 usable 1/18 이던
결함(사람을 문으로 세움)을 d954c5b7 로 걷었다 — `usable_as_reference = outcome == selected` · production 소비자는 날것 CP.

**자동 획득 5단계(af5344eb · 4b3fadc4)**: `grounding_target_research`(웹 조사 1회/대상: what_it_is · appearance_criteria ·
narrow/rough 질의 · 원고 근거 전문 · 근거 지문이 신원에) → 좁은 검색 → `coarse_type_pick` v2(criteria_match · similarity) →
넓은 재검색 → 마지막엔 반드시 한 장(`select_closest` · 판정 실패면 검색 순위 첫 장 · forced_reason). 받은 것 0 + 실패만 retryable.

**대상 병렬(6412fe5b · 56047391 · Codex APPROVE)**: `ca.run(workers=)` bounded pool(`grounding_acquire_workers` 기본 4 · 상한 8) ·
1차 전원 join 뒤 2차 · 결과 index 순 · 워커는 {ident,result} · 예산/정지 표 워커 전달 · fatal 뒤 pending 0(abort Event) ·
`OutboundBudget`/`RawFetchObserver` RLock · 조사 저작기는 legacy alias 를 안 냄.

**야외 structure_form 보충(설계 §8)**: 21.915 가 앞쪽 소유 판에서 `structure_form` 의무를 ID 로만 세우고 중앙 조사기와 같은
공장(`reference_acquisition_step.make_*`)·같은 `ca.run` 으로 산다 · 별도 CP append-only · merge view 하나 · 구조 오류는 provider 앞.
★outdoor ON 유료 canary 는 아직 안 돌렸다.

**run 45075f79441e 조사 재실행(02:11→02:58)**: 17/17 selected(기준 13 · closest 4) · alias 0 · 조사 호출 17 · acceptance overall_ok ·
글 누계 352/480 · OpenAI primary 키 credit 소진(secondary 슬롯). 03:07 이미지 단계 live(`scratchpad/period2_live43.log`).

**이어받는 사람이 볼 것**: 전이 기록의 from_tip 은 **마지막 attempt 의 tip** · 유료 프로세스가 도는 worktree 는 immutable(별도 worktree
`TheRoad-I1-parallel`) · 병렬 시험을 같은 DB/worktree 에서 같이 돌리면 거짓 실패가 난다.


## ⑤ 2026-09-03 08:10 — 인수인계 (Codex 승인 뒤 정리 · 모델 교체 지점)

### 단계 판정 (Codex 08:00)
| 단계 | 판정 | 근거 |
|---|---|---|
| 배경 → scene_detail 통합 | **통과** | run `f7cc45c576c0` · 5 attempt · 누계 글 228/480 · 이미지 1/18 · 중앙 15/15 · 배경 사슬 5 스텝 completed · scene_detail 8/8 · payload probe 5/5 · HITL 0 |
| 야외 structure_form 보충 | **독립 통과 7/7** | run `4398a55dc0bb` · `outdoor_acceptance.json` · 같은 run 재개 provider 0 |
| 한 run 야외 통합 | **미측정 · 별도** | scene_detail 닫힘에 야외 lane 없음(실측) — 새 유료 run 안 엶 |
| 재개 idempotency | **통과** | 연속 plain resume 3회 counted 0 · provider 0 · RECOVERY 0 · status 변화 0 (run_id 는 not_applicable 9행만) |
| outbound 소비자 문 | **통과** | 소비자 계약 `grounding_outbound_consumers.OUTBOUND_CONSUMER_STEPS` · 끝점 셋 · AST 잠금 |
| HITL | 0 | production 소비자는 중앙 CP 날것 · 사람 화면은 개발 감사 도구 |

### 정확한 재개 지점
- main `fix/outlook-phase2-no-borrow` tip = **`2d56609b`**(시험 셋 뒤집음 · 팩 래칫 굳힘) + 이 문서 commit. PR #82 OPEN(본문에 기준선 결과까지 갱신됨). 이 뒤로 유료 run 은 열지 않았다 — 여기가 모델 교체 지점이다.
- 두 canary run 은 모두 terminal · 열린 attempt 0. 다시 재개하려면 `run_integration.sh --dry` / `run_outdoor.sh --dry` 로 시작(전이 기록 먼저). 스크립트 사본은 `artifact/canary_f7cc45c576c0/`(run_*.sh · accept_*.py · idempotency.sh) — scratchpad 는 세션 한정이라 옮겨 두었다. `--live` 는 사용자 승인 뒤.
- 다음 유료 판을 열 때 반드시: dry 의 `forced_for_drift`/`reopened_for_debt`/`outbound_doors_this_attempt.consumers`/`image_sources` 를 읽고, 이미지 승인표(`APPROVED_IMAGES_BY_SCOPE`)·허용 source(`ALLOWED_IMAGE_STEPS_BY_SCOPE`) 에 그 범위가 있는지 본다.

### 남은 별도 항목 (열지 않은 것)
1. one-run outdoor integration — 야외 lane 을 소비하는 하류(scene_image_pipeline 계열)가 릴리스 범위에 들 때, target 을 그 하류로 잡은 새 run.
2. A/B 갤러리 사람 판정 — `artifact/20260903_period_ab_gallery/index.html` (key `artifact/ab_key.json`), §6.5b 에 결과 기록.
3. 남은 unverified 계측 단위: outdoor_structure_seed · background_render · shot_ref_classify · shot_continuity · shot_conti_light.
4. 기준선 밖 실패로 남긴 것(내 변경과 무관, main 에서도 실패): tests/core 의 key_failover 7 · opik_metadata 6 · visible_entities 3 · shot_conti_light 2 · outdoor_place_spec 1 · background_prompt_v7 1 (재확인은 아래 기준선 표).

### 기준선 회귀 결과 (2026-09-03 08:20 · 무료)
| 판 | 명령 | 결과 |
|---|---|---|
| 전체 suite · tip `0e988c38` | `pytest -q -p no:cacheprovider tests` (backend · 단일 프로세스) | **43 실패 / 10530 통과** · 16 파일 |
| 기준선 · 시작 tip `1d26aaad` | 같은 16 파일만 · side worktree detached | **40 실패** · 14 파일 |
| 양방향 차집합 | `comm` on FAILED id | tip 에만: **3** · 기준선에만: **0** |

tip 에만 있던 셋은 전부 **바뀐 계약을 옛 판으로 잠근 시험**이라 지우지 않고 뒤집었다(`2d56609b`):
`test_the_canary_declares_background_mode_honestly` 둘(문은 중앙 스텝 하나가 아니라 소비자 계약 전부가 끝나야 0) ·
`test_entity_sync_ext_inert::test_two_keys_pointing_at_different_canons_*`(short_id 가 정본 — 동명·다른 short_id 행은 남의 행이지 `SyncKeyConflict` 가 아니다).
같은 commit 에서 팩 래칫 기준선(`tests/_baselines/published_packs.json`, 508 팩 · v15 포함)을 굳혀 그 시험도 통과.
남은 40 은 기준선과 **같은 집합**(id 단위): episode_projection_strict 12 · openai_key_failover 7 · build_opik_metadata 6 · visible_entities_validator 3 ·
era_research 2 · shot_conti_light_lane 2 · step_config_drift_ack · select_judge_gemini_plus_sol(`outdoor_acceptance.py` 평문 비밀번호 — 기준선에도 같은 메시지) ·
canary_3defects_fix · all_provider_calls_are_traced(`grounding_claims_search._armed_create`) · still_cine_stage · outdoor_place_spec_step · background_prompt_step_v7 각 1.
★수 대조가 아니라 집합 대조다 — 로그: scratchpad `final_suite.log` · `baseline_1d26aaad.log` · `failing_lines.log`(세션 종료 뒤 사라진다 · 명령은 위 표).

### 오늘 서고 고친 자리 (재발 방지 규칙)
manifest 의존 누락 → legacy 구매 · 소유권 전환 hash 미결속 · 중앙 상한 계획 때 수 · 정지 요청이 검색 실패로 · 취소 9줄 completed 봉인 · 엔티티 큐 (name,type) dedupe ·
팩 버전 lexical 오독(진짜 loader 로 시험) · sync 동명 합침 · 렌더 스텝 문 0(이미지 호출도 스텝 문) · policy 스텝 저장/비교 지문 불일치(매 재개 하류 재구매) ·
소비자 계약을 스텝 모듈에서 import(자물쇠 전 DB 로드). 자세히 설계 문서 §8 정정 둘~다섯, 메모리 `feedback-a-free-steps-drift-rebuys-paid-downstream`.

## ⑥ 2026-09-03 09:35 — 한 run 야외 통합 통과 (Codex 09:30) · 남은 것은 §6.5 사람 평가

| 단계 | 판정 | 근거 |
|---|---|---|
| 한 run 야외 통합 (같은 run `f7cc45c576c0` → target seed) | **통과** | attempt 547b63787ab4 completed · `seed_integration_acceptance.json` A~F overall_ok · `link_report_seed.txt` 양방향(21.915 asset a34cdc4f ↔ image_asset 행 ↔ seed form_reference_input ↔ seed 자산 636a7867 input_image_ids) |
| 21.915 보충 재실행 | provider 0 | journal_supplement 재생 · llm_call_log 검색/조사 0 |
| entity_detail | 재실행 0 | hash adoption 8cd4198bba62 · data digest bbb20a5a 전후 동일 · 백업 manifest_pre_adoption_8cd4198bba62.json |
| 돈 | 글 243/480 · 이미지 장부 차감 7/18 (실제 전송 7 = 성공 3 · 오류 4) | 장부 `pipeline_attempts.json` · llm_call_log |

### 정확한 재개 지점
- main `fix/outlook-phase2-no-borrow` tip = **`af9f54ce`** + 이 문서 commit. PR #82 OPEN. run 은 terminal · 열린 attempt 0 · 다음 유료 판 없음.
- 이 run 을 더 잇는다면(예: shot_conti_light 까지) 먼저 unverified 3 스텝의 loop 를 읽어 단위를 선언하고(`METERING_UNITS`), 이미지 승인 범위(`APPROVED_IMAGES_BY_SCOPE`)에 그 target 을 더한 뒤 `run_seed.sh` 를 본떠 dry → Codex → live.
- 도구 사본: `artifact/canary_f7cc45c576c0/` — run_seed.sh · accept_seed_integration.py · link_report.py · adopt_entity_detail.py · record_transition_seed.py · supersede_transition_b6dfaa63a2b6.py · opik_seed_window.py · seed_live_attempt{1,2,3}.log · go_check_seed_attempt3.json · adoption_tuple_entity_detail.json.

### 남은 별도 항목
1. **§6.5b 사람 평가** — A/B 갤러리 `http://<LAN IP>:8940/artifact/20260903_period_ab_gallery/index.html` (key `artifact/ab_key.json`). 사용자 판정 결과를 TASKS·설계 문서에 적는다. production 문이 아니다(HITL 0).
2. unverified 계측 단위 3 — background_render · shot_continuity(SINGLE 2 + pose_fix 샷마다 — shot_continuity_author:375/409/505 읽음 · 표는 아직) · shot_conti_light.
3. adoption 사건 two-phase(Codex NON-BLOCK) · 이미지 문 셈에서 「예약 차감」과 「실제 전송」 칸 분리.

### 오늘 서고 고친 자리 (추가)
지문 어긋남의 force 연쇄를 dry 가 안 보여 줌 → `forced_would_invalidate_of` · 범용 drift_ack(자기만 다시·하류 보존)는 계보 단절이라 걷음(Codex BLOCK) → 정확한 hash adoption ·
투영이 자산을 안 묶어 seed fail-closed → `_bind_projected_asset` · 제 chain 이 `cut | tee` 로 사건 id 를 잘라 전이가 빈 목록으로 적힘 → supersedes 로 정정 ·
「이미지 1/18」이 completed attempt 의 성공만 센 수였음(장부 누계 5) → GO 직전에 **정지선 계산 함수**로 다시 재서 멈추고 Codex 에 물음. 메모리 `feedback-hash-recipe-drift-is-adopted-not-rerun`.

### 기준선 회귀 결과 둘째 (2026-09-03 09:50 · 최종 tip c739355a · 무료)
| 판 | 명령 | 결과 |
|---|---|---|
| 전체 suite · tip `a300ff3e` | `pytest -q -p no:cacheprovider tests` (backend) | **110 실패 / 13999 통과 / 60 skip** (08:20 판은 43/10530 — 같은 명령인데 모집단이 달랐다. 그때는 integration·scripts·prompts·최상위 시험이 빠졌고 왜 빠졌는지 못 밝혔다 — 이번 둘째 표가 정본) |
| 새 실패 파일 40 · 기준선 `1d26aaad` | 같은 40 파일 · side worktree(untracked 시험 7 파일을 복사해 넣고 · 처음엔 그 파일이 없어 pytest 가 시작 전에 서서 「실패 0」이 거짓으로 나왔다) | 149 실패 |
| 같은 40 파일 · tip `c739355a` | 같은 명령·같은 순서 | 70 실패 |
| 양방향 차집합 | tip 에만 **1** · 기준선에만 80 | tip 에만: `test_manifest_fields::test_resume_sensitive_steps_are_shot_more_cohort` — **순서 의존**(혼자 돌리면 두 tip 모두 실패 · `grounding_chunk` resume_sensitive 는 09-01 2520ab8c) · 이 세션의 manifest diff 는 depends_on 네 줄뿐 → 회귀 아님 |

이 세션의 진짜 회귀는 하나 있었고 닫았다: `test_form_reference_source_lock::test_producer_does_not_mint_its_own_asset_uuid`(투영 자산 id 를 스텝에서 uuid5 로 만들었다) → id 정책을 `form_ref_rounds.projected_asset_id` 로 옮김(`c739355a`). 기준선에서도 실패하는 것들 중 눈에 띄는 부류: `test_step_runner_run_flow` 7(08-30 26845fe88 의 `project_config` 결함) · manifest/catalog 수 시험(오래된 기대값) · `test_call_structured_fallback` 2 · api no-key 시험 4.

### §6.5 사람 평가 패키지 (2026-09-03 10:05 · 사용자가 할 것)
| 무엇 | 어디 |
|---|---|
| 기록 양식(판정을 여기 적는다) | `artifact/20260903_human_eval_template.md` — http://<LAN IP>:8940/artifact/20260903_human_eval_template.md |
| 두 샷 A/B 갤러리 (§6.5b) | http://<LAN IP>:8940/artifact/20260903_period_ab_gallery/index.html · 키 `artifact/ab_key.json` (다 적은 뒤 연다) |
| 참조 고증 화면 — 중앙 15 (86장) | http://<LAN IP>:8940/artifact/20260903_fidelity_review_f7cc45c576c0/reference_acquisition/review.html |
| 참조 고증 화면 — 보충 L02 (8장) | http://<LAN IP>:8940/artifact/20260903_fidelity_review_f7cc45c576c0/reference_acquisition_supplement/review.html |
| seed 산출 | `artifact/canary_f7cc45c576c0/projects/<pid>/…/outdoor_structure_seed/` |

LAN IP 는 `ipconfig getifaddr en0` (오늘 192.168.231.91). 화면은 개발 도구라 단추는 정적 판에서 안 눌린다 — 양식에 적는다. 판정이 적히면 TASKS §6.5b 행과 설계 §8 정정 여섯 「남은 것」에 옮기고 그때 full V2 완료를 선언한다.

### 다섯 갈래 끝점 — 이 run 에서 다시 잼 (2026-09-03 10:00 · `canary_payload_probe.py` · provider 0)
`artifact/canary_f7cc45c576c0/payload_probe_20260903/payload_probe.json`: 샷 8 · 다섯 축 전부 통과 — sidecar [L01, L02, L03, LP03, LP06](location·location_part) · 정책 lane [P01~P05](prop) · 확인 안 된 것 payload 0 · 두 lane 겹침 0 · 거절/미확인 bytes 누수 0. character·outlook 갈래는 앞 단계(entity_detail→entity_t2i→sync 신원 계약 · outlook_phase1~3)에서 닫혔다(④-f).
★probe 는 `--projects-dir` 가 아니라 settings 의 `PROJECTS_DIR` 로 CP 를 읽는다 — env 를 run 으로 맞춰 돌린다. 첫 시도는 제 셸이 project id 를 한 단 위 디렉토리로 잘못 잡아 「shot_director 없음」이 났다.

### unverified 계측 단위 3 — 읽어 둔 사실 (선언은 다음 판을 열 때)
- `shot_continuity`(shot_continuity_author.run_shot_continuity): pose_canon 1(:375) + carried 1(:409) + **pose_fix 는 (인물, 샷) 짝마다 1**(:505 · `for it in pose_canon: for tag in it["shots"]`) — 단위가 「판 2 + 짝 N」이라 지금 표(스텝당 한 단위)에 안 맞는다. 짝 수의 상한(선택 샷 × 샷당 인물)을 fixture 로 잠그면 SHOT 단위로 적을 수 있다.
- `background_render`: background 마다 `render_one_background(max_attempts=2)` 이미지 1(정상)/2(hard) · plate_multiroll·no_people_gate 는 기본 off — `app/modules/pipeline/background_render.py` 안의 VLM 호출 유무를 아직 안 읽었다.
- `shot_conti_light`: lane 샷마다 마커 맵(모델 수 × LANE_MARKER_ANNOTATE_MAX_ATTEMPTS 3 · 이미지) + marker_check(VLM · 시도마다) + 스케치(LANE_LEAKAGE_MAX_ATTEMPTS 3 · 이미지+누출 VLM) + 콘티(:509 시도 2) + bg_gen — 상한을 적으려면 :1208~1760 을 다 읽어야 한다.

## ⑦ 2026-09-03 10:20 — full V2 완료 (사용자 판단 기준) · 최종 요약 · 재개 지점

**사용자 지시:** 「정리시켜. 잘 되는 것 같아.」 → 「사용자 판단: 현재 결과는 잘 되는 것으로 보이며 추가 수동 평가 없이 마감」. §6.5 갤러리 평가는 선택적 후속/보존된 감사 자료 · production HITL 요구 0 · 미실시를 실패나 BLOCK 으로 해석하지 않음. A/B 의 구체적 승패는 적지 않는다(판정 안 함).

### 핵심 완료 범위 (증거 있음)
| 항목 | 상태 | 증거 |
|---|---|---|
| B-only C(c) BLOCK 무료 닫힘 · Codex 재리뷰 · B-only 실테스트 | ✅ | ④-a~④-f · 설계 §8 정정 하나~다섯 |
| C(c) production 원자 배선 · 다섯 갈래 producer→등록→의무→획득→소비 | ✅ | ④-f · `payload_probe_20260903/payload_probe.json`(다섯 축 통과) |
| 배경→scene_detail 통합 | ✅ | run `f7cc45c576c0` · ⑤ 표 |
| 야외 보충 독립 7/7 | ✅ | run `4398a55dc0bb` · `outdoor_acceptance.json` |
| 한 run 야외 통합 (21.915 → seed 링크) | ✅ | ⑥ · `seed_integration_acceptance.json` A~F · `link_report_seed.txt` |
| HITL 0 · 하드코딩/하드프롬프트 0 · VLM 은 거친 종류/가시성만 | ✅ | 설계 §7 · 소비자 계약 시험 |
| docs/TASKS·설계·HANDOFF·PR #82 동기화 · 기준선 밖 새 실패 0 · 재개/무효화/비용/감사 증거 | ✅ | ⑤·⑥ 기준선 표 둘 · `pipeline_attempts.json` · Opik/llm_call_log |
| §6.5 사람 평가 | ✅ 사용자 판단으로 마감 | 패키지 보존(⑥ 표) |

### 돈 (run f7cc45c576c0 · 최종)
글 243/480 · 이미지 장부 차감 7/18 · 실제 provider 전송 7(성공 3 · 오류 4) · 검색/받기는 마지막 세 판 0.

### 범위 밖 후속 (핵심 완료 범위 아님 · 열지 않았다)
1. unverified 계측 단위 3 — background_render · shot_continuity · shot_conti_light (읽어 둔 사실은 ⑥). 그 스텝을 canary 닫힘에 넣을 때 loop 를 읽어 `METERING_UNITS`·`CALLS_PER_UNIT`·`IMAGE_CALLS_PER_UNIT` 에 적고, `APPROVED_IMAGES_BY_SCOPE`·`ALLOWED_IMAGE_STEPS_BY_SCOPE` 에 그 target 을 더한다.
2. adoption 사건 two-phase(Codex NON-BLOCK) — manifest 교체 성공 뒤 append_event 실패의 좁은 창.
3. 이미지 문 셈에서 「예약 차감」과 「실제 전송」 칸 분리(장부에 둘 다 적기).

### 정확한 다음 재개 지점
- branch `fix/outlook-phase2-no-borrow` tip **`abcb2f7c`** + 이 문서 commit · origin 과 같음 · 트리 clean · PR #82 OPEN(본문 최신).
- 두 canary run 모두 terminal · 열린 attempt 0 · 유료 예약 없음.
- 다시 시작한다면: (a) PR #82 리뷰·병합, (b) 후속 1 을 하려면 `artifact/canary_f7cc45c576c0/run_seed.sh` 를 본떠 target 을 바꾸고 dry → Codex → live, (c) 도구 사본과 증거는 전부 `artifact/canary_f7cc45c576c0/` 와 `artifact/20260903_*`.

## ⑧ 2026-09-03 12:30 — PR #82 리뷰 수리 (5db210ce · 2e498074) · Codex 승인

전체 리뷰 `artifact/20260903_pr82_review.md`(리뷰어 넷 + 직접 file:line 확인 · 보안 축은 사용자 지시로 제외). 병합 전 다섯 + Codex P1 둘 + Codex 재리뷰 BLOCK 둘을 고쳤다:

| # | 무엇 | 어디 |
|---|---|---|
| 1 | legacy·v2 의 entity_detail/entity_t2i 지문을 옛 값 그대로(byte-identical) — 기존 에피소드 재개 409 회귀 | `entity_steps.py` `_config_hash` ×2 |
| 2 | 사는 lane(중앙·야외 보충)에 물리 전송 문 `research_run_scope`+`research_calls_armed` · worker 가 armed 를 물려받음 · `TRANSMISSIONS_PER_LOGICAL_SLOT=10` · `project_config[reference_transmission_cap]` 우선 | `reference_acquisition_step._central` · `outdoor_structure_form_reference_step` · `research_call_budget.bind_current_research_budget` |
| 3 | 승인 상한 자가 확대(`cap_n += orphan_slots`) 제거 — 상한은 지금 대상의 자리만(`reserve(slot_universe=)`) | `grounding_central_acquisition.run` · `grounding_chunk_journal.bought_slots/reserve` |
| 4 | journal: 우리 문(예산·마감·중단)이 세운 시도는 **그 논리 시도의 outbound 계수가 0 일 때만** `not_sent`, 하나라도 나갔거나 셀 수 없었으면 `uncertain`(연결·timeout 도 그대로) · 운영자 도구 `tools/grounding_audit/journal_settle.py` | `grounding_chunk_journal.buy_or_reuse` · `research_call_budget.OutboundAttempt` |
| 5 | API: `/verdicts` 인자 순서 · `require_episode`(Episode.id+project_id) 다섯 route · `_frozen`/`photo` 경로를 프로젝트 디렉토리 안으로 | `api/v1/grounding_fidelity.py` |

시험: `tests/grounding/test_pr82_review_fixes.py` 24 · `tests/api/test_grounding_fidelity_endpoints.py` 6(200/403/404·traversal · netprobe 0) · 사슬 시험 fixture 둘에 Episode 행. 넓은 회귀(grounding·tools·core·unit·api·services·modules·pipeline): **42 실패 / 12372 통과**, 실패 전부 기준선 집합 안(새 실패 0). Codex 재리뷰 둘: P1 둘 닫힘(5db210ce) → 새 BLOCK 둘(outbound 계수 · netprobe) 닫힘(2e498074) → **병합 승인**.

후속(병합 뒤 · 리뷰 파일 6~25 · T1~T7): 구매 신원에 모델(PICK_MODEL·SEARCH_ORCHESTRATOR) 접기 · plain v2 모드 정리(모드 집합에 남았는데 못 돈다) · closest 의 심판 평균 · 시험 정직성(어느 기계에서도 skip 6 · `or True` 2 · 새 판정 칸을 안 싣는 대역 8 파일).

### ⑧-b Codex 최종 재리뷰 BLOCK 셋 → 27650009
A) `journal_settle.load` 가 저장 contract 로 열고 끝점에서 contract 동일·calls 바이트 불변·settlements +1 확인 · B) `ChunkJournal.settle_reserved`(정확히 reserved · 원행 불변 · settlements 사건 · `_refold` 가 released 로) · CLI release 는 이것만 · C) 사는 lane 의 SDK 재시도 0(`openai_client(max_retries=0)` · writer client 전달) · judge `num_retries=0` · `TRANSMISSIONS_PER_LOGICAL_SLOT` 10→18(조사 1 + 검색 2 + 판정 2×3 tier = 9 · 키 슬롯 ×2). DB 시험 28(netprobe 0) · 회귀 42 실패 / 12378 통과 · 새 실패 0.

### ⑧-c Codex 최종 verdict (2026-09-03 13:10) — PR #82 병합 단계 **APPROVE** (27650009 · docs 100edf7e)
A·B·C 닫힘 확인(Codex 독립 재현: attempt 1 release 뒤 같은 identity 를 attempt 2 로 재예약해도 옛 settlement 가 새 시도를 안 가림 · max_retries/num_retries 0 이 실제 SDK/Router kwargs 까지 감). 표적 30 passed · netprobe 0.
**NON-BLOCK 후속:** legacy `ChunkJournal.release` 가 자동 canary 경로 둘(`bundle_canary_runner.py:320` · `canary_bootstrap.py:278`)에 남아 calls 원행을 제자리 변경한다 — 둘 다 provider 전송 0 이 확정된 자동 해제라 이중구매·오독 위험은 없고, journal 을 엄격 append-only 로 통일할 때 `settle_reserved` 경로로 옮긴다. 다음 단계: 사용자가 PR #82 병합.

