chore: address Copilot review round 2
- verify-skills: version-gate the optional `claude plugin validate`. Probing
only for the executable failed the MANDATORY gate for anyone on a CLI older
than 2.1.233, which has no such subcommand and exits nonzero on it. Skips
below the floor; a failure now means a supported validator rejected the skills.
- skill-eval: match the invoked skill structurally. A substring test counted
`{"skill":"not-testing"}` as a hit for `testing` and inflated the rate.
- skill-eval: `runOnce` → exported `runPrompt` with an injectable `spawnFn`, so
the nonzero-exit branch is actually pinned. Reverting it now fails a test
(verified by mutation) rather than leaving the suite green.
- board-ops: filter the item lookups by repository. Issue numbers are repo-local
and these are org boards — #11 really does carry a `servers` card — so an
unfiltered `select` can move or delete the wrong card, or pass two ids.
- issue-triage: the audit's `own()` filter dropped draft cards, which carry no
`.content.repository`, so the "non-Issue on a board" check reported 0 while
the invariant was being violated. Verified against a fixture.
- pr-flow: cut the branch from the base it will target. The blanket "cut from
v2/main" was wrong for v1, whose history is unrelated.
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
4520e6aa2c
commit
ca6828916f
3 changed files with 221 additions and 17 deletions
|
|
@ -128,9 +128,16 @@ above the board's item count (~265 as of 2026-08-01) — past it `item-list`
|
|||
truncates **silently**, `select` matches nothing, and `item-edit --id ""` fails
|
||||
with an opaque node-resolution error rather than saying the limit was too low.
|
||||
|
||||
⚠️ **Filter by repository, not by number alone.** These are **org** projects and
|
||||
issue numbers are **repo-local**, so an unfiltered `select` can match another
|
||||
repo's issue that happens to share the number — board #11 really does carry a
|
||||
`modelcontextprotocol/servers` card — and then moves or deletes the wrong card,
|
||||
or passes two ids at once (Copilot).
|
||||
|
||||
```sh
|
||||
ITEM_ID=$(gh project item-list 28 --owner modelcontextprotocol --format json --limit 500 \
|
||||
--jq '.items[] | select(.content.number==<ISSUE_NUMBER>) | .id')
|
||||
--jq '.items[] | select(.content.repository=="modelcontextprotocol/inspector"
|
||||
and .content.number==<ISSUE_NUMBER>) | .id')
|
||||
# e.g. Status → In Review, when its PR opens
|
||||
gh project item-edit --project-id PVT_kwDOCt2Azc4BJVxt --id "$ITEM_ID" \
|
||||
--field-id PVTSSF_lADOCt2Azc4BJVxtzg5iI8c --single-select-option-id 159c8a02
|
||||
|
|
@ -144,7 +151,8 @@ not parked in Done:
|
|||
|
||||
```sh
|
||||
ITEM_ID=$(gh project item-list 28 --owner modelcontextprotocol --format json --limit 500 \
|
||||
--jq '.items[] | select(.content.number==<ISSUE_NUMBER>) | .id')
|
||||
--jq '.items[] | select(.content.repository=="modelcontextprotocol/inspector"
|
||||
and .content.number==<ISSUE_NUMBER>) | .id')
|
||||
gh project item-delete 28 --owner modelcontextprotocol --id "$ITEM_ID"
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -219,7 +219,10 @@ for P in 28 11; do gh project item-list $P --owner modelcontextprotocol \
|
|||
jq -nr --slurpfile o "$D/i.json" --slurpfile a "$D/b28.json" --slurpfile b "$D/b11.json" --arg R "$R" '
|
||||
($o[0] | map({key:(.number|tostring), value:{st:.state, sr:(.stateReason // ""),
|
||||
lab:[.labels[].name], ms:(.milestone.title // null)}}) | from_entries) as $M
|
||||
| def own($s): [$s[].items[] | select(.content.repository==$R)];
|
||||
| def own($s): [$s[].items[]
|
||||
# A DRAFT card has no `.content.repository`, so filtering on equality
|
||||
# alone drops the very items the "non-Issue" check exists to find.
|
||||
| select((.content.repository // null) == null or .content.repository==$R)];
|
||||
def I($n): ($M[($n|tostring)] // null);
|
||||
def ms($n): (I($n).ms // null);
|
||||
def lab($n): (I($n).lab // []);
|
||||
|
|
@ -268,6 +271,11 @@ Two things the queries must account for, both learned the hard way:
|
|||
one*, so a predicate that only asks "is any version label present" passes an
|
||||
issue carrying **both** `v1` and `v2` — which belongs to two lines at once
|
||||
and shows up in both filtered queries. Same for the five type labels (Copilot).
|
||||
- **Keep drafts inside `own`.** A draft card carries no `.content.repository`,
|
||||
so a plain equality filter removes it before the "non-Issue" check can see it —
|
||||
and that check then reports `0` while the invariant it states (no drafts) is
|
||||
being violated (Copilot). The filter admits an item with no repository and
|
||||
excludes only cards that name a *different* one.
|
||||
- **Only open issues have a `$I` entry.** A closed issue still has a card
|
||||
(correctly, in `Done`), so a check that treats "no milestone found" as a
|
||||
violation must gate on `isopen(.n)` or it flags every closed card.
|
||||
|
|
|
|||
|
|
@ -38,8 +38,11 @@ Not `fix/oauth-resource-metadata`. This keeps the two lines legible in
|
|||
`git branch -a` and in the PR list once v1 and v2 branches coexist on the same
|
||||
remote, and it matches the base branches themselves (`v2/main`, `v1/main`).
|
||||
|
||||
**Cut the branch from `v2/main`**, never from a milestone-merge branch — the
|
||||
latter carries release-only commits that will show up in your PR's diff.
|
||||
**Cut the branch from the base it will target** — `v2/main` for v2 work,
|
||||
`v1/main` for v1. The two lines have unrelated histories, so a `v1/fix/…`
|
||||
branch cut from `v2/main` arrives at `v1/main` carrying the whole v2 tree
|
||||
(Copilot). And never cut from a milestone-merge branch — it carries release-only
|
||||
commits that will show up in your PR's diff.
|
||||
|
||||
Working in a git worktree is fine and often preferable. ⚠️ **A worktree needs a
|
||||
real `npm install`, not a symlinked `node_modules`** — a symlink passes
|
||||
|
|
|
|||
Loading…
Reference in a new issue