커뮤니티 도구 · Anthropic 공식 아님

캐시 유실 관측소

Claude Code 프롬프트 캐시 유실을 각 요청의 청구 필드로 판정해, 보고한 기계 단위로 추적한다. 기계 1대가 1행이고, 같은 기계의 두 번째 제출은 행을 늘리지 않고 기존 행을 갱신한다. 아래 모든 수치는 자발적 제출자의 브라우저에서 로컬로 파싱되어, 본인이 승인한 집계 숫자만 제출된 것이다.

보고한 기계 수
–
사람이 아니라 기계 1대 = 1행
총 관측 유실
–
정당한 TTL 만료는 제외
재과금 토큰
–
유실 후 다시 과금된 캐시 생성 토큰
관측 기간
–
제출된 가장 이른 날 ~ 가장 늦은 날
내 데이터 진단하기 →

왜 이 관측소가 있나

짧은 경위. 헤드라인에 불리한 사실도 함께 적는다.

2026년 봄부터 일부 Claude Code 사용자에게서 사용량이 비정상적으로 빨리 소진되는 일이 반복됐다. 5시간 한도 창이 수십 분 만에 바닥나는 수준이었다. 5월의 GitHub 신고(#63282)는 응답 없이 자동으로 닫혔다.

8월, 서버가 로컬 세션 로그에 직접 남기는 진단 필드 message.diagnostics.cache_miss_reason이 확인됐다. 이때부터 유실을 체감이 아니라 서버 기록으로 판정할 수 있게 됐다.

정직한 반론도 적어 둔다: 원시 집계의 대부분(운영자 데이터 기준 78%)은 장시간 유휴 후의 정당한 만료였다. 이 사이트는 그것을 제외하고 TTL 안쪽 유실만 센다.

통제된 재현에서는 같은 기계의 4개 세션이 같은 1분 안에 동시에 캐시를 잃었고, 생성된 지 24초 된 캐시 엔트리가 사라지는 것도 관측됐다. 같은 시그니처가 독립 계정 3곳에서 확인됐다.

개인 환경 문제인지 광범위한 문제인지 가르려면 여러 기계에서 모은 구조화된 데이터가 필요하다. 그것을 모으는 곳이 이 사이트다. 논의는 anthropics/claude-code#87966에서 진행 중이다.

진단하면 이런 걸 본다 운영자 기계 실측

내 로그로 진단을 돌리면 돌아오는 화면이 이 모양이다. 아래 테두리 안의 숫자는 지어낸 값이 아니라 운영자 기계 1대의 실측이다(기간은 데이터 파일이 말한다). fleet 집계가 아니라 한 대짜리라서 테두리를 둘렀다. 창은 아래 fleet 행과 같은 전체 기간이다. 숫자가 몇 건 어긋나 보인다면 두 스냅샷의 스캔 시각 차이다. 이 파일을 만든 뒤에 생긴 유실은 다음 제출 때 fleet 행에 합류한다. 만든 방법은 scripts/build_preview.js에 있고, 결과 파일은 assets/preview.js다.

시간대가 왜 여기만 보이나: 제출 스키마에는 일별 집계만 있고 시간대 항목이 아예 없다. 제출만으로 언제 일하는지가 드러나지 않도록 일부러 뺐고, 그 결정은 그대로다. 이 화면의 시간대는 운영자가 자기 기계 것을 스스로 공개한 것이지 누구에게서 걷은 값이 아니다. 제출하는 사람의 시간대는 애초에 수집되지 않는다. requestId와 로그 파일 경로는 이 파일에 없다. 생성기가 그 둘이 들어간 파일은 쓰지 않고 중단한다.

스캔한 요청
–
유실 (확정+유력)
–
30분(메인) / 5분(서브에이전트) 안쪽
iron 유실
–
유휴 간격 5분 미만
재과금 토큰
–
다시 과금된 캐시 생성 토큰
유실률
–
유실 / 요청
유실 건수 (좌축) 유실률 % (우축) 무결한 날
미사용(요청 0) 회색 음영 = 그 시간대 요청량(진할수록 많음) 적색 = 유실 건수(셀 안 숫자, 클릭하면 아래 표가 그 시간대로 바뀐다)

내 로그로 직접 돌려보기 → 파싱은 브라우저 안에서 일어난다. 로그 파일은 기기를 떠나지 않고, 공유 버튼을 누르기 전에는 아무것도 제출되지 않는다.

Fleet 일별 유실률 추이 실제 제출 데이터

그날 요청 대비 집계 유실 비율을 보고한 기계 전체를 하나로 합쳐 한 선으로 그린다. 선이 올라간다는 건 제출자가 늘었다는 뜻이 아니라 보낸 요청 중 잃은 비율이 커졌다는 뜻이다. 분모가 같은 날의 요청 수이기 때문이다. 유지되는 하락 계단은 수정 배포 시점을 가리킨다. 이 축의 하루는 모두 UTC 기준이고 모든 제출에 같은 기준이 적용된다. 서로 다른 기계를 같은 날짜에 합산하는 일이 의미를 가지는 근거가 이것이다. 한 대만 보고한 날은 그 한 대의 유실률이다. 그래서 그날 몇 대가 보고했는지도 함께 그린다. 날짜마다 기계 수가 달라지면 각 날짜 뒤에 옅은 세로 막대로 나타나고, 모든 날이 같은 수인 동안에는 범례가 그 수를 글로 적는다.

기계마다 한 선씩 그리는 게 이전 설계였다. 제출 1건일 때는 읽히지만 50건이면 읽을 수 없고, 방문자마다 모든 제출자의 일별 이력 전체를 내려받게 만든다. 기계별 숫자가 사라진 건 아니다. 제출 목록의 각 행이 그 행의 합계가 곧 그 합인 파일을 링크한다.

시간대별 실제 제출 데이터 · 옵트인

시간대 공개를 스스로 켠 기계만 반영한다(진단 페이지의 체크박스, 기본 끔). 칸마다 몇 대의 기계가 실려 있는지가 다르므로 각 칸 툴팁에 그 수를 함께 적는다. 1대짜리 칸은 그 1대의 기록이다. 모든 칸은 UTC 시간이다.

환경별 분해 실제 제출 데이터

같은 제출 데이터를 환경 항목 하나로 묶어 본 것이다. 표본 수는 모든 행에 함께 적는다. 기준 미만인 그룹은 건수만 보여주고 유실률은 내지 않는다.

제출 데이터를 어떤 자기신고 항목으로 묶을지 고르는 버튼이다. 고른 기준으로 아래 표가 다시 묶이고, 그룹마다 유실률을 새로 계산하며, 표본 수는 모든 행에 함께 적는다.

값표본 수 (n)합산 요청유실유실률
원자료 보기 (제출 1건 = 1행)
닉네임클라이언트플랜동시 세션총 요청유실유실률
  • 환경 항목은 전부 제출자가 스스로 적은 값이다. 검증할 수단이 없다.
  • –
  • 기계마다 요청 규모가 자릿수 단위로 다르다. 여기 유실률의 분모는 서로 크기가 비대칭이고, 큰 기계 하나가 그룹 전체를 끌고 갈 수 있다.
  • 제출 5건 미만인 그룹은 건수만 표시한다. 행 순서는 정렬이지 순위가 아니다. 한 행이 뒷받침하는 것은 "지금까지 제출된 것이 이렇다"까지다.

탐지기가 본 것 실제 제출

이 페이지의 모든 수치는 문자열 하나에서 나온다. 서버가 직접 찍는 cache_miss_reason이 previous_message_not_found일 때다. 이름에 의존한다는 뜻이고, 이름은 바뀐다. 만약 바뀌면 위의 모든 차트가 조용히 0으로 떨어지고 그게 좋은 소식처럼 읽힌다. 그래서 제출하는 기계마다 자기 로그에 실제로 있던 사유값 이름도 같이 보고한다. 이름만 보내고 각각 몇 건인지는 보내지 않는다. 이 표가 그 목록이다.

보고된 사유값

값기계 수

보고된 클라이언트 버전

버전기계 수

  • 기계는 자기 스캔에서 만난 이름을 보고한다. 여기 있는 어떤 것도 유실 건수가 아니고, 위의 어떤 수치도 바꾸지 않는다.
  • 보고 단위는 요청이 아니라 기계다. 한 번 본 값과 만 번 본 값이 똑같이 기계 1로 나온다.
  • 각 행은 그 기계의 가장 최근 스캔이 본 것이다. 더 이상 안 나오는 값은 목록에서 빠진다. 그게 의도다. 이름이 바뀐 건 변화로 보여야지, 지금까지 본 것 전부 밑에 묻히면 안 된다.
  • (none)은 로그 레코드가 버전을 안 남긴 것, (invalid)는 평범한 태그가 아닌 값, (other)는 그 기계에서 상위 12개 밖 전부다.

제출 목록 실제 제출 데이터

제출별 집계 합계. 시각·세션 ID·파일 경로는 없다. 스키마 차원에서 담을 수 없다. 닉네임은 마스킹해서 저장하므로, 본인이 제출한 행은 이 브라우저에 남은 기록으로 표시한다. 열 제목을 누르면 정렬된다. 화면에 보이는 행 순서만 바뀌고 이 페이지의 다른 것은 아무것도 바뀌지 않는다.

마지막 열은 그 행의 일별 원본 파일을 링크한다. 행의 합계가 곧 그 파일의 합이므로 산수를 한 행씩 따로 검증할 수 있다. 색인(이 표), 일자별 시계열(위 그래프), 그리고 기계당 상세 파일 1개다. 이 페이지가 내려받는 건 앞의 둘뿐이고 상세 파일은 절대 자동으로 받지 않는다. 여는 건 읽는 사람의 선택이다. 지문 파일도 마찬가지다. 공개돼 있고 여기서 링크하지만 받지는 않는다.

일별 원본

방법론 · 신뢰

무엇을 유실로 판정하는지, 그리고 왜 모든 단계를 직접 검증할 수 있는지.

  • 근거 데이터 (v3): 로컬 세션 로그(~/.claude/projects/**/*.jsonl) 각 요청의 청구 필드 cache_read_input_tokens와 cache_creation_input_tokens. 청구 그 자체다. 서버의 cache_miss_reason 주석은 캐시가 아니라 진단 기능의 상태를 말하므로(Anthropic 지원 답변, 2026-08) 유실을 세는 데 사유 이름이 필요 없다. 사유 이름의 유일한 힘은 면책이다. *_changed 4종은 프롬프트가 실제로 바뀌었다는 선언이라 그 재생성을 집계에서 뺀다.
  • 판정: 같은 세션 파일에서 직전 요청과의 유휴 간격이 30분 미만(메인) / 5분 미만(서브에이전트)이고 면책 사유가 없을 때, cache_read가 0인데 캐시를 새로 썼으면 확정 유실(캐시 전체가 사라짐), 프리픽스는 읽혔는데 10만 토큰 이상을 재생성했으면 유력 유실(전체 쓰기 중앙값 약 1,500 / p99 약 84,000). 그보다 긴 간격은 정당한 만료로 제외한다.
  • iron 유실: 집계된 유실 중 유휴 간격 5분 미만인 부분집합. 공표된 어떤 TTL로도 만료됐을 수 없는 구간.
  • v2.1 계열 병존: 옛 사유 기반 집계(previous_message_not_found + TTL 안쪽 간격)도 pmnf로 일별·행별로 계속 계산한다. 같은 자로 몇 달을 잰 시계열은 자를 바꾼 뒤에도 그대로 가치가 있다.
  • 재작성 고지 (2026-08): 위 규칙은 Anthropic 지원이 사유 필드가 그 무게를 감당하지 못한다고 확인해 준 뒤 v2.1 사유 기반 판정을 대체한 것이다. 이 페이지의 수치는 v3 수치이고, 변경 전 수치와 양방향으로 다르다. 재과금이 미미한 사유-단독 이벤트는 빠졌고, 옛 규칙이 못 보던 재생성(사유가 개명됐거나 아예 없는데 청구는 유실 모양인 것)은 들어왔다. 자를 조용히 바꾸는 쪽이 더 쌌겠지만 더 나빴을 것이다.
  • 중복 제거 · 비용: requestId 기준으로 중복을 제거하고, 유실 1건의 재과금 비용은 그 요청의 cache_creation_input_tokens다.
  • 요청이 어느 날짜로 세어지나: 이 관측소와 여기 쌓인 모든 제출은 하루를 UTC로 자른다. 여러 나라의 제출을 날짜별로 더하는 자리라, 각자의 현지 날짜로 자르면 전체 일별 합계가 어긋나기 때문이다. 진단 페이지는 일부러 반대다. 한 사람의 자기 진단이므로 그래프·히트맵·건별 시각을 읽는 사람의 현지 시각으로 그리고, 그 시간대는 브라우저에서 읽어 와 화면에 이름으로 적는다. 요청도 총계도 같고 날짜 경계만 움직이므로, 자정 근처의 요청은 그쪽에서 본 날짜와 여기의 날짜가 하루 다를 수 있다. 진단 페이지의 전송 미리보기가 보내기 전에 이 차이를 알려 준다.
신뢰 모델: 파싱은 당신의 브라우저에서 로컬로 실행된다. 로그 파일은 기기를 떠나지 않는다. 전송되는 것은 본인이 명시적으로 승인한 집계 숫자(일별 건수·합계)뿐이다. 진단 페이지는 결과를 그 브라우저의 저장 공간에 남길 수 있는데, 저장 버튼을 누르고 확인 창에서 확인했을 때만 그렇다. 저장분은 본인 컴퓨터 안에만 있고 서버로 가지 않으며 버튼 하나로 지운다. 이 사이트는 빌드 스텝이 없어서 실행되는 코드가 repo에 있는 코드 그대로다. 실행 전에 한 줄씩 읽어볼 수 있다.
내 대화 내용이 업로드되나?
아니다. 파싱은 전부 브라우저 안에서 일어난다. 직접 검증할 수 있다: F12 Network 탭을 열고 진단을 돌려 보면 네트워크 요청이 없다. 공유 버튼을 누르기 전에는 아무것도 전송되지 않고, 누르면 화면에 미리 보여준 집계 숫자 JSON만 나간다.
이 사이트가 내 컴퓨터에 뭔가를 남기나?

이 페이지는 아무것도 남기지 않는다. 진단 페이지는 기본값으로 남긴다. 거기서 스캔이 끝나면 총계·일별 집계·시간대별 요청 수가, 이 기계를 한 행으로 유지하는 지문 해시와 함께 그 브라우저의 저장 공간에 기록된다. 그 페이지의 체크박스로 끌 수 있고(스캔 전이든 후든), 최근 8건까지만 남는다.

저장분의 성격: 그 컴퓨터의 그 브라우저 안에만 있고, 서버로는 전송되지 않으며, "저장된 기록 지우기"를 누르면 즉시, 완전히 삭제된다. 다음 진단이 마지막 제출 다음 날부터 시작되게 해서 이미 공유한 기간을 다시 보내지 않도록 하는 용도다. 로그 파일 경로·세션 ID·requestId·대화 내용은 저장하지 않는다. 제출 스키마에서 빼 둔 것과 같은 기준이다. 공용·공유 컴퓨터에서는 저장하지 말 것.

이 코드가 뭐 하는지 어떻게 믿나?

실행되는 코드가 repo 파일 그대로다(빌드 없음). 브라우저 view-source와 repo를 한 줄씩 대조할 수 있다. 구성은 이게 전부다:

  • assets/parse.js: 유실 판정 엔진(브라우저에서 실행). CLI scripts/check_cache_loss.py와 같은 규칙이고, 두 결과가 같은지 자동 테스트로 대조한다.
  • assets/charts.js: 그래프 그리기 전용. 판정 계산은 하지 않는다.
  • assets/store.js: 진단 페이지의 로컬 저장. 브라우저 저장 공간만 쓰고 네트워크는 쓰지 않는다. 기본값은 켜짐이고 체크박스로 끈다.
  • functions/api/submit.js: 서버에서 도는 유일한 코드. 제출 버튼을 눌렀을 때만 호출되고, 스키마 검증 후 아래 네 데이터 파일을 한 커밋에 함께 쓴다.
  • data/submissions.json: 색인. 제출한 기계 1대가 1행이고 합계만 담는다. 이 페이지가 읽는다.
  • data/daily.json: 일자별 시계열. 달력 하루가 1행이고 모든 기계를 합산한 값이다. 그래프가 이걸 읽고, 이 페이지가 받는 파일은 이 둘뿐이다.
  • data/identity.json: 기계 지문. 해시된 anchor와 링크 토큰 해시를 제출 id별로 담는다. 다른 파일과 똑같이 공개돼 있고 이 링크로 바로 열린다. 이 페이지가 내려받지 않을 뿐이다. 예전에는 색인 행 안에 들어 있었고 지문 붙은 행 용량의 약 70%를 차지해서 모든 방문자가 그 무게를 같이 받았다. 빼낸 건 페이지를 가볍게 한 것이지 데이터를 감춘 게 아니다. 저장되는 값은 두 번 해시한 값이라 여기서 복사한 값으로는 아무것도 맞출 수 없다.
  • data/subs/<id>.json: 제출 1건당 1개 파일. 그 기계의 일별 원본이 들어 있다. 제출 목록의 모든 행에서 링크되지만 이 페이지가 내려받지는 않는다. 색인 행의 합계는 그 파일의 합과 정확히 같고, data/daily.json은 모든 상세 파일의 합과 정확히 같다. repo의 tests/dataset_validate.py가 둘 다 다시 검산한다.
  • wrangler.toml: 서버 설정도 repo에 공개. 숨겨진 백엔드가 없다.
돌리면 내 Claude 계정에 영향이 있나?
없다. 로그 파일을 읽기만 한다. Anthropic 계정이나 API와는 어떤 통신도 하지 않는다.
유실이 나왔다. 이제 뭐를 하나?
GitHub #87966에 결과를 남겨 달라. 0이 나왔어도 똑같이 가치 있는 데이터다. 정상 계정의 존재도 원인 특정에 필요하다.
제출하면 뭐가 공개되나?
미리보기로 승인한 집계·일별 숫자와 선택 입력한 닉네임뿐이다. 제출 이력 전체가 repo 커밋으로 남아 누구나 감사할 수 있다.
Anthropic 공식 사이트인가?
아니다. Anthropic과 무관한 커뮤니티 도구다.
내 데이터 진단하기 →