Index
2026-09-21 — Analysis

두 트랙의 가구 이름이 갈린다 — 읽기 관대화(R2)와 온라인 접지

scene_bench | 읽기 트랙은 이름을 채점하고, 온라인 트랙은 바디로 간다

TL;DR

170
차단 칸(수정 전)
0
차단 칸(수정 후)
3
이름 불일치 종
130
R2 위양성 의심
$0
API 비용

1배경 — 왜 이 질문이 나왔나

읽기 트랙(VLM eval)에 tv stand 구제 규칙(R2)을 넣어 정답이 늘었다. 원인은 하네스 결함 둘이다.

① uid 접두사 `stand_` 가 씬카드 category 기준 TVStand 와 SideTable 을 **둘 다** "tv stand" 로 접는다 ② type1 답 어휘 SURFACES 에 `side table` 이 아예 없어, 모델이 그렇게 답하면 채점기가 버린다 (routine 만 260914 에 SURFACES_ROUTINE 으로 고쳤다 — 가족 간 어휘 불일치)

질문은 둘이었다. (a) 읽기에서 정답을 늘린 게 타당한가? (b) 늘어난 답(desk·coffee table 등)을 온라인에서 실행하면 로봇은 어디로 가야 하나?

두 트랙의 계약이 다르다. 읽기는 이름 대 이름으로 채점한다. 온라인은 이름을 물리 바디로 접지해야 행동이 시작된다(navigate(room, surface) → grounding.ground_selection(strict=True)). 그래서 읽기의 관대화가 온라인으로 그대로 옮겨지지 않는다.

2읽기 R2는 괜찮은가 — 구제 473행의 근거 분포

구제 근거findrestore계
원문이 side table / nightstand / end table 을 말함102150252 (53%)
답 값이 desk · coffee table 이라서16061221 (47%)
  ↳ 그 방에 그 가구가 없다 (어휘 대체로 설명됨)15941200 (90%)
  ↳ 그 방에 진짜 있다 (위양성 의심)12021

헤드라인 영향은 find +0.2~2.6pp · restore 최대 +5.0pp(textlog). blind 는 +0.2pp만 움직이고 tagmem−vis-pure 격차는 오히려 줄어든다 — 우리 쪽에 유리한 방향의 관대화가 아니다.

판단: R2는 채점을 느슨하게 한 게 아니라 어휘 결함의 사후 보정이고, 근거 분포가 그걸 뒷받침한다. 다만 §5에서 이 그림이 한 번 더 뒤집힌다.

3두 트랙 가구 이름 대조표 (본 런이 쓰는 집 79채 · 표면 627바디)

GT 표면 uid를 씬카드 body로 조인해 진짜 category를 얻고, 읽기 이름(vocab.surface_display(uid 접두사))과 온라인 이름(naming.display_name(sim category))을 비교했다.

uid 접두사씬카드 category읽기 이름온라인 이름GT 사용(칸)
standSideTabletv standside table180
shelfShelvingUnitshelfshelving unit35
refrigeratorFridgerefrigeratorfridge0 (잠복)
나머지 15종 (dining table · countertop · chair · dresser · TVStand · toilet · sofa · bed · desk · armchair · sink · coffee table · cart · clothes dryer · washing machine)일치
shelf는 아무도 몰랐던 같은 결함이다. 이 79채에서 shelf_ 바디는 전부 ShelvingUnit이라, 읽기 GT가 "shelf"라고 말하는 순간 온라인에서는 항상 접지에 실패한다.

4수정과 결과 — 오라클-플랜 본 런 1,490칸

두 장치, 다른 역할

장치무엇을 한다GT를 보나
naming.COARSE_ALIASES (접지)거친 이름(tv stand·shelf)이 두 category에 닿게. 정밀 이름(side table)은 자기 것만 — 한 방향아니오 (누구에게나 같음)
online_plan.retarget_gt_surfaces (계획)GT/오라클 계획 문장이 그 씬이 부르는 이름을 쓰게GT→GT (누출 없음)
retarget_rescued_surfaces (구제 행)R2로 정답 판정된 행의 계획을 GT 바디로. 모델이 댄 가구가 그 방에 진짜 있으면 치환 안 함예 (사용자 결정 260921)
판정수정 전 (find · restore)수정 후
ok117 · 84126 · 97
ungroundable (그 방에 그 이름 가구 없음)17 · 17  170칸0 · 0
misrouted (엉뚱한 바디로)1 · 5  30칸0 · 0
ambiguous (같은 이름 가구 여럿)14 · 4223 · 51

남은 ambiguous는 이름 결함이 아니라 답 granularity 한계다 — "어느 의자인가"는 답 어휘로 표현할 수 없다. find는 instances_on이 같은 이름 앵커 전부에서 질의 물체를 찾아 흡수한다. §6에서 따로 다룬다.

이미 돌고 있던 모델-플랜 셀(find 302칸)의 노출은 2칸뿐이었고 둘 다 shelf였다. 온라인 셀이 "읽기에서 맞힌 칸"만 쓰기 때문에, tv stand 결함 행은 애초에 거의 안 들어왔다.

5⚠️ 발견 — R2의 원문 스캔이 dresser 기각을 우회한다

구제 행에 위양성 가드를 실제로 돌려 보니 473행 중 130행(27%)에서 모델이 댄 가구가 그 방에 진짜 있었다. 답 분포: dresser 84 · tv stand 18 · dining table 7 · toilet 5 · 그 외 16.

# naming_rescue.side_pass — 순서가 문제다 if RAW_PAT.search(raw): return True # ← 원문에 side table 이 있으면 **답 값을 보지 않고** 통과 return got in MAPPED # desk/coffee table 만 허용하는 이 줄에 도달하지 않는다

R2 문서는 "dresser 는 구제하지 않는다 — 실측상 그 방에 진짜 dresser 가 있었다(restore 54/54 · find 80/82)"라고 명시한다. 그런데 추론 원문 어딘가에 "side table"이 나오기만 하면 답이 dresser여도 통과한다. R3를 기각한 바로 그 행들이 다른 문으로 들어온다.

가족가장 큰 하락 (그 130행 제외 시)우리(tagmem-r3)
findtextlog(oracle) −0.007 ~ −0.014 (4~8행)−0.002 ~ −0.003
restoretextlog(oracle) −0.010 ~ −0.026 (6~15행)−0.002 ~ −0.005
해석: 이 구멍은 우리 수치가 아니라 천장(oracle)을 부풀린다 — 추론 원문이 가장 길고 가구 이름을 많이 부르는 전략이 textlog이기 때문이다. 방향은 우리 주장에 불리하지 않지만, "우리 방법 대 oracle 격차"를 인용하면 그만큼 과장된다. 온라인 쪽은 가드로 막아 뒀다(guarded: true로 표시, 셀에서 빼는 것을 권함). 읽기 본표를 고칠지는 사용자 결정 대기 — 고친다면 side_pass의 원문 분기 뒤에 "댄 가구가 그 방에 없을 것"을 더하면 dresser 기각과 잣대가 하나로 통일된다.

6모호(ambiguous) — 답 계약 아래 granularity, 결정 C

같은 방에 같은 이름 가구가 여러 개라 답이 어느 인스턴스인지 특정하지 못하는 면이다. 실례(restore train_1299__2, "종이타월을 원래 자리에"):

GT 수납처: chair_c3057864..._1_0_6 ← 정답은 이 의자 하나 그 방(kitchen)의 의자: _1_0_6 (5.47, 5.75) _2_0_6 (3.37, 5.75) _3_0_6 (3.99, 5.16) _4_0_6 (4.79, 6.34) _5_0_6 (4.78, 5.16) 계획 문장: "… on the chair in the kitchen" ← 똑같은 의자 5개, 구별할 말이 없다

이미 있는 두 장치는 이걸 못 푼다

장치하는 일왜 모호를 못 푸나
place_anchors (260918)든 채 이동 시 그 가구의 어느 쪽에 설지를 물체 원래 자리 기준으로 정렬게이트가 surface == decision.object_id — 이미 GT 가구를 골랐을 때만 걸린다(순환). 틀리면 접근 보정까지 같이 잃는다
instances_on같은 이름 앵커 전부에서 질의 물체를 찾아 "물체가 올려진 그 가구"로 접지find 전용. restore 목적지는 물체가 아직 거기 없다 — 그게 과제다

폴백(uid 오름차순)은 GT를 거의 못 맞힌다

모호한 면uid 1등 == GT
find20 (k=2가 12 · 최대 k=6)7
restore (목적지)29 (k=4가 14 · k=5가 6)6

결정 C — 전 가족 균일 (사용자, 260921)

답이 가리키는 가구가 여럿이면 하네스가 GT 인스턴스로 접지한다. 근거는 grounding.py의 기존 원칙 — "답의 granularity(방·가구)까지는 메모리 책임, 그 아래 국소 지각은 하네스가 대신한다". find는 그걸 지각으로 풀고, 지각 단서가 없는 목적지는 GT로 푼다.

채점 술어는 손대지 않는다 → routine A6("본표는 증거 인스턴스")와 충돌하지 않는다. 대안 B(아무 인스턴스나 정답)는 A6와 정면으로 어긋나므로 기각.

공정성: (방, 가구 이름)을 맞힌 arm이면 어느 전략이든 똑같이 받고, 틀린 답은 아무것도 못 받는다. "어느 의자인가"는 답 어휘로 표현할 수단이 없으므로 지워지는 능력 축이 없다. GT는 place_anchors와 같이 하네스 내부에만 쓰이고 VLM에 노출되지 않는다 — 프롬프트 패리티 게이트 통과(공유 프롬프트 288개 바이트 동일).
naming.resolve_name(..., preferred=()) # 후보에 GT uid 가 있으면 거리 대신 그것 online_planner._prefer(candidates, fallback) # navigate 는 g.candidates, place 는 resolve_name online.py plan.gt_faces → preferred_surfaces # 행에 ambiguous_decisions / preferred_hits 기록
이름이 안 맞으면 아무 일도 일어나지 않는다 — 후보에 GT가 들어있을 때만 순위를 바꾼다(테스트로 고정). 하네스가 틀린 답을 고쳐주지 않는다.

7Next

근거·재현 claude/260921/analysis-naming_two_track_grounding.md # 분석 본문 scripts/rescued_rows_for_online.py → tmp/rescued_rows_online.json # 구제 473행 + 가드 tests/exec/test_naming_retarget.py # 15개 테스트 tmp/naming_parity_table.py · naming_ground_impact.py · naming_final_state.py