{"version":"2.1.236","anchor":"plugin-and-skill-sync-abort-when-the-sync-directory-has-been","canonical_anchor":"plugin-and-skill-sync-abort-when-the-sync-directory-has-been","heading":"Plugin and skill sync abort when the sync directory has been tampered with","tier":"notice","area":"Elsewhere","scope":null,"heads_up":null,"url":"https:\/\/changelogs.core-directive.com\/v\/2.1.236\/e\/plugin-and-skill-sync-abort-when-the-sync-directory-has-been","release_url":"https:\/\/changelogs.core-directive.com\/v\/2.1.236","markdown":"### Plugin and skill sync abort when the sync directory has been tampered with\n\nSync aborts with a clear message if anything in the sync path looks tampered with.\n\n**What**\n\nBefore writing, sync now checks every path component from the config home down to the sync root and its `staging` and `staging_pid` folders, and aborts the whole round if any of them is a symlink or not a directory. Failures show up as \"sync root refused (a symlink or stray file is in the way, or it was removed mid-round)\" instead of silently writing through.\n\n**Details**\n\n- The root is re-verified partway through each round, when files are landed.\n- Replacing an existing plugin directory now moves the old one aside, either renaming it to a `.replaced-<pid>-<rand>` directory or moving it to a trash directory under the config home, and restores it if the replacement fails.\n- New warning telemetry: `plugins_sync_root_refused`, `skills_sync_root_refused`, `plugins_sync_trash_move_failed`, `plugins_sync_promotion_failed`, `skills_sync_manifest_unreadable`.\n- No flag guards this; it is the sync path for everyone on this build.\n\n**Evidence**\n\n`sync root refused (a symlink or stray file is in the way, or it was removed mid-round)`\n\n- Area: Elsewhere\n- Tier: You'll notice\n- Useful: 2\/5\n- Signal: 2\/5"}