docs(code-runtime-python): register the host-side open seal; note the empty-first-frame billing

The review's follow-ups on the open-seal fix: (1) the settlement note's seal
section now records the HOST-side open hold seal (openParts -> openSealed,
mirroring the child _LogStream and stray-capture seals), paired. (2) the
first-fragment guard comment notes the empty-first-frame case (bills cost + 1 =
3, establishes no hold, bounded over-charge in the safe direction). (3) a
regression case commits a SEALED open hold before the truncation marker —
verified to fail if truncateLogs drops openSealed.
This commit is contained in:
Chinesezjc
2026-08-31 15:06:50 +08:00
committed by Tianyi Cui
parent bca392e6d1
commit 74e9d97e37
5 changed files with 36 additions and 4 deletions
@@ -1567,6 +1567,13 @@ export class PythonCodeRuntime extends CodeRuntime {
// billed cost cost - 2 fits exactly when the walk's cost is at
// most logBudget + 2).
if (!logsTruncated) {
// An EMPTY first open frame (openParts empty AND text '') bills
// cost + 1 = 3 but establishes no hold (the push is skipped),
// so the next frame is billed as a new first fragment. Not
// reachable from an honest child (_LogStream.write('') returns
// early; flush_line pushes only non-empty pending); for a
// forged frame it is a bounded over-charge in the safe
// direction (a flood exhausts the ledger into truncation).
const cap = openParts.length === 0 ? logBudget - 1 : logBudget + 2
const cost = jsonStringCostUpTo(message.text, cap)
if (cost === undefined) {
@@ -1968,6 +1968,31 @@ describe('PythonCodeRuntime — programs and bindings', () => {
expect(result.logs).toEqual(['a'.repeat(60), logTruncationMarker(64)])
}, 15_000)
it('commits a sealed open hold before the truncation marker', async () => {
// The sealed variant of the prefix-commit case: an open flood past
// MAX_PENDING_CHUNKS lands in openSealed, then an over-budget line
// truncates — truncateLogs must commit the SEALED prefix (not only the
// current fragments) before the marker.
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')",
// 3000 single-character open continuations seal the hold, then a
// forged over-budget open frame trips the ledger: truncateLogs must
// commit the SEALED prefix before the marker.
'for _ in range(3000):',
" os.write(3, b'{\"type\":\"log\",\"text\":\"a\",\"open\":true}\\n')",
"os.write(3, ('{\"type\":\"log\",\"text\":\"' + 'z' * 70000 + '\",\"open\":true}\\n').encode())",
'return "done"',
].join('\n'),
bindings: [],
})
expect(result.error).toBeUndefined()
expect(result.logs[0]).toBe('x' + 'a'.repeat(3000))
expect(result.logs[result.logs.length - 1]).toBe(logTruncationMarker(65536))
}, 15_000)
it('commits a flushed open prefix before the truncation marker', async () => {
// A flushed unterminated line is billed and committed; when a later
// over-budget write truncates, the committed prefix must appear BEFORE the