fix: fail loud when a write task lands zero workspace writes#532
fix: fail loud when a write task lands zero workspace writes#532hopp2it wants to merge 1 commit into
Conversation
A task dispatched with --write can complete with zero workspace writes (e.g. the Windows sandbox denies every write path) while the job still reports status "completed" - the loss is only visible in the model's prose. Detect it mechanically: capture a working-tree fingerprint (status + diffs + untracked stats) before the turn, and when a write task ends with no apply_patch changes and an unchanged fingerprint, mark the job failed with result.degraded = "zero-writes" and prepend a DEGRADED banner to the rendered output. The fingerprint is content-aware so shell-only writes (PowerShell fallbacks) and edits to already-dirty files are not false-positived; non-git workspaces skip detection entirely. Co-Authored-By: SYNTAX AI v6.8.0 (using Claude Fable 5) <syntax@qntxlabs.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8c6406b532
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| rendered = | ||
| "DEGRADED: this write task landed zero workspace writes.\n" + | ||
| "No apply_patch changes were recorded and the working tree is unchanged. " + | ||
| "Treat the task as failed and check the job log before assuming any edits exist.\n\n" + | ||
| rendered; |
There was a problem hiding this comment.
Preserve degraded warnings in stored results
For degraded write tasks that finish in the background, the follow-up path is usually /codex:result; however renderStoredJobResult() prefers storedJob.result.rawOutput over storedJob.rendered, so adding the warning only to rendered means that command prints the model's original success-sounding final response with no zero-write banner even though the job is marked failed. This makes the new "fail loud" behavior disappear outside the initial foreground output.
Useful? React with 👍 / 👎.
Fixes #531.
Detect write-mode task jobs that land zero workspace writes and fail them loud instead of reporting
completed.Problem: when a
task --writedispatch fails to land any writes (e.g. the Windows sandbox deniesapply_patchand all fallback writes — openai/codex #30712/#31220/#32314), the job still recordsstatus: "completed"withtouchedFiles: []; the loss is only visible in the model's prose.Approach: capture a content-aware working-tree fingerprint (git status + staged/unstaged diffs + untracked file size/mtime) before the turn. When a write task ends with no
apply_patchfile changes and an unchanged fingerprint, mark the job failed withresult.degraded: "zero-writes", prepend a DEGRADED banner to the rendered output, and exit non-zero.False-positive safety:
touchedFilesonly tracksapply_patchevents, so the fingerprint is what covers shell-based writes (the common Windows fallback) and edits to files that were already dirty before the task — both have dedicated tests. Non-git workspaces skip detection entirely rather than guess.Tests: 6 new tests in
tests/write-task-degraded.test.mjs(zero-write → failed/degraded; apply_patch write, shell-only write, already-dirty-file edit, read-only task, non-git workspace → unchanged behavior). Three existing tests that used a--writetask with a fixture that never writes now use a fixture behavior that writes into the workspace, preserving their original assertions. Full suite failure set is identical to unmodifiedmainin my environment.🤖 Generated with SYNTAX AI v6.8.0 (using Claude Fable 5) — QNTx Labs