diff --git a/.github/workflows/external-plugin-command-router.yml b/.github/workflows/external-plugin-command-router.yml index e616b1c5..e5680c2e 100644 --- a/.github/workflows/external-plugin-command-router.yml +++ b/.github/workflows/external-plugin-command-router.yml @@ -298,7 +298,7 @@ jobs: }, 'rejected': { color: 'B60205', - description: 'Submission was rejected or failed intake validation' + description: 'Submission was rejected by a maintainer' } }; @@ -461,7 +461,7 @@ jobs: }, 'rejected': { color: 'B60205', - description: 'Submission was rejected or failed intake validation' + description: 'Submission was rejected by a maintainer' } }; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c0cf9b2..23233906 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -229,13 +229,13 @@ The public-submission policy builds on those rules and also requires `license` p ##### Review workflow 1. **Open an issue** using the external plugin issue form. Automation applies the `external-plugin` and `awaiting-review` labels. -2. **Automated intake validation** checks that the required fields are present and correctly formatted for a GitHub-hosted plugin. Invalid submissions are closed with a comment explaining what must be fixed before resubmitting. +2. **Automated intake validation** checks that the required fields are present and correctly formatted for a GitHub-hosted plugin. Invalid submissions are labeled `requires-submitter-fixes` with a comment explaining what must be fixed before maintainer review. 3. **Automated quality gates** run after metadata validation: - `skill-validator check --plugin` against the submitted plugin path/ref/sha - install smoke test via Copilot CLI against an ephemeral marketplace entry generated from the submission 4. **Ready for maintainer review**: if metadata validation and quality gates pass, automation removes `awaiting-review` and adds `ready-for-review`. 5. **Submitter-fix blocker**: if metadata is valid but quality gates fail, automation applies `requires-submitter-fixes` instead of advancing to human review. -6. **Requesting another intake pass**: after updating the issue body or source plugin, the issue author or a maintainer can comment `/rerun-intake` to re-run automated intake and quality gates on demand. Open issues still re-trigger intake automatically on edit, but closed rejected issues need `/rerun-intake`. When the rerun is accepted, automation reacts to the command comment with 👀 so it is visible that processing started. +6. **Requesting another intake pass**: after updating the issue body or source plugin, the issue author or a maintainer can comment `/rerun-intake` to re-run automated intake and quality gates on demand. Open issues re-trigger intake automatically on edit; closed maintainer-rejected issues need `/rerun-intake`. When the rerun is accepted, automation reacts to the command comment with 👀 so it is visible that processing started. 7. **Maintainer override path**: a maintainer with write access can comment `/mark-ready-for-review [optional reason]` to explicitly move a `requires-submitter-fixes` issue to `ready-for-review`. 8. **Maintainer decision**: once in `ready-for-review`, a maintainer with write access performs the manual review, then comments `/approve` or `/reject ` on the issue. Commands from non-maintainers are ignored. 9. **Approval path**: on `/approve`, automation removes `ready-for-review`, adds `approved`, closes the issue, and opens or updates a PR against `staged` that updates `plugins/external.json` and generated marketplace outputs. @@ -256,7 +256,7 @@ Maintainers are responsible for confirming that the submission: - `external-plugin`: applied to every public external plugin submission and retained on approved issues so scheduled review automation can find them later - `awaiting-review`: initial intake state before automation finishes validating the issue - `ready-for-review`: the issue passed automated intake checks and is waiting on a maintainer decision -- `requires-submitter-fixes`: metadata validation passed but automated quality gates failed; submitter updates are required before human review +- `requires-submitter-fixes`: automated intake found metadata or quality-gate issues; submitter updates are required before human review - `approved`: the issue was approved, closed, and can be used as the source of truth for six-month re-review - `rejected`: the issue was rejected and closed without being added to the marketplace - `re-review-due`: the approved issue reached the six-month review threshold and is waiting on a maintainer re-review decision diff --git a/eng/external-plugin-intake-state.mjs b/eng/external-plugin-intake-state.mjs index 9a43c764..2f7a09e9 100644 --- a/eng/external-plugin-intake-state.mjs +++ b/eng/external-plugin-intake-state.mjs @@ -21,7 +21,7 @@ export const EXTERNAL_PLUGIN_INTAKE_LABELS = Object.freeze({ }, rejected: { color: "B60205", - description: "Submission was rejected or failed intake validation", + description: "Submission was rejected by a maintainer", }, }); @@ -143,7 +143,7 @@ export async function applyExternalPluginIntakeEvaluation({ issueNumber, evaluation, }) { - const state = evaluation.intakeState ?? (evaluation.valid ? "ready-for-review" : "rejected"); + const state = evaluation.intakeState ?? (evaluation.valid ? "ready-for-review" : "requires-submitter-fixes"); const desiredLabelsByState = { "ready-for-review": new Set(["external-plugin", "ready-for-review"]), "requires-submitter-fixes": new Set(["external-plugin", "requires-submitter-fixes"]), diff --git a/eng/external-plugin-intake.mjs b/eng/external-plugin-intake.mjs index b767082b..ade914ec 100644 --- a/eng/external-plugin-intake.mjs +++ b/eng/external-plugin-intake.mjs @@ -492,7 +492,7 @@ function buildQualityGatesCommentSection(qualityResult) { function getIntakeStateFromQualityResult(baseResult, qualityResult) { if (!baseResult.valid) { - return "rejected"; + return "requires-submitter-fixes"; } if (qualityResult.failure_class === "submitter_fixes") { @@ -647,10 +647,10 @@ export async function evaluateExternalPluginIssue({ issue, token, runId, owner, ].join("\n") : [ marker, - "## ❌ External plugin intake failed", + "## ⚠️ External plugin intake requires submitter fixes", "", - "This submission did not pass automated intake validation, so the issue has been closed.", - `Edit the issue form to address the fixes below, then have the issue author or a maintainer comment \`${RERUN_INTAKE_COMMAND}\` to re-run intake for this closed submission.`, + "This submission did not pass automated intake validation and cannot move to maintainer review yet.", + `Edit the issue form to address the fixes below. Intake reruns automatically when the issue is edited, or the issue author/maintainer can comment \`${RERUN_INTAKE_COMMAND}\` to re-run on demand.`, "", "### Required fixes", "", @@ -663,7 +663,7 @@ export async function evaluateExternalPluginIssue({ issue, token, runId, owner, return { valid, - intakeState: valid ? "ready-for-review" : "rejected", + intakeState: valid ? "ready-for-review" : "requires-submitter-fixes", markerPresent: parsed.markerPresent, errors: dedupedErrors, warnings: dedupedWarnings,