Skip to content

CL-8980: make read_file continuation failures recoverable rather than terminal - #1172

Closed
TheGreatAxios wants to merge 4 commits into
mainfrom
cl-8980-make-read_file-continuation-failures-recoverable-rather-than
Closed

TheGreatAxios wants to merge 4 commits into
mainfrom
cl-8980-make-read_file-continuation-failures-recoverable-rather-than

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Collaborator

Truncated reads minted opaque one-shot in-memory handles: after session resume, prune, or compaction the URI was a bare missing blob with no source or offset named, and the notice hid the original path, leaving no fallback.

What changed:

  • Handles are self-describing (tool-output:///cursor/ carrying source, offset, window limit, nonce), so a verbatim follow serves the next window with no in-memory record — across resume, replay, and compaction.
  • Dead/unknown handles fail as isError naming the source and resume offset, never a bare missing blob. URIs that were never handles still fail as missing blobs.
  • Spent-handle replay stays a single-use error with one followable next call.
  • Truncation notices carry a plain path+offset fallback alongside the handle.
  • Compaction stubs preserve resume recipes (handles/spill URIs) instead of hollowing them.

Verification:

  • RED commit be9dca1 pinned the contract first (targeted run failed before the fix).
  • bun run typecheck: exit 0 (also via pre-commit).
  • Targeted (vendor/intx-tools-posix tools-posix, lazy-blob-reader, codex-tool-proxies, all of src/plugins/): 644 pass, 0 fail.
  • Full: bun test ./src ./tests ./evals ./scripts --randomize --seed 424242: 8043 pass, 0 fail.
  • bun run lint (oxfmt --check + oxlint): 0 warnings, 0 errors.
  • read_file continuation isErrors carry none of the four decline markers classifyDeclinedToolResult matches on, so director.ts stays out of this path (verified by marker-exclusion; the classifier is module-private).
  • Past-EOF contract shared with the CL-8979 lane ([offset N is beyond end of file (M lines)], isError) is untouched; resumed handles serve through the same readFileBounded path.

Sibling note: CL-8979 works the same read_file area on a separate branch; this diff is recovery behavior only.

Fixes CL-8980

Red tests for CL-8980: verbatim handle-following must yield the next window across session resume, dead handles must name source plus offset instead of a bare missing blob, never-handles must stay missing-blob errors, compaction stubs must preserve the resume recipe, spent replays stay single-next-call errors, and guard denials stay isError results outside decline classification.
Truncated reads minted opaque one-shot handles that died with the plugin instance: after resume, prune, or compaction the URI was a bare missing blob with no source or offset. Handles are now self-describing (source, offset, window, nonce ride in the URI), so a verbatim follow serves the next window with no in-memory record; dead handles fail as isError naming source plus offset; never-handles still fail as missing blobs; spent replays stay single-use errors; notices carry a plain path plus offset fallback; compaction stubs preserve resume recipes.
@linear-code

linear-code Bot commented Sep 25, 2026

Copy link
Copy Markdown

CL-8980

A hand-crafted tool-output:///cursor handle naming an outside-root file
passed the spill-URI exemption and was served without any containment
check. The sandbox now resolves the embedded file source through the
normal workspace check at authorize and execution time.
@TheGreatAxios

Copy link
Copy Markdown
Collaborator Author

Superseded by #1179 (single-way path+offset resume). Closing per release review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant