The object branch counted every own key before applying the size bound, so a
forged done.value with millions of keys and a small cap forced an O(frame)
walk — contradicting the O(cap) guarantee the comment promised and able to
block the host event loop. Bail mid-count the instant the running minimum
encoding (braces + 4 bytes/entry + commas) crosses maxBytes, and drop the now
-redundant post-count check the loop subsumes. Add a Proxy-based test proving
a 2M-key object enumerates fewer than 1000 keys under a 64-byte cap.
Also correct the checkDoneValue JSDoc: per-scalar byte length is measured via
scalarJson (exact BigInt digits for beyond-safe integers), not JSON.stringify.
- Translate README.zh.md's Model Experience body and KV Cache line, which
were left verbatim in English.
- Convert half-width punctuation to full-width across the README.zh.md
Known Limitations bullets and the entire Agent Note Chinese side, per
docs/i18n translation-rules.md Typography (MUST use ,。:()in Chinese prose).
- Re-record both README and Agent Note i18n.yaml pairing hashes.
- Reword the workspace-constraints extra-files comment: this layer's py/
ships only the wire-protocol mirror; the spawned bootstrap arrives later.
- Drop a CALL frame whose id is negative zero: it passes Number.isFinite but
the reply re-serializes it as `0`, colliding with a real call id `0`. The
honest child never issues `-0`.
- Document that validateChildFrame preserves a forged done frame's value and
error together on purpose, so consumers must check error before value.
- Cover the log-frame `truncated` rebuild branch: assert a literal-true flag
rides along and any other value (1, string, false) is dropped, closing the
protocol.ts branch the coverage gate flagged.
- Correct encodeJsonPlain's JSDoc: it matches compact JSON.stringify EXCEPT on
a beyond-safe-range integral double, where it emits the exact BigInt digits
(`...846976`) rather than the rounded `...847000` — the divergence the
"emits exact digits" test pins.
- Declare py/protocol.py's `global`-bearing frames (Namespace, CallMessage)
with functional TypedDict syntax so they carry the real wire key instead of
a `global_` attribute the wire never sends, and split optional-field messages
(Namespace/LogMessage/DoneMessage) into a required base plus a total=False
subclass so `type` and other required fields cannot be dropped. Widen
HostToChild to include the boot and run frames the host sends before replies.
- Reword the mirror e2e's py/ directory assertion to describe the source-tree
layout it actually checks.
- Drop the unused @deepseek-ai/dsh-code-runtime dependency: this layer
imports nothing from the seam (protocol.ts has no imports; the invariant
companion uses only cordis and dsh-invariants). The backend-core PR
re-adds it when PythonCodeRuntime consumes the seam. Fixes knip.
- Point the Agent Note's cross-reference to the seam note at the English
target on both language sides, per the bilingual-pairing contract (only
the language switcher flips to .zh.md). Re-record the sidecar.
- Add the Known Limitations section both READMEs require, covering the
cross-language guard's scope and the deferred runtime implementation.
- Regenerate the module graph for the dropped dependency edge.
Introduce @deepseek-ai/dsh-code-runtime-python with the versionless
JSON-lines protocol between the Node host and the CPython subprocess:
the host-side hostile-frame codec (validateChildFrame, encodeJsonPlain,
checkDoneValue, hasUnsafeIntegerToken, hasNonLosslessNumber,
logTruncationMarker) and the Python-side wire-vocabulary mirror
(py/protocol.py).
This is the protocol layer of the code-runtime-python stack, split from
#436 and based on the multi-language seam extension. The PythonCodeRuntime
implementation and its Python JSON codec land in the backend-core PR on
top of this branch.
Ship the minimal buildable package skeleton (package.json, tsconfig,
tsdown, barrel index, invariant companion, bilingual README) because the
workspace-constraint, coverage, and invariant-topology gates require the
package to exist and build the moment its directory does; the backend-core
PR extends those files rather than creating them.
Align py/protocol.py with src/protocol.ts (the round-12 review of #436
found LogMessage.truncated, DoneMessage.error.kind, and Namespace.errorClass
stale) and guard the two runtime-executed surfaces (PROTOCOL_FD and the log
truncation marker) with a real-python3 cross-language mirror e2e test.