Fix: status could not be serialised when the probe SUCCEEDED
The probe returned `error: undefined` on a dimension match. `undefined` is not a JSON value -- JSON.stringify silently drops it from an object -- so the shape looked harmless and was not: the harness enforces the declared output schema against the canonical value before materialising it, and an explicit undefined property fails that check. A perfectly healthy status call could not be returned at all. Fixed at the boundary rather than at each site. Every return now funnels through `toJsonValue`, which drops undefined properties exactly as JSON.stringify would, maps non-finite numbers to null (same reasoning: JSON.stringify(NaN) is "null"), turns an undefined array slot into null rather than shifting indices, and refuses a circular value instead of recursing forever. `update` was carrying `errorCode: undefined` and `ensureSlopo` a `detail: undefined` on the same path, so a per-site fix would have left two more of these waiting. The probe also now omits `error` rather than assigning undefined, since it is a plausible thing for another consumer to read. Four regression tests, and they were checked against a negative control: with the sanitiser reverted and the undefined restored, exactly the "probe SUCCEEDS" test fails with "does not survive a JSON round trip" and the others still pass, which is what makes it a test of this bug rather than of the JSON round trip in general.
This commit is contained in:
1 parent
534efa8b50
commit
46124b11aa
5 files changed
+249
-9
No files matched your search
@@ -34,6 +34,7 @@ import Schema from '@deepseek-ai/schemastery'
|
||||
|
||||
import { missingRequired, normalizeConfig, renderSlopoConfig } from './lib/config.js'
|
||||
import { probeEmbeddingEndpoint } from './lib/probe.js'
|
||||
import { toJsonValue } from './lib/json.js'
|
||||
import {
|
||||
resolveDshHome,
|
||||
workspaceStateDir,
|
||||
@@ -431,7 +432,18 @@ export function apply(ctx, config) {
|
||||
exec.agent === undefined ? {} : { session: exec.agent.session },
|
||||
)
|
||||
|
||||
const foreground = (value) => ({ kind: 'foreground', action: args.action, configPath: paths.configPath, logPath: paths.logFile, ...value })
|
||||
// Every return funnels through here. The harness enforces the declared
|
||||
// output schema against this value BEFORE materialising it, and an
|
||||
// explicit `undefined` property is not lossless JSON — which is exactly
|
||||
// how a probe result carrying `error: undefined` broke the status call.
|
||||
const foreground = (value) =>
|
||||
toJsonValue({
|
||||
kind: 'foreground',
|
||||
action: args.action,
|
||||
configPath: paths.configPath,
|
||||
logPath: paths.logFile,
|
||||
...value,
|
||||
})
|
||||
|
||||
if (args.action === 'status') {
|
||||
const binary = findSlopo(dshHome)
|
||||
@@ -698,7 +710,7 @@ export function apply(ctx, config) {
|
||||
return { cancel: () => controller.abort(), done }
|
||||
},
|
||||
})
|
||||
return { kind: 'background', action: args.action, jobId, logPath: paths.logFile, configPath: paths.configPath }
|
||||
return toJsonValue({ kind: 'background', action: args.action, jobId, logPath: paths.logFile, configPath: paths.configPath })
|
||||
}
|
||||
|
||||
const result = await run(command, { env, signal: exec.signal })
|
||||
|
||||
Reference in new issue
Block a user