Skip to content

feat: add marketplace-ops plugin for pruning stale content#445

Merged
openshift-merge-bot[bot] merged 12 commits into
openshift-eng:mainfrom
stbenjam:clean-up-ai-helpers
May 6, 2026
Merged

feat: add marketplace-ops plugin for pruning stale content#445
openshift-merge-bot[bot] merged 12 commits into
openshift-eng:mainfrom
stbenjam:clean-up-ai-helpers

Conversation

@stbenjam
Copy link
Copy Markdown
Member

@stbenjam stbenjam commented May 5, 2026

Summary

  • Adds the marketplace-ops plugin with two commands: /marketplace-ops:prune (analyze and open a PR removing stale plugins/commands/skills) and /marketplace-ops:prune-update (process /save comments on pruning PRs)
  • Includes Python scoring scripts (score-plugins.py for plugin-level and score-items.py for command/skill-level analysis) that use git metadata to identify inactive content
  • Adds .pruneprotect file for permanently protecting plugins from automated removal
  • Two-tier pruning: plugin-level is fully mechanical (score threshold), item-level uses LLM judgment

Design

Plugin-level scoring signals:

Signal Weight
Last commit >90d/120d/150d/180d ago +1/+2/+3/+4
Low commit count (<=3 or <=5) +2 or +1
Single contributor + inactive >60d +1
Small footprint (1-2 commands, no skills) +1
Minimal README (<100 bytes) +1
Has OWNERS file -2

Plugins younger than 90 days skip all maturity signals. Batch-update commits are detected and excluded from "last commit" calculations.

Item-level scoring runs on surviving plugins, flagging individual commands/skills by inactivity and size. The LLM then applies judgment (e.g., does this command require AI reasoning?).

/save workflow: Comment /save <path> on a pruning PR, then run /marketplace-ops:prune-update to restore the item and add it to .pruneprotect permanently.

Test plan

  • Run python3 plugins/marketplace-ops/scripts/score-plugins.py and verify output
  • Run python3 plugins/marketplace-ops/scripts/score-items.py and verify output
  • Run /marketplace-ops:prune --dry-run and verify report
  • Run make lint to validate plugin structure

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Marketplace Ops plugin with two maintenance commands: prune (analyze/prune stale marketplace items; supports --dry-run) and prune-update (process /save and /drop on pruning PRs).
    • Added CLI tools to score plugins, commands, and skills for staleness to assist pruning decisions.
  • Documentation

    • Detailed workflow docs, examples, command references, and protection guidance for Marketplace Ops.
  • Chores

    • Added prune-protection allowlist (includes Marketplace Ops) and bumped Marketplace Ops to v0.1.2.

stbenjam and others added 7 commits May 5, 2026 14:39
Adds a new plugin with two commands:
- /marketplace-ops:prune [--dry-run]: analyzes the marketplace for stale
  plugins, commands, and skills using git history and LLM judgment, then
  opens a PR to remove them
- /marketplace-ops:prune-update: processes /save comments on pruning PRs,
  restores items, and adds them to .pruneprotect permanently

Also adds .pruneprotect file for protecting paths from automated pruning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extracts the plugin-level scoring heuristics into a standalone Python
script that outputs structured JSON. The prune command now calls the
script first and uses its output as the starting point, reserving LLM
judgment for command/skill-level analysis.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New plugins naturally have few commits, low version numbers, and small
footprints. These aren't signs of staleness — they're signs of being
new. The script now tracks plugin age (first commit date) and only
applies commit-count, version, footprint, and README signals to plugins
older than 90 days.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove version-at-0.0.x penalty (most plugins stay at 0.0.x regardless
of maturity). Add OWNERS file as a -2 bonus — active ownership is a
strong positive signal that should protect a plugin from pruning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace flat +2 for >90 days inactive with a graduated scale:
>90d: +1, >120d: +2, >150d: +3, >180d: +4. Older dormant plugins
now rank higher than borderline ones.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Companion to score-plugins.py — analyzes individual commands and skills
within plugins that survived the plugin-level cut. Commands are scored
per markdown file, skills per directory. Supports --plugins filter to
scope analysis to specific plugins.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Plugin-level pruning is mechanical: if the script flags it, it goes.
No LLM override. LLM judgment only applies at the item level within
surviving plugins.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci openshift-ci Bot requested review from LuboTerifaj and zaneb May 5, 2026 18:48
@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 5, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new Marketplace Ops plugin (v0.1.2): registration and catalog entries, a .pruneprotect allowlist, docs and command specs for prune and prune-update, and two CLI scoring scripts (score-plugins.py, score-items.py) for identifying and operating on stale marketplace plugins, commands, and skills.

Changes

Marketplace Ops Plugin

Layer / File(s) Summary
Plugin Registration / Catalog
.claude-plugin/marketplace.json, docs/data.json
Registers marketplace-ops with source: ./plugins/marketplace-ops, description, version 0.1.2, and adds prune and prune-update command entries.
Protection Configuration
.pruneprotect
Adds .pruneprotect listing protected plugin paths: plugins/hello-world/, plugins/metrics/, plugins/native-notifications/, plugins/marketplace-ops/.
Plugin Metadata Bump
plugins/marketplace-ops/.claude-plugin/plugin.json
Bumps plugin version from 0.1.1 to 0.1.2.
High-Level Docs / Catalog
PLUGINS.md, plugins/marketplace-ops/README.md, docs/data.json
Adds TOC entry, README, and catalog metadata describing the plugin and its two commands.
Command Specs / Guides
plugins/marketplace-ops/commands/prune.md, plugins/marketplace-ops/commands/prune-update.md
Adds detailed specifications for prune (scoring, dry-run, branch/PR creation, removal manifest) and prune-update (discover PR, parse /save//drop, restore saves, update .pruneprotect, sync PR).
Plugin Logic — Plugin-level Scoring
plugins/marketplace-ops/scripts/score-plugins.py
New CLI that loads .pruneprotect, gathers git and filesystem signals, detects batch-update dates, computes multi-factor staleness score, classifies candidates vs protected/safe, and emits a JSON report.
Plugin Logic — Item-level Scoring
plugins/marketplace-ops/scripts/score-items.py
New CLI that loads .pruneprotect, extracts command/skill frontmatter, gathers per-file/git metrics and sizes, computes per-item staleness scores, and emits a structured JSON for LLM-assisted review.
Integration / Workflow Wiring (docs-only)
PLUGINS.md, plugins/marketplace-ops/README.md, command docs
Documents end-to-end prune workflow: scoring, cross-reference checks, dry-run vs full pruning, branch creation, removals, version bumps, make update, commit/push, PR creation with removal manifest and /save instructions, and the prune-update restore flow.

Sequence Diagram

sequenceDiagram
  participant Operator
  participant CLI as marketplace-ops CLI
  participant Repo as Git Repo
  participant LLM
  participant GitHub

  Operator->>CLI: run score-plugins / score-items (--dry-run?)
  CLI->>Repo: read .pruneprotect, plugin files, git history
  Repo-->>CLI: file & git metadata (commits, dates, sizes)
  CLI->>CLI: compute scores, detect batch dates
  CLI->>LLM: (optional) produce item review payload / prompt
  LLM-->>CLI: review output / decisions
  CLI->>GitHub: (full run) create branch, commit removals, push fork
  GitHub-->>Operator: opens PR with removal manifest
  Operator->>GitHub: comment with /save or /drop directives
  GitHub-->>CLI: (prune-update) PR comments fetched
  CLI->>Repo: restore saved paths, update .pruneprotect, commit & push
  CLI->>GitHub: update PR body and post result comment
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
No Assumed Git Remote Names ❌ Error Documentation uses {upstream_remote} and {fork-remote} placeholders without explicit discovery instructions. Assumes implementer knows remote names without first discovering them. Add explicit git remote discovery steps in prune-update.md (line 94) and prune.md (line 190) showing how to extract the actual remote names from git config.
Git Push Safety Rules ❌ Error Commands perform autonomous git push without user permission. prune.md Step 10: git push -u {fork-remote} HEAD. prune-update.md Step 9: git push. Neither requires confirmation before pushing. Add explicit user confirmation steps before both git push operations. Require user approval (e.g., 'Ready to push?' prompt) before executing push commands in both prune and prune-update workflows.
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add marketplace-ops plugin for pruning stale content' directly describes the main change—addition of a new marketplace-ops plugin—which is evident across all modified/created files including the new plugin directory, manifest entries, configuration, and documentation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Real People Names In Style References ✅ Passed No real people names found in style references, example prompts, or instructions. Only generic placeholders and product name (Claude Opus 4.6) appear.
No Untrusted Mcp Servers ✅ Passed No MCP servers or untrusted packages introduced. PR adds marketplace-ops plugin with Python scripts using only standard library imports (json, os, subprocess, sys, datetime, pathlib).
Ai-Helpers Overlap Detection ✅ Passed Marketplace-ops plugin is new/unique. No command/skill overlaps detected. PR #446 relationship is complementary infrastructure+application, not overlapping. Similarity: 48.5%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

stbenjam and others added 2 commits May 5, 2026 14:51
The CI version-check workflow requires a version bump for any plugin
with code changes. The prune command now bumps patch versions for
surviving plugins that had commands or skills removed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (3)
plugins/marketplace-ops/README.md (1)

21-27: ⚡ Quick win

Add a language tag to the fenced example block to satisfy markdownlint.

Line 21 starts an unlabeled fence; use text (or bash) to clear MD040.

Suggested patch
-```
+```text
 # Canonical example plugin
 plugins/hello-world/

 # Saved by `@username` on 2026-05-05
 plugins/foo/
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @plugins/marketplace-ops/README.md around lines 21 - 27, Add a language tag
to the fenced code block in the README example to satisfy markdownlint MD040:
update the opening triple-backtick that precedes the block containing "Canonical
example plugin" / "plugins/hello-world/" to include a language (e.g., change totext or ```bash) so the fenced block is labeled; ensure the closing
triple-backtick remains unchanged.


</details>

</blockquote></details>
<details>
<summary>plugins/marketplace-ops/commands/prune-update.md (1)</summary><blockquote>

`10-12`: _⚡ Quick win_

**Add language identifiers to unlabeled fenced code blocks.**

These fences trigger MD040; labeling them (`text`/`bash`) keeps docs lint-clean.
 


Also applies to: 82-85, 127-129, 133-135, 167-169, 172-174

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @plugins/marketplace-ops/commands/prune-update.md around lines 10 - 12,
Several fenced code blocks in the prune-update docs are unlabeled (e.g., the
block containing "/marketplace-ops:prune-update [PR number or URL]") which
triggers MD040; update each unlabeled triple-backtick fence to include an
appropriate language identifier (bash for shell/CLI examples, text for plain
output/snippets). Locate the command/example fences (including the other similar
examples in the file) and change tobash or ```text as appropriate so
lint no longer flags MD040.


</details>

</blockquote></details>
<details>
<summary>plugins/marketplace-ops/commands/prune.md (1)</summary><blockquote>

`10-12`: _⚡ Quick win_

**Add language tags to unlabeled code fences for markdownlint compliance.**

These blocks should be tagged (`text`/`bash`) to satisfy MD040 consistently.
 


Also applies to: 200-203, 228-230, 233-235

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @plugins/marketplace-ops/commands/prune.md around lines 10 - 12, The
unlabeled fenced code blocks (for example the snippet containing
"/marketplace-ops:prune [--dry-run]") must include a language tag (e.g., bash or text) to satisfy markdownlint MD040; update each opening tobash
(or ```text for plain output blocks) for the affected fences and apply the same
change to the other unlabeled blocks mentioned (around the sections containing
the command examples at the later ranges) so all code fences are consistently
labeled.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @plugins/marketplace-ops/commands/prune-update.md:

  • Around line 38-52: When collecting /save <path> directives from issue and
    review comments, only accept and persist paths into .pruneprotect if the
    commenter is a trusted repository participant: for each matched commenter call
    the GitHub collaborators/permission API (e.g., GET
    /repos/{owner}/{repo}/collaborators/{username}/permission via gh api) and verify
    their permission/association is one of OWNER, MEMBER or COLLABORATOR (or matches
    an explicit allowlist); ignore and log any /save from other associations and
    do not write those paths to .pruneprotect. Ensure deduplication still runs only
    on the filtered list and add a clear message when untrusted directives are
    skipped.

In @plugins/marketplace-ops/commands/prune.md:

  • Around line 136-138: The current branch naming in prune.md uses a date-only
    suffix (prune/$(date +%Y%m%d)) which can collide on multiple runs the same day;
    change the branch name generation to include a high-resolution timestamp or
    unique token (for example append hours/minutes/seconds or epoch seconds) so each
    run produces a unique branch name — update the git checkout -b branch creation
    example in prune.md to use date with time (e.g., include %H%M%S or %s) or a
    random suffix to avoid collisions.

In @plugins/marketplace-ops/scripts/score-items.py:

  • Around line 56-61: The git(...) helper currently swallows failures by
    returning empty stdout even when git returns a non-zero exit code; update the
    subprocess.run call in git to fail fast: use check=True (or inspect
    result.returncode) and raise an exception that includes result.stderr (and
    stdout) so callers won't continue with empty data; also catch and re-raise a
    clearer error for subprocess.TimeoutExpired with context. Ensure the error
    message references the repo_root and the git args for easier debugging.
  • Around line 49-53: The is_protected function overmatches because it uses raw
    startswith; change it to perform segment-safe matching: for each prefix in the
    protected list, normalize both path and prefix (remove trailing slashes), split
    each into segments and consider the prefix a match only if the path segments
    start with the exact sequence of prefix segments (or the normalized path equals
    the normalized prefix). Update the is_protected function to use these normalized
    segment comparisons (referencing is_protected, path, and protected) so sibling
    paths like plugins/foo do not match plugins/foobar.
  • Around line 130-141: The scoring logic for inactivity (variable days_inactive)
    currently uses strict greater-than comparisons and thus misses exact boundary
    days (90,120,150,180); update the comparisons in the block that adjusts score
    and appends to reasons so each condition uses >= instead of > (preserve the
    existing ordering and increments to score and messages that reference
    days_inactive and the thresholds) to ensure boundary-day commits receive the
    intended score.

In @plugins/marketplace-ops/scripts/score-plugins.py:

  • Around line 55-60: The git() helper currently swallows failures by returning
    empty stdout on errors/timeouts; update git(repo_root, *args) to surface
    failures by using subprocess.run with check=True (or call
    result.check_returncode()) and include stderr in any raised exception, and add a
    try/except to catch TimeoutExpired and re-raise or raise a descriptive error
    including the command, repo_root, timeout, and stderr so callers of git() cannot
    proceed on silent failures.
  • Around line 177-188: The inactivity-tier comparisons currently use strict
    greater-than, so plugins with days_inactive equal to 90,120,150,180 are not
    scored into the higher tier; update the conditions in the scoring block that
    adjusts score and appends to reasons to use greater-than-or-equal (>=) for 90,
    120, 150, and 180 (i.e., change each ">" to ">=" for the comparisons against
    those thresholds for the days_inactive variable where score is incremented and
    reasons appended).
  • Around line 48-52: The current is_protected(path, protected) uses
    path.startswith(prefix) which incorrectly treats sibling prefixes (e.g., "foo"
    vs "foobar") as matches; change the logic to compare normalized,
    trailing-slash-stripped values and only accept exact matches or prefix + '/'
    directory boundaries. Specifically, inside is_protected normalize both values (p
    = path.rstrip('/') and pref = prefix.rstrip('/')) and return True only if p ==
    pref or p.startswith(pref + '/'); keep the same function name is_protected and
    parameters path, protected.

Nitpick comments:
In @plugins/marketplace-ops/commands/prune-update.md:

  • Around line 10-12: Several fenced code blocks in the prune-update docs are
    unlabeled (e.g., the block containing "/marketplace-ops:prune-update [PR number
    or URL]") which triggers MD040; update each unlabeled triple-backtick fence to
    include an appropriate language identifier (bash for shell/CLI examples, text
    for plain output/snippets). Locate the command/example fences (including the
    other similar examples in the file) and change tobash or ```text as
    appropriate so lint no longer flags MD040.

In @plugins/marketplace-ops/commands/prune.md:

  • Around line 10-12: The unlabeled fenced code blocks (for example the snippet
    containing "/marketplace-ops:prune [--dry-run]") must include a language tag
    (e.g., bash or text) to satisfy markdownlint MD040; update each opening
    tobash (or ```text for plain output blocks) for the affected fences and
    apply the same change to the other unlabeled blocks mentioned (around the
    sections containing the command examples at the later ranges) so all code fences
    are consistently labeled.

In @plugins/marketplace-ops/README.md:

  • Around line 21-27: Add a language tag to the fenced code block in the README
    example to satisfy markdownlint MD040: update the opening triple-backtick that
    precedes the block containing "Canonical example plugin" /
    "plugins/hello-world/" to include a language (e.g., change totext or
remains unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b40fb766-2d36-4a5e-bc50-69da31c0759a

📥 Commits

Reviewing files that changed from the base of the PR and between b56bad0 and 1ea6497.

📒 Files selected for processing (10)
  • .claude-plugin/marketplace.json
  • .pruneprotect
  • PLUGINS.md
  • docs/data.json
  • plugins/marketplace-ops/.claude-plugin/plugin.json
  • plugins/marketplace-ops/README.md
  • plugins/marketplace-ops/commands/prune-update.md
  • plugins/marketplace-ops/commands/prune.md
  • plugins/marketplace-ops/scripts/score-items.py
  • plugins/marketplace-ops/scripts/score-plugins.py

Comment thread plugins/marketplace-ops/commands/prune-update.md Outdated
Comment thread plugins/marketplace-ops/commands/prune.md
Comment thread plugins/marketplace-ops/scripts/score-items.py
Comment thread plugins/marketplace-ops/scripts/score-items.py
Comment thread plugins/marketplace-ops/scripts/score-items.py Outdated
Comment thread plugins/marketplace-ops/scripts/score-plugins.py
Comment thread plugins/marketplace-ops/scripts/score-plugins.py
Comment thread plugins/marketplace-ops/scripts/score-plugins.py Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
plugins/marketplace-ops/commands/prune.md (1)

136-138: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use a unique prune branch name to avoid same-day collisions.

Line 137 uses a date-only branch suffix, so a second run on the same day can fail on branch creation.

Suggested patch
-git checkout -b prune/$(date +%Y%m%d) main
+git checkout -b "prune/$(date +%Y%m%d-%H%M%S)" main
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/marketplace-ops/commands/prune.md` around lines 136 - 138, The branch
creation snippet using the git command "git checkout -b prune/$(date +%Y%m%d)
main" can collide when run more than once per day; update that command to append
a unique suffix (e.g., a high-resolution timestamp like hours/minutes/seconds or
a random/PID-based token) so the branch name is unique on repeat runs and avoid
same-day collisions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/marketplace-ops/commands/prune.md`:
- Around line 10-12: In plugins/marketplace-ops/commands/prune.md update the
unlabeled fenced code blocks to include a language label (e.g., text or bash)
and avoid nested triple-backtick clashes: change the top snippet containing
"/marketplace-ops:prune [--dry-run]" to use ```text, change the saved paths
snippet containing "/save plugins/foo/" and "/save plugins/bar/commands/baz.md"
to use ~~~text (or otherwise use tildes for the inner block) and update the
PR-body inner fenced snippets that contain "/marketplace-ops:prune --dry-run"
and "/marketplace-ops:prune" to ```text so markdownlint MD040 is satisfied and
the outer bash block rendering is preserved.
- Around line 202-220: Update the PR body placeholders that incorrectly
reference "Step 7": replace the literal placeholder "{paste the table from Step
7}" with "{paste the table from Step 5}", replace "{paste protected list from
Step 7}" with "{paste protected list from Step 5}", and ensure any other
occurrences that point to Step 7 (e.g., the two placeholders at the top and
bottom of the snippet) are changed to reference Step 5 so the artifacts match
the actual production step.

---

Duplicate comments:
In `@plugins/marketplace-ops/commands/prune.md`:
- Around line 136-138: The branch creation snippet using the git command "git
checkout -b prune/$(date +%Y%m%d) main" can collide when run more than once per
day; update that command to append a unique suffix (e.g., a high-resolution
timestamp like hours/minutes/seconds or a random/PID-based token) so the branch
name is unique on repeat runs and avoid same-day collisions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0bb4cdb0-1338-424e-b6e2-acc6e6f4907e

📥 Commits

Reviewing files that changed from the base of the PR and between 1ea6497 and 405bcd3.

📒 Files selected for processing (4)
  • .claude-plugin/marketplace.json
  • docs/data.json
  • plugins/marketplace-ops/.claude-plugin/plugin.json
  • plugins/marketplace-ops/commands/prune.md
✅ Files skipped from review due to trivial changes (1)
  • plugins/marketplace-ops/.claude-plugin/plugin.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • .claude-plugin/marketplace.json

Comment thread plugins/marketplace-ops/commands/prune.md Outdated
Comment thread plugins/marketplace-ops/commands/prune.md Outdated
- Use segment-safe path matching in is_protected() to prevent
  plugins/foo/ from matching plugins/foobar/
- Fail fast on git command errors instead of silently continuing
- Use >= instead of > for inactivity tier thresholds
- Add timestamp to prune branch name to avoid same-day collisions
- Fix step references in PR body template
- Add language labels to fenced code blocks
- Only accept /save from trusted PR participants (OWNER/MEMBER/COLLABORATOR)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@stbenjam stbenjam changed the title feat: add marketplace-ops plugin for pruning stale content [wip] feat: add marketplace-ops plugin for pruning stale content May 5, 2026
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 5, 2026
@enxebre
Copy link
Copy Markdown
Collaborator

enxebre commented May 6, 2026

this is nice! curious if you thought about how would we handle adding /save but then want it to drop it in the same PR?

Adds /drop as the inverse of /save on pruning PRs. Supports two modes:
undoing a previous /save (re-removes files, cleans .pruneprotect) and
manually adding new removals not in the original manifest. Includes
--force flag to override .pruneprotect and last-writer-wins conflict
resolution when both /save and /drop target the same path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@stbenjam stbenjam changed the title [wip] feat: add marketplace-ops plugin for pruning stale content feat: add marketplace-ops plugin for pruning stale content May 6, 2026
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 6, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/marketplace-ops/commands/prune-update.md`:
- Around line 59-60: The parser currently only recognizes `/save <path>` and
`/drop <path>` and must be extended to accept an optional `--force` flag (i.e.,
`/drop --force <path>`); update the directive parsing routine (the function that
matches comment bodies for `/save` and `/drop`) to allow an optional `--force`
token, ensure the extracted directive object includes a boolean `force` field,
and make sure the trusted-author check (author_association in
OWNER/MEMBER/COLLABORATOR) and the warning message logic also handle forced
drops so `--force` directives are actionable; apply the same change to the other
parser occurrences referenced in the spec (the other directive matching sites
mentioned at lines 74-75 and 239-243).
- Around line 120-123: The Markdown file contains unlabeled fenced code blocks
that trigger markdownlint MD040; update each triple-backtick fence in
plugins/marketplace-ops/commands/prune-update.md to include the language tag
"text" (e.g., change ``` to ```text) for the blocks that include the snippet
beginning "# Saved by `@username` on 2026-05-05" and the subsequent table rows
(the blocks showing "| plugin | `plugins/foo/` ..." and the other table lines),
and also apply the same change to the other occurrences called out (around the
blocks at the other ranges noted such as 169-171, 175-177, 181-183, 187-189) so
all unlabeled fences become ```text.
- Around line 49-57: Update the gh api fetches for issue and PR review comments
to include created_at and id in the jq output so comments can be
deterministically ordered; modify the two jq expressions (currently '.[] |
{author: .user.login, association: .author_association, body: .body}') to also
emit .created_at and .id. Then update the explanatory text at the "latest
comment wins" line (referenced near line 66) to state that deduplication uses
created_at (and id as a tiebreaker) to sort comments so the newest comment for a
given path wins.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 693b6ff1-8776-48a4-b363-ddbca45dc429

📥 Commits

Reviewing files that changed from the base of the PR and between 3079286 and 0e59ccd.

📒 Files selected for processing (6)
  • .claude-plugin/marketplace.json
  • PLUGINS.md
  • docs/data.json
  • plugins/marketplace-ops/.claude-plugin/plugin.json
  • plugins/marketplace-ops/commands/prune-update.md
  • plugins/marketplace-ops/commands/prune.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/data.json

Comment thread plugins/marketplace-ops/commands/prune-update.md
Comment thread plugins/marketplace-ops/commands/prune-update.md Outdated
Comment on lines +120 to +123
```
# Saved by @username on 2026-05-05
plugins/foo/
```
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language tags to fenced blocks to satisfy markdownlint (MD040).

Several fenced snippets are unlabeled; adding text preserves rendering and removes lint noise.

Proposed doc patch
-```
+```text
 # Saved by `@username` on 2026-05-05
 plugins/foo/

- +text
| plugin | plugins/foo/ | No commits in 7 months, v0.0.1 |


-```
+```text
| ~~plugin~~ | ~~`plugins/foo/`~~ | ~~SAVED by `@username`~~ |

- +text
| plugin | plugins/foo/ | Dropped by @username |


-```
+```text
| command | `plugins/bar/commands/baz.md` | Manually dropped by `@username` |
</details>

 


Also applies to: 169-171, 175-177, 181-183, 187-189

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.22.1)</summary>

[warning] 120-120: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @plugins/marketplace-ops/commands/prune-update.md around lines 120 - 123, The
Markdown file contains unlabeled fenced code blocks that trigger markdownlint
MD040; update each triple-backtick fence in
plugins/marketplace-ops/commands/prune-update.md to include the language tag
"text" (e.g., change totext) for the blocks that include the snippet
beginning "# Saved by @username on 2026-05-05" and the subsequent table rows
(the blocks showing "| plugin | plugins/foo/ ..." and the other table lines),
and also apply the same change to the other occurrences called out (around the
blocks at the other ranges noted such as 169-171, 175-177, 181-183, 187-189) so
all unlabeled fences become ```text.


</details>

<!-- fingerprinting:phantom:poseidon:hawk -->

<!-- d98c2f50 -->

<!-- This is an auto-generated comment by CodeRabbit -->

@stbenjam
Copy link
Copy Markdown
Member Author

stbenjam commented May 6, 2026

this is nice! curious if you thought about how would we handle adding /save but then want it to drop it in the same PR?

That makes sense to add: #446 (comment)

Add id and created_at to comment API queries for deterministic
ordering, parse optional --force flag on /drop directives, and
clarify last-writer-wins deduplication logic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
plugins/marketplace-ops/commands/prune-update.md (2)

117-128: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language tag to .pruneprotect example (MD040).

The fenced code block at line 121 also lacks a language specifier.

🔧 Proposed fix
 For `/save` items: append each saved path to `.pruneprotect` with a comment indicating who requested the save:

-```
+```text
 # Saved by `@username` on 2026-05-05
 plugins/foo/

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @plugins/marketplace-ops/commands/prune-update.md around lines 117 - 128, The
fenced code block in "Step 7: Update .pruneprotect" is missing a language tag
(MD040); update the example fenced block that shows the .pruneprotect entry by
adding a language identifier (e.g., use ```text) to the opening fence so the
snippet becomes a labeled text block; locate the block under the Step 7 heading
where the example shows "# Saved by @username on 2026-05-05" and "plugins/foo/"
and add the language tag to that fenced code block.


</details>

---

`161-195`: _⚠️ Potential issue_ | _🟡 Minor_ | _⚡ Quick win_

**Add language tags to fenced code blocks (MD040).**

The fenced code blocks at lines 170, 176, 182, and 188 lack language specifiers, triggering markdownlint MD040 warnings. This is the same issue raised in previous reviews but not yet addressed.





<details>
<summary>🔧 Proposed fix</summary>

```diff
 **For `/save` paths:** In the removal manifest table, find the rows for saved paths and apply strikethrough with a `[SAVED]` tag. For example, change:

-```
+```text
 | plugin | `plugins/foo/` | No commits in 7 months, v0.0.1 |
 ```

 To:

-```
+```text
 | ~~plugin~~ | ~~`plugins/foo/`~~ | ~~SAVED by `@username`~~ |
 ```

 **For `/drop` paths that undo a save:** Remove the strikethrough and `[SAVED]` tag, restoring the row to its original state with the original reason (if available from git history of the PR body), or use a new reason:

-```
+```text
 | plugin | `plugins/foo/` | Dropped by `@username` |
 ```

 **For new `/drop` paths:** Add a new row to the manifest table:

-```
+```text
 | command | `plugins/bar/commands/baz.md` | Manually dropped by `@username` |
 ```
```

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @plugins/marketplace-ops/commands/prune-update.md around lines 161 - 195, The
markdown examples in Step 10 contain fenced code blocks missing language tags
(MD040); update each example fence (the three table examples and the final code
fence around the gh pr edit snippet) to use a language tag such as "text" (i.e.,
change totext) so lint stops flagging MD040—look for the fenced blocks
showing the table rows (the examples with | plugin ... and | plugin ... and
| command ...) and the final ``` block around gh pr edit and add the language
specifier.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @plugins/marketplace-ops/commands/prune-update.md:

  • Around line 85-98: Replace the ambiguous {upstream_remote} placeholder in Step
    5 with a concrete instruction: explain that implementers should set an
    upstream_remote variable (e.g., name it upstream_remote) and show how to
    determine it for their workflow (common values: "upstream" when working from a
    fork, "origin" when working directly in the main repo), then update the git
    checkout example to use that variable (references: upstream_remote and
    base_branch) and add a short note telling users to confirm their remotes with
    git remote -v before running the restore step.

Duplicate comments:
In @plugins/marketplace-ops/commands/prune-update.md:

  • Around line 117-128: The fenced code block in "Step 7: Update .pruneprotect"
    is missing a language tag (MD040); update the example fenced block that shows
    the .pruneprotect entry by adding a language identifier (e.g., use ```text) to
    the opening fence so the snippet becomes a labeled text block; locate the block
    under the Step 7 heading where the example shows "# Saved by @username on
    2026-05-05" and "plugins/foo/" and add the language tag to that fenced code
    block.
  • Around line 161-195: The markdown examples in Step 10 contain fenced code
    blocks missing language tags (MD040); update each example fence (the three table
    examples and the final code fence around the gh pr edit snippet) to use a
    language tag such as "text" (i.e., change totext) so lint stops flagging
    MD040—look for the fenced blocks showing the table rows (the examples with |
    plugin ... and | plugin ... and | command ...) and the final ``` block
    around gh pr edit and add the language specifier.

</details>

<details>
<summary>🪄 Autofix (Beta)</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Path: .coderabbit.yaml

**Review profile**: CHILL

**Plan**: Enterprise

**Run ID**: `27a88e00-56c4-443a-beae-50e2a5d8574f`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 0e59ccddcadce5cc57ebe601afee7f0131b399f7 and 7e047a675e219fb750db39b030fee7504dc9bc67.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `plugins/marketplace-ops/commands/prune-update.md`

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread plugins/marketplace-ops/commands/prune-update.md
Copy link
Copy Markdown
Contributor

@bryan-cox bryan-cox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label May 6, 2026
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 6, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: bryan-cox, stbenjam

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot openshift-merge-bot Bot merged commit a8a4ee3 into openshift-eng:main May 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants