Ver Fonte

docs(code-runtime-python): correct the ProtocolChannel serialization docstring

The class docstring still credited the GIL plus per-frame PIPE_BUF atomicity for
serializing writes, which _write_lock's full-write loop already superseded. State
the current contract (writers serialized by _write_lock around a full-write loop)
and drop the double blank line under the binding-replies note heading.
Chinesezjc há 2 meses atrás
pai
commit
9f449a79a6

+ 1 - 1
.agents/notes/implemented/bug-fix/2026-07-31-code-runtime-python-settlement-fixes.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-07-31-code-runtime-python-settlement-fixes.md
-2026-07-31-code-runtime-python-settlement-fixes.md: d276c04e0182dc589f48a77d8dd73b233ae11d9d
+2026-07-31-code-runtime-python-settlement-fixes.md: b51fb2e9c28d07efa1691b1036b7b6e899b21062
 2026-07-31-code-runtime-python-settlement-fixes.zh.md: a59e5457f2469e86ed4120ce47ed8a5d8ae08f4f

+ 0 - 1
.agents/notes/implemented/bug-fix/2026-07-31-code-runtime-python-settlement-fixes.md

@@ -40,7 +40,6 @@ In [`py/bootstrap.py`](../../../../packages/code-runtime/code-runtime-python/py/
 
 ### Binding replies complete on the calling loop's thread
 
-
 Also in `py/bootstrap.py`, a binding reply Future is created on the loop that ran `dispatch`. When the model calls a binding from a worker THREAD via `asyncio.run(tools.x(...))`, that Future belongs to the thread's loop, not the main loop where `_pump_replies` reads the reply. `asyncio.Future` is not thread-safe: completing it from another thread does not wake its own loop, so the direct `set_result`/`set_exception` left the awaiting thread stranded and the run degraded to a wall-clock timeout. Each pending entry now records its Future's loop alongside the Future, and `_pump_replies` completes it via that loop's `call_soon_threadsafe`. The shared `pending`/`next_id` state is guarded by a `threading.Lock` held across the id claim, the fd-3 write, and the counter advance, so concurrent callers cannot interleave frames out of the id order the host requires. `call_soon_threadsafe` onto a loop that has already CLOSED (the worker thread finished and abandoned its call before the reply arrived) raises `RuntimeError`; that schedule is wrapped so the moot reply is dropped rather than letting the exception end the pump task and strand every later reply.
 
 ## Testing

+ 6 - 3
packages/code-runtime/code-runtime-python/py/bootstrap.py

@@ -345,9 +345,12 @@ class ProtocolChannel:
 
     Writes are unbuffered and go straight to the fd, so ``send_sync`` is safe
     from inside model code (which may run outside an asyncio task) and from
-    background tasks alike. The single writer is serialized by CPython's GIL
-    plus one os.write per frame (POSIX guarantees atomicity for writes below
-    ``PIPE_BUF``, and our frames are short JSON lines).
+    background tasks alike. Concurrent writers are serialized by ``_write_lock``
+    around a full-write loop (see ``send_sync``): ``os.write`` releases the GIL,
+    a frame may exceed ``PIPE_BUF`` (logs up to ``maxLogBytes``, completions up
+    to ``maxValueBytes``, uncapped ``call`` args), and one ``os.write`` may
+    consume only part of a frame — so neither the GIL nor per-frame atomicity is
+    relied on for framing.
     """
 
     def __init__(self, fd: int) -> None: