Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,26 @@ jobs:
BASE_REF: ${{ github.base_ref }}
run: scripts/sync-spawn-noise.sh --check-bump "origin/$BASE_REF"

check-retirements-sync:
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- name: Check out
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Fetch base
uses: ./.github/actions/checkout-with-base
- name: Verify check-retirements cluster matches canonical
run: scripts/sync-check-retirements.sh --check
- name: Run check-retirements tests
run: bash plugins/claude-config/lib/check-retirements.test.sh
- name: Verify carrying plugins bumped when canonical changed
if: github.event_name == 'pull_request'
env:
BASE_REF: ${{ github.base_ref }}
run: scripts/sync-check-retirements.sh --check-bump "origin/$BASE_REF"

resolve-convention-pattern-sync:
runs-on: ubuntu-24.04
timeout-minutes: 15
Expand Down Expand Up @@ -1404,6 +1424,13 @@ jobs:
run: bash scripts/validate-plugin-contracts.test.sh
- name: Validate plugin and catalog manifests
if: needs.scope.outputs.run_full == 'true'
# validate-plugins.sh runs scripts/validate-plugin-contracts.mjs, whose
# retirements append-only check diffs each plugins/*/retirements.yaml
# against this ref and skips (with a notice) when it is unset. The
# checkout-with-base step above already deepens history and fetches
# origin/<base_ref> on pull_request, so the ref resolves here.
env:
VALIDATE_CONTRACTS_BASE_REF: origin/${{ github.base_ref || 'main' }}
run: scripts/validate-plugins.sh
- name: Report not applicable to a docs-only diff
if: needs.scope.outputs.run_full == 'false'
Expand Down Expand Up @@ -1750,6 +1777,7 @@ jobs:
- managed-scope-sync
- state-key-sync
- spawn-noise-sync
- check-retirements-sync
- resolve-convention-pattern-sync
- index-regen-sync
- standards-contract-sync
Expand Down
1 change: 1 addition & 0 deletions docs/PLUGIN-PHILOSOPHY.md
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ doc before a second plugin adopts it. Fleet audits check conformance per row.
| Untrusted-content framing contract | [`docs/conventions/untrusted-content/`](conventions/untrusted-content/README.md) |
| Reply affordance on decision-collecting artifacts | [`docs/FINDING-YOUR-UNKNOWNS.md`](FINDING-YOUR-UNKNOWNS.md#reply-affordance-convention) |
| Export button on interactive HTML artifacts | [`docs/FINDING-YOUR-UNKNOWNS.md`](FINDING-YOUR-UNKNOWNS.md#export-button-rule) |
| Retired-convention detection and cleanup (manifest + shared helper) | [`docs/conventions/retired-conventions/`](conventions/retired-conventions/README.md) |

## Cross-platform contract

Expand Down
4 changes: 4 additions & 0 deletions docs/conventions/plugin-reconfiguration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ record. Canonical citation (installed plugins cannot read this repository's work
the published URL):

<https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/plugin-reconfiguration/README.md>

The setup contract's other fixed step — retired-conventions detection in `check` and gated cleanup
in `apply` — is conditional on the plugin shipping `retirements.yaml`, and its canonical text lives
in the [retired-conventions convention](../retired-conventions/README.md#the-two-fixed-setup-lines).
37 changes: 37 additions & 0 deletions docs/conventions/retired-conventions/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Retired Conventions Convention — Changelog

Notable changes to the retired-conventions contract. Versioned by `contract_version` (SemVer),
governing the manifest schema, the helper CLI contract, the two fixed setup lines, the append-only
and demotion rules, the eval-per-record requirement, and the fleet sweep's finding contract. Which
surfaces retire is each plugin's own migration PR and is never versioned here. Adding a required
field, removing a field, changing a kind's detection semantics, an exit code's meaning, or the
severity map is a major bump; adding an optional field, a `status` value, or a new `kind` with its
own detection rule is a minor bump.

## 1.0 — 2026-09-01

Initial published contract, landing with the mechanism PR that ADR 0018 named (helper, validator,
sync registration, owner doc, audit-pass sweep lane, pointer-line resolver). No plugin ships a
manifest yet; the Implementers table is empty by design.

- Manifest: `plugins/<plugin>/retirements.yaml`, a flat YAML subset (`---`-separated records of
flat `key: value` scalars). Fields `id`, `retired`, `plugin_version`, `kind`, `path`, `match`,
`content_match`, `action`, `successor`, `note`, `status`. Unknown keys fail validation.
- Append-only with three enumerated legal edits: status flip, defect fix to `note`/`successor`,
and demotion to `report-only` instead of pruning when a path is deliberately re-adopted (recorded
in the plugin CHANGELOG). Deletion never.
- Helper: `lib/check-retirements.sh`, canonical in `claude-config`, synced byte-identical. TSV
`id\tkind\tpath\taction\tstatus\tnote`; detection exit 0/1/2 (clean / active leftovers / error,
with an invalid record failing the whole run); `--clean <id> [--i-migrated]` exit 0/1/2. Paths
emitted repo-relative; consumer content only ever grep-matched.
- The two fixed setup lines (`check` and `apply`), conditional on the plugin shipping a manifest,
with the severity map `migrate` FAIL / `delete`,`remove-line` WARN / `report-only` INFO, exit 2
as a visible FAIL, and bash-unavailable as UNKNOWN. Wiring is CI-checked in both directions.
- One eval case per record id in the plugin's setup evals; validator failure when missing.
- Runtime fleet sweep as a `claude-config` audit-pass lane over installed plugins' manifests, using
claude-config's own helper copy; read-only, no generator, no committed aggregate.
- Dual-read deprecation window bounds: a `migrate` record opens it; cleanup closes it per consumer;
demotion to `report-only` closes it fleet-wide.
- Scope: repository-scope only; machine-scope surfaces excluded (ADR 0018).
- Deferred: the CI-aggregated fleet registry, revived only when orphan leftovers from an
uninstalled plugin are observed in practice.
Loading