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:
dsh-slopo agent committed 2026-09-22 13:08:22 +01:00
1 parent 534efa8b50
commit 46124b11aa
5 files changed
+249 -9

No files matched your search

+14 -2
View File
@@ -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 })