mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-30 04:40:37 +00:00
fix(code-runtime-python): make checkDoneValue over-budget precedence order-independent
checkDoneValue returned non-lossless the instant it hit a non-finite/negative- zero number, before finishing the budget metering. A value that is BOTH over- budget and non-lossless then classified by member order: `["<huge>", 1e400]` gave non-lossless while `[1e400, "<huge>"]` gave over-budget — the same value, two verdicts — which would drive the consumer to emit invalid-output vs output-limit non-deterministically, contradicting the JSDoc promise that an over-budget value is rejected as over-budget regardless. Record the number violation in a flag and let metering finish; return non-lossless only once the whole value is confirmed within budget. Add a regression test asserting both member orders classify as over-budget.
This commit is contained in:
@@ -217,12 +217,19 @@ function scalarJson(current: unknown): string {
|
||||
*/
|
||||
export function checkDoneValue(value: unknown, maxBytes: number): { ok: true; bytes: number } | { ok: false; reason: 'over-budget' | 'non-lossless' } {
|
||||
let bytes = 0
|
||||
// A non-lossless number is recorded, not returned on sight: over-budget must
|
||||
// win regardless of where in the value each violation sits, so the whole
|
||||
// metering finishes first. Otherwise `["<huge>", 1e400]` and `[1e400,
|
||||
// "<huge>"]` — the same over-budget value in two member orders — would
|
||||
// classify differently (non-lossless vs over-budget), and the JSDoc promises
|
||||
// an over-budget value is rejected as over-budget regardless.
|
||||
let nonLossless = false
|
||||
const stack: unknown[] = [value]
|
||||
while (stack.length > 0) {
|
||||
const current = stack.pop()
|
||||
if (typeof current === 'number') {
|
||||
if (!Number.isFinite(current) || Object.is(current, -0)) return { ok: false, reason: 'non-lossless' }
|
||||
bytes += Buffer.byteLength(scalarJson(current), 'utf8')
|
||||
if (!Number.isFinite(current) || Object.is(current, -0)) nonLossless = true
|
||||
else bytes += Buffer.byteLength(scalarJson(current), 'utf8')
|
||||
} else if (typeof current === 'string') {
|
||||
// Lower-bound BEFORE materializing the escaped form: every UTF-16 code
|
||||
// unit is at least one UTF-8 byte plus the two quotes, so a huge or
|
||||
@@ -262,6 +269,8 @@ export function checkDoneValue(value: unknown, maxBytes: number): { ok: true; by
|
||||
}
|
||||
if (bytes > maxBytes) return { ok: false, reason: 'over-budget' }
|
||||
}
|
||||
// The whole value fit the budget; a recorded number violation is the verdict.
|
||||
if (nonLossless) return { ok: false, reason: 'non-lossless' }
|
||||
return { ok: true, bytes }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user