fix(code-runtime-python): bill a merged open entry incrementally on both sides

The review's critical: the open-merge branch re-joined and re-walked the whole
held text per frame, so k tiny open frames cost O(k * budget) (thousands of
1-byte frames against a near-64 MiB budget would re-traverse hundreds of GB and
block the host event loop). The host now holds a fragment ARRAY with an
incrementally billed cost — each fragment's jsonStringCostUpTo walks only its
own text — and the closing frame bills only its own content, so the merged
entry's wire cost is charged exactly once, split across the fragments. The
child bills symmetrically: the first open fragment pays quotes+separator, each
continuation pays only its content, matching the host ledger (the review's
warning: per-fragment full billing truncated a 16-char merged entry under
maxLogBytes: 64 that costs only 19 bytes as one entry).

Regression cases: 16 single-character flushes merge to one whole entry; a
closing frame that overflows the remaining budget truncates to the marker; a
closing frame after an open flood already truncated the ledger is a no-op; and
a forged open-frame flood stays bounded by the ledger. The closing-frame
post-truncation guard is an invariant-false branch (an open frame that would
trip the ledger resets openParts, so a non-empty hold implies no truncation)
and carries a v8 ignore with that reason.
This commit is contained in:
Chinesezjc
2026-08-31 15:03:20 +08:00
committed by Tianyi Cui
parent ea1d28a068
commit 4fd0068fb7
3 changed files with 131 additions and 21 deletions
@@ -1898,6 +1898,64 @@ describe('PythonCodeRuntime — programs and bindings', () => {
expect(result.logs).toEqual([logTruncationMarker(64)])
}, 15_000)
it('no-ops a closing frame once an open flood already truncated the ledger', async () => {
// The closing-frame branch's post-truncation arm: an open flood exhausts
// the ledger (logsTruncated set, marker pushed), then a closing frame
// arrives — it must be a no-op, not append content past the marker.
const { runtime } = await setup({ maxLogBytes: 64 })
const result = await runtime.run({
program: [
'import os',
'for _ in range(2000):',
" os.write(3, b'{\"type\":\"log\",\"text\":\"a\",\"open\":true}\\n')",
"os.write(3, b'{\"type\":\"log\",\"text\":\"b\"}\\n')",
'return "done"',
].join('\n'),
bindings: [],
})
expect(result.error).toBeUndefined()
expect(result.logs).toEqual([logTruncationMarker(64)])
}, 15_000)
it('bills a merged open entry once, not per fragment', async () => {
// A merged entry's wire cost is billed ONCE, split across its fragments
// (first fragment pays quotes+separator, continuations pay only content).
// Under maxLogBytes: 64, 16 single-character flushes merge to one 16-char
// entry (2 quotes + 16 content + 1 separator = 19), which fits; per-
// fragment billing (each charged quotes+separator, ~4 bytes) would truncate
// at 16 x 4 = 64.
const { runtime } = await setup({ maxLogBytes: 64 })
const result = await runtime.run({
program: [
'for _ in range(16):',
" print('x', end='', flush=True)",
"print('')",
'return "done"',
].join('\n'),
bindings: [],
})
expect(result.error).toBeUndefined()
expect(result.logs).toEqual(['x'.repeat(16)])
}, 15_000)
it('truncates when the closing frame of a merged entry overflows the budget', async () => {
// The merged entry's billed-once cost: an open fragment that nearly
// exhausts the budget, then a closing frame whose content no longer fits —
// the closing frame's exact-cost walk trips and the marker replaces the
// entry, exactly like any other over-budget log traffic.
const { runtime } = await setup({ maxLogBytes: 64 })
const result = await runtime.run({
program: [
"print('x' * 40, end='', flush=True)",
"print('y' * 40)",
'return "done"',
].join('\n'),
bindings: [],
})
expect(result.error).toBeUndefined()
expect(result.logs).toEqual([logTruncationMarker(64)])
}, 15_000)
it('keeps a float completion exact when the program mutates the decimal context', async () => {
// The float encoder's Decimal(repr(value)).normalize() used the process
// GLOBAL decimal context: a legitimate program setting