fix(source-control): name --keep-data in setup's uninstall guidance (0.55.6) - #3211
Conversation
596e2a7 to
33f77fd
Compare
|
Claude finished @kyle-sexton's task in 42s —— View job Security review —
|
|
Claude finished @kyle-sexton's task in 1m 54s —— View job Claude's ReviewTasks
SummaryThis is a documentation-only fix (
No bugs, factual errors, or style violations found in the diff. One very minor observation, not a blocker: the PR title metadata ( Nice work tracing the multi-rung resolution logic precisely rather than over-warning — the distinction between |
|
Last security-reviewed head: |
|
Claude has reviewed this PR 2 times. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
33f77fd to
a78a2ec
Compare
|
Claude finished @kyle-sexton's task in 57s —— View job Security review —
|
|
Claude finished @kyle-sexton's task in 1m 3s —— View job Claude's ReviewTasks
SummarySkip gate: this head already has a successful review from this lane that still applies. I diffed the current head ( returns no output — the added paragraph in
I independently re-verified the core technical claim rather than taking that on faith: No findings. Nothing in this push changes the reviewable surface beyond a mechanical version renumber from rebasing. |
…0.55.8) (#3240) Closes #3212 Closes #3238 ## Summary `claude plugin uninstall` deletes the target plugin's `${CLAUDE_PLUGIN_DATA}` directory whenever the scope being removed is that plugin's last remaining one, unless `--keep-data` is passed. Five sites in this repo issued that uninstall without the flag, and none of them intends data removal. #3212 is the highest-blast-radius site: `reap-project-plugin-records.sh` runs non-interactively over every plugin id holding a project-scope record for a worktree `/source-control:worktree cleanup` is tearing down. For any plugin whose project-scope record was its last remaining scope, that call deleted *that* plugin's data directory as a side effect of reaping a stale *record*. #3238 is the same class at the four remaining executable or copy-paste sites outside that helper, found by the independent review on the #3212 fix. ## Fix `--keep-data` is now unconditional on every one of those calls. There is no branch in any of them where omitting it is correct. | Site | Change | |---|---| | `plugins/source-control/scripts/reap-project-plugin-records.sh` | `claude plugin uninstall "$id" -s project --keep-data`. Header documents the flag as a third safety property next to never-`-s user` / never-`--prune`. | | `.claude/cloud-bootstrap.sh` | Stale-snapshot refresh: `plugin uninstall "$id" --keep-data` before reinstall/re-enable. The existing comment already anticipated the loss of enabled state; it now also names the data-directory loss the flag closes. | | `plugins/source-control/skills/worktree/fixtures/project-scope-reap-probe.sh` | All five uninstalls pass `--keep-data`. The probe writes and removes its own project-scope records; a documented recheck must not destroy data as a last-scope side effect. | | `docs/MIGRATION-PLAYBOOK.md` | Force-a-fresh-snapshot recipe is `uninstall <name>@<marketplace> --keep-data` then `install` then `enable`. | | `plugins/claude-ops/skills/plugins/context/converge.md` | Consolidation templates carry `--keep-data` on `uninstall` only. `update` has no such flag. The `cd "<projectPath>"` form is split so the flag cannot be pasted onto `update`. | **Probe re-run (site 2 is not a one-flag change).** Adding the flag without re-running would leave `fixtures/README.md`'s As-of block describing a command the script no longer runs. Re-ran 2026-08-23 on Claude Code 2.1.238, Linux, against `markdown-format@melodic-software` and `bash-format@melodic-software`. Path-resolution outcomes match the 2026-08-22 Windows measurement on every arm. Counts: 1 → 4 (install) → 4 (other-cwd no-op) → 2 (live uninstall of two ids) → 1 (recreated-empty-dir uninstall). Failure text on arms 3 and 6 names "not installed in project scope" when the plugin has no user-scope record; the cwd-mismatch / no-record-here no-op is the same. The original Windows `caveman@caveman` "installed in user scope… Use --scope user" text is retained, because that is the trap the reap must never follow. `docs/extensibility-contract-smoke-tests.md` also omits the flag. Wiping the throwaway smoketest plugin's state is that procedure's stated purpose, so it is left alone, matching #3238. ## Verification | Gate | Result | |---|---| | `plugins/source-control/scripts/reap-project-plugin-records.test.sh` | All 44 cases passed, including the new `always passes --keep-data` assertion on the clean reap and the no-op uninstall path | | `claude plugin validate plugins/source-control` | Validation passed | | `claude plugin validate plugins/claude-ops` | Validation passed | | `scripts/check-changed-skills.sh origin/main` | PASS — plugins + worktree, 0 errors | | `scripts/check-changelog-parity.sh` `--check` / `--check-bump` / `--check-order` / `--check-preserved` | PASS | | `scripts/sync-plugin-options-docs.py --check` | up to date | | `scripts/check-skill-count-claims.sh --check` | PASS | | `scripts/check-skill-leaf-names.sh --check` | PASS | | `scripts/check-cross-plugin-source-drift.sh --check` | PASS | | `markdownlint-cli2` (changed markdown) | 0 issues | | `typos` | clean | | `shellcheck` (changed scripts) | clean | `claude plugin uninstall --help` on the installed CLI (2.1.238) confirms: `--keep-data Preserve the plugin's persistent data directory (~/.claude/plugins/data/{id}/)`. ## Related - Closes #3212 — reap helper reachable from `/source-control:worktree cleanup`. - Closes #3238 — the four remaining sites of the same class. - Refs #3131 / #3211 — documentation-side `--keep-data` gap in setup's uninstall guidance, already merged. This PR is the code-level sibling that #3211 deliberately left alone. - `docs/extensibility-contract-smoke-tests.md` left unchanged: wiping the throwaway smoketest plugin's state is that procedure's stated purpose. --------- Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
Closes #3131
Summary
/source-control:setup's babysit-config section warned operators not to uninstall the plugin in order to reconfigure it, citing thepluginConfigsentry that an uninstall drops — and stopped there.--keep-dataappeared nowhere in the plugin (grep -rn 'keep-data' plugins/source-control/returned zero hits before this change).That left a real gap for the operator who uninstalls for one of the other legitimate reasons — troubleshooting, changing scopes, reinstalling a version. Uninstalling from the last remaining scope deletes
${CLAUDE_PLUGIN_DATA}by default, and this plugin keeps durable state there.Fix
One paragraph added to
skills/setup/SKILL.md's "Babysit config" section, after the reconfigure bullets. It names the flag, says what the directory holds, and — the part that took the most care — states the resolution rung each worktree root must fall through before it lands there.What the directory actually holds, verified in-tree rather than assumed:
${CLAUDE_PLUGIN_DATA}/state/babysit-prsbabysit_state.py,queue-state.json), worker leases (manage_babysit_lease.py), feedback ledger (manage_feedback_ledger.py)userConfigkey relocates it${CLAUDE_PLUGIN_DATA}/worktrees/source-control:worktreetrees"Left unset" is necessary but not sufficient for
worktree_root.scripts/worktree-create.sh:20-32resolves a root over five rungs, and the plugin option is rung 3, below the target repository'smelodic.worktreerootgit config at rung 2. So/source-control:worktree createlands in the data directory only when neither resolves.babysit_worktree_rootis the simpler case and does fall back there whenever it is unset. Stating only "unset" would have over-warned the operator who uses the recommended per-repo git key, and the paragraph now distinguishes the two.The emphasis is on the losses that are actually irrecoverable. Babysit's own worktrees are ephemeral scratch that rebuild from GitHub; the state directory and a
/source-control:worktreetree holding uncommitted work are not. An earlier draft had this backwards.Follows
docs/conventions/plugin-data-report-keying/README.mdRule 4 ("state the uninstall fragility where the artifact is the only copy").Verification
claude plugin validate plugins/source-controlscripts/check-changed-skills.sh(setup)scripts/check-changelog-parity.sh--check/--check-bump/--check-order/--check-preservedscripts/sync-plugin-options-docs.py --checkscripts/check-skill-count-claims.sh --checkscripts/check-skill-leaf-names.sh --checkscripts/check-cross-plugin-source-drift.sh --checkmarkdownlint-cli2(both changed markdown files)typosDoc claims re-fetched at rung 1, not taken from a repo snapshot.
curl https://code.claude.com/docs/en/plugins-reference.mdon 2026-08-23, 108305 bytes: "By default, uninstalling from the last remaining scope also deletes the plugin's${CLAUDE_PLUGIN_DATA}directory. Use--keep-datato preserve it", and theplugin uninstallflag table carries--keep-dataspelled exactly that way.Rebased twice onto a moving
main; now at 0.55.6.mainlanded #3108 during this work, which de-slopped every source-control instruction surface under the repo's zero-tolerance em dash policy and took0.55.4; the worktree-claim change from #3104 / #2882 then took0.55.5. The added prose is written em dash free to match the rewritten file it lands in (grep -c '—'over the changedSKILL.mdreturns 0). Left unrebased, the version collision would have failedcheck-changelog-parity.shand the prose would have silently reintroduced the marks #3108 had just removed.Independent review. A fresh-context reviewer checked the diff against the issue's acceptance criteria with the author's rationale withheld. It raised one blocker (the
worktree_rootconditional was false in both directions — it over-warned pastmelodic.worktreerootand under-warned by omitting/worktree createtrees from the consequence) and two should-fixes (state described as "lane and lease state", which misattributes loop-lane telemetry that actually lives in a GitHub tracking issue and survives an uninstall; and a "neither has another copy" claim that contradicted the plugin's ownreference/worktrees.md). All three are fixed above; the reviewer's nits on length and antecedent are applied too.Related
/plugin-quality:auditpacket. The other findings in that packet are out of scope here and tracked separately.work-items.scripts/reap-project-plugin-records.sh:238runsclaude plugin uninstall "$id" -s projectwithout--keep-data, non-interactively, for every plugin id with a project-scope record keyed to a worktree being torn down (/source-control:worktree cleanupStep 4b). For any plugin whose project-scope record was its last remaining scope, that call deletes that plugin's${CLAUDE_PLUGIN_DATA}. Verified directly against the script. It is other plugins' data and a code change rather than prose, so it sits outside source-control/setup: uninstall guidance omits --keep-data (destroys babysit worktrees and lease state) #3131's prose-only acceptance criteria and is tracked on its own rather than folded in here.plugins/source-control/README.md:337-338carries a parallel uninstall warning, but it sits inside theBEGIN GENERATEDblock emitted byscripts/sync-plugin-options-docs.py:100-101and shared verbatim by every plugin README in the marketplace — a hand-edit is clobbered on the next sync, and editing it here would have been the mistake. Adding--keep-datato the generator is a one-line change that fixes roughly forty READMEs at once; it is left out of this PR because it changes every plugin's README rather than source-control's, not because it needs a decision.Generated by Claude Code