chore: address Copilot review round 6

- verify-skills: the best-effort `plugin validate` hand-off now also requires
  the EXACT pinned CLI. `local:gate` runs `validate` before the pinned
  `verify:skills:cli` step, so a newer local CLI could reject skills that CI's
  pinned validator accepts — and the gate would exit there, never reaching the
  reproducible check. One schema everywhere, or none.
- Dropped `PLUGIN_VALIDATE_MIN_VERSION`: with both validators on the exact pin
  it was read only by its own test, and a constant nothing enforces is a claim
  nothing enforces. Its test now pins what actually matters — that equality is
  distinguishable from newer as well as older.
- The CI step's comment described the old floor behavior.
- issue-create: the duplicate check searched only open issues, so a completed or
  rejected match was invisible to a procedure that says never to duplicate.
  Searches all states and reports state/stateReason.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-29 02:15:02 -04:00
commit c3c8a33e2c
2 changed files with 46 additions and 35 deletions

View file

@ -237,9 +237,6 @@ export function validateEvalCases(skillName, cases) {
*/
export const PINNED_CLI_VERSION = "2.1.250";
/** First Claude Code release with `claude plugin validate`. */
export const PLUGIN_VALIDATE_MIN_VERSION = [2, 1, 233];
/**
* Read a semver triple out of `claude --version` output ("2.1.250 (Claude Code)").
*

View file

@ -13,7 +13,7 @@ import {
listingCost,
parseClaudeVersion,
compareVersions,
PLUGIN_VALIDATE_MIN_VERSION,
PINNED_CLI_VERSION,
} from "./skill-manifest.mjs";
const fm = (body) => `---\n${body}\n---\n\n# Body\n`;
@ -208,16 +208,18 @@ test("parseClaudeVersion reads the CLI's version banner", () => {
assert.equal(parseClaudeVersion("no version here"), null);
});
test("compareVersions orders the plugin-validate floor correctly", () => {
// An older CLI has no `plugin validate` and exits nonzero on it as an unknown
// command; failing the mandatory gate for that would be wrong, so the probe
// must skip below the floor rather than run and fail.
assert.ok(compareVersions([2, 1, 232], PLUGIN_VALIDATE_MIN_VERSION) < 0);
assert.equal(compareVersions([2, 1, 233], PLUGIN_VALIDATE_MIN_VERSION), 0);
assert.ok(compareVersions([2, 1, 250], PLUGIN_VALIDATE_MIN_VERSION) > 0);
assert.ok(compareVersions([2, 2, 0], PLUGIN_VALIDATE_MIN_VERSION) > 0);
assert.ok(compareVersions([3], PLUGIN_VALIDATE_MIN_VERSION) > 0);
assert.ok(compareVersions([1, 9, 999], PLUGIN_VALIDATE_MIN_VERSION) < 0);
test("compareVersions can decide exact equality with the pin", () => {
// Both validators require the EXACT pinned version, so what matters is that
// "equal" is distinguishable from newer as well as older — a floor would let a
// newer local CLI validate against a different schema than CI's.
const pin = parseClaudeVersion(PINNED_CLI_VERSION);
assert.equal(compareVersions(pin, pin), 0);
assert.ok(compareVersions([pin[0], pin[1], pin[2] - 1], pin) < 0);
assert.ok(compareVersions([pin[0], pin[1], pin[2] + 1], pin) > 0);
assert.ok(compareVersions([pin[0] + 1, 0, 0], pin) > 0);
// Shorter and longer triples still order sanely.
assert.ok(compareVersions([pin[0]], pin) < 0);
assert.equal(compareVersions([...pin, 0], pin), 0);
});
test("the listing-entry cap covers description AND when_to_use together", () => {