Index
2026-09-21 — Analysis

온라인 메모리 계약 — 전략별 프롬프트 · 실제 갱신 실측 · 스냅샷 패리티 게이트

scene_bench | 온라인 실행 트랙 (find v1.2 + restore + routine)

TL;DR

48/48
공유 프롬프트 일치
3
계약 일치 트리
16
역방향 적발 프롬프트
81%
vis-pure 온라인프레임 칸
$0
이번 작업 API

1배경 — 왜 계약을 기계로 재야 하나

온라인 실행 트랙은 워킹트리(src/)가 아니라 동결 스냅샷에서 돈다. 스냅샷은 심링크가 아니라 하드 카피라, 한 세션이 워킹트리를 고쳐도 남의 런은 영향받지 않는다.

트리쓰는 곳상태
tmp/plan_main/src_w2find v1.2 + restore 본 런 (이 세션)기준
tmp/routine_online/src_r1routine 온라인 (다른 세션)계약 일치
src/ (워킹트리)다음 스냅샷 원본계약 일치
안전장치의 이면. 스냅샷 분리는 런을 지키지만, 반대로 한 세션의 수정이 다른 세션 스냅샷에 자동 반영되지 않고 그 사실이 보이지 않는다. "우리 둘 다 같은 메모리 계약으로 재고 있는가"를 눈으로 diff 해서는 답할 수 없다.

판정 기준을 옮겼다

파일이 몇 개 다른지는 신호가 아니다. 15파일이 달라도 프롬프트는 같을 수 있고, 1파일이 달라도 16개 프롬프트가 갈릴 수 있다(둘 다 이번에 실측했다). 판정은 모델이 실제로 받는 바이트로 한다.

2프롬프트 조립 순서와 전략별 계약

① 역할·입력 설명 (전 전략 동일) ② Skills / Rules (navigate·pick·pick_and_place·open/close·done·abort + "저수준 정책은 자주 실패한다. 프레임으로 판단하라") ③ 메모리 계약 블록 ← 전략별로 다른 유일한 부분 (memory_block) ④ Plan 블록 (plan_block: fixed | rewrite) ⑤ 출력 JSON 스키마 {"note", ["keep"], "reasoning", "next"}

WRITER_POLICY × PLAN_UPDATE

전략notesimagesplan온라인에 실제로 쌓이는 것
blindnonenonefixed없음
textlognonenonefixed없음 (§3)
frames-uniformnoneuniformfixed자동 균등 샘플 (순증 ≈0)
rollforward-v3rewritenonerewrite재작성된 노트 전체
rollforward-vis-purenonekeepfixed모델이 고른 프레임만
tagmem-r3appendkeepfixed태그 엔트리 + [now] + 프레임

노트를 쓰는 전략의 공통 머리말 — 1~4는 동일, 5번만 갈린다

Notes — this is the ONLY record you will have of earlier turns; you will not see those frames again: 1. 마지막 프레임이 명확히 보여주지 않으면 서브골 완료를 주장하지 마라 2. 확신 없는 것은 "uncertain: " 접두사 3. 시도한 것 / 눈에 띄게 바뀐 것 / 남은 것을 기록 4. 행동 안 했어도 목표 관련 물체를 본 방·표면 기록 5. ← writer 규칙 (rewrite: 전체 대체 / append: 한 줄 + [now])

1~4가 전 전략 공통이라 편향이 없다. 이것이 "전략 차이는 메모리 방식뿐"이라는 주장의 근거다.

KEEP 축출 정상화 문장 (260920, 기본 켬)

3. Your memory starts full with {cap} frames from the context phase. Dropping one of them to record what you just did is expected, not a loss — keep whichever set best explains where things are now.

예산·규칙을 바꾸지 않고 하네스가 만든 조건(시드 8장으로 꽉 찬 채 시작)을 명시할 뿐이다. SBENCH_KEEP_EVICTION_NOTE=0 이면 260920 이전 프롬프트를 바이트 단위로 재현한다.

tagmem 온라인 저장/재검색 (결정 D)

프롬프트에 보이는 것 = 시드 줄 + [예산 안의 과거 줄] + [now] 상태 한 줄

3정정 — textlog 는 온라인에서 로그가 쌓이지 않는다

# online.py:590 oracle_log=(wpolicy["notes"] == "oracle") # WRITER_POLICY["textlog"] = {"notes": "none", ...} → oracle_log=False # orchestrator.py:810 record_oracle() if not (memory_mode == "unified" and oracle_log): return # ← textlog 는 항상 여기서 반환. 줄이 한 번도 안 붙는다

memory_block 에 oracle 분기가 존재하지만 아무도 그 분기로 들어가지 않는다. 260920 사용자 결정에서 "A(textlog 오라클 로그)는 안 함"으로 정했기 때문이며, 의도된 상태다.

결과: 온라인 textlog = blind + 얼어붙은 컨텍스트 로그 시드. 21칸에서 온라인 줄 0/21, 프롬프트 md5 도 blind 와 같다(7a5678ecfd79). memory_block(notes="oracle", ...) 을 손으로 호출해 렌더하면 실제와 다른 문장이 나오니 주의 — 이 세션도 한 번 그렇게 잘못 읽었다.

실제 에피소드(03986eff86b2, 8턴) — 첫 턴부터 마지막 턴까지 노트 블록이 글자 하나 안 변한다:

[context] [ 0s– 126s] I picked up the key chain from the tv stand in the bedroom and placed it on the drawer... [context] [ 126s– 176s] I picked up remote control #1 ... but I could not place it [context] [ 176s– 307s] I picked up the potato from the countertop in the kitchen and placed it on the chair... [context] [ 307s– 451s] ... [context] [ 452s– 673s] ... [plan] 1. [ ] pick up the key chain — on the dresser in the bedroom [plan] 2. [ ] pick up the irish potato — on the chair in the living room

4실제로 갱신되고 있는가 — v1.2 진행 중 런 실측

260921 10:40 UTC 기준. find v1.2 3팔 + restore 가 도는 중의 중간 집계다.

전략칸턴/칸시드줄최종줄온라인 줄줄 증가 칸온라인 프레임
blind410.51.51.50.000/4—
textlog2125.06.96.90.000/21—
frames-uniform1318.61.81.80.000/131.00 (자동)
rollforward-v31115.92.55.02.8211/11—
rollforward-vis-pure1327.01.21.20.000/1320.91 · 81% 칸
tagmem-r31257.135.943.07.11125/1252.13 · 98% 칸
vis-pure 턴당KEEP=0.273 온라인프레임 보유칸 106/131 (81%) 시드잔존 7.08/8 tagmem-r3 턴당KEEP=0.568 온라인프레임 보유칸 122/124 (98%) 시드잔존 5.86/8
축출 문장이 뒤집었다. 문장 전에는 vis-pure 가 89% 칸에서 온라인 프레임 0장이었다 → 지금 81% 칸이 보유. 능력이 아니라 축출 비용의 프레이밍 문제였다는 진단이 맞았다.
함정. online_frames_in_memory 필드는 uniform 전용이고 keep 전략에서는 null 이다. keep 전략 지표는 keep_stats.{keep, drop, evict, seed_left, online_kept} 를 봐야 한다. 이걸 모르고 보면 "KEEP 이 하나도 안 된다"는 오판을 한다 — 이번에 실제로 한 번 했다.

실제 갱신 예시 — tagmem [now] 상태 슬롯 (920acd6c51b0, 성공)

t=4 시점에 모델이 보는 노트 블록:

[context] ... (35줄: 태그 엔트리 + TIMELINE/PREV-HOP/LEDGER) [plan] 1. [ ] pick up the mug — on the toilet in the bathroom [t=0] Current view shows kitchen countertop. The mug moved earlier was placed on the toilet in the bathroom. [t=1] Navigated to bathroom toilet. Attempting to pick mug on toilet. [t=2] Grasped the mug on the toilet with gripper; continuing pick to lift it. [t=3] Gripper closed around mug rim on toilet, continuing pick to ensure full lift. [now] Gripper is grasping the mug on the toilet; continuing pick to lift it. → 그 턴 출력: note = 새 한 줄, keep = "KEEP: F4 DROP: m8"

과거 줄은 [t=n] 도장이 붙어 쌓이고, 최신 줄만 [now] 로 갱신되어 항상 맨 아래 붙는다. KEEP 도 DROP: m8 로 시드 프레임을 실제로 버리며 온라인 프레임을 넣는다.

rf-v3 계획 체크 (b2b0790f88de, 성공)

t=0 출력 → [plan] 1. [ ] navigate to the egg 2. [ ] navigate to the tissue box 3. [ ] pick the tissue box ← 항목을 스스로 추가 t=1 출력 → 1. [x] navigate to the egg - Arrived at bedroom dresser (egg location). t=2 출력 → 2. [x] navigate to the tissue box t=4 출력 → 3. [x] pick the tissue box - Tissue box was successfully lifted. Goal completed.

[plan] 을 노트 안에 넣은 설계가 의도대로 작동한 첫 증거다.

5남은 문제 2건

(1) 노트가 같은 말을 반복한다

노트 줄유사도>0.8 연속쌍
tagmem-r3908146/781 (19%)
rollforward-v3175114/164 (70%)

위 mug 예시에서 t=2~t=10의 9턴이 전부 같은 문장의 변주다. 파지가 7~9턴 걸리는 동안 상태가 안 바뀌어 쓸 새 정보가 없는 것이라 파지 병목(실패의 84%)이 메모리에 비친 것이지 메모리 결함은 아니다. 다만 tagmem 은 이 반복 줄이 장부에 누적돼 검색 예산을 먹는다.

(2) rf-v3 는 여전히 계획을 지운다

rf-v3 11칸 마지막 턴까지 계획줄 생존 : 1/11 계획 전멸 : 10/11 턴 합계 removed_open=16 vs checked=2

"안 끝난 항목은 절대 지우지 마라"는 지시를 받고도 미완 항목을 8배 더 지운다. 260918의 "rf-v3 계획 100% 삭제"가 완화됐을 뿐 해결되진 않았다. §4에 보인 예시는 사실 1/11 소수 케이스였다. rf-v3 는 아직 11칸뿐이라 잠정치 — delta4 완주 후 확정한다.

대응 방침

둘 다 기록만 하고 프롬프트를 더 밀어붙이지 않는다(evaluate-don't-optimize). 계획 보존이 안 되는 것은 rewrite 전략의 성질이고, 그걸 프롬프트로 강제하면 재는 대상이 바뀐다.

6패리티 게이트 — scripts/check_online_prompt_parity.py

전략 6 × 가족 × 관절 2 × press 2 격자의 시스템 프롬프트를 각 트리마다 별도 프로세스에서 렌더해 md5 를 비교한다(한 프로세스에 두 트리의 sbench_exec 를 같이 올릴 수 없다). 배선 파일 6개 해시, 4개 수정 마커, WRITER_POLICY/PLAN_UPDATE, BUDGET_TEXT·ONLINE_NOTE_TAIL 설정도 함께 본다.

conda activate mlspaces # (a) 트리끼리 비교 — 첫 트리가 기준 python3 scripts/check_online_prompt_parity.py \ --tree tmp/plan_main/src_w2 --tree tmp/routine_online/src_r1 --tree src # (b) 기준선과 비교 — 스냅샷 뜨기 직전 게이트 (종료코드 0/1) python3 scripts/check_online_prompt_parity.py --tree src \ --baseline claude/260921/online_prompt_baseline_v12.json # (c) 기준선 갱신 — 계약을 의도적으로 바꿨을 때만 python3 scripts/check_online_prompt_parity.py --tree <새 스냅샷> \ --write-baseline claude/260921/online_prompt_baseline_vNN.json
파괴적 / 추가분을 나눠 판정한다. 가족·전략이 늘어난 것은 기준이 재던 것을 건드리지 않으므로 실패가 아니다(+ 로 표시). 공유 프롬프트 바이트가 바뀌거나, 정책·설정이 달라지거나, 수정 마커가 빠지거나, 기준에 있던 가족이 사라지면 종료코드 1. 이 구분이 없으면 캠페인이 늘어날 때마다 거짓 경보가 난다.

실행 결과

기준: claude/260921/online_prompt_baseline_v12.json (프롬프트 48개) 가족 ['find','restore'] · eviction_note=True store_tile=True budget_text=12 수정 마커: tag_entries_and_requery=O · now_state_slot=O · keep_eviction_note=O · keep_store_tile=O ── tmp/routine_online/src_r1 ✅ 계약 일치 — 공유 프롬프트 48개 바이트 동일, 정책·설정·수정 마커 동일 + 가족 'routine' 추가 — 프롬프트 24개 (기준이 재던 것에는 영향 없음) ℹ️ 배선 파일 4/6개가 다름 (계약이 같으니 추가분) ── src ✅ 계약 일치 — 공유 프롬프트 48개 바이트 동일, 정책·설정·수정 마커 동일 + 가족 'routine' 추가 — 프롬프트 24개 전부 계약 일치. 스냅샷을 새로 떠도 같은 것을 잰다. 종료코드=0

역방향 검증 — 노트 규칙 uncertain: → maybe: 한 단어

❌ 계약 불일치 16건 - 프롬프트 rollforward-v3|find|art=0|press=0: c01c71dc19c4(3754) → c1e905778764(3750) - 프롬프트 rollforward-v3|find|art=1|press=0: ab762d959afb(3797) → b75eebea0437(3793) - 프롬프트 tagmem-r3|find|art=1|press=0: ef375aa9f05c(4585) → a41445330236(4581) ... (노트 블록을 받는 두 전략 × 2가족 × art 2 × press 2 = 16개만 정확히 적발) ℹ️ 배선 파일 1/6개가 다름 종료코드=1

기준선 프롬프트 md5 (art=1, press=0)

전략findrestore
blind7a5678ecfd79 (2947)50f7a153dd33 (3009)
textlog7a5678ecfd79 (2947)50f7a153dd33 (3009)
frames-uniform2f58f1e1dec4 (2978)778aec25f738 (3040)
rollforward-v3ab762d959afb (3797)0373dd1ff3d9 (3859)
rollforward-vis-pure63fa98083c7c (3649)750b9c35818f (3711)
tagmem-r3ef375aa9f05c (4585)9cd06c16f85a (4647)

blind 와 textlog 가 같은 해시라는 것이 §3 의 기계적 증명이다.

7Takeaway & Next

Next

산출물
  • scripts/check_online_prompt_parity.py — 게이트
  • claude/260921/online_prompt_baseline_v12.json — 캠페인 기준선(48프롬프트)
  • claude/260921/analysis-online_memory_contract_parity.md — 계약 정본 문서
  • claude/260921/plan-resume_routine_online_handoff.md — 다른 세션용 포인터 추가