Skip to content

[Bug] responses-state.json repeatedly rewrites a near-24 MiB snapshot under sustained traffic #2460

Closed

Description

@twk0672005

Client or integration

Codex App

Area

Proxy and routing

Summary

@bitkyc08/opencodex@2.31.0 still rewrites the complete responses-state.json snapshot on a fixed 2-second debounce. On one Windows host the file reached 25,165,601 bytes (approximately the 24 MiB snapshot budget). While the snapshot was near that size and actively mutating, process-wide Bun counters showed approximately 2.4–5.2 MB/s of write I/O and 20–50% of one logical core.

Those counters were not isolated to responses-state.json; the tagged source behavior plus the file's size/mtime establish the repeated full-snapshot rewrite mechanism. The process-wide samples quantify the host impact during the same active window, not an exclusively path-attributed SSD-write rate.

This is a properly templated re-report and current-version confirmation of #1385, which was closed automatically because it did not use a recognized issue template. The underlying design remains present in 2.31.0.

Reproduction

  1. Install and run @bitkyc08/opencodex@2.31.0 as a local proxy.
  2. Route sustained Codex/agent traffic through it until the continuation-state snapshot approaches its 24 MiB budget.
  3. Monitor ~/.opencodex/responses-state.json size/mtime together with Bun process write-I/O and CPU counters while responses continue mutating state.
  4. Observe repeated atomic replacement of the complete near-24 MiB JSON snapshot after successive debounce/flush cycles.

Observed on this machine:

  • Snapshot size: 25,165,601 bytes.
  • Bun process-wide sampled write I/O during active state mutation: approximately 2.4–5.2 MB/s.
  • Bun process-wide CPU: approximately 20–50% of one logical core during the same active samples.
  • No path-filtered Procmon/ETW capture was taken, so the process counters may include other Bun I/O/CPU work.
  • The file stayed near the designed cap, so each persistence cycle paid the complete retained-snapshot serialization and replacement cost.

Expected behavior:

Persistence cost should scale with changed state rather than the complete retained snapshot, or operators should have a supported way to trade continuation-cache durability against write amplification.

Potential directions (also consistent with #1385):

  • adaptive/longer debounce based on snapshot size;
  • skip identical payloads;
  • append-only journal with periodic compaction;
  • a supported configuration knob for snapshot cadence/budget;
  • move continuation state to an incremental store.

Actual behavior:

The first state mutation while no flush is pending schedules a complete snapshot rewrite two seconds later; additional mutations coalesce into that pending flush. Under sustained mutation, later flush cycles continue serializing and atomically replacing the complete bounded snapshot.

Version

@bitkyc08/opencodex@2.31.0 (npm global installation).

Operating system

Windows 11 Home, build 10.0.26200.

Provider and model

Not provider-specific. This is local continuation-state persistence performed by the proxy.

Logs or error output

responses-state.json size: 25,165,601 bytes
sampled Bun process-wide write I/O while active: approximately 2.4–5.2 MB/s
sampled Bun process-wide CPU while active: approximately 20–50% of one logical core

Source behavior in v2.31.0:

  • fixed SNAPSHOT_DEBOUNCE_MS = 2_000;
  • approximately 24 MiB snapshot-entry budget;
  • JSON.stringify of retained state followed by atomic replacement of the complete file.

Screenshots and supporting files

No private screenshots attached. The issue was diagnosed from file metadata sampling, process-wide I/O/CPU sampling, and the tagged v2.31.0 source.

Prior report: #1385 (auto-closed for missing template, not technically resolved).

Redacted configuration

{
  "install_method": "npm -g",
  "version": "2.31.0",
  "service_backend": "scheduler",
  "listen_port": 10100,
  "providers": "redacted",
  "credentials": "removed"
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    bugSomething isn't working
    proxyHTTP proxy, routing, reverse-proxy / management auth
    on Aug 23, 2026
  2. coderabbitai commented on Aug 23, 2026

    @coderabbitai
    Contributor
    ⚠️ Possible Duplicate Issue(s)

    📝 Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  3. lidge-jun commented on Aug 24, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 54 / 80

    설명: 이 이슈는 이어가기 상태 스냅샷 responses-state.json 이 고정 2초 디바운스로 통째로 다시 쓰인다고 한다. 한 윈도우 호스트에서 파일이 25,165,601 바이트, 곧 24 메비 예산 근처까지 컸다. 스냅샷이 그 크기에서 계속 바뀔 때, 프로세스 전체 번 쓰기 카운터는 초당 대략 2.4에서 5.2 메가, 논리 코어 하나는 20에서 50 퍼센트였다. 그 카운터는 이 파일만의 숫자가 아니다. 태그 소스와 파일 크기와 시각이 통째 다시 쓰기 길을 보여 준다. 프로세스 숫자는 같은 창의 호스트 부담이다. 경로만의 에스에스디 속도는 아니다. 이것은 1385 의 템플릿을 갖춘 재보고다. 1385 는 템플릿이 없어서 자동으로 닫혔다. 기술적으로 고친 것이 아니다. 작성자 버전은 엔피엠 전역 2.31.0 이다. 지금 CURRENT dev HEAD 는 35a89903c 이다. 이번 시간에 origin/dev 는 그대로다. 새 머지는 없다. package.json 은 2.27.0 이다. src/config.ts 는 3238줄이다. src/runtime 폴더는 지금 HEAD 에 없다.

    살아 있는 재현은 이렇다. 로컬 프록시로 코덱스 에이전트 요청을 오래 보낸다. 이어가기 스냅샷이 24 메비 예산 근처까지 큰다. 파일 크기와 수정 시각을 보고, 같은 창의 번 쓰기와 시피를 본다. 디바운스와 플러시가 돌 때마다 통째 스냅샷이 원자로 교체된다. 이 기계에서는 파일 25,165,601 바이트였다. 경로를 가린 프로크몬은 없다. 그래서 프로세스 카운터에는 다른 번 일도 섞일 수 있다. 기대는 바뀐 상태만큼만 쓰거나, 운영자가 이어가기 캐시 내구성과 쓰기 증폭을 바꿀 손잡이를 갖는 것이다. 실제는 대기 플러시가 없을 때 첫 변경이 2초 뒤 통째 다시 쓰기를 예약한다. 그 사이 변경은 그 플러시에 합쳐진다. 계속 바뀌면 다음 주기마다 예산만큼의 스냅샷을 다시 직렬화하고 원자로 바꾼다.

    지금 HEAD 의 src/responses/state.ts 20줄은 SNAPSHOT_DEBOUNCE_MS = 2_000 이다. 27줄은 스냅샷 전체 예산 24 메바다. 24줄 메모리 캡은 64 메바다. 스냅샷과 메모리는 다른 한도다. 760줄 근처 쓰기 함수는 고른 항목을 최신부터 담는다. 항목이 2 메비를 넘으면 건너뛴다. 합이 24 메비를 넘으면 멈춘다. 그 다음 793줄이 전체 제이슨을 문자열로 만들어 원자 파일로 바꾼다. 같은 내용인지 비교하지 않는다. 812줄 예약은 타이머가 이미 있으면 그냥 돌아온다. 대기 중에는 합쳐진다. 그런데 820줄 지금 쓰기가 끝나면 타이머가 비고, 다음 변경이 또 2초 통째 쓰기를 건다. 지속 변경에서는 2초마다 최대 24 메비를 다시 쓴다. 스필은 램을 줄인다. 디스크 스냅샷은 여전히 고른 항목 전체를 다시 쓴다. 이 설계는 지금 HEAD 에 있다.

    1385 는 템플릿 없어서 자동 닫힘이다. 이번 이슈는 템플릿을 갖췄다. 1385 를 다시 열지 말 것. 이번을 닫지도 말 것. 코더래빗이 중복이라고만 적었다. 그 봇 댓글은 기술 판결이 아니다. 고침 후보는 크다. 스냅샷 크기에 따라 디바운스를 늘리기, 같은 페이로드 건너뛰기, 추가만 하는 저널과 가끔 압축, 운영자 손잡이, 이어가기를 증분 저장소로 옮기기. 지금은 범위를 좁혀야 한다. 같은 페이로드 건너뛰기와 큰 스냅샷에서 디바운스를 늘리는 것이 가장 작다. 저널과 증분 저장소는 별 사이클이다. 손잡이는 기본값을 안전하게 둔 뒤에만 넣는다. 2459 윈도우 모듈 지도와 길이 다르다. 한 기차에 섞지 말 것. 프로세스 전체 쓰기 숫자를 이 파일만의 속도로 단정하지 말 것. 작성자도 그렇게 적었다.

    사용자 길이로는 긴 세션에서 디스크가 2초마다 24 메비 근처를 다시 써서 노트북이 뜨거워질 수 있어서 54. 요청이 바로 502 로 죽지는 않는다. 카탈로그 팁은 Ox Alpha x-preview-f-free + deepseek-v4-flash-vision-exp. Cursor 정적 카탈로그는 opus-4-8-fast / opus-5-fast. 2334 CursorCredentialRouter 는 여전히 src/providers/cursor-pool.ts 모듈+테스트만 있고 어댑터에 연결되지 않았다. 2332 H2 는 discovery 전용. 2320 overflow + 2342 는 이미 dev. 2188 사이드카는 이미 dev. 2361 __omit__ 는 이미 HEAD 다. combo-stream-preflight.ts 는 지금 HEAD 에 있다. src/lib/bounded-body.ts 128줄 취소 없는 던짐과 2426 나가는 크기 가드는 그대로다. 2451 wait 허용 목록은 아직 하이픈이다. 이번 스냅샷 쓰기는 그 구멍들이 아니다.

    src/responses/state.ts 라인 20 - 디바운스가 고정 2초다. 스냅샷이 커져도 그대로다
    src/responses/state.ts 라인 27 - 스냅샷 전체 예산은 24 메바다. 작성자 파일은 그 근처다
    src/responses/state.ts 라인 793 - 고른 항목 전체를 문자열로 만들어 원자로 바꾼다. 같은 내용 비교가 없다
    src/responses/state.ts 라인 812 - 대기 타이머가 있으면 합친다. 쓰기가 끝나면 다음 변경이 또 통째 쓰기를 건다
    src/responses/state.ts 라인 24 - 메모리 캡은 64 메바다. 스필은 램을 줄인다. 디스크 통째 쓰기는 남는다
    이슈 1385 - 템플릿 없어서 자동 닫힘이다. 다시 열지 말 것. 이번 이슈를 그 이유로 닫지 말 것

    메인테이너의 판단이 필요한 지점

    • 같은 페이로드 건너뛰기를 먼저 넣을지. 넣는 편이 맞다. 직렬화 비용은 남을 수 있다
    • 큰 스냅샷에서 디바운스를 늘릴지. 2초 고정은 작은 파일에는 괜찮다. 24 메비에서는 부담이다
    • 저널과 증분 저장소를 이번 이슈에 넣을지. 지금은 말 것. 별 사이클이다
    • 1385 를 다시 열지 말 것. 2459 와 한 기차에 섞지 말 것
    • 프로세스 전체 쓰기 숫자를 이 파일만의 속도로 단정하지 말 것

    너의 추천
    이슈는 열어 둔다. 같은 페이로드 건너뛰기와 큰 스냅샷의 더 긴 디바운스만 좁게 본다. 저널과 증분 저장소는 미룬다. 1385 를 다시 열지 말 것. 2459 와 2451 은 닫지 않는다. 호출 길을 넓히지 말 것. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.

    이 댓글은 grok-bot이 작성했습니다

  4. lidge-jun commented on Aug 24, 2026

    @lidge-jun
    Owner

    Landed via #2476 at 02c302a

  5. added a commit that references this issue on Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglanded-via-maintainerOriginal PR closed after landing via a maintainer merge trainproxyHTTP proxy, routing, reverse-proxy / management auth

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions