Skip to content

[Bug] Cursor/Grok 4.6 no-progress loop persists on OpenCodex 2.42.0 after #2600 #3506

Open

Description

@stephen-drew

Client or integration

Codex App

Area

Cursor provider adapter / Responses continuation / loop control

Summary

This is a fresh recurrence of #2600 on the current installed OpenCodex package/CLI 2.42.0.

A Codex App task routed to cursor/grok-4.6 made some useful early reads and correctly identified the current blocker, but then spent 82 minutes repeatedly rediscovering the same checkpoint. It continued producing near-equivalent future-tense commentary and successful read-only tool traffic without completing the requested work, returning a typed blocker, or terminating. The operator had to interrupt it.

The earlier report was closed after #2628 recorded that OpenCodex cannot safely infer workspace progress from protocol activity. This report does not dispute that constraint or claim a proven root cause. It shows that the combined route still has no effective enforcement mechanism for this failure class on 2.42.0.

Reproduction

  1. Run Codex App on Windows through OpenCodex 2.42.0.
  2. Start a new task on cursor/grok-4.6.
  3. Ask it to resume a bounded delivery task from durable handoff files.
  4. Let it read the handoff, inspect the repository and determine the next gate.
  5. Observe that it identifies the correct blocker, then repeatedly rereads the same files and reruns repository discovery instead of finishing or stopping.
  6. Manually interrupt the turn.

Observed trace

Before interruption:

  • Duration: 82 minutes 5 seconds
  • Observable items: 590
  • Assistant messages: 127
  • Shell commands: 284, of which 28 failed
  • Connector/MCP calls: 35
  • Image inspections: 8
  • Git inspection commands: 31
  • Final answer: none
  • Typed blocker: none
  • Requested state change: none observed

Seven small checkpoint files were reread between 12 and 19 times each:

  • intent/authority file: 19
  • progress file: 19
  • blocker file: 18
  • implementation brief: 17
  • three short commit-note files: 16, 15 and 12

The turn repeatedly ran Git status/log discovery against a directory already shown not to be a repository, despite having located the actual checkout earlier. Connector calls in the captured turn were read-only. The shell trace contains no file-edit, commit or push command.

Important new detail

This task already received an explicit workspace-aware no-progress policy in its developer instructions:

  • after two equivalent failed attempts or unchanged reads, change method;
  • permit a third equivalent action only when new evidence justifies it;
  • after a third equivalent no-progress action, stop and report the completed work, current state, remaining work and blocker.

The model did not follow that policy. The trace reached 31 Git inspections and 12 to 19 reads of the same checkpoint files.

This supports the ownership concern recorded on #2600: prompt-level model guidance is not an enforcement mechanism. It also means that simply placing the stopping rule where the workspace context is visible does not solve the user-facing failure unless something outside the model enforces it.

Expected behaviour

After a bounded amount of activity, the combined route should do one of the following:

  • make an observable state change and continue;
  • complete the task;
  • return a typed, actionable blocker;
  • terminate as a no-progress failure without replaying potentially side-effecting work.

Repeated read-only calls and reworded planning should not keep one turn active indefinitely.

Suggested scope

I agree with the #2600 finding that OpenCodex should not guess whether arbitrary tools changed a workspace. A narrower supported contract could be:

  1. Accept an explicit, privacy-safe progress marker from a capable client.
  2. Enforce an opt-in sequential-continuation/no-progress budget against that marker for Cursor routes.
  3. Allow the guard to cancel an already active Cursor stream.
  4. Return one typed terminal result containing the last confirmed checkpoint.
  5. Never automatically replay a potentially side-effecting call after cutoff.
  6. Expose enough diagnostics to distinguish a client continuation, an OpenCodex continuation and one still-active Cursor stream.

If this must remain entirely client-owned, please keep a linked upstream issue or an upstream tracking state so users can see that the combined route remains affected rather than interpreting #2600 as resolved.

Version

OpenCodex installed package/CLI 2.42.0. The task record reports Codex runtime 0.153.0.

Operating system

Windows 25H2, build 26200.9168, x64.

Provider and model

cursor / grok-4.6

Logs or error output

There was no single terminal error. The defect is continued successful activity without task progress or termination. The sanitised counters are listed in Observed trace above.

Redacted configuration

{
  "client": "Codex App",
  "proxy": "local OpenCodex",
  "provider": "cursor",
  "model": "grok-4.6"
}

Captured on 4 September 2026.

Screenshots and supporting files

No task screenshots, prompts, local paths or repository content are attached. The counters above were derived from the local Codex task record and have been sanitised.

Checks

  • I searched existing open issues.
  • I linked the closed prior report instead of presenting this as unrelated.
  • I removed task content, repository details, local paths, credentials, tokens, account data and personal data.
  • I separated observed facts from suspected ownership and root cause.

Activity

  1. coderabbitai commented on Sep 4, 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!

  2. github-actions commented on Sep 4, 2026

    @github-actions
    Contributor

    Issue reopened

    The report now contains the information required by the automated check. Thanks for updating it.

  3. lidge-jun commented on Sep 4, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 64 / 80

    이 이슈는 닫힌 #2600의 같은 실패 등급이 OpenCodex 2.42.0 + Codex App + cursor/grok-4.6에서 다시 살아 있다는 새 보고입니다. 작성자는 stephen-drew이고, 이전 보고도 같은 사람입니다. #2600은 #2628로 “의미 있는 진전(progress)을 OpenCodex가 프로토콜 활동만 보고 추론할 수 없다”는 소유권·진단 기록으로 닫혔고, 런타임 컷오프를 넣지 않았습니다. 이번 글은 그 결론을 뒤집으려 하지 않습니다. 대신 “그 제약 때문에 사용자 앞에 남는 구멍”이 2.42.0에서도 그대로라는 증거와, 프롬프트만으로는 막히지 않는다는 새 사실을 붙입니다.

    재현 줄거리는 짧습니다. Windows에서 Codex App이 OpenCodex 2.42.0을 거쳐 cursor/grok-4.6 작업을 시작합니다. 초반에는 핸드오프를 읽고 막힌 지점을 맞게 집습니다. 그다음 82분 동안 같은 체크포인트 파일을 12~19번씩 다시 읽고, 이미 저장소가 아닌 디렉터리에 Git status/log를 31번 돌리며, 읽기 전용 도구·커넥터만 이어갑니다. 최종 답도 없고, 타입이 있는 blocker도 없고, 관찰된 상태 변경도 없습니다. 운영자가 끊었습니다. 숫자만 보면 활동은 많습니다(관측 590, 어시스턴트 메시지 127, 셸 284). 하지만 “일이 앞으로 갔다”는 신호는 없습니다.

    새 디테일이 중요합니다. 이번 작업의 developer 지시에는 이미 워크스페이스를 아는 no-progress 규칙이 들어 있었습니다. 같은 실패/같은 읽기가 두 번이면 방법을 바꾸고, 세 번째는 새 증거가 있을 때만 허용하고, 세 번째 동등 no-progress 뒤에는 멈추고 보고하라는 내용입니다. 모델은 그 규칙을 지키지 않았습니다. 그래서 #2600/#2628이 남긴 소유권 메모(“프롬프트 수준 안내문은 강제 장치가 아니다”)가 실험으로 한 번 더 확인된 셈입니다. 규칙을 모델이 볼 수 있는 자리에 넣는 것만으로는 사용자 앞 실패가 사라지지 않습니다.

    지금 CURRENT dev HEAD 4cacdfbb6(package 2.43.0)의 방향은 macOS CI 샤딩, apply_patch 봉투, 관리자 토큰 로컬 UX, 카탈로그/어댑터 쪽 열차입니다. #2600 이후에도 “의미 진전 예산으로 Cursor 스트림을 끊는” 런타임은 HEAD에 새로 들어온 것으로 보이지 않습니다. 기존 stall 시계는 업스트림이 조용할 때만 셉니다. 읽기와 계획 말이 계속 오면 시계는 다시 0으로 돌아가고, 82분 루프와 맞습니다. 침묵 스톨과 “진전 없음”은 다른 문제입니다. #2210 계열 조용한 죽음과 이 이슈를 하나로 합치지 마세요.

    작성자가 제안한 좁은 계약은 대략 이렇게 읽힙니다. (1) 능력 있는 클라이언트가 프라이버시 안전한 진전 마커를 명시적으로 넘긴다. (2) Cursor 경로에 한해 그 마커 기준의 연속/no-progress 예산을 옵트인으로 강제한다. (3) 이미 열린 Cursor 스트림도 가드가 취소할 수 있다. (4) 마지막 확인 체크포인트를 담은 타입 있는 종료 결과를 한 번 낸다. (5) 컷오프 뒤 부작용 가능 호출을 자동 재실행하지 않는다. (6) 클라이언트 연속 / OpenCodex 연속 / 아직 살아있는 Cursor 스트림을 진단으로 구분한다. 이건 구현 PR이 아니라 제품·소유권 설계 제안입니다. OpenCodex가 워크스페이스 diff를 추측하지 않는다는 #2628 전제와 충돌하지 않게 가려면, “마커는 클라이언트가 주고 OpenCodex는 그 마커만 센다”는 선을 유지해야 합니다.

    경로 #2600 / #2628 - 이전 보고는 진단·소유권 기록으로 닫혔고, 이번은 그 결정 이후에도 사용자 앞 증상이 남았다는 회귀 증거입니다. 자동으로 중복 닫지 마세요.
    경로 src/stall-timeout.ts / bridge stall 리셋 - 침묵만 재는 한도라서, 읽기·계획 말이 이어지는 이번 궤적에는 불이 켜지지 않습니다. 이 이슈의 직접 수정 지점으로 단정하지 마세요.
    경로 cursor 어댑터 / Responses continuation - 루프의 “누가 이어 주는가”(클라이언트 vs OpenCodex vs 업스트림 한 스트림)를 나누지 못하면 잘못된 층에 예산을 넣게 됩니다. 본문 Suggested scope 6번이 그 전제입니다.
    심볼 cursor/grok-4.6 + Codex App 0.153.0 + OpenCodex 2.42.0 - 재현 좌표는 충분히 구체적입니다. 다만 루트코즈(모델 vs 클라이언트 연속 vs 프록시)는 여전히 증명되지 않았고, 작성자도 그렇게 적었습니다.

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

    • 이 실패 등급을 OpenCodex 런타임 책임으로 다시 올릴지, #2628대로 클라이언트/업스트림 소유로 두고 upstream 추적 상태만 살릴지.
    • 클라이언트가 주는 명시적 progress 마커 + 옵트인 예산이 받아들일 만한 계약인지, 아니면 Codex App/Cursor 쪽에만 이슈를 링크할지.
    • #2600을 재오픈할지, 이 #3506을 정식 후속 티켓으로 두고 #2600은 닫힌 채 링크만 유지할지.

    너의 추천

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

  4. added
    upstream-trackingBlocked on an upstream (Codex CLI/Desktop) fix; kept open for discoverability
    streamingSSE, WebSocket, terminal stream frames
    toolstool_calls, MCP, web-search / sidecar tools
    on Sep 4, 2026
  5. Ingwannu commented on Sep 4, 2026

    @Ingwannu
    Owner

    Confirmed as a real recurrence of the user-visible failure class, not as proof of the same root cause and not as a duplicate to close against #2600.

    Current dev still has only silence/stall budgets at this boundary. Repeated read-only tool calls and planning text are protocol activity, so they legitimately reset those timers even when the task makes no semantic progress. The new evidence is useful because the model also ignored an explicit workspace-aware stopping policy; prompt guidance is therefore not an enforcement boundary.

    We will keep this issue open as the follow-up tracker. OpenCodex must not guess workspace progress from arbitrary tool traffic or replay potentially side-effecting calls after a cutoff. A mergeable runtime design needs this narrower contract:

    1. a capable client supplies an explicit, privacy-safe progress/checkpoint marker;
    2. an opt-in Cursor continuation budget is measured only against that marker;
    3. the guard can cancel the already-active Cursor stream;
    4. termination returns one typed no-progress result with the last confirmed checkpoint; and
    5. no potentially side-effecting call is automatically replayed after cutoff.

    Before implementation, we still need to distinguish from sanitized evidence whether each continuation is client-owned, OpenCodex-owned, or part of one still-active Cursor stream, and whether Codex App exposes a stable marker/cancellation seam. If it does not, this remains upstream-tracked rather than being “fixed” with a heuristic timer. I added upstream-tracking, streaming, and tools labels and am intentionally leaving the issue open.

  6. lidge-jun commented on Sep 9, 2026

    @lidge-jun
    Owner

    Direction note from maintainer triage (post-2.49 scope round): we are keeping #2600's stance — the proxy must not infer semantic progress. The direction we would accept for this loop is better translation fidelity on the Cursor/Grok 4.6 exchange (so the client does not re-issue the same turn in the first place), not a proxy-side progress cutoff. Deferred from the current bug round; if you can capture a redacted request/response pair showing where the translation loses the thread, that evidence would reopen it as a translation bug.

  7. stephen-drew commented on Sep 11, 2026

    @stephen-drew
    Author

    Update: the long-task problem is still reproducible in normal use after a local history-retention patch on OpenCodex 2.50.0, Windows, Bun 1.4.2, cursor/grok-4.6, requested effort xhigh. Please do not treat the earlier bounded continuation checks as resolution of this issue.

    Observed recurrence

    • The installed encoder was independently verified against the locally tested V2 source. V2 retains a partial older turn even when newer user/developer metadata already occupies the replay budget. It addresses a demonstrated history-pruning defect, but has not resolved the wider looping behaviour.
    • One continuation lasted about 375 seconds before interruption, with nine assistant messages and eight client tool calls/results. The proxy recorded nine completed Cursor requests, each with one attempt and one send. No proxy recovery/retry loop was present.
    • The task had no native compaction event, so an unreadable earlier compaction summary does not explain this example.
    • A later continuation did complete some local preparation, then repeated a malformed patch opening after receiving the precise formatting error. This was not zero progress throughout the entire continuation.

    The final repeated failure had this shape, with project content removed:

    exec calls tools.apply_patch with first line: *** Begin Patch ***
    
    tool result:
    Script failed
    Wall time 0.0 seconds
    Output:
    Script error:
    apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'
    
    next exec call again uses first line: *** Begin Patch ***
    

    Translation evidence and limits

    I reconstructed full replay from the saved client history using the real parser, request builder and encoder, then hydrated the model-visible root blobs. This is offline reconstruction with a minimal code-mode catalogue, not a capture of the exact live HTTP request or provider checkpoint.

    • In the first incident, the previous final checkpoint and all eight recent tool results survive the reconstruction.
    • Immediately after the first rejected patch in the later continuation, the reconstructed roots contain the complete error, the bad opening from the original invocation, and OpenCodex's existing recovery hint requiring the bare *** Begin Patch line. There are 106 roots totalling 524,272 bytes. The invocation arguments are truncated to the existing per-call budget, but the offending opening is retained.
    • An opt-in, metadata-only diagnostic sample during the later run showed a Cursor/Grok xhigh tool continuation using full-replay, checkpointPresent:false, missing_ref, 42 roots and 514,310 root bytes. Its opaque Cursor conversation ID has not been independently mapped to this specific task, so this sample is supporting context rather than exact-task proof.

    The encoder currently represents external tool results as assistant-role text and describes their calls inside the text envelope. A public, synthetic fixture through the actual encoder produces this model-visible shape:

    {
      "role": "assistant",
      "content": [{
        "type": "text",
        "text": "[Tool Result]\n[tool_result]\ncall_id: fixture_call_1\nname: exec\ninvoked: exec with {\"input\":\"text(await tools.apply_patch(`*** Begin Patch ***\\n*** End Patch ***`));\"}\nis_error: false\noutput:\nScript failed\nWall time 0.0 seconds\nOutput:\nScript error:\napply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'\n[recovery: The patch text must open with the bare marker line `*** Begin Patch`: no code fence, prose, or extra asterisks on that line (blank lines or indentation before it are tolerated).]"
      }]
    }

    No structured tool-call or tool-result content parts are emitted in that fixture. This is an observed representation difference, not proof that the format causes Grok's repetition.

    oh-my-pi PR #7186 preserves structured tool-call/result history in Cursor root messages, alongside a model-specific K3 reasoning change. Could the structured root-message format be validated for Cursor/Grok? The K3 reasoning change should not be assumed applicable to Grok, and OpenCodex's existing native-protobuf compatibility guards need to remain separate from root-JSON format experiments.

    Checks that passed, without resolving the issue

    • The local V2 history-retention change passed 1,176 Cursor tests across 63 files, TypeScript checking, the privacy scan and documentation build.
    • Its original three live continuation checks passed in about 72 seconds.
    • Following this recurrence, three further synthetic requests through the installed Responses route passed in about 31 seconds: correction after the patch error, the same correction with a 380,105-byte history, and final completion after a simulated successful patch result. No returned tool calls were actually executed. The three requests each had one send and no recovery.

    These checks show that simple and padded-history examples can work; they do not validate long-task reliability. No semantic cutoff, model switch, retry increase or further runtime patch has been applied in response to this recurrence. The next useful evidence is a repeatable, privacy-safe failing case that distinguishes textual and structured history on the same Cursor/Grok route.

  8. stephen-drew commented on Sep 13, 2026

    @stephen-drew
    Author

    Follow-up after updating to OpenCodex 2.52.0 on Windows, 13 September 2026. The service and CLI both report 2.52.0. The Desktop task record reports Codex 0.153.4 and requests cursor/grok-4.6 at xhigh; this is recorded selection, not independent backend-effort proof.

    Thank you for #4281 and #4283. We prefer a maintained product fix over continuing to patch the installed package locally.

    What improved, and what recurred

    One completed test ran for 10 minutes 31 seconds, with 27 assistant messages and 18 tool calls/results. It was repetitive but reached a real self-test blocker, wrote a stop receipt and returned a final answer. We do not count that as an endless no-progress loop or proof that #3506 is fixed.

    The subsequent repair continuation has now been interrupted by the operator after 15 minutes 3 seconds, with 33 assistant messages and 30 tool calls/results. Its record contains both genuine progress and repeated no-progress segments:

    • Four consecutive patch attempts over approximately 175 seconds retained the invalid opening *** Begin Patch ***, despite four explicit errors specifying *** Begin Patch.
    • All four call inputs were below 2 KiB: 1,648, 1,396, 1,670 and 1,900 UTF-8 bytes. The rejected opening was near the start.
    • The model changed JavaScript construction while keeping the same rejected opening. It then changed method and successfully edited the target file. We therefore do not claim that the entire continuation made no changes.
    • It ran the self-test once. That run stopped at the existing integrity check because the edited test file no longer matched its recorded hash.
    • It updated the two corresponding hash checks. Independent file read-back confirms the target edit and both hash updates.
    • After that update, it made six further promises to rerun the self-test and eight tool calls, returning to hash/metadata checks and instruction reads. No second self-test ran before interruption, approximately 2 minutes 52 seconds after the hash update.
    • Three tool outputs in this continuation were explicitly truncated. The four patch errors were short and intact in the client record.

    This narrows the symptom to repeated rejected calls and failure to advance from verified preparation to the stated verification step. It does not establish that OpenCodex lost feedback, that every subsequent read was unnecessary, or that the unfinished local edit is correct.

    The client rollout contains full tool-result text as arrays of input_text blocks. An initial inspection incorrectly string-cast those arrays as blank; that extraction mistake was corrected and no empty-result transport claim is being made.

    Minimal shape of the failing exchange

    The following is a synthetic, content-replaced illustration of the observed client-side pattern, not a captured outbound Cursor protobuf payload:

    await tools.apply_patch(`*** Begin Patch ***
    *** Update File: fixture.txt
    @@
    -old
    +new
    *** End Patch`);

    Tool result:

    apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'
    

    Next attempt retains *** Begin Patch ***, including when the patch is built with an array joined by newlines.

    Separate reproducible argument-loss finding

    Before the upgrade we isolated another translation issue in the replay encoder: a successful call's arguments are clipped to a 2 KiB prefix even when the total replay is small. A synthetic write placed a random verification value after that cutoff, with a result that only said the file was written.

    Live isolated comparisons through the existing Cursor transport:

    • Existing bounded arguments: value absent from model-visible roots; answer MISSING.
    • Same text-role format, complete arguments: exact value recalled.
    • A candidate that restores whole recent invocations only within unused replay bytes: exact value recalled.

    The candidate preserves the existing root-count/byte limits, retained history and result output. Its Cursor regression suite passed 1,179 tests. It was not installed. This proves that particular recall defect, not the cause of the current malformed-patch repetition. The released 2.52.0 encoder still has the 2 KiB argument-prefix limit, and the four rejected calls are below it.

    Requested next step

    Could you advise the supported, privacy-safe way to capture the exact outbound model-visible roots and corresponding response for one rejected-patch continuation under 2.52.0, including checkpoint coverage? That would distinguish translation loss from the upstream model ignoring intact feedback.

    Would you prefer the independently reproduced argument-loss defect as a separate linked issue with a self-contained regression fixture? We can supply synthetic evidence without private prompts, business files, task IDs, credentials or account data.

    Please keep #3506 open. We are not requesting a heuristic progress timer or replay of side-effecting calls. #4281's checkpoint capture is relevant progress, but the observations above do not establish that the wider repetition problem is resolved.

  9. Ingwannu commented on Sep 13, 2026

    @Ingwannu
    Owner

    Thanks for separating the two observations. I checked current dev 6aaab49f6.

    The independent argument-retention case is worth a separate linked bug report using the bug template. Please include the synthetic encoder fixture and candidate diff: the >2 KiB marker, result containing no copy of that marker, and hydrated roots before/after. In src/adapters/cursor/protobuf-request.ts::toolCallArgumentsText, arguments are still capped independently at 2 KiB even when the aggregate replay has space. That cap deliberately prevents a large invocation from displacing its result. A spare-budget improvement must preserve result priority, existing retained history, the 192-root/512-KiB aggregate bounds, and UTF-8 accounting; removing the cap outright would regress that protection. Your live comparison supports that specific recall problem, not the cause of the four under-limit rejected patches.

    For capture: the existing provider diagnostics are metadata, not an exact payload export. run-request records continuation mode, checkpoint presence/invalidation, root counts/bytes and any unmeasured roots; cursorCheckpointShape intentionally returns counts only. Those fields cannot prove that the exact error text reached the model, and checkpoint arrival alone is not complete history-coverage proof.

    I cannot point you to a supported content-safe exact-root dump in those diagnostics. Please do not upload production protobuf/checkpoints, task histories or raw debug bundles. The useful next artifact is a standalone synthetic rejected-patch fixture through the real parser/builder/encoder, identifying full-replay versus checkpoint mode and showing the hydrated roots plus the corresponding synthetic response. Clearly label reconstructed roots as reconstruction, not a live capture. Any live capture instrumentation should be narrowly scoped to that synthetic test session and reviewed first.

    Keeping #3506 open; no heuristic progress cutoff or automatic replay of side-effecting calls is proposed.

  10. lidge-jun commented on Sep 13, 2026

    @lidge-jun
    Owner

    Status after the 60-plus contributor backlog pass, which landed 12 lanes on dev. This issue is not closed by it, and the reason is specific rather than a blanket deferral.

    #4363 landed first-overflow surfacing with bounded thread remints, carried from #4229. Conversation-only requests now fail closed instead of replenishing their allowance after every remint, and ownership is stable across both client thread aliases.

    That addresses the remint loop mechanically. This issue stays open for the redacted translation-fidelity evidence it asks for, which the landing does not supply.

  11. lidge-jun commented on Sep 19, 2026

    @lidge-jun
    Owner

    Recording the source analysis behind the upstream-tracking label, because the label alone reads like deferral and the reason is more specific than that.

    The question is who continues the loop. Following the source: when Cursor asks for a client-owned tool, OpenCodex emits the call, ends the Responses turn deliberately, and cancels the Cursor stream (src/adapters/cursor/live-transport.ts at the emit and the cancel). The actual tool result arrives on the next /v1/responses request. So an 82-minute trajectory is 590 separate requests from the proxy's point of view, not one loop. A budget placed in the proxy cannot see the loop it would be budgeting, because no single request contains it. Upstream Codex agrees from the other side: turn.rs keeps sampling while needs_follow_up holds. The exception worth knowing is that nativeLocalExec: "on" or explicit mcpServers can run several tools inside one stream, which changes that answer.

    Every clock currently in the path measures silence, not repetition. The 300-second default stall resets on any adapter event, and the Cursor 30/90-second watchdog classifies only heartbeats and checkpoints as liveness-only — read traffic and planning prose count as meaningful. The two objective ceilings added since 2.42.0 do not light up on this trajectory either: the default 256 physical sends per 10 minutes is far above the reported rate of roughly 40, and the token ceiling is opt-in and needs an operator-supplied number.

    The strongest evidence is upstream. openai/codex#28707 solved the same family with a rollout token budget and a SessionBudgetExceeded error type — measuring an objective resource rather than inferring that a workspace is stuck. No repeat-call detector exists in the upstream checkout, and Cursor's own documentation states there is no limit on tool-call count.

    Of the six contracts proposed in this thread, three are reachable with today's code: cancelling an active stream, refusing to replay side-effecting calls after a cutoff, and consecutive-subject diagnostics. Two are bilateral — they only hold if the client emits a marker first — and the "last confirmed checkpoint" one is something the proxy cannot state honestly, because it does not know which calls the client actually applied. The conclusion in #2628 still stands.

    Leaving this open and tracked rather than implementing a heuristic that would have to guess what the upstream loop is doing.

  12. added
    priority: P2Medium: provider/client-specific bug with a workaround, bounded enhancement tied to a tracked issue,
    on Sep 24, 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 workingpriority: P2Medium: provider/client-specific bug with a workaround, bounded enhancement tied to a tracked issue,streamingSSE, WebSocket, terminal stream framestoolstool_calls, MCP, web-search / sidecar toolsupstream-trackingBlocked on an upstream (Codex CLI/Desktop) fix; kept open for discoverability

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions