Skip to content

source-control/setup: uninstall guidance omits --keep-data (destroys babysit worktrees and lease state) #3131

Description

@kyle-sexton

From a /plugin-quality:audit run (packet source-control-config/20260823T014416Z), source-control 0.54.16. 8 findings — 2 High, 3 Medium, 3 Low. claude plugin validate passes. Cross-plugin findings from the same run: #3128. Prior hardening pass: #912.

How this surfaced. The tracked .claude/source-control.md team layer in melodic-software/.github was read, audited against reference/config-resolution.md, and modified. No source-control skill was executed — this is a config-surface audit.

F3 (High) — uninstall guidance omits --keep-data

setup/SKILL.md:245-259 prescribes claude plugin uninstall … then reinstall and warns at length about losing pluginConfigs — but never mentions --keep-data. Per the docs, uninstalling from the last remaining scope also deletes the plugin's ${CLAUDE_PLUGIN_DATA} directory, where this plugin stores babysit worktrees and lane/lease state.

grep -rn 'keep-data' across the whole plugin: zero hits.

One-token fix, and the highest damage-per-character finding in the set. This was outside the audit's original dispatch scope and is included because scope was locked to all findings.

Caveat carried with it: F4 below undercuts the premise this path rests on.

F1 (High) — overlay-ignore guard reachability → tracked in #3128 (S2)

The trigger-condition defect is shared with work-items and is filed once in #3128 to avoid sending the same fix request twice. Summary only: the guard is conditioned on the overlay already existing (setup/SKILL.md:77-78, Absent → INFO, which is the common case), so it cannot fire in the window that creates the exposure. source-control's probe itself is correct — it is the two-probe form work-items lacks. Cheapest fix, per #3128, is decoupling the rule probe from the file probe.

Correction on the record: an earlier framing during this audit claimed the plugin does not carry the gitignore requirement. That was wrong and is withdrawn. config-resolution.md:310 (## Consumer .gitignore, prescribing .claude/*.local.*), :321 (## Failure modes), and apply-convention.md step 6 all carry it correctly.

Remaining findings

  • F5 (Medium) — the userConfig/tracked split is doc-correct (project pluginConfigs entries are ignored by Claude Code, so tracked markdown is the only carrier for repo-scoped policy), but the wrong-surface mistake fails silently in the motivated direction: a babysit_* userConfig key written as an H2 is inert with no report row. babysit_merge_method vs babysit_loop_merge is never disambiguated, though babysit_default_tier is.
  • F2 (Medium) — the absent-key fall-through chain includes commit-msg hooks but not CI workflows. The consumer's pr-title.yml enforces Conventional Commits on a squash title that becomes the commit subject, while the config surface was silent on subject_pattern — correct only by coincidence of the bundled default. The contract reasons carefully about exactly this divergence for convention_source rung 2 and applies none of that care to the plain absent-key case. Cheapest surface is a third probe in setup check's existing "Neutral-SSOT drift probes" block; the plugin already names amannn/action-semantic-pull-request at pull-request/SKILL.md:41.
  • F4 (Medium)--config "ignored once installed" is undocumented (exhaustive grep -F -- '--config' over the 108305-byte page: two hits, neither says this) and unstamped, yet it is the sole premise for F3's destructive path.
  • F6/F7/F8 (Low) — the density problem is ordering: the loop-lane section runs 168 lines (51% of the document) and the two rules governing both key families land at lines 250 and 271, after it. Plus unmarked eval fixtures shipped as live-looking config, and a userConfig count that has drifted — prose says twenty-nine, the manifest has 35 (independently re-verified).

Remediations, cheapest first

  1. Add --keep-data to the uninstall guidance (F3).
  2. Fix the userConfig count and mark the eval fixtures (F8).
  3. Move the two cross-family rules ahead of the loop-lane section (F6).
  4. Report a wrong-surface babysit_* key instead of silently ignoring it (F5).
  5. Add a CI-workflow probe to setup check's drift block (F2).
  6. Ignore-rule trigger decoupling — see Cross-plugin: hook-utils skip latch silences 9 formatters, overlay-ignore guard unreachable, plugin-quality seal premise false #3128.

Caveats

No source-control skill was executed — contract-read plus static repo state only. The auditor's scratch-repo reproduction of the F1 mechanism was blocked by the sibling guardrails PreToolUse hook and it did not route around it, so that mechanism is reasoned from source, not observed. Every check behavior cited is prose an LLM must follow, not a tested code path — temper "setup check already covers it" accordingly. Doc citations are rung-1 curl, fetched 2026-08-23, with byte counts and line numbers; slugs checked against llms.txt.

Metadata

Metadata

Assignees

Labels

agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.priority: highSignificant impact, or blocks an imminent release; staff this cycle.work-class: mechanicalDeterministic, trivially reversible maintenance: dependency bumps, lint/format, sync.

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions