fix(ci): align the CLAUDE.md contract with the symlink, unbreaking main#244
Merged
Conversation
5336d5f made CLAUDE.md a symlink to AGENTS.md (git mode 120000) but left the test and docs asserting the old `@AGENTS.md` shim, so main has been red since: (fail) CLAUDE.md is a shim that @-imports AGENTS.md (no duplicated content) Expected substring or pattern: /^@agentS\.md\s*$/m Reading CLAUDE.md now follows the link and yields all of AGENTS.md, so both assertions failed: the regex, and `not.toContain('.agents/atlas/artifacts/')`. The contract the test defends is unchanged -- "CLAUDE.md must never carry a second copy of the guide" -- but a symlink satisfies it by construction: there is literally one file, so content cannot drift. So assert the LINK, not the content. A content assertion here would just be asserting AGENTS.md twice. Adds a guard for the symlink's known failure mode: with core.symlinks=false (a common Windows default) git materializes CLAUDE.md as a plain file whose whole content is the literal string "AGENTS.md", and Claude Code would silently load that as the entire guide. The new test fails loudly instead. This affects only contributors -- the CLAUDE.md installed for users comes from templates/CLAUDE.md.template and is unaffected. Docs realigned (they described a mechanism that no longer exists): - AGENTS.md:3, :37, :105 -- "thin shim that @-imports" -> "symlink" - AGENTS.md Agent Context Files -- documents the symlink, the /init hazard, and the core.symlinks=false limitation - docs/releasing.md pre-flight -- `cat CLAUDE.md` would now print the whole guide, so the check is `ls -l CLAUDE.md`; recovery is `ln -sf AGENTS.md CLAUDE.md`
edheltzel
added a commit
that referenced
this pull request
Jul 15, 2026
…g-regressions * origin/main: fix(ci): align the CLAUDE.md contract with the symlink, unbreaking main (#244)
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.
main is red.
5336d5f("claude.md is a symlink to agents.md") changedCLAUDE.mdto a symlink but left the test and docs asserting the old@AGENTS.mdshim.5336d5f= CI failure ·58cb1d1= success. This unblocks it.Why both assertions broke
Reading
CLAUDE.mdnow follows the link and returns all ofAGENTS.md, so:expect(body).toMatch(/^@AGENTS\.md\s*$/m)— the import line no longer existsexpect(body).not.toContain('.agents/atlas/artifacts/')— it does now; that's AGENTS.md's own contentThe fix: assert the link, not the content
The contract being defended is unchanged — "CLAUDE.md must never carry a second copy of the guide." A symlink satisfies it by construction: there is literally one file, so content cannot drift. A content assertion here would just be asserting
AGENTS.mdagainst itself.Plus a guard for the symlink's real failure mode
With
core.symlinks=false(a common Windows default), git materializesCLAUDE.mdas a plain file whose entire content is the literal stringAGENTS.md— and Claude Code would load that as the whole guide, silently, with no error. The@-import shim had no such failure mode, so this risk is new and worth a test:Scope note: this affects contributors only. The
CLAUDE.mdRecall installs for users is generated fromtemplates/CLAUDE.md.templateand is untouched by this.Docs realigned
They described a mechanism that no longer exists:
AGENTS.md:3,:37,:105— "thin shim that@-imports" → "symlink"AGENTS.md→ Agent Context Files — documents the symlink, the/inithazard (now "replaces the symlink with a copy"), and thecore.symlinks=falselimitationdocs/releasing.mdpre-flight — this mattered: it told maintainers to runcat CLAUDE.mdand confirm it prints "the @AGENTS.md import — nothing else." That now prints the entire guide, so the pre-flight would fail every release. Changed tols -l CLAUDE.md(expectsCLAUDE.md -> AGENTS.md); recovery isln -sf AGENTS.md CLAUDE.md.Verification
tests/commands/scout-workflow.test.ts: 27 pass / 0 fail.bun run lintclean. New pre-flight command verified against the real file:Blocks #242 and the v0.9.4 patch release — merge this first.