WRITER_POLICY 표(커밋 fc51c6f)로 5전략 규칙을 읽기 단계와 1:1 대응 배선 — KeepDropImageMemory·UniformImageMemory·전략별 시스템 프롬프트 계약.policy = writer_policy(plan.strategy)가 VLA 정책 객체를 넘겨받는 동명 인자를 덮어써, 872008b 이후 모든 온라인 런이 첫 조작(pick/open) 서브골에서 즉사. navigate만 있는 플랜만 살아남아 "완료"로 위장했다.사용자 지적(260909): "온라인 노트 규칙은 context 때의 본인 노트 규칙이랑 똑같아야지 — 시작만 그런 게 아니라." 코드를 확인해보니 실제로 그렇지 않았다:
run_online_plan이 전략과 무관하게 memory_mode="append"를 넘김(online.py:390) — 전 전략이 매 턴 텍스트 노트 한 줄을 추가. OnlineBenchPlanner.memory_images는 생성 시 한 번 세팅된 뒤 한 번도 갱신되지 않음 — vis-pure의 본체인 KEEP/DROP이 온라인에 아예 없었다.즉 지금까지의 온라인 비교는 "각 방법의 메모리 시스템을 온라인에서 돌린 것"이 아니라 "서로 다른 시드 + 공통 writer"였다. 특히 vis-pure는 자기 방법에 없는 텍스트 노트를 쓰고, 자기 방법의 본체인 프레임 선택은 못 하는 상태로 측정되고 있었다.
읽기 단계 write 규칙(sbench_eval)과 1:1 대응하는 online_memory.WRITER_POLICY 표를 만들고(모르는 전략은 즉시 ValueError) 배선했다.
| 전략 | 읽기 단계 write 규칙 | 온라인 writer (신규) |
|---|---|---|
| blind | 메모리 없음 | notes none / images none — 진짜 무기억 |
| textlog | GT 이벤트 로그(모델 writer 없음) | notes none / images none — 시드 고정 |
| frames-uniform | 균등 샘플러(모델 없음) | notes none / images uniform — 통합 타임라인 매 턴 재샘플 |
| rollforward-v3 | 청크마다 요약 전체 재작성(MEM식) | notes rewrite / images none |
| rollforward-vis-pure | KEEP/DROP 프레임만, 텍스트 없음 | notes none / images keep |
중간에 "온라인엔 GT 행동이 없으니 textlog는 시드 고정"이라는 판단이 틀렸다는 걸 발견 — 읽기 단계 textlog도 모델이 쓴 게 아니라 데이터셋 생성기의 이벤트 로그다. 하네스가 서브골 실행 직후 로그를 이어 붙이는 oracle_log=True 경로를 구현(커밋 20156b3)했으나, 사용자 판단으로 철회하고 시드 고정으로 복귀했다: 온라인 시도는 대부분 실패·타임아웃(중간 런 pick 시도 대비 lift 15~26%)이라 "행동 기억"이 아니라 "헛수고 기록"이 되고, 판정 대상 GT 프로브와 VLA가 실제로 건드린 물체가 다를 수 있기 때문(restore v5 실측: bowl#2 대신 remote를 들었는데 held=bowl#2로 기록된 전례).
원인: run_online_plan(env, cfg, sampler, first_task, ep, plan, client, policy, ...)의 8번째 인자 policy는 VLA 정책 객체(MolmobotPolicy)인데, fc51c6f가 본문 안에서 policy = writer_policy(plan.strategy)로 그 인자를 덮어썼다. 첫 VLA 서브골(pick/open)이 시작되는 순간 task.register_policy(dict)에서 죽고, navigate만 하고 끝난 플랜은 살아남아(6행) 샤드가 조용히 "완료"로 보인 것.
조치: 변수를 wpolicy로 개명(online.py:390, 사용처 395·410·470·474·475). 실런 없이 잡을 수 있는 유일한 지점이라 AST 회귀 테스트 추가 — tests/exec/test_online_pure.py::test_run_online_plan_does_not_shadow_vla_policy가 run_online_plan 본문에서 policy 재대입을 금지한다. 결함본(당시 HEAD)에 돌리면 잡히는 것을 확인.
소모 비용 $0.1354 / 6행(승인분 $6 중, 취소 시점 기준). 살아남은 6행은 VLA 서브골이 없던 플랜만 남은 편향 표본이라 성능 비교에는 못 쓰지만, writer 동작 자체는 확인됐다:
| 전략 | writer_notes | writer_images | seed→final imgs | online_in_mem |
|---|---|---|---|---|
| blind | none | none | 0→0 | — |
| textlog | none | none | 0→0 | — |
| frames-uniform | none | uniform | 8→8 | 1 |
| rollforward-v3 | rewrite | none | 0→0 | — |
| vis-pure | none | keep | 8→8 | 0 (KEEP 기회 없음, 2턴) |
부수 확인: 예산 초과 행(blind 1887/1500, rf-v3 1532/1500)은 설계대로다 — drive는 경로 중간에 자르지 않고 초과분을 within_budget=False로 걸러 SR 0 처리(orchestrator.py:582-589, 260907 결정).
final: done 59 · budget_exhausted 23 · abort 10 · max_subgoals 8. within_budget False 14행.
| 전략 | writer(notes/img) | 메모리 이미지 | keep/drop/evict | 시드 잔존 |
|---|---|---|---|---|
| blind | none / none | 0 | — | — |
| textlog | none / none | 0 | — | — |
| frames-uniform | none / uniform | 8 | — | — |
| rollforward-v3 | rewrite / none | 0 | — | — |
| rollforward-vis-pure | none / keep | 8 | 4/4/0 | 7.80/8 |
frames-uniform: 메모리 8칸 중 온라인 프레임 평균 0.90장(20행 중 18행이 1장, 2행이 0장) — 온라인 구간이 컨텍스트 영상(1만+ 프레임)보다 훨씬 짧으니 균등 규칙의 산술적 귀결.
| 전략 | 첫 행동 적중 구→신 | SR 구→신 | 악화/개선 | McNemar p |
|---|---|---|---|---|
| blind | 0.25→0.20 | 0.20→0.15 | 1/0 | 1.000 |
| textlog | 0.55→0.55 | 0.25→0.40 | 3/6 | 0.508 |
| frames-uniform (n=9) | 0.44→0.40 | 0.00→0.22 | 0/2 | 0.500 |
| rollforward-v3 | 0.40→0.40 | 0.30→0.30 | 1/1 | 1.000 |
| rollforward-vis-pure | 0.55→0.50 | 0.20→0.50 | 0/6 | 0.031 |
첫 행동 적중이 다섯 전략 모두 사실상 그대로인 것이 설계 확인이다 — t=0 결정은 시드 메모리만 보고 내리고 writer는 t≥1부터 작동하므로, writer 교체가 첫 행동을 바꾸면 안 된다. 실제로 안 바뀌었다. n=20이라 SR 차이 0.15는 노이즈와 구분 안 됨 — 프로토콜 변화가 없는 blind조차 0.20→0.15로 움직인 게 이 표본 크기의 노이즈 바닥이다.
이제 온라인 축이 재는 것은 "같은 시드 + 공통 writer"가 아니라 각 메모리 시스템을 온라인에서 돌린 결과다 — 논문에서 "we run each memory method online"이라고 쓸 수 있는 상태가 됐다. 기존 온라인 수치 중 t≥1 지표(SR@예산·도달·예산 소진)는 전부 무효고, t=0 지표(첫 행동 적중)는 대부분 유지된다. 이 수정이 없었다면 이후 670행 grid 런(260909-online_w2_grid_670.html)의 blind 대비 메모리 우위 결론이 "결함이 만든 우연"이었는지 검증 자체가 불가능했다 — 검증 결과 writer를 고친 뒤에도 결론이 같다(압축 원인은 writer가 아니었음).
또한 이 사고는 "순수 테스트 286개가 전부 통과해도 새는 지점이 있다"는 사례다 — run_online_plan은 env/policy/client가 필요해 단위 테스트 사각지대였고, AST 가드가 그 사각을 좁힌 구체적 방식이 됐다.
vis-pure 온라인 KEEP이 160턴에 4회뿐인 것을 그대로 둘지 결정 필요 — 규칙은 읽기 단계와 동일하므로 "모델이 안 쓰는 것"이 사실이지만, 그렇다면 vis-pure의 온라인 축은 시드 이미지만으로 굴러간다는 뜻이라 논문 서술에 반영이 필요하다.
수정본으로 재제출한 본 런(670행, $42.84)이 이미 완료되어 260909-online_w2_grid_670.html로 별도 보고됨: writer 결함을 고친 뒤에도 "메모리끼리는 분리 안 됨" 결론은 그대로였고, blind 대비 메모리 우위는 네 전략 모두 처음으로 유의하게 나왔다.