fix(#571): forbid Write in doc-writer fix mode; add workflow truncation guard

* fix(#571): forbid Write in doc-writer fix mode; add workflow truncation guard

gsd-doc-writer in fix mode only had Write in its tools list, so when
correcting a specific failing claim it would re-emit the whole file with
only the lines it had in context — truncating untracked docs with no git
recovery path.

Fix 1 (root cause): add Edit to the agent tools frontmatter and rewrite
fix_mode instructions to mandate Edit for surgical corrections and
explicitly forbid Write on existing files. Also reinforced in
critical_rules.

Fix 2 (safety net): add a post-fix line-count guard in the fix_loop step
of docs-update.md. If the file shrank by >90% after a fix agent runs,
the orchestrator restores the file from the existing_content it captured
before dispatch and logs a WARNING. This makes the previously
unrecoverable case recoverable.

Regression test: tests/bug-571-doc-writer-fix-mode-edit-only.test.cjs
covers both the agent contract and the workflow guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add changeset for fix #571

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(#571): address codex adversarial review findings

- Quote {doc_path} in shell snippets to handle paths with spaces (#SECURITY)
- Clarify corrupted doc re-verification vs re-fix distinction (#CORRECTNESS)
- Strengthen regression tests with structural ordering assertions (#REGRESSION)
- Move docs-update.md from global ALLOWLIST to SIZE_ONLY_WORKFLOWS so
  injection scanning still runs while only the 50K size finding is exempt (#SECURITY)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-01 09:44:58 -04:00
committed by GitHub
parent 2ba6b69d53
commit c2ebb1ba16
5 changed files with 242 additions and 9 deletions

View File

@@ -902,7 +902,10 @@ Correct flagged inaccuracies by re-sending failing docs to the doc-writer in fix
**For each iteration (while iteration < MAX_FIX_ITERATIONS and there are docs with failures):**
1. For each doc with `claims_failed > 0` in the latest verification_results:
a. Read the current file content from disk.
a. Read the current file content from disk. Record the pre-fix line count:
```bash
PRE_FIX_LINES=$(wc -l < "{doc_path}" 2>/dev/null || echo 0)
```
b. Spawn `gsd-doc-writer` agent (or invoke sequentially) with a fix assignment:
```xml
<doc_assignment>
@@ -919,6 +922,15 @@ Correct flagged inaccuracies by re-sending failing docs to the doc-writer in fix
</doc_assignment>
```
c. One agent spawn per doc with failures. Do not batch multiple docs into one spawn.
d. **Post-fix truncation guard:** After the fix agent completes, check for file corruption:
```bash
POST_FIX_LINES=$(wc -l < "{doc_path}" 2>/dev/null || echo 0)
```
If `POST_FIX_LINES` is less than 10% of `PRE_FIX_LINES` (i.e. the file shrank by more than 90%), the fix agent corrupted the file via a full-file Write. Restore it immediately:
- Write the `existing_content` captured in step 1a back to `"{doc_path}"` using the Write tool
- Log: `WARNING: Fix agent corrupted {doc_path} ({POST_FIX_LINES} lines after fix, was {PRE_FIX_LINES}). Restored from pre-fix content. Failures for this doc require manual correction.`
- Mark this doc as `"fix-corrupted"` in the manifest; it will appear in remaining failures at the end
- Do NOT attempt to fix this doc again this iteration. It is still included in the step 2 re-verification (so its failures are counted) but no further fix agent will be dispatched for it in this iteration.
2. After all fix agents complete, re-verify ALL docs (not just the ones that were fixed):
- Re-run the same verification process as verify_docs step.