From 18c22f1ddb564fa5cd1411dd56f3194f5c409309 Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Thu, 27 Aug 2026 17:13:07 +0300 Subject: [PATCH] Say what the sandbox's connection lock guards The lock claimed to serialize a whole read, while `_documents` resolves the owners under it and then reads through them outside. That is right: resolving the owners is an operation on the shared connection, reading through them is not, and each owner is a session of its own. Holding the lock across a read per database would serialize them against the capability's searches to guard state none of them touch. --- haiku_rag_slim/haiku/rag/sandbox/sandbox.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/haiku_rag_slim/haiku/rag/sandbox/sandbox.py b/haiku_rag_slim/haiku/rag/sandbox/sandbox.py index 58c9bb61..7b676683 100644 --- a/haiku_rag_slim/haiku/rag/sandbox/sandbox.py +++ b/haiku_rag_slim/haiku/rag/sandbox/sandbox.py @@ -225,13 +225,17 @@ class Sandbox: async def _connection( self, owner: "HaikuRAG | None" = None ) -> "AsyncIterator[HaikuRAG]": - """Yield the shared connection (serialized by the lock), or an ephemeral - read-only one. The lock guards the whole block so a read's awaits cannot - interleave with another task's operation on the same connection. + """Yield the shared connection, or an ephemeral read-only one. + + The lock, where there is one, is held for the block: what a caller does + to the shared connection is serialized against the capability's own tool + calls, since both hold that client. It guards that connection and not + the databases underneath, which have their own locks. `owner` is the client holding one document, for the reads addressed to a single document. The shared connection covers a set of databases and has - no repositories of its own, so those reads have to name their owner. + no repositories of its own, so those reads have to name their owner. An + owner is a session of its own, so it is yielded unserialized. """ connection = owner if owner is not None else self._rag if connection is not None: @@ -272,6 +276,8 @@ class Sandbox: docs = await rag.list_documents(filter=self._context.filter) return docs, {} owners = await rag.clients_covering(self._context.sources) + # Resolve owners under the shared-client lock; owner sessions perform + # reads independently. groups = await asyncio.gather( *(owner.list_documents(filter=self._context.filter) for owner in owners) )