fix(audit): 턴 귀속을 응답 그룹의 첫 행에 맞추고 라벨 고착을 없앤다 (gen25) - #376
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
709a50f to
9849a81
Compare
턴 귀속을 응답 그룹의 첫 행에 맞추고, 새 도구 결과가 없는 턴이 앞 턴의 라벨을 물려받지 않게 한다. 두 결함은 함께 고쳐야 한다. 라벨만 고치면 여러 행으로 나뉜 응답이 전부 no_tool_result 로 잘못 분류돼 지금보다 나빠진다. 스냅샷 초기화를 행마다가 아니라 응답 그룹 경계에서만 하도록 옮겼다. 그래서 그룹 첫 행의 스냅샷이 곧 '이전 응답이 시작된 이후 도착한 전부'가 되고, 소비자는 group_first_row_ordinal 한 곳만 읽으면 된다. 그룹 중간에 도착한 tool_result 가 아무 턴에도 귀속되지 않던 문제도 함께 사라진다. cache_read 와 cache_creation 의 관계로 턴을 cold_start / cache_rewrite / incremental 셋으로 가르는 직교 필드를 추가했다. rows 의 행이 아니라 별도 필드다. 행으로 두면 그 버킷이 1위가 되어 covers_all_turns 가 거짓이 되고 aim 권고가 그 버킷을 지목한다. parse_json_line 이 올리던 전역 재귀 한도를 scan() 이 끝날 때 되돌린다. 안 되돌리면 같은 프로세스의 다른 코드가 적대적 깊이를 조용히 받아들인다. 실제로 이 PR 의 새 테스트가 core 파티션에서 audit 스캔을 더 일찍 돌리자, 벤치마크 스트림 파서가 2,000단 중첩을 거부하지 못해 CI 가 두 번 실패했다. 이 변경과 무관한 테스트였다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DE3AupXcyv64SEuQeTckSh
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DE3AupXcyv64SEuQeTckSh
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DE3AupXcyv64SEuQeTckSh
…chor Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DE3AupXcyv64SEuQeTckSh
턴 귀속을 응답 그룹의 첫 행에 맞추고, 새 도구 결과가 없는 턴이 앞 턴의 라벨을 물려받지 않게 한다. 두 결함은 함께 고쳐야 한다. 라벨만 고치면 여러 행으로 나뉜 응답이 전부 no_tool_result 로 잘못 분류돼 지금보다 나빠진다. 스냅샷 초기화를 행마다가 아니라 응답 그룹 경계에서만 하도록 옮겼다. 그래서 그룹 첫 행의 스냅샷이 곧 '이전 응답이 시작된 이후 도착한 전부'가 되고, 소비자는 group_first_row_ordinal 한 곳만 읽으면 된다. 그룹 중간에 도착한 tool_result 가 아무 턴에도 귀속되지 않던 문제도 함께 사라진다. cache_read 와 cache_creation 의 관계로 턴을 cold_start / cache_rewrite / incremental 셋으로 가르는 직교 필드를 추가했다. rows 의 행이 아니라 별도 필드다. 행으로 두면 그 버킷이 1위가 되어 covers_all_turns 가 거짓이 되고 aim 권고가 그 버킷을 지목한다. parse_json_line 이 올리던 전역 재귀 한도를 scan() 이 끝날 때 되돌린다. 안 되돌리면 같은 프로세스의 다른 코드가 적대적 깊이를 조용히 받아들인다. 실제로 이 PR 의 새 테스트가 core 파티션에서 audit 스캔을 더 일찍 돌리자, 벤치마크 스트림 파서가 2,000단 중첩을 거부하지 못해 CI 가 두 번 실패했다. 이 변경과 무관한 테스트였다. 지문은 생산 canonicalizer 로 계산했고 기존 레코드와 지문은 건드리지 않았다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DE3AupXcyv64SEuQeTckSh
core-pr 실패 추적: 제 변경이 드러낸 잠재 결함이었습니다core-pr 이 두 번 실패했습니다. 저장소 규칙대로 대조 실험부터 했습니다. 1차 실패 4건 중 3건은 알려진 flaky. 남은 1건은 재현됐고, 진짜였습니다. 원인. 한 프로세스에서 순서대로 돌려 로컬 재현했습니다. 조치. 누수를 막았습니다. 같은 프로세스에서 audit 테스트 뒤에 벤치마크 스위트를 돌려 191건이 모두 통과합니다. 이 수정은 동결 파일이라 세대를 최종 내용으로 다시 작성했습니다. 지문은 그대로 |
9849a81 to
6c3c11b
Compare
* docs: 0.13.0 의 81.5% 주장을 정정하고, 살아남는 근거를 대신 적는다 0.13.0 항목은 Bash escrow 를 기본으로 만든 근거로 "새 토큰의 81.5% 가 Bash 결과 직후에 온다" 를 든다. 그 표에 결함이 둘 있었고 #376 에서 고쳤다. last_result 가 파일 단위로만 초기화돼 새 도구 결과가 없는 턴이 앞 턴의 라벨을 물려받았고, 스냅샷은 accepted 행마다 찍히고 비워지는데 reducer 는 응답 그룹의 마지막 행을 고르므로 여러 행으로 나뉜 응답은 이미 비워진 스냅샷을 읽었다. 교정하면 no_tool_result 약 72%, Bash 약 18% 이고 multi_result_turns 는 약 108 에서 약 2,150 으로 간다. 중요한 것은 escrow 기본값 결정 자체는 다른 근거로 살아남는다는 점이다. 턴은 두 번째 축으로도 갈린다. 캐시 접두사를 다시 썼는가, 이어 붙였는가. 도구가 돌려준 양에 비례해 과금되는 것은 incremental 턴뿐이고, 그 안에서는 Bash 가 여전히 약 69% 를 선행한다. 접두사를 쓴 턴은 cache_creation 의 약 77% 인데 어떤 도구 훅도 줄일 수 없고, 이제 audit 이 cold_start / cache_rewrite / incremental 필드로 따로 보고하며 권고에서도 그 사실을 말한다. 발행된 0.13.0 항목 본문은 고치지 않고 정정을 가리키는 한 줄만 덧붙였다. 이미 나간 릴리스 노트를 조용히 다시 쓰지 않기 위해서다. 수치는 살아 있는 디렉터리에서 나오므로 반올림해 적고 방법은 safety-reference 를 가리킨다. 이 세션 안에서도 같은 스크립트가 76.7 에서 76.9 로 움직였다. audit 스킬 문서도 고쳤다. "가장 많이 선행한 도구를 앞세우라" 는 지시가 접두사 쓰기가 우세한 코퍼스에서 틀린 곳을 가리킨다. 세 필드를 먼저 읽고 incremental 턴이 도구를 가리킬 때만 도구를 앞세우도록 바꿨다. 검증: 인용한 네 수치를 병합된 main 에서 재측정해 확인. tests.test_contextguard_stage2_feasibility + standing_cost 13건 OK, ci_test_gate fast 76건 OK, prepublish_check --skip-tests OK, preflight 경고 없음. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DE3AupXcyv64SEuQeTckSh * docs: GLM 리뷰 blocker — "어떤 도구 훅도 줄일 수 없다" 의 범위를 한정한다 GLM 이 정확히 짚었다. "no tool hook can reduce them" 은 무제한 보편 부정인데 측정된 바 없고 턴 간 효과를 보면 거짓이다. 컨텍스트를 작게 유지하는 훅은 이후 턴의 접두사 크기를 줄이고, 그것이 곧 재작성 비용이다. 이 플러그인의 escrow 가 바로 그런 종류다. 이제 이렇게 적는다. "하나의 도구 결과만 잘라내는 것으로는 그 턴들이 달라지지 않는다. 크기가 그 시점의 컨텍스트 전체를 따라가기 때문이다. 다만 세션 내내 컨텍스트를 작게 유지하는 훅은 나중 재작성이 써야 할 양을 줄인다." 같은 검토에서 나온 나머지도 반영했다. - "the only ones that bill in proportion to what a tool returned" 의 only 를 뺐다. incremental 턴에도 도구 결과가 아닌 텍스트가 붙고, 재작성 턴의 새 접미사에도 도구 반환물이 들어간다. - "escrow default itself survives" 를 순위 서술로 낮췄다. 한 코퍼스에서의 순위이지 측정된 절감이 아니라는 것을 문장 안에 적었다. - SKILL.md 의 지시가 실행 불가능했다. by_preceding_tool 표는 모든 턴을 덮는데 "incremental 턴이 도구를 가리킬 때만" 을 그 표만으로 판단할 수 없다. 표가 전 턴 기준임을 밝히고, 접두사 쓰기가 우세하면 표의 1위를 지목하지 말고 그 사실을 말하라고 바꿨다. 같은 문구가 claude_transcript_cost_audit.py:3365 의 권고 텍스트에도 있다. 그 파일은 Gate-B 동결이라 별도 세대로 고친다. 검증: tests.test_contextguard_stage2_feasibility + standing_cost 13건 OK, ci_test_gate fast 76건 OK, sync_plugin_copies --check 동기화 확인. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DE3AupXcyv64SEuQeTckSh * docs: GLM 후속 non-blocker — 발행 항목 처리 방식을 정확히 적는다 "Historical entries below are left as they were published" 라고 썼는데 실제로는 0.13.0 항목에 정정을 가리키는 괄호 문장을 넣었다. 내부 모순이라 "발행 당시의 본문은 그대로 두되, 영향받은 수치 옆에 이 정정을 가리키는 표시를 덧붙였다" 로 고친다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DE3AupXcyv64SEuQeTckSh --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
두 결함, 반드시 함께 고쳐야 한다
라벨 고착.
claude_transcript_cost_audit.py는last_result를 파일 시작에서만 초기화한다. 그래서 새 도구 결과가 없는 턴이 앞 턴의 라벨을 물려받는다. 코드 자신의 주석(:1465-1467)과 사용자용 노트가 반대를 약속하고 있었다.스냅샷/reducer 불일치. 스냅샷은 accepted 행마다 찍히고 매번 비워지는데, reducer 는 한 응답 그룹의 마지막 행을 고른다. 여러 행으로 나뉜 응답은 이미 비워진 스냅샷을 읽는다.
순서가 결론이다. 라벨만 고치면 지금보다 나빠진다. 다중 행 턴이 전부
no_tool_result로 재분류되기 때문이다. 이 PR 의 테스트는 라벨을 카운터보다 먼저 단언하므로, 앵커 없이 라벨만 고친 트리는 여기서 실패한다(변이 A1 로 확인).창 누적을 별도 합산 없이 얻는 방법
검증에서 "바이트 카운터는 창 누적이 필요하다" 는 지적이 나왔다. 스냅샷 초기화를 행마다가 아니라 응답 그룹 경계에서만 하도록 옮겨서 해결했다. 그러면 그룹 첫 행의 스냅샷이 곧 "이전 응답이 시작된 이후 도착한 전부"가 되고, 소비자는 #375 가 노출한
group_first_row_ordinal한 곳만 읽으면 된다. 그룹 중간에 도착한tool_result가 아무 턴에도 귀속되지 않던 문제도 함께 사라진다.multi_result_turns가 108 에서 2,150 으로 올라 독립 측정치(~2,137)와 맞는다.세 갈래 캐시 축
cache_read <= cache_creation하나로 묶으면 콜드 스타트가 재작성에 섞인다. 실측으로 콜드 스타트가 전체 토큰의 18.75%다. 그래서 셋으로 가른다.cache_read없음)0 < cache_read <= cache_creation)rows의 행이 아니라 직교 필드다. 행으로 두면 이 버킷이 1위가 되어covers_all_turns가 거짓이 되고 aim 권고가 그 버킷을 지목한다. 테스트가 행이 되지 않는 것을 고정한다.권고도 함께 고쳤다
접두사 쓰기가 우세하면 도구를 지목하지 않는다. 고치기 전에는
no_tool_result를 지목하며 "규칙 파일과 MCP 카탈로그를 보라" 고 했는데, 그 버킷의 대부분이 접두사 재작성이라 틀린 곳을 가리킨다.교정된 수치
no_tool_result점유multi_result_turnsCHANGELOG.md:53-55의 "81.5% of new tokens per turn landing right after a Bash result" 는 별도 PR 에서 정정한다. 정직한 대체값도 측정해 뒀다. incremental 턴만 보면 Bash 가 69.32% 로 여전히 1위이므로 escrow 기본값 결정 자체는 그 근거로 살아남는다.변이 테스트
검증
preflight 이 세대 밖 동결 편집을 실제로 잡는지 대조 실험으로 확인했다. 같은 편집을 세대 없이 별도 워크트리에 커밋하면
::warning::Gate-B frozen paths changed (gen24)가 나온다.🤖 Generated with Claude Code
https://claude.ai/code/session_01DE3AupXcyv64SEuQeTckSh