Merge pull request #1709 from behruznassre/fix/1698-codex-output-last-message
fix(#1698): capture codex review via --output-last-message, not stdout
This commit is contained in:
5
.changeset/daring-badgers-forage.md
Normal file
5
.changeset/daring-badgers-forage.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 1709
|
||||
---
|
||||
Codex reviewer now captures the review via codex's --output-last-message flag instead of redirecting stdout, so Windows process-teardown output no longer pollutes the review file and slips past the empty-output guard.
|
||||
@@ -277,10 +277,15 @@ fi
|
||||
# $CODEX_BYPASS_FLAG is capability-gated above (#1115). Capture stderr to a .err
|
||||
# file (not /dev/null) so a non-zero exit — e.g. a flag the installed codex-cli
|
||||
# does not support — is diagnosable instead of a silent empty review.
|
||||
# Capture the review via codex's own `-o/--output-last-message <FILE>` (only the
|
||||
# final agent message) and discard stdout (#1698): on some platforms (Windows)
|
||||
# codex writes process-teardown output to stdout *after* the final message, and a
|
||||
# stdout redirect would append that noise to a non-empty file — slipping past the
|
||||
# `[ ! -s … ]` empty-output guard as a silently polluted review.
|
||||
if [ -n "$CODEX_MODEL" ] && [ "$CODEX_MODEL" != "null" ]; then
|
||||
cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --model "$CODEX_MODEL" --skip-git-repo-check - 2>/tmp/gsd-review-codex-{phase}.err > /tmp/gsd-review-codex-{phase}.md
|
||||
cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --model "$CODEX_MODEL" --skip-git-repo-check -o /tmp/gsd-review-codex-{phase}.md - 2>/tmp/gsd-review-codex-{phase}.err >/dev/null
|
||||
else
|
||||
cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --skip-git-repo-check - 2>/tmp/gsd-review-codex-{phase}.err > /tmp/gsd-review-codex-{phase}.md
|
||||
cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --skip-git-repo-check -o /tmp/gsd-review-codex-{phase}.md - 2>/tmp/gsd-review-codex-{phase}.err >/dev/null
|
||||
fi
|
||||
if [ ! -s /tmp/gsd-review-codex-{phase}.md ]; then
|
||||
echo "Codex review failed or returned empty output. stderr:" > /tmp/gsd-review-codex-{phase}.md
|
||||
|
||||
@@ -99,3 +99,42 @@ describe('enh-773: automated codex exec invocations include --ephemeral and --da
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('#1698 regression: codex review is captured via --output-last-message, not stdout', () => {
|
||||
// WHY: on some platforms (Windows) `codex exec` writes process-teardown output
|
||||
// to stdout *after* the final agent message. A `> FILE` stdout redirect appends
|
||||
// that noise to a non-empty file, so it slips past the `[ ! -s … ]` empty-output
|
||||
// guard and downstream consumers (severity extraction, the
|
||||
// plan-review-convergence "concerns resolved?" gate) parse a polluted review.
|
||||
// `-o/--output-last-message <FILE>` writes only the final message — robust on
|
||||
// every platform — so each codex invocation must capture via -o and discard stdout.
|
||||
const workflow = fs.readFileSync(
|
||||
path.join(process.cwd(), 'gsd-core', 'workflows', 'review.md'),
|
||||
'utf8'
|
||||
);
|
||||
const codexExecLines = workflow
|
||||
.split(/\r?\n/)
|
||||
.filter((line) => line.includes('codex exec') && !line.includes('codex exec --help'));
|
||||
|
||||
test('every codex exec invocation captures the review via -o <FILE>', () => {
|
||||
for (const line of codexExecLines) {
|
||||
assert.ok(
|
||||
/\s-o\s+\/tmp\/gsd-review-codex-\{phase\}\.md\b/.test(line),
|
||||
`codex exec invocation must capture the review via -o /tmp/gsd-review-codex-{phase}.md:\n ${line.trim()}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('no codex exec invocation redirects stdout into the review file', () => {
|
||||
for (const line of codexExecLines) {
|
||||
assert.ok(
|
||||
!/>\s*\/tmp\/gsd-review-codex-\{phase\}\.md\b/.test(line),
|
||||
`codex exec must not redirect stdout into the review file (teardown noise pollutes it); use -o + >/dev/null:\n ${line.trim()}`
|
||||
);
|
||||
assert.ok(
|
||||
/>\s*\/dev\/null\b/.test(line),
|
||||
`codex exec must discard stdout to /dev/null so teardown output is not captured:\n ${line.trim()}`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "6b9947fba1a97f46",
|
||||
"gsd-core/workflows/remove-workspace.md": "95f05defffe6754e",
|
||||
"gsd-core/workflows/resume-project.md": "cadf390bae95fc76",
|
||||
"gsd-core/workflows/review.md": "4d1ea3f9785044b3",
|
||||
"gsd-core/workflows/review.md": "aa08449a6a180944",
|
||||
"gsd-core/workflows/scan.md": "f2754f3e3ea528ff",
|
||||
"gsd-core/workflows/secure-phase.md": "78705b7f09612464",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "d030f80ca0df4fa9",
|
||||
"gsd-core/workflows/remove-workspace.md": "b8817a3a5907f5bc",
|
||||
"gsd-core/workflows/resume-project.md": "b18b51fd15cbce95",
|
||||
"gsd-core/workflows/review.md": "fc23a807c6c3d6d9",
|
||||
"gsd-core/workflows/review.md": "fbfa6eebcad41aa0",
|
||||
"gsd-core/workflows/scan.md": "54ff1ff60041d065",
|
||||
"gsd-core/workflows/secure-phase.md": "1d1c66ad9ea01bd2",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -273,7 +273,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "f76e1c2a4dd31a09",
|
||||
"gsd-core/workflows/remove-workspace.md": "0e73844f0f41cbc3",
|
||||
"gsd-core/workflows/resume-project.md": "3dcaa7abe1800d35",
|
||||
"gsd-core/workflows/review.md": "1660ff860e79f9b7",
|
||||
"gsd-core/workflows/review.md": "a1d3ebce6222ff72",
|
||||
"gsd-core/workflows/scan.md": "8e1bbf2eed1752ca",
|
||||
"gsd-core/workflows/secure-phase.md": "b2b9100ff79d6017",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -277,7 +277,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "61b68a4af414e3c2",
|
||||
"gsd-core/workflows/remove-workspace.md": "411bfff942216185",
|
||||
"gsd-core/workflows/resume-project.md": "f8f71b5a98374b85",
|
||||
"gsd-core/workflows/review.md": "a74ae666e01ceebb",
|
||||
"gsd-core/workflows/review.md": "f7d5b0f64631adea",
|
||||
"gsd-core/workflows/scan.md": "db0c48c3963f9a8b",
|
||||
"gsd-core/workflows/secure-phase.md": "c51b86e369574195",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "d030f80ca0df4fa9",
|
||||
"gsd-core/workflows/remove-workspace.md": "b8817a3a5907f5bc",
|
||||
"gsd-core/workflows/resume-project.md": "b18b51fd15cbce95",
|
||||
"gsd-core/workflows/review.md": "fc23a807c6c3d6d9",
|
||||
"gsd-core/workflows/review.md": "fbfa6eebcad41aa0",
|
||||
"gsd-core/workflows/scan.md": "54ff1ff60041d065",
|
||||
"gsd-core/workflows/secure-phase.md": "1d1c66ad9ea01bd2",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -309,7 +309,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "75c8ca0dbd1ce404",
|
||||
"gsd-core/workflows/remove-workspace.md": "a9d1dcda7755b6c9",
|
||||
"gsd-core/workflows/resume-project.md": "94ac2cac4c562557",
|
||||
"gsd-core/workflows/review.md": "014d2f4d7c892e58",
|
||||
"gsd-core/workflows/review.md": "bd3873bea54d6143",
|
||||
"gsd-core/workflows/scan.md": "29f3b65f5d9de885",
|
||||
"gsd-core/workflows/secure-phase.md": "858b5e1152b569ed",
|
||||
"gsd-core/workflows/session-report.md": "dd8fa011c9394075",
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "e94ddfe4eabc0e08",
|
||||
"gsd-core/workflows/remove-workspace.md": "f28be7f32249f0d4",
|
||||
"gsd-core/workflows/resume-project.md": "4ebcb4acd3c29302",
|
||||
"gsd-core/workflows/review.md": "7c04ed635c7e1c56",
|
||||
"gsd-core/workflows/review.md": "60b8ca1c543ccdfa",
|
||||
"gsd-core/workflows/scan.md": "28a2847b8d04156e",
|
||||
"gsd-core/workflows/secure-phase.md": "bae509fa254fe435",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "f76e1c2a4dd31a09",
|
||||
"gsd-core/workflows/remove-workspace.md": "dadbb14d9033ea3f",
|
||||
"gsd-core/workflows/resume-project.md": "3dcaa7abe1800d35",
|
||||
"gsd-core/workflows/review.md": "28d673b6267b12c2",
|
||||
"gsd-core/workflows/review.md": "141589a39b8c7e18",
|
||||
"gsd-core/workflows/scan.md": "8e1bbf2eed1752ca",
|
||||
"gsd-core/workflows/secure-phase.md": "7bd4c335484fd121",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "d030f80ca0df4fa9",
|
||||
"gsd-core/workflows/remove-workspace.md": "9f5589b4b3a0639a",
|
||||
"gsd-core/workflows/resume-project.md": "b18b51fd15cbce95",
|
||||
"gsd-core/workflows/review.md": "fc23a807c6c3d6d9",
|
||||
"gsd-core/workflows/review.md": "fbfa6eebcad41aa0",
|
||||
"gsd-core/workflows/scan.md": "54ff1ff60041d065",
|
||||
"gsd-core/workflows/secure-phase.md": "a2f6a03034444f14",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "f27cecd8c78008ae",
|
||||
"gsd-core/workflows/remove-workspace.md": "977155e18b9df623",
|
||||
"gsd-core/workflows/resume-project.md": "849f3d49d366ff13",
|
||||
"gsd-core/workflows/review.md": "d6c1c729a2627b2b",
|
||||
"gsd-core/workflows/review.md": "06cd9992e289b241",
|
||||
"gsd-core/workflows/scan.md": "cbde2b8b2b5fa5dd",
|
||||
"gsd-core/workflows/secure-phase.md": "5fc8fbd5e217e48d",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "f76e1c2a4dd31a09",
|
||||
"gsd-core/workflows/remove-workspace.md": "7bd5d1b63ef091a8",
|
||||
"gsd-core/workflows/resume-project.md": "3dcaa7abe1800d35",
|
||||
"gsd-core/workflows/review.md": "50e945dade0a5a67",
|
||||
"gsd-core/workflows/review.md": "9ed1fda4d8b657f1",
|
||||
"gsd-core/workflows/scan.md": "8e1bbf2eed1752ca",
|
||||
"gsd-core/workflows/secure-phase.md": "87fdcb37a8610e58",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -310,7 +310,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "d030f80ca0df4fa9",
|
||||
"gsd-core/workflows/remove-workspace.md": "b8817a3a5907f5bc",
|
||||
"gsd-core/workflows/resume-project.md": "b18b51fd15cbce95",
|
||||
"gsd-core/workflows/review.md": "fc23a807c6c3d6d9",
|
||||
"gsd-core/workflows/review.md": "fbfa6eebcad41aa0",
|
||||
"gsd-core/workflows/scan.md": "54ff1ff60041d065",
|
||||
"gsd-core/workflows/secure-phase.md": "1d1c66ad9ea01bd2",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "863c58e99e9d630d",
|
||||
"gsd-core/workflows/remove-workspace.md": "4ed03c52e5c7bd4d",
|
||||
"gsd-core/workflows/resume-project.md": "15153ce5a4c38674",
|
||||
"gsd-core/workflows/review.md": "544103be3247bbd1",
|
||||
"gsd-core/workflows/review.md": "4076abd5ff01195d",
|
||||
"gsd-core/workflows/scan.md": "4634caefa32a7307",
|
||||
"gsd-core/workflows/secure-phase.md": "9616682fe23cf042",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "17c46fdcef27df2d",
|
||||
"gsd-core/workflows/remove-workspace.md": "1d34788a9b2272d2",
|
||||
"gsd-core/workflows/resume-project.md": "bba3250afbea8f09",
|
||||
"gsd-core/workflows/review.md": "926f2f15676a21cc",
|
||||
"gsd-core/workflows/review.md": "8ed9a9e7d150978d",
|
||||
"gsd-core/workflows/scan.md": "514d3eba81565193",
|
||||
"gsd-core/workflows/secure-phase.md": "a7e8edb0e5f48256",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "5a2521695edd486b",
|
||||
"gsd-core/workflows/remove-workspace.md": "ed8e5e30c33f1bfd",
|
||||
"gsd-core/workflows/resume-project.md": "ee9dcc4e3dd3e32c",
|
||||
"gsd-core/workflows/review.md": "6529c2ee9b33f1fc",
|
||||
"gsd-core/workflows/review.md": "a2dab55fa3acfca0",
|
||||
"gsd-core/workflows/scan.md": "afc48f3339293b30",
|
||||
"gsd-core/workflows/secure-phase.md": "882886f04d3b7e82",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
"gsd-core/workflows/remove-phase.md": "24559d23e008c9c3",
|
||||
"gsd-core/workflows/remove-workspace.md": "e958c1e932aef492",
|
||||
"gsd-core/workflows/resume-project.md": "c5731b8aabed70f9",
|
||||
"gsd-core/workflows/review.md": "21152d6ce0c4efa8",
|
||||
"gsd-core/workflows/review.md": "dc8366ef168183db",
|
||||
"gsd-core/workflows/scan.md": "8aa95448b1ba4a4a",
|
||||
"gsd-core/workflows/secure-phase.md": "550152cd82c25c00",
|
||||
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
"remove-phase.md": 8469,
|
||||
"remove-workspace.md": 7507,
|
||||
"resume-project.md": 17226,
|
||||
"review.md": 40539,
|
||||
"review.md": 40956,
|
||||
"scan.md": 7688,
|
||||
"secure-phase.md": 13476,
|
||||
"session-report.md": 4044,
|
||||
|
||||
Reference in New Issue
Block a user