Skip to content

fix(agents): keep a changelog capture going past files the agent can't read - #359

Merged
earakely-scale merged 1 commit into
mainfrom
fix/changelog-unreadable-files
Oct 27, 2026
Merged

earakely-scale merged 1 commit into
mainfrom
fix/changelog-unreadable-files

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The claude-code, gemini and opencode agents' changelog captures pass --ignore-failed-read to GNU tar. A file the agent can't read no longer drops the whole increment. It's skipped, and the rest of the tool call's writes are captured and uploaded.

Why

claude-code and gemini capture /usr/local and /etc by default, beside the workspace and the CLI's state. Their images run as the non-root user agent. Where the agent runs as that user, as in a VM sandbox's container, tar can't read root-only files such as /etc/ssl/private and exits 2:

[changelog] tar failed seq=1 rc=2: tar: /etc/ssl/private: Cannot open: Permission denied

The post-tool hook treats exit 2 as a failed capture, so it uploaded nothing. An apply-changelog then had no increments to replay. The validator's round trip reported save: true, apply: true, roundtrip: false, and the marker file never reached the apply agent. Where the agent runs as root, as on a container sandbox, every file is readable, so the round trip passed there. That's why it failed on VMs only.

A file the agent can't read is one it couldn't have written, so skipping it loses none of the agent's changes. With the flag, tar exits 0 when the only problem is an unreadable file. A file that changed while it was read still exits 1, which the hook already accepts as a warning.

opencode captures only its workspace by default, so it didn't hit this. Its capture gets the same flag, because a caller may name other roots.

Testing

  • Unit:

    • claude-code's and gemini's new test: a root holding a directory the test user can't read. The hook still exits 0, logs captured seq=0, and uploads the new file. It's skipped as root, who reads everything, and without GNU tar, like the other changelog tests.
    • opencode's two capture tests located --listed-incremental= by its position in the tar command line. They now find it by prefix, and one of them checks that --ignore-failed-read is passed.
    • The three agents' changelog and object-transfer suites pass with GNU tar 1.35: 192 passed, 4 skipped. The two opencode tests failed until their fakes were updated.
  • End to end, in a deployment's dev stage on VM sandboxes, with the validator's own round trip (capture agent, marker write, apply-changelog onto a fresh agent, marker check):

    agent, released image capture hook increments roundtrip
    gemini 0.9.1366 as released 0 (tar failed … /etc/ssl/private) false
    gemini 0.9.1366 --ignore-failed-read added in the running container 2 true; the marker and its token are in the apply agent's /app
    claude-code 0.9.1366 as released 0 (same error) false
    claude-code 0.9.1366 --ignore-failed-read added 2 true

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 4/5

The PR appears safe to merge, with a non-blocking gap in the new Gemini test.

Fix All in CursorFindings

  1. P2 Missing writes could pass ▶
Fix with agent prompt
### Issue 1
tst/unit/agents/gemini/test_object_transfer.py:401-402
The new Gemini test writes `marker.txt` but only checks that an archive was uploaded. An archive containing metadata alone would pass, even if readable writes were lost. Check that the uploaded archive contains `marker.txt`, as the Claude Code test does.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds --ignore-failed-read to baseline and capture commands for Claude Code, Gemini, and OpenCode.

  • Changelog captures skip unreadable files and keep archiving readable changes.

earakely-scale explicitly identifies skipping unreadable files as intentional so other writes can still be captured.

Reviews (1) · Last reviewed commit: "fix(agents): keep a changelog capture go..." · Reviewed by Greptile

…t read

The claude-code and gemini captures archive /usr/local and /etc with GNU tar.
Run as a non-root user, as on a VM sandbox's container, tar can't read
/etc/ssl/private and exits 2, so every increment was dropped and an apply had
nothing to replay. --ignore-failed-read skips what the agent can't read, which
it can't have written either. opencode's capture gets the same flag.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comment on lines +401 to +402
assert "captured seq=0" in result.stderr, result.stderr
assert f"{staging.ROOT_PATH}/000000.tgz" in staging.objects

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing writes could pass

The new Gemini test writes marker.txt but only checks that an archive was uploaded. An archive containing metadata alone would pass, even if readable writes were lost. Check that the uploaded archive contains marker.txt, as the Claude Code test does.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tst/unit/agents/gemini/test_object_transfer.py
Line: 401-402

Comment:
**Missing writes could pass**

The new Gemini test writes `marker.txt` but only checks that an archive was uploaded. An archive containing metadata alone would pass, even if readable writes were lost. Check that the uploaded archive contains `marker.txt`, as the Claude Code test does.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

@earakely-scale
earakely-scale merged commit fa1529e into main Oct 27, 2026
13 of 14 checks passed
@earakely-scale
earakely-scale deleted the fix/changelog-unreadable-files branch October 27, 2026 23:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant