test(code-runtime-python): cover the finish-residual sealed side; use a block array for the open seal

The review's two remaining non-blocking items: (1) a case where the run ends
with a SEALED open hold (past MAX_PENDING_CHUNKS) — finish() must commit the
sealed prefix, verified to fail if finish drops openSealed. (2) openSealed is
now a block ARRAY (one joined block per seal) matching the fd-3 reader's
blocks and the stray capture's seal, instead of one repeated string concat
that leaned on V8 ConsString amortization.
This commit is contained in:
Chinesezjc
2026-08-31 15:06:50 +08:00
committed by Tianyi Cui
parent 74e9d97e37
commit 771872a73d
2 changed files with 38 additions and 17 deletions
@@ -1052,14 +1052,16 @@ export class PythonCodeRuntime extends CodeRuntime {
// ARRAY, so k tiny open frames cost O(k) — re-joining and re-walking the
// whole held text per frame would be O(k * budget).
let openParts: string[] = []
// Past MAX_PENDING_CHUNKS, the held fragments are coalesced into ONE
// sealed block (mirroring the fd-3 reader's `blocks` and the stray
// capture's seal): each fragment is a distinct array slot plus string
// object header — ~30x overhead the byte cap cannot see — so a
// budget-sized single-character open flood would otherwise accumulate
// thousands of slots. Sealing bounds the live fragment count exactly
// like the sibling paths; the merge reads sealed + current fragments.
let openSealed: string | undefined
// Past MAX_PENDING_CHUNKS, the held fragments are coalesced into sealed
// blocks (mirroring the fd-3 reader's `blocks` and the stray capture's
// seal): each fragment is a distinct array slot plus string object
// header — ~30x overhead the byte cap cannot see — so a budget-sized
// single-character open flood would otherwise accumulate thousands of
// slots. Sealing bounds the live fragment count exactly like the
// sibling paths; the merge reads sealed + current fragments. A block
// ARRAY (not one repeated string concat) matches the sibling shape and
// avoids depending on V8 ConsString amortization.
let openSealed: string[] = []
// Every truncation arm funnels here: the committed open prefix was
// ALREADY billed, so it is pushed BEFORE the marker — a flushed line is
// never lost (only the marker stays last), and no ledger re-charge
@@ -1067,9 +1069,9 @@ export class PythonCodeRuntime extends CodeRuntime {
// it.
const truncateLogs = (): void => {
logsTruncated = true
if (openSealed !== undefined || openParts.length > 0) {
logs.push((openSealed ?? '') + openParts.join(''))
openSealed = undefined
if (openSealed.length > 0 || openParts.length > 0) {
logs.push(openSealed.join('') + openParts.join(''))
openSealed = []
openParts = []
}
logs.push(logTruncationMarker(this.config.maxLogBytes))
@@ -1587,7 +1589,7 @@ export class PythonCodeRuntime extends CodeRuntime {
// the push, the merge result is unchanged.
if (message.text !== '') {
if (openParts.length >= MAX_PENDING_CHUNKS) {
openSealed = (openSealed ?? '') + openParts.join('')
openSealed.push(openParts.join(''))
openParts = []
}
openParts.push(message.text)
@@ -1610,10 +1612,10 @@ export class PythonCodeRuntime extends CodeRuntime {
truncateLogs()
} else {
logBudget -= Math.max(cost - 2, 0)
logs.push((openSealed ?? '') + openParts.join('') + message.text)
logs.push(openSealed.join('') + openParts.join('') + message.text)
}
}
openSealed = undefined
openSealed = []
openParts = []
return
}
@@ -2002,10 +2004,10 @@ export class PythonCodeRuntime extends CodeRuntime {
// logsTruncated implies the hold is already empty (truncateLogs
// committed and cleared it), so this is reachable only when the run
// ends with the hold still open and untruncated.
if (openSealed !== undefined || openParts.length > 0) {
logs.push((openSealed ?? '') + openParts.join(''))
if (openSealed.length > 0 || openParts.length > 0) {
logs.push(openSealed.join('') + openParts.join(''))
}
openSealed = undefined
openSealed = []
openParts = []
if (child.pid === undefined) {
settle(result)
@@ -1890,6 +1890,25 @@ describe('PythonCodeRuntime — programs and bindings', () => {
expect(result.logs).toEqual(['ab'])
}, 15_000)
it('keeps a SEALED open hold when the run ends with it still open', async () => {
// The finish-residual's sealed side: an open hold past MAX_PENDING_CHUNKS
// lands in openSealed, and the run ends without a closing frame — finish()
// must commit the SEALED prefix, not only the current fragments.
const { runtime } = await setup({ maxLogBytes: 65536 })
const result = await runtime.run({
program: [
'import os',
"os.write(3, b'{\"type\":\"log\",\"text\":\"x\",\"open\":true}\\n')",
'for _ in range(3000):',
" os.write(3, b'{\"type\":\"log\",\"text\":\"a\",\"open\":true}\\n')",
'return "done"',
].join('\n'),
bindings: [],
})
expect(result.error).toBeUndefined()
expect(result.logs).toEqual(['x' + 'a'.repeat(3000)])
}, 15_000)
it('keeps a flushed unterminated line when the run ends with it still open', async () => {
// The settlement flush pushes the residual with `open: true`; finish()
// admits it so a program that commits a partial line and returns does not