feat(S-104): Add stderr-length and exit-code correlation diagnostics

This commit is contained in:
2026-05-19 19:51:10 -05:00
parent 106c7d6425
commit 1983dd82e7
3 changed files with 46 additions and 1 deletions
+3 -1
View File
@@ -90,15 +90,17 @@ export async function executePrompt(
clearTimeout(timeout); clearTimeout(timeout);
const durationMs = Date.now() - startMs; const durationMs = Date.now() - startMs;
if (options.debug || options.onDebug) { if (options.debug || options.onDebug) {
const effectiveExitCode = result?.exitCode ?? (err instanceof ExecError ? err.result.exitCode : null);
const debugInfo: DebugInfo = { const debugInfo: DebugInfo = {
command, command,
args, args,
pid: child.pid ?? undefined, pid: child.pid ?? undefined,
exitCode: result?.exitCode ?? (err instanceof ExecError ? err.result.exitCode : null), exitCode: effectiveExitCode,
exitSignal, exitSignal,
durationMs, durationMs,
stderrLength: stderr.length, stderrLength: stderr.length,
stdoutLength: stdout.length, stdoutLength: stdout.length,
noisySuccess: effectiveExitCode === 0 && stderr.length > 0,
}; };
options.onDebug?.(debugInfo); options.onDebug?.(debugInfo);
} }
+1
View File
@@ -24,6 +24,7 @@ export interface DebugInfo {
durationMs: number; durationMs: number;
stderrLength: number; stderrLength: number;
stdoutLength: number; stdoutLength: number;
noisySuccess: boolean;
} }
export interface DispatchConfigFile { export interface DispatchConfigFile {
@@ -320,4 +320,46 @@ describe("executePrompt", () => {
assert.strictEqual(debugInfos[0].exitCode, null); assert.strictEqual(debugInfos[0].exitCode, null);
assert.strictEqual(debugInfos[0].exitSignal, null); assert.strictEqual(debugInfos[0].exitSignal, null);
}); });
it("reports noisySuccess=true when stderr is non-empty and exitCode is 0", async () => {
const scenarios = new Map<string, MockScenario>([
["codex exec --yolo hello", { stdout: "ok", stderr: "warn", exitCode: 0 }],
]);
const debugInfos: any[] = [];
await executePrompt("codex", "hello", {
spawn: mockSpawn(scenarios),
existsSync: () => true,
debug: true,
onDebug: (info) => debugInfos.push(info),
});
assert.strictEqual(debugInfos[0].noisySuccess, true);
});
it("reports noisySuccess=false when stderr is empty and exitCode is 0", async () => {
const scenarios = new Map<string, MockScenario>([
["codex exec --yolo hello", { stdout: "ok", stderr: "", exitCode: 0 }],
]);
const debugInfos: any[] = [];
await executePrompt("codex", "hello", {
spawn: mockSpawn(scenarios),
existsSync: () => true,
debug: true,
onDebug: (info) => debugInfos.push(info),
});
assert.strictEqual(debugInfos[0].noisySuccess, false);
});
it("reports noisySuccess=false when exitCode is non-zero even if stderr is non-empty", async () => {
const scenarios = new Map<string, MockScenario>([
["codex exec --yolo fail", { stdout: "", stderr: "error", exitCode: 1 }],
]);
const debugInfos: any[] = [];
await executePrompt("codex", "fail", {
spawn: mockSpawn(scenarios),
existsSync: () => true,
debug: true,
onDebug: (info) => debugInfos.push(info),
});
assert.strictEqual(debugInfos[0].noisySuccess, false);
});
}); });