fix(code-runtime-python): cap the done-frame rejection diagnostic and sync stale docs
The review's remaining items: - _done_with_value's rejection branch now caps the _check_done_value diagnostic through _cap_message (a reason embedding a hostile class name could otherwise push the done frame past the host's 64 MiB parse cap, misreporting an invalid-output run as a worker-exit). - The settlement note (en + zh) updates three stale facts (load bound is now parse-cap minus envelope at 67108800; the sink goes directly through the bound primitives); the fd-3 protocol note (en + zh) no longer claims the package ships protocol without the runtime; FRAME_ENVELOPE_BYTES' JSDoc and _cap_message's docstring follow the new bound. Pairings re-recorded.
This commit is contained in:
parent
d90155714b
commit
3f8b45f9bb
8 changed files with 19 additions and 12 deletions
|
|
@ -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/architecture/2026-07-31-code-runtime-python-fd3-protocol.md
|
||||
2026-07-31-code-runtime-python-fd3-protocol.md: 5572fe58cb1dd8832ff9405670afc7f80a20362c
|
||||
2026-07-31-code-runtime-python-fd3-protocol.zh.md: 6254e94a7b48b38edfbe23a6ea0b994d04ac21f4
|
||||
2026-07-31-code-runtime-python-fd3-protocol.md: 6e5d96c5cff0ccdb6ecb1779bc5aa003f0b0881f
|
||||
2026-07-31-code-runtime-python-fd3-protocol.zh.md: 928be28f15212cb39dff1b215cdfee58da0ac130
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ English | [中文](2026-07-31-code-runtime-python-fd3-protocol.zh.md)
|
|||
|
||||
`@deepseek-ai/dsh-code-runtime-python` owns the wire protocol intended for a CPython code-runtime provider. Such a provider runs each model program in a fresh `python3 -I` subprocess and bridges binding calls and completion values over the child's fd 3. The host cannot trust that channel: model code has full access to fd 3 and can forge any frame, so every inbound frame is hostile input that the host must validate and rebuild before reading. The protocol also has to carry lossless JSON without the depth limit `JSON.stringify` and `json.dumps` impose, because the seam's `CodeJsonValue` is depth-unbounded.
|
||||
|
||||
The package ships the protocol independently from a runtime implementation. It exports no `PythonCodeRuntime`, subprocess path, or Python-side JSON codec; those remain work for a future provider. The protocol builds on the [portable identifier seam](2026-07-31-code-runtime-portable-identifier-seam.md).
|
||||
The package ships the protocol AND the runtime implementation: `PythonCodeRuntime` (the plugin's default export), the `python3 -I` subprocess path, and the Python-side JSON codec all live in `@deepseek-ai/dsh-code-runtime-python`. The protocol builds on the [portable identifier seam](2026-07-31-code-runtime-portable-identifier-seam.md).
|
||||
|
||||
## Decision
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Status: implemented
|
|||
|
||||
`@deepseek-ai/dsh-code-runtime-python` 负责供 CPython code-runtime 提供方使用的 wire protocol。这样的提供方会在全新的 `python3 -I` 子进程中运行每个模型程序,并通过子进程 fd 3 桥接 binding 调用与完成值。Host 不能信任这条通道:模型代码可以完全访问 fd 3 并伪造任意帧,因此 host 必须把每个入站帧视为敌意输入,先校验并重建后才能读取。协议还必须承载无深度限制的 lossless JSON,因为 seam 的 `CodeJsonValue` 深度无界,而 `JSON.stringify` 和 `json.dumps` 都有递归深度限制。
|
||||
|
||||
该包独立交付协议,不包含 runtime 实现。它不导出 `PythonCodeRuntime`、子进程路径或 Python 侧 JSON codec;这些属于未来提供方。协议建立在[可移植标识符 seam](2026-07-31-code-runtime-portable-identifier-seam.zh.md)之上。
|
||||
该包同时交付协议与 runtime 实现:`PythonCodeRuntime`(插件的默认导出)、`python3 -I` 子进程路径与 Python 侧 JSON codec 都在 `@deepseek-ai/dsh-code-runtime-python` 中。协议建立在[可移植标识符 seam](2026-07-31-code-runtime-portable-identifier-seam.zh.md)之上。
|
||||
|
||||
## Decision
|
||||
|
||||
|
|
|
|||
|
|
@ -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: 94d5a7b6608f54a6eaa9b1640cf017d16a1c5b8c
|
||||
2026-07-31-code-runtime-python-settlement-fixes.zh.md: f542216b7be865fbbbfed15d77a41f5aa8080912
|
||||
2026-07-31-code-runtime-python-settlement-fixes.md: 869c2736dbd3207b92e7ac7362176d4001629389
|
||||
2026-07-31-code-runtime-python-settlement-fixes.zh.md: 30bcdb95b46c7c551027e654a807042c9364b55d
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -2172,7 +2172,7 @@ def _cap_message(message: str, max_bytes: int) -> str:
|
|||
roughly six times that and breach the 256 MiB frame ceiling — the silent
|
||||
``worker-exit`` inversion the load-time cap check exists to prevent, and a
|
||||
several-hundred-MiB escape allocation besides. The seam's load bound admits
|
||||
``maxValueBytes`` up to ``ceiling - envelope`` on the premise that both the
|
||||
``maxValueBytes`` up to ``parse-cap - envelope`` on the premise that both the
|
||||
completion value and the diagnostic are metered in serialized bytes, so this
|
||||
honors that premise for the diagnostic.
|
||||
|
||||
|
|
@ -2408,6 +2408,7 @@ def _done_with_value(
|
|||
# `exception`. Defaults are evaluated at def time, so they are the originals.
|
||||
_check_done_value: Any = _check_done_value,
|
||||
_encode_json_plain: Any = _encode_json_plain,
|
||||
_cap_message: Any = _cap_message,
|
||||
) -> dict[str, Any] | str:
|
||||
"""Build the terminal done frame under the seam's lossless-JSON contract.
|
||||
|
||||
|
|
@ -2444,7 +2445,12 @@ def _done_with_value(
|
|||
rejection = _check_done_value(value, max_value_bytes)
|
||||
if rejection is not None:
|
||||
kind, message = rejection
|
||||
return {"type": "done", "error": {"kind": kind, "message": message}}
|
||||
# The rejection diagnostic is capped like an exception message: a
|
||||
# reason embedding a hostile class name (a huge `type(value).__name__`)
|
||||
# could otherwise make the done frame exceed the host's frame parse cap
|
||||
# and be silently dropped — an invalid-output run misreported as a
|
||||
# worker-exit.
|
||||
return {"type": "done", "error": {"kind": kind, "message": _cap_message(message, max_value_bytes)}}
|
||||
# Pre-encode the value at the validation point (not in `_run`'s later send,
|
||||
# which is outside the try): see the TOCTOU note in the docstring. The value
|
||||
# is JSON-plain by construction, so `_encode_json_plain` is the encoder.
|
||||
|
|
|
|||
|
|
@ -231,7 +231,8 @@ const MAX_PENDING_CHUNKS = 1024
|
|||
|
||||
/**
|
||||
* Bytes a frame spends on its own JSON structure around a capped payload, used
|
||||
* to bound `maxLogBytes`/`maxValueBytes` against {@link FRAME_CEILING_BYTES}.
|
||||
* to bound `maxLogBytes`/`maxValueBytes` against {@link FRAME_PARSE_CAP_BYTES}
|
||||
* (the receive path drops raw frames past that cap before decoding).
|
||||
* The widest carrier is `{"type":"log","text":"","truncated":true}` at 41
|
||||
* bytes; 64 rounds that up so adding a field to either frame does not silently
|
||||
* invalidate the bound. A protocol constant, not a deployment choice.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue