The fd-3 note's Status line moved off line 3 when the experimental-location
fact was added; it is back as the sole line-3 status. The zh portable-identifier
note's merged Scope paragraph lost its blank-line separator, which the
md-wrap gate read as one hard-wrapped paragraph — the blank line is restored.
The review's move-follow-ups: the Windows test exclude now points at
packages/experimental/code-runtime-python (the constructor throws by design on
Windows, so the suite must stay excluded); the invariant companion and
@module annotations use the new npm name; the truncation marker text and
tmpdir prefix stay as-is (tests anchor them); the package JSDoc and READMEs no
longer call the private experimental backend 'published'/'shipped'; the
code-runtime README row describes the package as protocol AND runtime; the
fd-3 note records the package's experimental location.
The CPython code runtime's complete public contract is experimental, so it
moves to packages/experimental per the experimental-packages rules: npm name
@deepseek-ai/dsh-experimental-code-runtime-python, private: true, no
publishConfig. All references updated (code-runtime READMEs, config-catalog
and module-graph regenerated with zh alignment, tsconfig paths, doc-standard
and workspace-constraints scripts, the fd-3 and settlement Agent Notes, and
the package README links); md-links and translation pairing pass, and the
suite still runs green.
The review's warning: the READMEs (outer and inner wire sections, en + zh) and
the fd-3 protocol note still claimed the next log frame always merges into an
open entry, while truncateLogs commits the already-billed prefix as its own
entry before the marker. The one exception (truncation) is now stated in both
READMEs and the owning note, paired and re-recorded. The prefix-commit case's
parenthetical describing the pre-fix implementation is removed per the
comment-does-not-record-review-history rule.
The review's suggestion: the open-merge mechanism (incremental split billing on
both sides, host caps logBudget-1/logBudget+2, the sub-2-byte walk guard, the
child's _open_started-keyed billing) lived only in code comments. The wire
contract section of the note now states it, paired and re-recorded.
The review's critical: the open-merge branch accumulated the held fragment
before any ledger check, so a forged open flood could grow host memory without
touching logBudget. The held fragment is now bounded by the exact-cost walk
(jsonStringCostUpTo against the remaining budget; the closing frame's admit()
still bills the merged entry once), and the open field is registered in the
README wire-contract section and the fd-3 protocol note (en + zh). A forged
open-flood case asserts truncation to the marker under a 64-byte budget.
The forged-second-boot-ack regression makes the re-entry guard covered, so its
v8 ignore is removed. Doc drift: the python README and run() JSDoc state the
resolve-with-value/resolve-with-error contract without inversion; the README
Known Limitations gains the setsid-escaped-orphan entry (the settlement note
referenced it); the settlement note drops the stale drops/discard phrasing and
the two 256 MiB references; the fd-3 protocol zh note no longer claims the
codec is undelivered; the code-runtime seam README (en + zh) says both
backends ship. Pairings re-recorded.
The fd-3 protocol note (en + zh) drops the 'future provider/runtime' staging
language (the runtime is delivered and its real-subprocess suite owns the
field-type gap), and the settlement note's Testing paragraph records the
frame-cap, multi-frame, sealing-threshold, and pythonBin resolution cases now
in the suite. Pairings re-recorded.
The review's remaining critical: the fd-3 data handler checked the unframed
counter against the 256 MiB wire ceiling, so a single 64-256 MiB frame was
fully Buffer.concat-joined (a second copy) and only then dropped in the line
loop — the peak-memory doubling the pre-join check exists to prevent, for a
frame the parser is guaranteed to discard. The counter is now checked against
FRAME_PARSE_CAP_BYTES before the join; the regression case asserts a worker-exit
with 'protocol frame exceeded' (fail-before: reverting to the ceiling turns it
green, proving the join path). FRAME_CEILING_BYTES is removed.
The rejection-cap fix now has its regression: a completion value whose class
name is 70 MiB of Ns asserts invalid-output, not worker-exit (fail-before:
uncapping the diagnostic turns it red).
The settlement note (en + zh) updates the remaining stale bound text, and the
fd-3 protocol note (en + zh) no longer claims protocol-only exports or a
missing Python codec. Pairings re-recorded.
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.
Rename UnionCoversRoster/RosterCoversUnion to UnionSubsetOfRoster/RosterSubsetOfUnion so
the names read in the same direction as their extends clauses, share the python3 -I -B
flags between the two mirror probes, and align the README and Agent Note prose with the
checkDoneValue JSDoc: the escaped-size scan is the metering itself, not deferred work.
Regenerate docs/module-graph.md, which listed code-runtime-python twice.
Address the latest review round:
- WireFrameShapesCoverUnions checked only union ⊆ roster, so removing a frame
from a message union (e.g. dropping ReplyErr from ReplyMessage) left the check
true while the public TS union diverged from the wire. Replace it with a
bidirectional equivalence between MessageFrames and the roster's message-frame
value types (nested Namespace/ErrorClass/DoneErrorField excluded): both a frame
added to a union without a roster entry and a frame removed from a union now
fail typecheck (both verified).
- The mirror e2e's python3 probes imported protocol.py without -B, writing
py/__pycache__/*.pyc into the (un-ignored) source tree. Add -B to both.
- Refresh the metering prose (checkDoneValue JSDoc + README both sides + Agent
Note both sides): the incremental-work list no longer says "per-key
JSON.stringify" now that jsonStringBytesUpTo scans without stringifying;
re-record the README and Agent Note i18n pairings.
Address the two standing review suggestions in this layer rather than deferring
them to PR #4:
- Extend tests/protocol-mirror.e2e.ts to read each py/protocol.py TypedDict's
required/optional key set and assert it against the wire field names
src/protocol.ts declares (global included, via functional TypedDict). The
round-12 class of drift — a renamed/dropped field, or one side making a field
optional the other requires — now fails a test instead of relying on review.
Field types remain review-guarded (no mechanical TS/Python equivalent).
- Drop the forward references to PR #4's internal mechanisms from this layer's
prose: the "256 MiB frame ceiling" figure and the "(index.ts)" fd-3 pinning
citation become an abstract "host-side inbound frame-size cap" so the JSDoc,
spec, README, and Agent Note describe only what this layer owns.
Update both README sides and the Agent Note (both languages) to state the
mirror is now executable, and re-record their i18n pairings.
- Replace four raw U+0000 bytes in protocol.spec.ts string literals with the
\0 escape so the source stays plain text (a bare NUL makes text tools treat
the file as binary); the runtime value is unchanged, so the bytes:8 NUL-escape
assertion still holds.
- Sync the Agent Note (both languages) with the corrected checkDoneValue
contract: the walk bounds only the incremental allocation it would add, not
the frame width, which is already parsed and capped upstream by the host's
fd-3 receive buffer. Drop the "prevents a hundreds-of-MB allocation" overclaim
that the code JSDoc already retracted. Re-record the note i18n pairing.
- 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 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.