Repository navigation
Conversation
sfroment
marked this pull request as ready for review
October 28, 2026 14:02
anthonycorbacho
approved these changes
Oct 28, 2026
Streamed /files/stat, PUT /files and chunked GET /files with an idle-bounded read loop, plus a cached has_files_routes() probe so callers pick routes once per handle instead of probing per call. Only 400/404 count as route answers; anything else is an error.
write_file, read_file, open_read and stat() ride the streamed transports with end-to-end content verification; the base64 legacy routes stay as fallback when /files is absent and fail fast on inputs they cannot carry. FileStat is exported.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Every file operation now dispatches once per handle, and the streamed
/filesroutes (executor v0.0.24+, koyeb/sandbox-container#29) become the default — with automatic fallback to the legacy JSON routes:New surface (sync + async twins, parity-pinned):
Evidence
Before: any binary write corrupted or crashed —
write_file("/a.bin", b"\x00\xff")raisedUnicodeDecodeErrorunder the default encoding, andencoding="base64"wrote the base64 text to disk (users had to runbase64 -din the sandbox). Reads lost invalid UTF-8 to U+FFFD. No test could round-trip arbitrary bytes; a 256 MiB legacy write peaked at 1.2 GB executor RSS.After: byte-exact both directions, verified end to end:
test_upload_streams_binary_raw— 256 KiB ofbytes(range(256))uploads raw, and the executor's{size, sha256}reply is cross-checked against a locally computed digest (constant memory) — "corrupted in transit" on mismatch. A mid-streamfiles_putfailure is pinned as never retried (idempotent=False): a replayed stream could write empty content.test_bytes_go_raw/test_encoding_none_returns_raw_bytes— write and read back exact bytes;encoding="base64"now means real bytes on disk (the changelog-named behavior change).AsyncClientraiseRuntimeError— every async upload failed against a real executor, masked by bytes-only fakes._async_streamnow adapts sync streams on the async twin, transport-tested with both iterables and file objects.SandboxTimeoutErrornaming the bound that fired ("Request timed out after 60s"on the files routes,…30son legacy) — read streams included; resets mid-stream stay generic..part+os.replacedownloads leave the destination untouched on failure (pinned by mid-transfer-404 tests); progress is throttled to 100 ms with a guaranteed final call (pinned on an exact float boundary)..part, swallowed byOSError), hand-verified three times. The mutator's snapshot cache was caught giving false greens twice; every named survivor since is red-green-proven by hand-mutation before it counts.Six rounds of
/ub-review(spec / standards / ub-mode / crapper+dryer+mutator, parallel lenses) dispositioned on ST-125 — the last round closed with zero genuine findings. Follow-up debt is ledgered on the ticket (all pre-existing: SandboxFileIO write machinery,_request_with_retry's retry ladder, 18 pre-existing mutator survivors).Merge Danger
Door: two-way — pure client-side addition; the probe falls back to the legacy routes on executors < v0.0.24, and a revert restores the previous behavior entirely.
Blast radius: default-behavior change, contained. On v0.0.24+ executors,
encoding="base64"onread_file/write_fileflips from "the file holds base64 text" to "the transport encodes the real bytes" (ST-103's release notes name it);stat, binary-safeopen_readand stream content raise clear errors naming v0.0.24 on legacy executors; every other caller sees unchanged behavior plus at most one warning per handle. Live e2e rides the v0.0.24 rollout / ST-102's kind stack — the unit bar here is fakes at the raw-HTTP seam, plus MockTransport transport tests that drove out the async-wire bug the fake-based suite could not see.Part of KOYEB-6631 — Python slice 1 of 3 (ST-126 multipart + resume — also inherits the per-call
timeout=override and theparentswiring — and ST-127sync()follow as separate PRs behind their executor gates).