# task-3070 — 벤치마킹 이미지 프롬프트 구획 출력 보장 + CLI 타임아웃 180→420

- **팀**: dev4 (비슈누) · **레벨**: Lv.2 · **저장소**: `Jeon-Jonghyuk/InsuRo`
- **PR**: [#282](https://github.com/Jeon-Jonghyuk/InsuRo/pull/282) **draft** · base `bd0c5b4` · head `7b6167a` · mergeable=true
- **브랜치**: `task/task-3070-dev4`
- **범위**: PR 생성까지. 머지·배포는 ANU.
- **지시서 sha256(앞16)**: `0a05a174e575dac8` (대조 일치)

## 봉투 (한 줄)
B-1/B-2/C 구현·PR #282 draft·필수체크 **8/8 success**·회귀 3073→3102(+29, 실패 0)·변이 5종 전부 사망 —
다만 **실호출 A/B 는 결함을 재현하지 못했다(BASE 28/28 마커 정상)**, 수정본은 18/18 무퇴행.

## 요약

회장님 라이브 장애 2건 수정. **PR 까지만 — 머지는 ANU.**

| 작업 | 내용 | 상태 |
|---|---|---|
| B-1 | 최종 지시(§7)에 이미지 구획 요구 결선 | 완료 |
| B-2 | `_BENCHMARK_OUTPUT_SCOPE_RULE` 자기모순 제거 | 완료 |
| C | `CONTENT_CLI_TIMEOUT_SECONDS` 180 → 420 | 완료 |
| D · E | haiku 차단 · 본문키워드 재측정 | **지시대로 미수행** |

## 원인 규명 — 프로덕션 실패 산출물 직접 조회

`contents` `27ac814c…`(2026-08-30 20:47:21 KST, 5,491자)를 DB에서 직접 읽었다.

- `## 이미지 프롬프트` 마커 **부재** (ANU 실측 재현 확인)
- 대신 본문에 `**[이미지 삽입 N]**` 이 **정확히 6개** — 채널 프롬프트
  (`generateOptions.ts:22` naver-blog)의 *"4. 이미지 가이드: [이미지 삽입 위치] 표시 3~5곳"* 을 따랐다
- `## 📊 품질 체크리스트 결과` · `## 📋 메타 데이터` 래퍼 구획까지 출력 — 기존 [출력 범위] 규칙을 **정면 위반**

즉 모델은 "이미지 6개"를 **본문 내 인라인 표시로 이미 만족했다고 판단**하고 별도 구획을 만들지 않았다.
경쟁 지시가 이겼다.

★ 같은 채널 프롬프트에 *"소제목(■ 또는 ▶ 기호 사용, **`##` 마크다운 아님**)"* 이 있어
마커의 `##` 자체와도 충돌한다.

### t3068 과의 관계 — 이번 건은 **별개**

`insuro-api` 는 **18:52:30** 재기동됐고 t3068 머지는 **18:42:44** 였다.
장애 job(20:39~20:47)은 t3068 수정이 **이미 반영된** 서버에서 발생했다.
t3068(해시태그 후처리의 마커 파괴)은 정상 수정됐고, 남은 결함은 프롬프트 계약 쪽이다.

## ★ B-3 실호출 검증 — `claude -p` 46회

프로덕션 `benchmark_sources` 실데이터(대장암 자가진단, `image_count=6`)로
서버와 동일하게 프롬프트를 조립해 실호출했다.

| 조건 | 프롬프트 | N | 마커 | 개수정확 | 최소 | 최대 | >180s |
|---|---|---|---|---|---|---|---|
| BASE/sonnet | 4,098자 | 5 | 5/5 | 5/5 | 114.1s | 184.2s | 1 |
| BASE/haiku | 4,098자 | 5 | 5/5 | 5/5 | 127.3s | 233.3s | 2 |
| BASEPROD/sonnet | 7,763자 | 5 | 5/5 | 5/5 | 130.8s | 236.9s | 2 |
| BASEPROD/haiku | 7,763자 | 5 | 5/5 | 5/5 | 86.7s | 212.0s | 1 |
| BASEHARD/sonnet | 9,054자 | 4 | 4/4 | 4/4 | 208.2s | 225.4s | 4 |
| BASEHARD/haiku | 9,054자 | 4 | 4/4 | 4/4 | 104.0s | 241.7s | 1 |
| **FIXPROD/sonnet** | 7,980자 | 5 | **5/5** | **5/5** | 135.9s | 185.9s | 1 |
| **FIXPROD/haiku** | 7,980자 | 5 | **5/5** | **5/5** | 109.5s | 170.7s | 0 |
| **FIXHARD/sonnet** | 9,271자 | 4 | **4/4** | **4/4** | 145.4s | 195.5s | 2 |
| **FIXHARD/haiku** | 9,271자 | 4 | **4/4** | **4/4** | 133.7s | 224.4s | 1 |

- 수정본: **sonnet 9/9 · haiku 9/9 마커 출력, 개수 6/6 정확** (rc≠0 0건)
- BASEHARD/FIXHARD 는 회장 플랜(Hidden)의 전체 스킬 6종을 얹은 조건

### ★ 정직 보고 — A/B 가 판별하지 못했다

**BASE 도 28/28 마커가 나왔다.** 즉 실호출로는 결함을 재현하지 못했다.
프로덕션 산출물이 결함의 증거이지만, 내 프롬프트 재구성은 그 발동 조건을 담지 못했다.
수정본이 더 낫다는 것을 실호출 A/B 로는 **입증하지 못했다** — 입증된 것은
(a) 실패 산출물의 구조가 경쟁 지시를 따른 결과라는 것, (b) 수정본이 18/18 로
**퇴행이 없다는 것**이다. 이 한계를 ANU 가 알고 판단해야 한다.

## 작업 C 근거

- 실호출 46회: **최대 241.7초 · 180초 초과 15건(33%) · 420초 초과 0건**
- 420 / 241.7 = **1.74배 여유** (t3007 선례: 실측 248초 → 420초, 이후 초과 0건)
- `_run_content_cli_async` · `_run_codex_cli_async` 두 경로가 상수 **하나를 공유** — 테스트로 봉인(숫자 하드코딩 금지)
- ★ 프론트 폴링(`Generate.tsx:401`)은 2초 간격이며 **시도/경과 상한이 없다**.
  `completed`/`failed`/HTTP오류에서만 `clearInterval` → t3007 과 달리 프론트 동반 수정 불필요 (코드 확인 완료)

## 검증

- 회귀: base `bd0c5b4` **3,073 passed / 5 skipped** → 본 PR **3,102 passed / 5 skipped**
  · 델타 **+29 = 신규 테스트 수와 정확히 일치** · 실패 0
- 변이 테스트 **5종 전부 사망**:
  | 변이 | 결과 |
  |---|---|
  | 타임아웃 420→180 | 3 failed |
  | B-1 최종지시 제거 | 3 failed |
  | B-2 분기 원복 | 2 failed |
  | B-1 **호출부 결선** 끊기 | 2 failed |
  | codex 타임아웃 하드코딩 | 1 failed |
  - 변이 주입 전 `assert 원문 in 소스` 로 **no-op 아님을 선증명**
  - ★ 호출부 변이는 처음에 **생존**했다(헬퍼만 덮은 봉인). 호출부 봉인을 추가해 죽였다.
- 일반 생성 무영향: `imageCount` 미지정/0/음수 · `benchmark_prompt=""` 경로 봉인
- QC: red-team **base 7건 = 본 PR 7건**(동일 집합, 라인번호만 이동) — **델타 0**, 전부 선재 오탐

## 기존 테스트 계약 변경 (검토 요망)

`test_task3064_benchmark_grounding.py::test_output_scope_rule_coexists_with_image_prompt_exception`
이 `assert "예외" in prompt` 로 **구 자기모순 문구를 봉인**하고 있었다.
그 표현이 곧 결함이므로 새 계약(`3가지다` 긍정 단정)으로 갱신하고 이름도 바꿨다.

## 미해결 · ANU 판단 필요

1. **실호출 A/B 미판별** (위 정직 보고) — 수정 효과가 실측으로 입증되지 않았다
2. **채널 프롬프트의 경쟁 지시는 그대로 남아 있다** — `generateOptions.ts` 의
   *"`##` 마크다운 아님"* 과 *"[이미지 삽입 위치] 표시 3~5곳"*. 프론트 파일이라
   이번 범위 밖으로 두었다. 근본 해소를 원하면 별도 태스크 필요
3. **머지 후 `insuro-api` 재기동 필요** — 서버는 디스크 파일을 실행한다. 머지만으로 반영 안 됨
4. scope-guard: dispatch 미경유로 `memory/capabilities/task-3070.json` **스냅샷 부재** (선례와 동일한 오탐)

---

## 실행 절차 · 산출물

- 실호출 하네스: `teams/dev4/task-3070/realcall_n.py` · `realcall_prod.py`
- 프로덕션 픽스처: `benchmark_fixture.json` (Supabase `benchmark_sources` 3행 실데이터)
- 프로덕션 실패 산출물: `prod_failing_output.md` (`contents` `27ac814c…`, 5,491자)
- 실호출 원문 46건: `out_*.md` · `pout_*.md` / 집계: `res_*.json` · `pres_*.json`
- CI_WATCH_HANDOFF: `memory/events/task-3070.ci-watch-handoff.json`

## 하지 말 것 — 준수 확인

| 금지 | 확인 방법 | 결과 |
|---|---|---|
| D — haiku 차단 | `git diff` 에 haiku/sonnet/MODEL_CAP/PLAN_LEVEL/resolved_model | **0건** |
| E — 본문키워드 재측정 | `git diff` 에 bodyKeyword/body_keyword | **0건** |
| 분량/글자수 수정 | `git diff` 에 charCount/char_count | **0건** (`settings.charCount` 미결선 건 미접촉) |
| 머지 | PR draft 유지, 머지 미실행 | **준수** |

## 실측 vs 명세 대조

| 항목 | 명세(ANU) | 본 실행 실측 | 판정 |
|---|---|---|---|
| job1 180초 kill | 20:39:20→20:42:20 | 재현 안 함(과거 이벤트) — 대신 실호출 46회 중 **15건이 180초 초과** | 뒷받침 |
| job2 225초 성공 5,491자 | 있음 | `contents` `27ac814c…` **5,491자 확인** | **일치** |
| 저장 결과물에 마커 부재 | DB 직접 조회 | DB 직접 조회로 **독립 확인** | **일치** |
| haiku 마커 X (16.8초/444자) | 있음 | 실호출 18회 haiku **전부 마커 O**, 최소 86.7초 | **미재현** |
| sonnet 마커 O (58.2초/2,698자) | 있음 | 실호출 전부 마커 O, 최소 114.1초 | 일치(시간은 상이) |

★ ANU 실측의 haiku 16.8초/444자는 본 실행에서 한 번도 재현되지 않았다(최소 86.7초/2,395자).
프롬프트 구성이 달랐을 가능성이 높다.

## 결론

작업 **C 는 실측으로 충분히 뒷받침된다**(46회 중 33%가 구 상한 초과, 신 상한 초과 0건).
작업 **B 는 프로덕션 산출물이라는 직접 증거로 정당화되지만, 실호출 A/B 로는 효과가
입증되지 않았다**(BASE 28/28). 이 한계를 감춘 채 "해결"로 보고하지 않는다.
