control = M3, M2 < control(시각 메모리는 오히려 방해).action_acc 0→0.67, place_acc 0.00→0.667.ours는 시각 조상 M2를 +50% 능가했고, M3v2와는 부분 상보적(ours만 맞힌 3건 존재).fine_subtasks.json 재생성이 선행 과제.붉은 점 = 이전 결론이 뒤집힌 지점.
eval_spec.lang("Show me where the steak is placed.")이 진짜 최종 goal임을 발견 → recall 모드 구현.
M3 over-advance 대책으로 m3v2(자기서술 대신 emit한 subtask 로그) 추가.
--state-align leadup으로 윈도를 한 칸 당김.
M3 = control(0.333 동일), M2 < control(0.128 ≪ 0.333, 순 −8행).
약·강모델 공통. GOAL 텍스트에 정답이 verbatim 포함(recipe leak)돼 메모리 없이 풀리는 perception task였음.
RECALL_SYSTEM(과거 배치 보고, 다음 행동 금지)으로 교체. "Navigate to the fridge" 병리 소멸.
보존형(M1/M2/M3v2) > 무보존(control/M3=0) 확인. M3(덮어쓰기)의 장기 망각도 데이터로 확정 → M3 deprecated.
"Close the freezer door" — 배치 사건 자체가 기록 안 됨. 누적 walk가 세그먼트당 1콜(coarse) + 세그먼트 끝 윈도라 over-advance가 메모리 적재 단계에도 있었던 것.
--recall-walk fine으로 fine-subtask 단위 + leadup 누적 전환.
in/on을 그대로 출력 → action=other로 깎임) 수정.
fine_subtasks.json 0개 → 재생성이 선행 블로커설정: gemini-3.5-flash · diverse12(서로 다른 12 태스크 패밀리) · n=39 · --target recall --recall-style report --recall-walk fine · 파서 수정 반영.
주 지표 = place_acc(물건이 최종적으로 어디 놓였는지 회상).
| method | 메모리 형태 | place_acc | slot_acc | exact | 비용/스윕 |
|---|---|---|---|---|---|
| control | 없음 (floor) | 0.154 | 0.077 | 0 | $6.20 |
| M1 | 전체 균일 8샘플 이미지 | 0.179 | 0.128 | 0 | $11.92 |
| M2 MemER | 모델 지목 keyframe 이미지 ≤8 | 0.308 | 0.154 | 0 | $10.42 |
| ours 우리 | keyframe + inline 구조화 태그 + 검색 | 0.462 | 0.256 | 0.077 | ~$10 |
| M3v2 | emit한 subtask append 로그 (~23줄) | 0.564 | 0.282 | 0.128 | $6.20 |
| 시점 / 설정 | 당시 1등 | 수치 | 왜 폐기됐나 |
|---|---|---|---|
| 260528 next-subtask (chunk) | M2 | slot .34 | STATE 윈도 off-by-one 착시 |
| 260623 next-subtask (leadup) | control (메모리 무효) | slot .333 | recipe leak — 모드 자체가 메모리를 안 잼 |
| 260623 recall (coarse walk) | M2 | place .444 (n=9) | 누적 walk가 coarse → 메모리 내용물 파손 |
| 260624 recall (fine, 파서수정 전) | M3v2 | place .564 (M2 3.1×) | 파서 버그로 이미지 메서드 과소평가 → 실제 1.8× |
이 프로젝트의 실질적 산출물은 메서드 순위보다 "무엇이 측정을 망가뜨리는가"에 가깝다.
타깃 세그먼트를 fine 개수 K로 균등 분할하고 k=tfi chunk를 STATE로 제시했는데, 그 chunk의 마지막 프레임은 타깃 행동이 완료된 뒤였다. 모델은 정상적으로 그 다음 행동(tfi+1)을 답했고, 이것이 "over-advance"로 관측됐다.
지표 지문: fixture는 유지되니 place_ok는 0.59로 살아남고 action_ok만 0.00 → 정확히 "한 칸 앞서감".
진단법(핵심): 메모리가 원인이라는 가설을, 메모리가 0인 control과 row-join해서 반증했다. control도 182건 동일하게 틀렸고 예측 문자열이 80% 일치 → 메모리는 원인이 아니라 같은 STATE에서 파생된 쌍둥이 증상.
chunk[tfi-1]) 마지막 프레임이 배치 직전이 되게 했다. 변수 격리를 위해 윈도 모양은 건드리지 않음.윈도를 고친 뒤에도 M3 = control(0.333 완전 동일), M2 < control(0.128)이 약·강모델 공통으로 나왔다. 원인은 메서드가 아니라 태스크 구조: GOAL 텍스트에 타깃 fine-subtask가 verbatim 포함돼 현재 화면만으로 답이 나온다.
즉 이 모드는 perception / instruction-following 과제였고, 메모리는 필요 없거나(control과 동률) 오히려 방해(M2는 주입된 keyframe이 시간축을 흩뜨려 net-negative)였다.
recall 모드로 바꿔도 전 메서드 slot=0이었다. STEP_SYSTEM이 "다음 행동을 실행하라"를 강제하기 때문에, "Show me where the steak is placed."에 "Navigate to the fridge"로 답한 것.
형식이 교정되자 action_acc 0.00 → 0.667. 그리고 이때 남은 place_acc = 0이 비로소 진짜 메모리 신호였다 — M3의 running-notes에 스테이크가 아예 없었다(덮어쓰기 설계의 장기 망각). next-subtask 모드에서는 결코 볼 수 없었을 신호.
Bug 1의 over-advance가 채점뿐 아니라 메모리 적재 단계에도 있었다. recall의 누적 walk가 세그먼트당 1콜(coarse) + 세그먼트 끝 윈도라, 한 세그먼트의 navigate→pick→place→close가 한 줄로 뭉개지고 그 한 줄이 over-advance했다.
왜 이게 순위를 뒤집었나: over-advance 오염은 메모리의 내용인 텍스트 로그를 가장 크게 파괴한다(한 줄이 틀리면 회상할 사실이 틀림). 이미지는 프레임이 한 칸 어긋나도 장면이 남아 덜 망가진다. 그래서 fine walk의 수혜가 M3v2에 불균형하게 집중되며 시각 < 텍스트로 역전됐다.
모델이 프롬프트 템플릿의 "...in/on the <place>"에서 in/on을 그대로 출력하는 경우가 있었는데, place 정규식이 이 슬래시 연결어를 인식 못 해 action='other'로 강등됐다. 정답을 정답으로 채점하도록 정규식에 in/on|on/in 추가(치팅 아님).
| method | 수정 전 | 수정 후 |
|---|---|---|
| control | 0.026 | 0.154 |
| M1 | 0.077 | 0.179 |
| M2 | 0.179 | 0.308 |
| M3v2 | 0.564 | 0.564 (무변 — 로그는 헤지 안 함) |
결과적으로 이전에 보고한 "M3v2가 M2를 3.1× 압도"는 이 버그로 과장된 것이었고, 실제 격차는 1.8×였다.
모든 메서드가 동일한 프롬프트·동일한 walk·동일한 채점을 쓰고, 오직 "장기 메모리를 어떻게 만들고 회상 때 무엇을 붙이나"만 다르다.
현재 window만. 상식·현재 장면으로 얼마나 맞히는지의 바닥선. place 0.154.
전체 영상에서 균일하게 8장. 지능적 선택 없음 = naive 하한. place 0.179 (control과 큰 차 없음).
모델이 매 콜에 중요 프레임을 지목 → 인덱스 누적 → d=5 단일연결 클러스터링 → 대표들 중 최근 8개 이미지를 회상 때 제시. place 0.308.
매 스텝 running-notes를 통째로 다시 씀 → 초반 사건이 소실(장기 망각). place 0.000 = control과 동일. 덮어쓰기는 메모리가 아니다는 걸 데이터로 확정하고 폐기.
모델이 실제로 emit한 sub-task 문장을 덧붙이기만 함(~23줄/에피소드). 회상 때 로그 전체를 제시. 최고 place 0.564, 최저 비용(이미지 미첨부).
walk 한 콜에서 next-subtask와 keyframe 태그(objects·place·action)를 동시 emit(fused). 회상 때 질문의 object로 태그를 검색해 매칭된 태그 + 그 이미지만 제시. place 0.462.
fused가 실제로 고친 것: 초기엔 walk 후 별도 캡션 콜을 돌렸는데, 단일 정지프레임만 보고 캡션해 steak@fridge/open처럼 오라벨이 났다. 한 콜에서 모션 윈도와 함께 판단하게 하니 steak@freezer/place로 교정되고, 태그 수도 6→16으로 늘며 콜은 39→33으로 줄었다.
M2 메모리가 빈약한 이유는 용량(8칸)이 아니라 모델이 애초에 거의 지목하지 않는 것이었다. 11콜 중 ~2콜에서만 지목해 8칸 중 3~5칸만 찼다. 강제 지목(--m2-force)으로 keyframe 5.3→12.6장으로 늘렸으나 place는 0.179→0.231에 그쳤다 — 강제로 고른 중앙 프레임이 배치 순간이 아니면 오히려 노이즈가 되는 양날.
| next-subtask 무효 | recall 유효 | |
|---|---|---|
| 질문 | "지금 할 다음 sub-task는?" | "그 물건이 어디 놓였나?" (eval_spec.lang) |
| 채점 | 타깃 step 예측 ↔ target_fine_subtask | 회상 답 ↔ 최종 배치 fixture (place_acc) |
| 메모리 필요? | 아니오 — GOAL에 정답 verbatim(recipe leak) | 예 — 과거 사건은 현재 화면에 없음 |
| 관측 결과 | control = M3, M2 < control (net-negative) | control < M1 < M2 < ours < M3v2 |
| 필요한 수정 | leadup 윈도 (그래도 무효) | 회상 프롬프트 + fine walk (둘 다 필수) |
초기 토큰 기반 추정이 6–8× 과소였다(추정 $38 → 실비 ~$300). 이후 게이트웨이가 응답에 반환하는 estimated_cost.amount를 콜마다 누적해 runner summary에 COST $X로 출력하도록 바꿨다 — 단가표 추측 금지, 게이트웨이 값이 ground truth.
| 단위 | 실측 |
|---|---|
| API 콜 1회 | ≈ $0.0192 (prompt ~9.1k tok, 이미지가 대부분) |
| 시나리오 1개 (3 test) | ≈ $0.23 (next-subtask) / $0.44 (recall fine walk) |
| diverse12 스윕 1메서드 | $6.2 (텍스트) ~ $11.9 (이미지) |
| 4메서드 풀 스윕 | ≈ $24.7 |
Letsur: 키는 COST 한도 소진 → 현재 Letsur_qualcomm: 사용.벤치가 07-22에 879 시나리오 / 7,680 test로 재릴리즈됐고 전체 재다운로드·검증은 끝났다(8,803/8,803, 24GB). 문제는 ID가 공통인 623개조차 전부 다른 영상이라는 점(video_total_frames 623/623 불일치) — 구 fine_subtasks.json 858개는 구 영상에 index-align된 것이라 재사용이 불가능하다.
dataset.py는 이 파일을 fall back 없이 요구하고 신 릴리즈엔 0개다. 즉 핵심 결과의 근거인 --recall-walk fine이 신 데이터에서 동작하지 않는다. 재생성이 끝나야 DATA_ROOT를 신 경로로 전환할 수 있다.
| 항목 | 구 (858) | 신 (879) |
|---|---|---|
| test 수 | ~2,600 | 7,680 |
tests[].task 필드 | 없음 | restore 3,181 / find_target 2,878 / find_distractor 1,621 |
| 채점 함수 | 단일 | memory_success + restore_success |
| fine_subtasks.json | 858개 (자체 생성) | 0개 |
find_distractor(1,621건, 영상 중 조작 대상이 아니었던 물체의 위치를 회상)로 먼저 제공해줬다.reps[-8:]) 대신 시간 분산 선발(초반+중반+말)로 초반 사건 보존.task 3종 분기(특히 restore는 채점 기준 자체가 다름), diverse12 재선정.각 조합은 캐시 subdir와 결과 파일 suffix가 분리돼 있어 과거 결과를 덮어쓰지 않고 A/B가 가능하다. 프로젝트 규칙: try-except 금지(에러를 감싸지 말고 근본 원인 수정), 임시파일은 ./tmp/.
claude/)260727/progress-benchmark_879_resync.md — 879 재동기화 전 과정260625/plan-ours_tagged_keyframe.md — ours 설계→피드백→fused 구현→최종 스윕260624/analysis-recall_fine_walk.md — coarse→fine 전환과 순위 역전260623/analysis-m3_overadvance_leadup_fix.md — 근본 원인 규명 (이 프로젝트의 분수령)260616/analysis-metric_definitions.md — slot/place/action 채점 정의와 한계260619/exp-recall_m3v2_S100.md · 260528 260528/exp-cross_model_memory_S100.md260519/ plan · progress · v2 core rework · docs/specs/2026-05-19-...-design-v2.md