Summary
`RemoteWorkspaceBackend::build_full_file_diff()` in `inc/Workspace/RemoteWorkspaceBackend.php` (lines 663-679) is not a unified diff. It dumps the entire old content as `-` lines and the entire new content as `+` lines, regardless of how small the actual change is.
```php
private function build_full_file_diff( string $path, string $old_content, string $new_content ): string {
$old_lines = $this->diff_lines( $old_content );
$new_lines = $this->diff_lines( $new_content );
\$diff = 'diff --git a/' . \$path . ' b/' . \$path . \"\n\";
\$diff .= '--- a/' . \$path . \"\n\";
\$diff .= '+++ b/' . \$path . \"\n\";
\$diff .= sprintf( '@@ -1,%d +1,%d @@', count( \$old_lines ), count( \$new_lines ) ) . \"\n\";
foreach ( \$old_lines as \$line ) {
\$diff .= '-' . \$line . \"\n\";
}
foreach ( \$new_lines as \$line ) {
\$diff .= '+' . \$line . \"\n\";
}
return \$diff;
}
```
Impact: agents misread their own edits
`workspace_edit` correctly applies a surgical `substr_replace` against the file content. But when the agent then calls `workspace_git_diff` to verify, it sees the entire 250-line file marked for removal and re-addition. This looks like "my edit nuked the file" or "the file has line-ending weather," even though the actual write to GitHub is correct.
Real example from world-of-wordpress agent run 26050485830:
- Agent edits a single `
` heading on `content/page/world-observatory.md` (one-line change).
- `workspace_edit` returns `replacements: 1` — fine.
- `workspace_git_diff` returns `@@ -1,250 +1,278 @@` followed by every line of the file removed then re-added.
- Agent concludes "the edit produced whole-file line-ending weather" and reverts the change to avoid committing a noisy rewrite.
The agent has now hit this pattern three cycles in a row on the same Observatory page (PR #343, PR #345, and an earlier cycle), each time exercising the restraint verb the prompt menu provides. The restraint is correct given what the agent sees, but it's based on a phantom diff.
Why "line-ending weather" is a phantom
`diff_lines()` does `explode("\n", rtrim($content, "\n"))`. The actual content stored in `pending_files` after `edit_file` is byte-identical to what came out of `read_file` except for the `substr_replace` window. The fake diff format hides that — the agent has no way to see what actually changed.
Fix sketch
Replace the whole-file dump with a real unified diff. Options:
- PHP-side unified diff — use `xdiff_string_diff()` if available, else `league/uri`-style minimal-myers-diff in PHP. ~50-100 line implementation, no new dependencies if we accept basic Myers diff.
- Shell out to git — DMC already coordinates GitHub-backed worktrees; we could write the old + new content to temp files and call `git diff --no-index --unified=3 old new`. Cleaner output, but requires git on the WP host.
- Use `sebastian/diff` library — small composer dep, produces real unified diffs, well-tested.
Option 1 or 3 is preferable on `intelligence-chubes4`-style hosts where shelling to git is sketchy.
Workaround for agents in the meantime
Until this is fixed, prompts that rely on `workspace_git_diff` verification should either (a) skip the diff step on edits and trust `workspace_edit`'s `replacements: 1` return, or (b) treat the diff output as advisory only and not as evidence the edit failed. The bundle's prompt for `world-creator` will be widened to mention this.
Related
AI assistance
Diagnosed by Claude Code (Sonnet 4.5) from the world-creator agent's transcript and DMC source, after the agent's daily memory described "line-ending weather" three cycles in a row. The diff function source was the smoking gun.
Summary
`RemoteWorkspaceBackend::build_full_file_diff()` in `inc/Workspace/RemoteWorkspaceBackend.php` (lines 663-679) is not a unified diff. It dumps the entire old content as `-` lines and the entire new content as `+` lines, regardless of how small the actual change is.
```php
private function build_full_file_diff( string $path, string $old_content, string $new_content ): string {
$old_lines = $this->diff_lines( $old_content );
$new_lines = $this->diff_lines( $new_content );
}
```
Impact: agents misread their own edits
`workspace_edit` correctly applies a surgical `substr_replace` against the file content. But when the agent then calls `workspace_git_diff` to verify, it sees the entire 250-line file marked for removal and re-addition. This looks like "my edit nuked the file" or "the file has line-ending weather," even though the actual write to GitHub is correct.
Real example from world-of-wordpress agent run 26050485830:
` heading on `content/page/world-observatory.md` (one-line change).
The agent has now hit this pattern three cycles in a row on the same Observatory page (PR #343, PR #345, and an earlier cycle), each time exercising the restraint verb the prompt menu provides. The restraint is correct given what the agent sees, but it's based on a phantom diff.
Why "line-ending weather" is a phantom
`diff_lines()` does `explode("\n", rtrim($content, "\n"))`. The actual content stored in `pending_files` after `edit_file` is byte-identical to what came out of `read_file` except for the `substr_replace` window. The fake diff format hides that — the agent has no way to see what actually changed.
Fix sketch
Replace the whole-file dump with a real unified diff. Options:
Option 1 or 3 is preferable on `intelligence-chubes4`-style hosts where shelling to git is sketchy.
Workaround for agents in the meantime
Until this is fixed, prompts that rely on `workspace_git_diff` verification should either (a) skip the diff step on edits and trust `workspace_edit`'s `replacements: 1` return, or (b) treat the diff output as advisory only and not as evidence the edit failed. The bundle's prompt for `world-creator` will be widened to mention this.
Related
AI assistance
Diagnosed by Claude Code (Sonnet 4.5) from the world-creator agent's transcript and DMC source, after the agent's daily memory described "line-ending weather" three cycles in a row. The diff function source was the smoking gun.