Skip to content

fix(generate): tighten the symlink-aware orphan sweep follow-ups from #3288 - #3297

Merged
dyoshikawa merged 3 commits into
mainfrom
resolve-issue-3294-followups
Oct 3, 2026
Merged

dyoshikawa merged 3 commits into
mainfrom
resolve-issue-3294-followups

Conversation

@dyoshikawa

Copy link
Copy Markdown
Owner

Summary

Follow-ups 1-6 from #3294 (the non-blocking review notes on #3288). Item 7, the deletion through a symlinked output directory, is fixed separately in #3295.

Item Change
1. Symlinked orphans landing on a claim Kept (no deletion), which is the conservative choice: the link is the user's own wiring of one tool's file into another's directory. Now documented on OrphanSweepPlan and covered by a test.
2. Unfollowable links kept silently createOrphanSweepPlan({ logger }) now warns Refusing to sweep "<path>": its symbolic links cannot be followed (a link cycle or an unreadable directory), once per path.
3. Missing safety-branch tests Tests for the a -> b, b -> a cycle branch, and for landing-claim cache invalidation after rejectClaimed has already run, for both registerGenerated and registerGeneratedTree. Both cache tests fail when the landingClaims = undefined lines are removed.
4. Lexical isGenerated JSDoc says it compares paths as spelled and must not decide deletions, and points to rejectClaimed / isGeneratedExactly. It is still public because rejectClaimed and the existing tests use it.
5. Maintainability rejectClaimed reads getPath(item) once. Added a comment on the cost of the one unbounded Promise.all in getLandingClaims.
6. Refused tool dir silencing --delete processDirFeatureGeneration no longer registers a tree claim for a directory whose path leads out of the output root, which writeAiDirs refuses to write anyway. Before this, .claude/skills/review -> <parent of project> claimed the whole parent tree, so .claude/commands/stale.md survived generate --delete. A new e2e test in e2e-skills.spec.ts fails on main and passes here. The lexical claim on the directory path itself is unchanged.

Verification

  • pnpm cicheck and pnpm cicheck:content pass locally.
  • Reproduced item 6 with the CLI before and after the change.

Refs #3294

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y4MwhqMc6s4ct5MzMReGJj

dyoshikawa and others added 3 commits October 2, 2026 19:45
…3288

- Keep a refused skill directory that leads out of the output root out of
  the generated-tree claims, so a .claude/skills/foo -> $HOME link no
  longer silences every --delete sweep in the run.
- Warn once when a sweep keeps a candidate because its links cannot be
  followed (a cycle or an unreadable directory).
- Document that isGenerated compares paths lexically only and must not
  decide deletions, and that symlinked orphans landing on a claim are kept.
- Read getPath once per item in rejectClaimed and comment on the cost of
  following every claim.
- Test the cycle branch, landing-claim cache invalidation, and the kept
  symlinked orphan.

Refs #3294

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4MwhqMc6s4ct5MzMReGJj
…he root

A skill directory linked onto the output root itself (for example
~/.claude/skills/foo -> ~ in global mode) passed the escape check and
still claimed the whole root. Require the landing to be strictly below
the root, and cover both the outside and the root case in e2e.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4MwhqMc6s4ct5MzMReGJj
@dyoshikawa
dyoshikawa merged commit 802e08a into main Oct 3, 2026
9 checks passed
@dyoshikawa

Copy link
Copy Markdown
Owner Author

@dyoshikawa Thank you!

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.

1 participant