fix: prevent corruption when agent files share a target - #723
Open
Davide Leopardi (Hexecu) wants to merge 1 commit into
Open
fix: prevent corruption when agent files share a target#723Davide Leopardi (Hexecu) wants to merge 1 commit into
Davide Leopardi (Hexecu) wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 1f5d9f5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #719.
Reported by Neils Christoffersen (@NeilsC) in #719.
Context
PR #547 made code-mode setup prepare both agent files before writing either one,
so malformed markers cannot partially refresh the other file. PR #640 then
intentionally gave
AGENTS.mdthe full instructions andCLAUDE.mda shortpointer to them.
Those two guarantees conflict when both paths refer to the same physical file.
The setup prepared different contents from the same initial state, then raced
two
writeFilecalls against one target. Depending on filesystem timing, thefirst run could silently leave a mixed managed block and a later run would
reject the duplicated markers.
What changed
This follows relative symlinks and symlink chains, handles dangling symlinks,
and uses device/inode identity for hard links.
AGENTS.mdremains first in theexisting ordered list, so a shared target receives the canonical full snippet
instead of the
CLAUDE.mdpointer.keep malformed shared targets byte-for-byte unchanged.
This does not change either generated snippet or the behavior of repositories
where
AGENTS.mdandCLAUDE.mdare distinct files.Regression coverage
The focused tests use real temporary files rather than mocking
fs. They runsetup twice and cover:
CLAUDE.md -> AGENTS.md, including preservation of surrounding user contentand the symlink itself;
CLAUDE.md -> AGENTS.mdbeforeAGENTS.mdexists;all-validate-before-write cases.
The primary symlink regression test fails against the current
mainbaseline(
27d835c) on the second setup attempt because the first attempt leavesmalformed or duplicated markers. It passes after this change.
I also ran the compiled implementation against the local filesystem through 50
fresh repositories per topology, before and after the fix:
mainAGENTS.mdAGENTS.mdAGENTS.md -> CLAUDE.md)For every stable alias case, both paths had identical content, the link was
preserved, the full
AGENTS.mdsnippet won, and exactly one start/end markerpair remained.
Related work
preserves it for every distinct physical target.
change preserves that behavior for distinct files and gives a shared target
the canonical full snippet.
does not change agent-file writes. I verified this patch applies cleanly to
its current head (
8e60470) with no changeset collision.Test results
pnpm exec vitest run test/ingestion/code-mode.test.tson Node 22.20.0 — 29passed.
pnpm exec vitest run test/ingestion/code-mode.test.tson Node 24.12.0 — 29passed.
pnpm teston Node 22.20.0 — 219 files passed, 2 skipped; 2,911 testspassed, 3 skipped.
pnpm teston Node 24.12.0 — 219 files passed, 2 skipped; 2,911 testspassed, 3 skipped.
pnpm run format:check— passed.pnpm run lint:check— passed.pnpm exec changeset status—openwikipatch bump detected.git diff --check— passed.Coverage after the full runs: 89.39% statements, 83.67% branches, 94.32%
functions, and 89.67% lines.