Skip to content

fix(init): refuse a file/directory collision before the first write (PHARN-16) - #210

Merged
PrzemekGalarowicz merged 1 commit into
mainfrom
claude/bold-archimedes-5czyyn
Sep 24, 2026
Merged

PrzemekGalarowicz merged 1 commit into
mainfrom
claude/bold-archimedes-5czyyn

Conversation

@PrzemekGalarowicz

Copy link
Copy Markdown
Contributor

Problem

A directory where init writes a file (e.g. .claude/commands/pharn-spec.md/), or a file where it needs a directory, made cpSync fail part-way through the install. The project was left with about 300 new files, no pharn.config.json, and no records.

Fix

  • The destination pre-flight in installCapabilities now also checks entry types for every path in the install manifest.
  • A collision means either an existing intermediate component that is not a directory, or an existing leaf that is not a regular file.
  • Any collision refuses the whole install before the first write, naming each colliding path (sorted, capped at five).
  • .claude/settings.json is left out of the check, since init never overwrites it.
  • features/README.md keeps its skip-on-collision behaviour. A directory there is now skipped; the old code threw.
  • The new findTypeCollision lives in symlink-guard.ts next to findSymlinkComponent, because tests/symlink-guard.test.ts requires every path-component walk to be in that module. That was a plan amendment, approved by the user.
  • Docs updated: docs/troubleshooting.md.

Tests

  • 6 cases fail on the old code:
    • four collision shapes, each checked against a snapshot of the whole project tree (nothing written);
    • the error message listing several collisions;
    • a directory at features/README.md.
  • A re-install over existing regular files still succeeds.
  • Local gates, run as a non-root user on node 22: all green. 1444/1444 tests pass and statement coverage is 97.23%.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TvcuVhk8hTeDskp5pAJhnc


Generated by Claude Code

…PHARN-16)

A directory where init writes a file (or a file where it needs a directory)
used to surface from cpSync part-way, leaving ~300 new files with no
pharn.config.json and no records. The destination pre-flight now also walks
every manifest path's component TYPES (findTypeCollision, beside
findSymlinkComponent in symlink-guard.ts) and refuses the whole install,
naming each collision. The optional features/README.md keeps its
skip-on-collision contract.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvcuVhk8hTeDskp5pAJhnc
@coderabbitai

coderabbitai Bot commented Sep 24, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 936d150a-94ae-48c6-bc27-22e94b87f877


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@PrzemekGalarowicz
PrzemekGalarowicz merged commit 1c4b107 into main Sep 24, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants