From d1ad14f44b578a0e2ec8ca6183610256ddb844f0 Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Tue, 28 Jul 2026 19:09:04 +0300 Subject: [PATCH] Point the limit comments at the right limits _session_limits still called the session budget the backstop for code that computes, which stopped being true when the pool gained a request_timeout in the same commit. The watchdog kills such a call at code_timeout, so it can never spend a budget of code_timeout * max_executions. The docstring now names the two per-call limits and claims neither. The crash test said the discard prevents a RuntimeError escaping execute(). The handler catches RuntimeError too, so without the discard every later call returns a failed result instead. Name MemoryFile's missing write hook as the reason metadata.json takes a reader and a deny pair. Drop the clause in the CHANGELOG that narrated how the old overrun accumulated. --- CHANGELOG.md | 2 +- haiku_rag_slim/haiku/rag/sandbox/sandbox.py | 10 +++++----- tests/sandbox/test_sandbox.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d42fc52a..2b775f76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ - `evaluations run` opens the database read-only outside the population phase, so an embedder identity differing from the stored one warns instead of aborting the run. - `docs/installation.md` documents the `jina`, `s3` and `ingester` extras, names the extras the full package actually pulls, drops the removed MixedBread AI reranker, and no longer lists Anthropic as a built-in provider. - `docs/tuning.md` no longer points at the removed `claim_timeout_s` setting. -- `analysis.code_timeout` is checked before each document read; code that reads in a loop no longer overruns it by the duration of the outstanding reads. +- `analysis.code_timeout` is enforced before each document read, bounding a call that reads in a loop. - `metadata.json` in the document VFS rejects writes, matching `content.txt`, `items.jsonl` and `toc.json`. ### Removed diff --git a/haiku_rag_slim/haiku/rag/sandbox/sandbox.py b/haiku_rag_slim/haiku/rag/sandbox/sandbox.py index f808ccf9..0812e250 100644 --- a/haiku_rag_slim/haiku/rag/sandbox/sandbox.py +++ b/haiku_rag_slim/haiku/rag/sandbox/sandbox.py @@ -415,8 +415,8 @@ class Sandbox: ensure_ascii=False, ) - # A MemoryFile accepts writes, so mount metadata.json through the - # same read and deny pair as the rest. The content is already built. + # MemoryFile has no write hook, so metadata.json goes through the + # same read and deny pair as the rest. Its content is already built. files.append( CallbackFile( f"{doc_dir}/metadata.json", @@ -472,9 +472,9 @@ class Sandbox: Monty spends ``max_duration_secs`` across the session's whole life, and the session is reused so variables persist between calls. Budget it for the run rather than for one call, or the first slow call starves every - later one. ``code_timeout`` is enforced per call by the read deadline in - ``_run_on_loop``. This is the backstop for code that computes without - reading, and one such call can spend all of it. + later one. ``code_timeout`` is enforced per call elsewhere: the read + deadline in ``_run_on_loop`` bounds a call that reads, and the pool's + ``request_timeout`` bounds one that computes. """ analysis = self._config.analysis return {"max_duration_secs": analysis.code_timeout * analysis.max_executions} diff --git a/tests/sandbox/test_sandbox.py b/tests/sandbox/test_sandbox.py index 21d148a6..90423a5a 100644 --- a/tests/sandbox/test_sandbox.py +++ b/tests/sandbox/test_sandbox.py @@ -894,7 +894,7 @@ class TestSandboxWorkerCrash: assert crashed.success is False assert "restarted" in crashed.stderr - # Without the discard this raises RuntimeError out of execute(). + # Without the discard every later call fails on the dead session. recovered = await sb.execute("print(3)") assert recovered.success, recovered.stderr assert "3" in recovered.stdout