← Index
2026-09-09 — scene_bench · resume 트랙 입력 검증 · 오라클 해부 · 러너 v2

resume 트랙 VLM 입력 실물 검증 + 오라클 "미완주" 해부 + 러너 v2 마이그레이션

"글만 읽지 말고 들여다보라"는 지적에서 시작해 픽셀 단위 검증 → cap 8 결정 → 측정 착수까지

TL;DR

53%
press cap8 필요조건 충족
50%
visit cap8 필요조건 충족
27/27
오라클 실패=꼬리 필요 행
23
러너 v2 계약 테스트

1배경 / 목적

260908 검수(claude/260908/analysis-resume_dataset_61871a3e.md)는 필드·문서 수준이었다. 사용자 지적: "질의가 뭐고, 어떤 영상이 들어가고, VLM eval 때 어떤 current image가 들어가 어떤 메모리를 요구하고, 어떻게 측정하나 — 글만 읽지 말고 들여다봐. 그리고 오라클 미완주가 정확히 무슨 뜻인지 말해봐." → 하네스가 실제로 모델에 넣는 픽셀을 눈으로 확인하고, 오라클 필드를 해부하는 것이 목적.

2작업 내용

2.1 하네스 입력 경로 코드 확인 + 픽셀 재구성

run_eval_resume.py → cut_view(ep, f1) # 구간 [0,f1] 뷰 → build_memory_turns_type2 # blind/textlog/frames-uniform, rollforward는 ingest 접두사 → build_query_parts = 이미지 1장 + 질의문 # QUERY_CAM=exo_camera_1, last_frame_index=f_cut → build_resume_command_part # 발화 목록, blind 포함 전 전략 공통 → score_resume # task_ok ∧ remaining_ok = resume_ok

재구성 도구: tmp/hf_check/make_row_montage.py <query_id> <cap>(현재 이미지 3캠 + frames-uniform cap장 메모리(유닛/세그먼트 라벨) + 완료 유닛 manip 순간), press_evidence.py(버튼 누름 순간만 12장), 정량 스크립트 6종(frame_budget_resume/bytype.py·sample_vs_units.py·press_spacing.py·leak_crosstab.py·oracle_anatomy.py·budget_gap.py). 리포트에 §4 "VLM이 실제로 보는 것" 신설(사진 6장 + 표 4개).

2.2 cap 8 확정 + TDD 러너 v2 마이그레이션

사용자 결정(260909): 이미지 예산은 find/restore와 같은 cap 8로 간다. 가족 간 같은 예산 비교가 우선이고, press/visit이 이미지 전략에서 무너지는 것은 결함이 아니라 결과로 보고한다.

계약 테스트(tests/eval/test_resume_contract.py, 23개)를 먼저 고정한 뒤 구현: - 답 스키마 v2(answer.py): ResumeAnswer.unfinished: list[UnfinishedItem] 구판 단수형(task/remaining) 오면 파스 실패→재시도(조용한 "다 했음" 오독 방지) - 채점 v2(grading.py): tasks_ok · remaining_ok · resume_ok(헤드라인) · slot_ok_frac(multi 부분점수) · named_finished(finished[] 미끼 지목 여부) - 프롬프트 v2: 미완 명령 전부 나열, 개수 안 흘림(테스트로 고정) - 러너 v2(run_eval_resume.py): resume_gt/resume_labels(oracle_ok 포함) · --contexts/--limit-contexts 플래그 - rollforward-v3 지원 신규 추가(기존 resume 미지원) — prefix_memory(rf, f1) + rewrite_memory_turns, ingest를 마지막 컷까지만(절단 계수 실측 평균 0.895) - 실행 스크립트 scripts/run_resume_shards.sh (find 샤드 스크립트와 같은 규약, 편 단위 체크포인트)

2.3 end-to-end 검증: 구간 자르기 + 오라클 독립성

사용자 확인 질문 2개: "영상 입력 구간 잘 자르고 질의할 수 있는 형태로 잘 만들어져 있지?", "오라클은 사실 필요 없는 거잖아?" → 문서·필드가 아니라 하네스 코드로 끝까지 태워서 확인.

3결과 (수치)

3.1 현재 이미지(exo1@f_cut) 1장 — 실물 확인

3.2 메모리 프레임 예산 — cap 8은 카운팅 과제에 구조적으로 부족

유닛 길이 median: move 82.7s · put 84.2s · visit 35.4s · press 16.2s. task 전체 span median: move 275s · put 276s · visit 111s · press 62s. cap 8 표본 간격 = median 51초.

pending 종류m 이상이 실행 구간에 들어간 슬롯 (cap 8/16/32)manip 순간 적중
move_objects100% / 100% / 100%41% / 71% / 100%
put_in_container100% / 100% / 100%41% / 72% / 99%
press_button53% / 86% / 100%23% / 48% / 69%
visit_rooms50% / 94% / 100%—
press·visit 슬롯의 절반은 cap 8에서 "셀 수 있는 최소 조건"조차 만족하지 못한다. 물체 task는 유닛이 길어 8장으로도 "출발면이 줄었다"는 증거가 잡힌다(실물: mem8_1543 [2/8] 서랍장 7개 → [6/8] 줄어듦 → [8/8] 식탁 1개).

3.3 버튼 누르기는 화면에 흔적이 없다 (실물 확인)

press_evidence.jpg: train_746의 press #1(f=529)·#2(f=726)·#3(f=3130) 프레임이 사실상 동일 — 같은 전자레인지, 같은 팔 자세, 표시등·상태 변화 없음. train_3118 건조기 #1·#2·#3은 8초 간격으로 붙어 있다. train_3610:cut_04의 cap 8 메모리에서 T1(커피머신 3회, m=1) 구간에 걸린 2장은 복도 바닥과 벽이었다.

press/visit 111슬롯(222 중 절반)은 이미지로 원리적으로 복원 불가 — 행동을 기록한 텍스트 메모리만 풀 수 있다. 예측: 읽기 격자에서 textlog·rollforward > frames·vis로 순위가 뒤집힌다(find는 vis 우위였음).

3.4 오라클 "미완주"의 정확한 의미 — 해부

오라클 = 대본 로봇(규칙 기반 스크립트, VLM 아님)이 그 컷 상태에서 남은 유닛을 실제로 실행해 본 기록. 역할 둘: ① 정답 실행 가능 증거 ② 예산 근거(budget_steps = max(400, 1.5×oracle.steps)). 남은 유닛의 출처는 컷 이후 편 안에서 실제 실행된 유닛 + 편이 끝난 뒤 이어 붙인 꼬리(tail) 롤아웃 — source = tail 109 / episode+tail 52.

해부 결과: 실패 27행은 전부 꼬리가 최소 1유닛을 해야 하는 행이었다(편 실행분만으로 r이 채워진 경우 0건). 실패율은 tail 19/109=17% · episode+tail 8/52=15%로 거의 동일 → 깨지는 지점은 꼬리 롤아웃. 필요 유닛 수만큼 기록하고도 FAIL인 행이 5개(예: train_3911:cut_02 r=2·기록 2·FAIL) — unit_order는 시도를 세고 completed는 최종 상태 확인이라 갈린 것으로 보인다.

예산 부족의 크기: 오라클 성공 행의 r별 median steps = r1 1646 / r2 3187 / r3 4010 / r4 5690 / r5 8542, r=1 최소값 510. steps=0인 10행은 budget 400 → 관측된 가장 싼 1유닛(510)보다도 적은 예산으로 1–4 유닛을 해야 한다(같은 r 정상 예산 대비 4.7–16.2%).

3.5 구간 자르기 정확성 + 오라클 독립성 — end-to-end 실측

tmp/hf_check/e2e_resume_load.py(API 0): cut_view(ep, 1966) → 컷 이후 유닛 t2u0..t2u3, e1이 정확히 잘려나감(7→2). textlog 4줄 전부 컷 이전 · frames-uniform 인덱스 전부 ≤ f_cut. 컷~편 끝 여유 프레임 min 12 · median 2080. 막고 있는 것은 데이터가 아니라 러너: 구 러너는 v1 스키마(query["task"] 단수·decoy_tasks)만 읽고 v2 행에는 그 필드가 없었다.

독립성 검증 (슬롯 222)불일치
m == 컷 이전 완료 유닛 수 (subtasks[] 직접 집계)0
done_units[].frame == 유닛 종료 프레임0
m == cuts[].done[task_id]0
n == 발화 속 수사 (visit 제외)0
읽기 격자는 161행을 전부 쓴다 — 오라클 필터는 실행 트랙(134행/331정답)에만 필요. 부수 발견: load_episode가 type2에서 traj.h5를 fps/steps_emitted 때문에만 열어 100편 4.2GB가 낭비됨(meta.json+states/index.json으로 대체 가능).

3.6 러너 v2 구현 결과

테스트 23개 통과(파서 9·채점 8·러너 계약 3·접두사 3, 실데이터 통합 스모크 1건 포함, API 비용 0). dry-run: train_3610__2000 --cap 8 → resume1 행 press_button r_total=2, multi 행 press_button+put_in_container r_total=5, frames-uniform 이미지 8장.

모델ingest(100편)질의(161행)합계
gemini-3.7-flash$32.5$6.7$39.2
claude-sonnet-5$47.4$8.1$55.5

비용의 83%가 ingest — resume은 편당 1.61행(find는 5.9행)이라 ingest가 행 수로 분산되지 않는다.

4Takeaway

의미

resume은 find/restore와 성격이 반대인 과제다. find는 "마지막 위치"라 이미지 메모리가 이겼지만, resume은 절반이 흔적 없는 카운팅이라 행동 로그형 메모리만 풀 수 있다 — 벤치 라인업에 넣는 값어치가 여기 있다. 예산(cap)을 find와 공유하면 측정 자체가 성립하지 않을 위험이 있었지만, 사용자 결정으로 공유 예산을 유지하고 측정 한계로 서술하는 쪽을 택했다. 데이터는 처음부터 문제가 없었고(구간 자르기·GT 모두 검증 통과), 막고 있던 것은 러너 하나였다 — 이제 풀렸다. resume의 비용 구조는 find와 달리 ingest가 지배적이라 모델을 늘리는 것보다 전략을 줄이는 게 비용에 효과적이다.

5Next Steps

미해결 한계

데이터팀 전달 5건(260908) + 오라클 재롤아웃 시 completed를 최종 상태 기준으로 기록(현재 unit_order와 불일치 5행) 여전히 열림. cap 32는 비용이 4배라 press/visit만 고밀도 샘플링하는 종류별 예산이 가능한지는 미검토.

완료된 후속 — 참고

파일럿 승인 후 3모델(flash-3.7·sonnet-5·luna) 161행 전량이 완료되어 260910-resume_read_grid.html로 별도 보고됨: 오라클/최고비오라클 격차 3.7~6.8배(쓰기 병목 최강 증거), press_button은 rf-v3·tagmem 정확히 .000(이 카드의 예측대로), visit_rooms는 오라클 상한도 1.0이 아님(발화에 총 방 수가 없음, 이 카드의 §3.1과 무관한 신규 발견).