feat(code-runtime-python): add the fd-3 frame protocol
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.
2026-07-31 18:51:03 +08:00
|
|
|
import { execFile } from 'node:child_process'
|
|
|
|
|
import { existsSync } from 'node:fs'
|
|
|
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
|
import { promisify } from 'node:util'
|
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
|
import { logTruncationMarker } from '../src/protocol.ts'
|
|
|
|
|
|
|
|
|
|
/**
|
2026-08-02 17:45:11 +08:00
|
|
|
* Cross-language mirror check between `src/protocol.ts` and `py/protocol.py`,
|
|
|
|
|
* spawning a real `python3` to read the Python side. Two things are asserted:
|
|
|
|
|
* the runtime surfaces both sides EXECUTE against — `PROTOCOL_FD` and the log
|
|
|
|
|
* truncation marker text, where a drift silently corrupts a live run — and the
|
|
|
|
|
* per-frame wire field sets (required/optional keys of each `TypedDict`), which
|
|
|
|
|
* turns the otherwise review-only shape mirror into an executable check that
|
|
|
|
|
* catches the round-12 kind of drift (a renamed/dropped field, or one side
|
|
|
|
|
* making a field optional the other requires). Self-skips when no `python3` is
|
feat(code-runtime-python): add the fd-3 frame protocol
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.
2026-07-31 18:51:03 +08:00
|
|
|
* on PATH — CI provides one; the pure-TS `protocol.spec.ts` covers the host
|
|
|
|
|
* codec unconditionally.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const execFileAsync = promisify(execFile)
|
|
|
|
|
const pyDir = fileURLToPath(new URL('../py', import.meta.url))
|
|
|
|
|
|
|
|
|
|
async function hasPython3(): Promise<boolean> {
|
|
|
|
|
try {
|
|
|
|
|
await execFileAsync('python3', ['--version'])
|
|
|
|
|
return true
|
|
|
|
|
} catch {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const python3Available = await hasPython3()
|
|
|
|
|
|
|
|
|
|
describe.skipIf(!python3Available)('protocol.py mirrors protocol.ts at runtime', () => {
|
|
|
|
|
it('agrees on PROTOCOL_FD and the log truncation marker across byte budgets', async () => {
|
|
|
|
|
const budgets = [1, 65536, 1048576]
|
|
|
|
|
const probe = [
|
|
|
|
|
'import json, sys',
|
|
|
|
|
`sys.path.insert(0, ${JSON.stringify(pyDir)})`,
|
|
|
|
|
'from protocol import PROTOCOL_FD, log_truncation_marker',
|
|
|
|
|
`budgets = ${JSON.stringify(budgets)}`,
|
|
|
|
|
'print(json.dumps({',
|
|
|
|
|
' "fd": PROTOCOL_FD,',
|
|
|
|
|
' "markers": [log_truncation_marker(b) for b in budgets],',
|
|
|
|
|
'}))',
|
|
|
|
|
].join('\n')
|
|
|
|
|
const { stdout } = await execFileAsync('python3', ['-I', '-c', probe])
|
|
|
|
|
const seen = JSON.parse(stdout) as { fd: number; markers: string[] }
|
2026-08-02 17:45:11 +08:00
|
|
|
// fd 3 is the wire contract, not a tunable: the host pins it positionally
|
|
|
|
|
// when it spawns the child.
|
feat(code-runtime-python): add the fd-3 frame protocol
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.
2026-07-31 18:51:03 +08:00
|
|
|
expect(seen.fd).toBe(3)
|
|
|
|
|
expect(seen.markers).toEqual(budgets.map(budget => logTruncationMarker(budget)))
|
|
|
|
|
})
|
2026-08-02 17:45:11 +08:00
|
|
|
|
|
|
|
|
it('agrees on every frame type\'s wire field set between the TS and Python declarations', async () => {
|
|
|
|
|
// Turn the TypedDict mirror from a review-only obligation into an executable
|
|
|
|
|
// check: read each Python TypedDict's required/optional key sets and assert
|
|
|
|
|
// them against the wire field names the TS side declares. `global` is the
|
|
|
|
|
// reserved-keyword key the Python side carries via functional TypedDict —
|
|
|
|
|
// catching exactly the round-12 kind of drift (a renamed/dropped field, an
|
|
|
|
|
// optional field the other side made required).
|
|
|
|
|
const probe = [
|
|
|
|
|
'import json, sys',
|
|
|
|
|
`sys.path.insert(0, ${JSON.stringify(pyDir)})`,
|
|
|
|
|
'import protocol as p',
|
|
|
|
|
'def keys(td): return {"required": sorted(td.__required_keys__), "optional": sorted(td.__optional_keys__)}',
|
|
|
|
|
'print(json.dumps({',
|
|
|
|
|
' "BootMessage": keys(p.BootMessage),',
|
|
|
|
|
' "Namespace": keys(p.Namespace),',
|
|
|
|
|
' "RunMessage": keys(p.RunMessage),',
|
|
|
|
|
' "BootAckMessage": keys(p.BootAckMessage),',
|
|
|
|
|
' "CallMessage": keys(p.CallMessage),',
|
|
|
|
|
' "LogMessage": keys(p.LogMessage),',
|
|
|
|
|
' "DoneErrorField": keys(p.DoneErrorField),',
|
|
|
|
|
' "DoneMessage": keys(p.DoneMessage),',
|
|
|
|
|
' "ErrorClass": keys(p.ErrorClass),',
|
|
|
|
|
'}))',
|
|
|
|
|
].join('\n')
|
|
|
|
|
const { stdout } = await execFileAsync('python3', ['-I', '-c', probe])
|
|
|
|
|
const seen = JSON.parse(stdout) as Record<string, { required: string[]; optional: string[] }>
|
|
|
|
|
// The wire field sets each frame carries, mirroring src/protocol.ts. `global`
|
|
|
|
|
// is the JSON key `CallMessage`/`Namespace` send (a Python keyword, declared
|
|
|
|
|
// functionally on the Python side).
|
|
|
|
|
expect(seen).toEqual({
|
|
|
|
|
BootMessage: { required: ['addressSpaceBytes', 'cpuSeconds', 'maxLogBytes', 'maxValueBytes', 'namespaces', 'type'], optional: [] },
|
|
|
|
|
Namespace: { required: ['global', 'names'], optional: ['errorClass'] },
|
|
|
|
|
RunMessage: { required: ['program', 'type'], optional: [] },
|
|
|
|
|
BootAckMessage: { required: ['type'], optional: [] },
|
|
|
|
|
CallMessage: { required: ['args', 'global', 'id', 'name', 'type'], optional: [] },
|
|
|
|
|
LogMessage: { required: ['text', 'type'], optional: ['truncated'] },
|
|
|
|
|
DoneErrorField: { required: ['kind', 'message'], optional: [] },
|
|
|
|
|
DoneMessage: { required: ['type'], optional: ['error', 'value'] },
|
|
|
|
|
ErrorClass: { required: ['memberNameProperty', 'name'], optional: [] },
|
|
|
|
|
})
|
|
|
|
|
})
|
feat(code-runtime-python): add the fd-3 frame protocol
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.
2026-07-31 18:51:03 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('names the py/ directory that ships with the package', () => {
|
2026-07-31 19:20:28 +08:00
|
|
|
// Resolves py/ relative to this test file; the same directory ships in the
|
|
|
|
|
// package.json `files` whitelist (`py/**/*.py`). The tests/ directory itself
|
|
|
|
|
// is not published — this asserts the source-tree layout the mirror test
|
|
|
|
|
// depends on, so it holds even when python3 is absent from the runner.
|
feat(code-runtime-python): add the fd-3 frame protocol
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.
2026-07-31 18:51:03 +08:00
|
|
|
expect(existsSync(pyDir)).toBe(true)
|
|
|
|
|
})
|