Repository navigation
fix(health-check): the shadowed-skill repair put the backup where the loader scans it - #2765
Conversation
…up where it loads as a skill `check_skill_symlinks` prints a repair command for a skill destination that is a real directory instead of a symlink. It recommended moving the directory aside to `<dst>/<name>.local-backup` — inside `<dst>`, which is the directory the skill loader scans. Following it verbatim on a live core produced exactly that: after the repair, `skill-usage-report.local-backup` was registered as an available skill, a phantom duplicate of the skill just relinked. The advice is otherwise good and hard-won (#2660 fixed the quoting so a spaced path no longer silently no-ops), which is why the destination was easy to miss: the command does repair the symlink. It just leaves a second problem behind. Backup now goes to `<dst>/../<name>.skill-backup` — outside the scanned directory, using only placeholders the message already has. Test: the existing activation test executes the emitted command, so it now asserts the backup lands OUTSIDE `<dst>`, plus a new assertion that nothing named `*.skill-backup` is left inside it. Both fail against the previous recommendation (verified by restoring the old string: 2 failures) and pass with the change. Stand: Echo Act IV Pro Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Coverage Gate✅ Diff coverage PASSES the 95% bar. Whole-tree (informational): 78%. Diff CoverageDiff: origin/main...HEAD, staged and unstaged changesNo lines with coverage information in this diff. |
qingyun-wu
left a comment
There was a problem hiding this comment.
Reviewed head 30d19a43b22613c65debf339dfc68b684909dee2.
No blocking findings. The remedy now moves a shadowing real skill directory outside the loader-scanned destination before recreating the symlink, so the backup no longer becomes a phantom duplicate skill. The regression test executes the advertised command against a spaced-path fixture and asserts both sides of the behavior: local edits are preserved in <dst>/../<name>.skill-backup, and no backup directory is left inside <dst>.
Checks run in an isolated /private/tmp worktree:
python3 tests/health-check-dangling-symlinks.test.pyPYTHONPYCACHEPREFIX=/private/tmp/sutando-pr-2765-30d19a/.pycache python3 -m py_compile src/health-check.py tests/health-check-dangling-symlinks.test.pypython3 scripts/gen-src-map.py --checkgit diff --check origin/main...HEADgit diff origin/main...HEAD | bash scripts/review-checks.sh
Hosted status at review time: diff coverage and fast gates are green; clean-install was still running.
Reviewed by Qingyun's Personal Codex.
bassilkhilo-ag2
left a comment
There was a problem hiding this comment.
Verified in an isolated worktree off a freshly-fetched origin/main (dev checkout left untouched):
python3 tests/health-check-dangling-symlinks.test.py -vat HEAD: 14/14 pass.- Reverted only
src/health-check.pyback toorigin/mainwhile keeping the PR's updated tests: reproduces exactly the 2 failures the PR body claims (the remedy did not preserve the local edits it moved aside, and the not-quoted assertion) — confirms the new tests actually pin the new behavior rather than passing vacuously. - Note for future readers: my first pass at this diffed against a stale local
origin/main(hadn't fetched since before #2664 landed) and briefly looked like #2765 might be stacked on unmerged #2660 — it isn't; #2660 is merged,git merge-base origin/main pr-2765-reviewmatches the freshorigin/maintip exactly.
Small, single-purpose fix: moves the backup destination outside <dst> so the skill loader can't register it as a phantom duplicate. Diff is exactly what the description says — no changes to quoting, ln -sfn handling, or shadow detection itself. Approving.
|
@cla-assistant check |
What
check_skill_symlinksprints a repair command when a skill destination is a real directory instead of a symlink. It told you to move the directory aside to<dst>/<name>.local-backup— inside<dst>, which is the directory the skill loader scans.Why it matters — reproduced on a live core, not theorised
I hit the warning today, ran the emitted command verbatim, and the harness immediately registered the backup as a skill:
The symlink repair itself works. The command just leaves a second problem behind, and the operator has no reason to look for it — the probe goes green.
This is easy to miss precisely because the surrounding advice is hard-won: #2660 fixed the quoting so a spaced path no longer silently no-ops, and the comment block explains that at length. The destination was never the part under examination.
Change
Outside the scanned directory, using only placeholders the message already carries. The quoting property #2660 established is preserved, and its test still enforces it.
Evidence
tests/health-check-dangling-symlinks.test.pyalready executes the emitted command rather than string-matching it, so it extends naturally. It now asserts the backup lands outside<dst>, plus a new assertion that nothing named*.skill-backupremains inside it.Both fail against the previous recommendation — verified by restoring the old string rather than assuming:
Scope
Two files, one behaviour. No change to the quoting, the
ln -sfnwarning, the shadow detection, or any other probe.Stand: Echo Act IV Pro
🤖 Generated with Claude Code