Procházet zdrojové kódy

docs(code-runtime-python): correct the claims the new backend invalidated

Adding a published Python backend and reordering `flush_line` left several
owning documents stating things that are no longer true.

`src/invariant.ts` justified its empty installer with "ships only the fd-3
wire-protocol codec", which the subprocess execution path contradicts. The
reason now states the actual one: every relation this backend maintains lives
in the CPython child or on the fd-3 wire, so no same-process event sequence is
observable from a listener -- the same shape the sibling worker-thread backend
uses.

The seam's `PORTABLE_RESERVED_WORDS` and `language` JSDoc, the code-runtime
README pair, and docs/subsystems/code-runtime both said only TypeScript has a
published backend. Corrected in all four, with the generated cordis catalog
regenerated for the `language` change.

The note attributed the 12x multiple to the settlement flush holding three
copies. That stopped being true when `flush_line` was reordered to drop the
pending chunks before its push: the binding worst case is the newline path's
single near-budget write. Corrected in the note (both sides) and in the test
comment that repeated it.

The note's Testing section now registers the cases this stack added, and the
Chinese side receives the O(depth) entry it never got plus the new ones -- it
had drifted from the English.

`INTERPRETER_BASELINE_BYTES` argued 64 MiB from a RESIDENT set while RLIMIT_AS
bounds address space. It now cites the bootstrap's own measurement (30.23 MiB
of mappings for `python3 -I`), making 64 MiB roughly twice the measured
baseline.

Also: a hardcoded `(:232-235)` comment reference becomes a reference by name,
a "which now walks in O(depth) too" change narrative becomes a current-state
statement, and a stray double blank line is removed.
Chinesezjc před 3 týdny
rodič
revize
2e3cf144d5

+ 2 - 2
.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: 0614d4f40c03c01b63c0ef3ae5584e667d94dddc
-2026-07-31-code-runtime-python-settlement-fixes.zh.md: c1320696c6a8c2316befd79396618157299a9484
+2026-07-31-code-runtime-python-settlement-fixes.md: b3a5242c661fc162dc95cde41497940d2e36b447
+2026-07-31-code-runtime-python-settlement-fixes.zh.md: a78aa5a5682b76b6b2d02c1519f29128e59b6111

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
.agents/notes/implemented/bug-fix/2026-07-31-code-runtime-python-settlement-fixes.md


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
.agents/notes/implemented/bug-fix/2026-07-31-code-runtime-python-settlement-fixes.zh.md


+ 2 - 2
docs/subsystems/code-runtime.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 docs/subsystems/code-runtime.md
-code-runtime.md: 0f633df9fc657d9d80fc04df3bc8ad6fafdddcb2
-code-runtime.zh.md: 43b78ce49575741f7ae6c4e2751b63b7562fc99a
+code-runtime.md: eaffa17b552f4d91440c7f9f4ca089549d1e8966
+code-runtime.zh.md: 762c21d9366f33129f1e4e386b5d6ae2d3a44258

+ 1 - 1
docs/subsystems/code-runtime.md

@@ -158,7 +158,7 @@ interface CodeRunFailure {
 
 ## The service
 
-`CodeRuntime` (`ctx.codeRuntime`, abstract — defined in [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts)) is `run(request)` plus two readonly descriptors: `language` (what the program must be written in — `'typescript'` and `'python'` are the well-known values, those `dsh-tools` presents, and only `'typescript'` has a published backend; a consumer generating language-specific presentation switches on it and fails loud on one it cannot present) and `isolation` (the execution substrate — `'worker-thread'`, `'process'`, `'container'`; a diagnostic label, **not a security claim**). Implementations must keep runs isolated from each other (no cross-run state) and dispose to quiescence: in-flight runs are terminated and awaited before teardown completes.
+`CodeRuntime` (`ctx.codeRuntime`, abstract — defined in [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts)) is `run(request)` plus two readonly descriptors: `language` (what the program must be written in — `'typescript'` and `'python'` are the well-known values, those `dsh-tools` presents, and each has a published backend; a consumer generating language-specific presentation switches on it and fails loud on one it cannot present) and `isolation` (the execution substrate — `'worker-thread'`, `'process'`, `'container'`; a diagnostic label, **not a security claim**). Implementations must keep runs isolated from each other (no cross-run state) and dispose to quiescence: in-flight runs are terminated and awaited before teardown completes.
 
 <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
 

+ 1 - 1
docs/subsystems/code-runtime.zh.md

@@ -158,7 +158,7 @@ interface CodeRunFailure {
 
 ## 服务
 
-`CodeRuntime`(`ctx.codeRuntime`,抽象服务,定义于 [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts))由 `run(request)` 加两个只读描述符组成:`language`(程序必须使用的语言,已知值为 `'typescript'` 与 `'python'`,即 `dsh-tools` 能呈现的那些,其中只有 `'typescript'` 有已发布的后端;生成语言相关展示的 Consumer 据此切换,遇到无法展示的语言时应显式报错)和 `isolation`(执行基底,`'worker-thread'`、`'process'`、`'container'`;仅为诊断标签,**不构成安全承诺**)。实现必须保证各次运行彼此隔离(无跨运行状态),并在 dispose(资源释放)时等待系统完全停稳:teardown 要等到所有进行中的运行均已终止并结算后才完成。
+`CodeRuntime`(`ctx.codeRuntime`,抽象服务,定义于 [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts))由 `run(request)` 加两个只读描述符组成:`language`(程序必须使用的语言,已知值为 `'typescript'` 与 `'python'`,即 `dsh-tools` 能呈现的那些,两者都有已发布的后端;生成语言相关展示的 Consumer 据此切换,遇到无法展示的语言时应显式报错)和 `isolation`(执行基底,`'worker-thread'`、`'process'`、`'container'`;仅为诊断标签,**不构成安全承诺**)。实现必须保证各次运行彼此隔离(无跨运行状态),并在 dispose(资源释放)时等待系统完全停稳:teardown 要等到所有进行中的运行均已终止并结算后才完成。
 
 <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
 

+ 4 - 4
packages/code-runtime/code-runtime-python/py/bootstrap.py

@@ -363,8 +363,8 @@ class _LogStream(io.TextIOBase):
         # against them.
         with self._logs.lock:
             if self._pending:
-                # Join, drop the chunks, THEN push — the same order the newline
-                # path uses (:232-235). Pushing before the clear would keep the
+                # Join, drop the chunks, THEN push — the same join-clear-push order
+                # as `_write_locked`'s newline branch. Pushing before the clear would keep the
                 # pending chunks alive through `_push_locked`'s `text.encode`, so
                 # the chunks, their join, and the encode copy would all be live at
                 # once; dropping the chunks first leaves only the join and its
@@ -1184,8 +1184,8 @@ def _encode_json_plain(value: Any) -> str:
     # that pulls its children one at a time and writes each into the shared buffer,
     # rather than one stack entry (plus a separator marker) per child: a flat
     # `[0] * 6_000_000` encodes to ~12 MB but per-element frames are ~400 MB — an
-    # RLIMIT_AS death on a value `_check_done_value` already admitted (which now
-    # walks in O(depth) too). The output string is the only width-proportional
+    # RLIMIT_AS death on a value `_check_done_value` already admitted (it walks by
+    # depth as well). The output string is the only width-proportional
     # allocation, and its size the caller metered within budget. `io.StringIO`
     # accumulates without the intermediate `"".join(chunks)` second copy. A cursor
     # frame is [kind, iterator, wrote_any]; a visit frame is (VISIT, value).

+ 15 - 4
packages/code-runtime/code-runtime-python/src/index.ts

@@ -266,13 +266,16 @@ const OUTPUT_BUDGET_WORST_CASE_ADDRESS_SPACE_MULTIPLE = 12
  * multiple claims the rest. The budget check subtracts this from `addressSpaceMb`
  * so a budget sized right at `addressSpaceMb / MULTIPLE` — which the multiple
  * alone would admit — cannot leave the peak output allocation plus the
- * interpreter over the limit. 64 MiB is generous for a `python3 -I` process
- * whose own resident set is tens of MiB; the value is a fixed safety margin, not
- * a deployment knob.
+ * interpreter over the limit. Sized against ADDRESS SPACE, which is what
+ * `RLIMIT_AS` bounds, not resident set: the bootstrap's own measurement is
+ * 30.23 MiB of mappings for a `python3 -I` child (see `_make_cpu_enforcer`,
+ * which also records the 64 MiB glibc per-thread arena reservation that pushes
+ * it to 102.37 MiB when threads are used). 64 MiB is roughly twice the measured
+ * baseline, leaving room for allocator arenas and import jitter. The value is a
+ * fixed safety margin, not a deployment knob.
  */
 const INTERPRETER_BASELINE_BYTES = 64 * 1024 * 1024
 
-
 /**
  * Interval between process-group liveness probes while settlement waits for an
  * escalated SIGKILL to empty the group (see the `killing` branch in
@@ -794,6 +797,14 @@ export class PythonCodeRuntime extends CodeRuntime {
     // peak plus the reserved baseline is the whole address space, the RLIMIT_AS
     // edge. `ceil(budgetableBytes / MULTIPLE) - 1` is the last integer strictly
     // under `budgetableBytes / MULTIPLE`.
+    // Reject a too-small address space on its own terms FIRST. Once
+    // `budgetableBytes` is zero or negative no budget can pass, and the loop
+    // below would report "a limit of -1" (or -2796203 at addressSpaceMb 32) while
+    // naming `maxLogBytes` -- pointing the operator at the knob that is not the
+    // problem. The baseline is what `addressSpaceMb` must clear here.
+    if (budgetableBytes <= 0) {
+      throw new Error(`dsh-code-runtime-python: config.addressSpaceMb must exceed the ${INTERPRETER_BASELINE_BYTES}-byte interpreter baseline with room for the output budgets, so the child has address space left to build and encode them; got ${String(this.config.addressSpaceMb)} MiB (${addressSpaceBytes} bytes)`)
+    }
     const admissibleBudget = Math.ceil(budgetableBytes / OUTPUT_BUDGET_WORST_CASE_ADDRESS_SPACE_MULTIPLE) - 1
     for (const key of ['maxLogBytes', 'maxValueBytes'] as const) {
       if (this.config[key] * OUTPUT_BUDGET_WORST_CASE_ADDRESS_SPACE_MULTIPLE >= budgetableBytes) {

+ 5 - 3
packages/code-runtime/code-runtime-python/src/invariant.ts

@@ -15,9 +15,11 @@ export const name = 'code-runtime-python-invariant'
 export const inject = ['invariants']
 
 /**
- * No runtime invariant: this package ships only the fd-3 wire-protocol codec and its Python mirror,
- * exposing no runtime event sequence or mutable data relation; `protocol.spec.ts` and
- * `protocol-mirror.e2e.ts` cover the protocol's behavior.
+ * No runtime invariant: every relation this backend maintains — frame ordering, budget accounting,
+ * and process teardown — lives in the CPython subprocess or on the fd-3 wire, so no same-process
+ * event sequence or mutable data relation is observable from a Cordis listener. `protocol.spec.ts`,
+ * `protocol-mirror.e2e.ts`, and the real-subprocess `runtime.spec.ts` cover that behavior, matching
+ * the sibling process-boundary backend `@deepseek-ai/dsh-code-runtime-worker-thread`.
  */
 const install: InvariantInstaller = () => {}
 

+ 15 - 3
packages/code-runtime/code-runtime-python/tests/runtime.spec.ts

@@ -827,12 +827,24 @@ describe('PythonCodeRuntime — programs and bindings', () => {
       .rejects.toThrow(/maxValueBytes times the 12x worst-case Unicode expansion must fit/)
     // Discriminates 12 from 8: a 48 MiB maxLogBytes against a 512 MiB address
     // space leaves 448 MiB budgetable. 48*8 = 384 MiB fits (the old 8x multiple
-    // wrongly ADMITTED this), but 48*12 = 576 MiB does not — and this is exactly
-    // the config that OOMs, since a settlement flush holds the pending chunks,
-    // their join, and the encode copy at once (~12x). The 12x gate rejects it.
+    // wrongly ADMITTED this), but 48*12 = 576 MiB does not. The ~12x peak this
+    // guards is the NEWLINE path's single near-budget write — the caller's own
+    // string, the line slice, and the encode copy live at once. The settlement
+    // flush is no longer the binding case: `flush_line` drops the pending chunks
+    // before its push, so it holds two copies, not three.
     const ctxTwelve = new Context()
     await expect(ctxTwelve.plugin(PythonCodeRuntime, { maxLogBytes: 48 * 1024 * 1024, addressSpaceMb: 512 }))
       .rejects.toThrow(/maxLogBytes times the 12x worst-case Unicode expansion must fit/)
+    // An addressSpaceMb at or below the interpreter baseline leaves nothing
+    // budgetable, so no budget value can pass. It is rejected on its own terms:
+    // the budget loop would otherwise report "a limit of -1" (or -2796203 at
+    // 32 MiB) while naming maxLogBytes, sending the operator to the wrong knob.
+    const ctxBaseline = new Context()
+    await expect(ctxBaseline.plugin(PythonCodeRuntime, { addressSpaceMb: 64 }))
+      .rejects.toThrow(/addressSpaceMb must exceed the 67108864-byte interpreter baseline/)
+    const ctxBelow = new Context()
+    await expect(ctxBelow.plugin(PythonCodeRuntime, { addressSpaceMb: 32 }))
+      .rejects.toThrow(/addressSpaceMb must exceed the 67108864-byte interpreter baseline/)
     // The default caps against the default 512 MiB address space load.
     const ok = new Context()
     const fiber = await ok.plugin(PythonCodeRuntime, { maxLogBytes: 65536, maxValueBytes: 32768, addressSpaceMb: 512 })

+ 2 - 2
packages/code-runtime/code-runtime/README.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 packages/code-runtime/code-runtime/README.md
-README.md: e3d43e7add4992c44fef966651f91addb81aa1eb
-README.zh.md: bcbeaa8bbdfee33baa1b29e232038e2bd6b77728
+README.md: b16a8c81e80e07665b7ac868e4cb643529938055
+README.zh.md: ad5ec96fc8df00c0f3c1b1771bc5efbf148de054

+ 2 - 2
packages/code-runtime/code-runtime/README.md

@@ -41,7 +41,7 @@ const result = await ctx.codeRuntime.run({
 
 ### Choose a backend
 
-Backends declare two descriptors you can rely on: `language` — what the program must be written in, with `'typescript'` and `'python'` as the well-known values and only TypeScript shipped — and `isolation` — the execution substrate (`'worker-thread'`, `'process'`, `'container'`), a label for deployments and diagnostics, not a security claim. The shipped backend is [`dsh-code-runtime-worker-thread`](../code-runtime-worker-thread/README.md), which executes TypeScript in a fresh Node worker thread; [`dsh-code-runtime-python`](../code-runtime-python/README.md) owns the wire protocol for the CPython backend.
+Backends declare two descriptors you can rely on: `language` — what the program must be written in, with `'typescript'` and `'python'` as the well-known values and both backed by published providers — and `isolation` — the execution substrate (`'worker-thread'`, `'process'`, `'container'`), a label for deployments and diagnostics, not a security claim. [`dsh-code-runtime-worker-thread`](../code-runtime-worker-thread/README.md) executes TypeScript in a fresh Node worker thread; [`dsh-code-runtime-python`](../code-runtime-python/README.md) executes Python in a fresh CPython subprocess.
 
 ### Name your bindings portably
 
@@ -98,7 +98,7 @@ Read these when the package-level contract is not enough. They move from the PTC
 
 - [PTC mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-ptc.md) — how the tool registry consumes `ctx.codeRuntime` and presents `run_code` to the model.
 - [Worker-thread backend](../code-runtime-worker-thread/README.md) — the shipped TypeScript execution backend.
-- [Python protocol package](../code-runtime-python/README.md) — the wire protocol for the CPython backend.
+- [Python backend](../code-runtime-python/README.md) — the CPython subprocess execution provider and its fd-3 protocol.
 - [Code runtime subsystem reference](../../../docs/subsystems/code-runtime.md) — request/result vocabulary, bindings, and the `ctx.codeRuntime` cordis surface.
 - [Capability seams](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) — the Service Definition / Service Provider / Consumer split.
 

+ 2 - 2
packages/code-runtime/code-runtime/README.zh.md

@@ -41,7 +41,7 @@ const result = await ctx.codeRuntime.run({
 
 ### 选择后端
 
-后端声明两个你可以依赖的描述符:`language`——程序必须使用的源语言,已知值为 `'typescript'` 与 `'python'`,目前只有 TypeScript 已发布——以及 `isolation`——执行基底(`'worker-thread'`、`'process'`、`'container'`),仅供部署与诊断使用,不构成安全声明。已发布的后端是 [`dsh-code-runtime-worker-thread`](../code-runtime-worker-thread/README.zh.md)在全新的 Node Worker 线程中执行 TypeScript;[`dsh-code-runtime-python`](../code-runtime-python/README.zh.md) 持有 CPython 后端的协议格式(wire protocol)
+后端声明两个你可以依赖的描述符:`language`——程序必须使用的源语言,已知值为 `'typescript'` 与 `'python'`,两者都有已发布的提供方——以及 `isolation`——执行基底(`'worker-thread'`、`'process'`、`'container'`),仅供部署与诊断使用,不构成安全声明。[`dsh-code-runtime-worker-thread`](../code-runtime-worker-thread/README.zh.md) 在全新的 Node Worker 线程中执行 TypeScript;[`dsh-code-runtime-python`](../code-runtime-python/README.zh.md) 在全新的 CPython 子进程中执行 Python
 
 ### 可移植地命名绑定
 
@@ -98,7 +98,7 @@ binding-global 与 error-class 名称是语言可移植的:必须匹配标识
 
 - [PTC mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-ptc.zh.md)——工具注册表如何消费 `ctx.codeRuntime` 并把 `run_code` 呈现给模型。
 - [Worker 线程后端](../code-runtime-worker-thread/README.zh.md)——已发布的 TypeScript 执行后端。
-- [Python 协议包](../code-runtime-python/README.zh.md)——CPython 后端的协议格式
+- [Python 后端](../code-runtime-python/README.zh.md)——CPython 子进程执行提供方及其 fd-3 协议
 - [代码运行时子系统参考](../../../docs/subsystems/code-runtime.zh.md)——请求/结果词汇、绑定与 `ctx.codeRuntime` 的 cordis 接口面。
 - [能力 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md)——Service Definition / Service Provider / Consumer 拆分。
 

+ 3 - 3
packages/code-runtime/code-runtime/src/index.ts

@@ -66,8 +66,8 @@ export const DUNDER_MEMBER = /^__.+__$/
 /**
  * Reserved words of every portable target language (ECMAScript ∪ Python),
  * refused as {@link CodeBindingNamespace.global} / error-class names by all
- * backends. Python is a portability target here even though only the
- * TypeScript worker has a published backend. The portable-identifier contract
+ * backends, which ship for both languages: the TypeScript worker thread and
+ * the CPython subprocess. The portable-identifier contract
  * promises a namespace list valid on one backend is valid on every backend; a
  * per-language check would let `lambda` pass the TypeScript backend and fail
  * the Python one. Extending the seam with a new language means widening this
@@ -106,7 +106,7 @@ export abstract class CodeRuntime extends Service {
    * generates language-specific presentation (typed SDK stubs, usage
    * instructions) switches on it and fails loud on a language it cannot
    * present. Well-known values: `'typescript'` and `'python'`, those
-   * `dsh-tools` presents; only `'typescript'` has a published backend.
+   * `dsh-tools` presents; each has a published backend.
    */
   abstract readonly language: string
 

+ 1 - 1
packages/extensions/tool-cordis/src/api-catalog.ts

@@ -598,7 +598,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
     methods: [
       {
         signature: 'abstract readonly language: string',
-        description: 'The source language run expects `program` to be written in, as a lowercase identifier. Informational, not gating — a consumer that generates language-specific presentation (typed SDK stubs, usage instructions) switches on it and fails loud on a language it cannot present. Well-known values: `\'typescript\'` and `\'python\'`, those `dsh-tools` presents; only `\'typescript\'` has a published backend.',
+        description: 'The source language run expects `program` to be written in, as a lowercase identifier. Informational, not gating — a consumer that generates language-specific presentation (typed SDK stubs, usage instructions) switches on it and fails loud on a language it cannot present. Well-known values: `\'typescript\'` and `\'python\'`, those `dsh-tools` presents; each has a published backend.',
         parameters: [],
       },
       {

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů