Skip to content

docs(skills): stop board lookups from trusting item-list --limit - #2452

Merged
cliffhall merged 6 commits into
v2/mainfrom
v2/fix/2451-board-lookup-limits
Sep 23, 2026
Merged

cliffhall merged 6 commits into
v2/mainfrom
v2/fix/2451-board-lookup-limits

Conversation

@cliffhall

Copy link
Copy Markdown
Member

Closes #2451

Problem

gh project item-list --limit N truncates silently. Board #28 now holds 534 items, and the board-ops lookups asked for 500, so a card past that point read as missing. This produced two confidently wrong conclusions in one session: a Done card and all 16 GHSA drafts were reported absent.

What changed

Issue cards are looked up from the issue (board-opsMove an existing card, Delete a card). The lookup queries the issue's projectItems through GraphQL and selects the card by the board's node id. The result no longer depends on board size. It also rules out another repo's issue sharing the number, and a user-owned project that happens to be numbered 28. The || ITEM_ID= guard matters because gh api prints the raw error JSON to stdout on a GraphQL error (a PR number, a rate limit). Without the guard, that error JSON would become a non-empty "id".

Full listings stay full, and prove it. The GHSA draft lookup, the pre-edit snapshot, the recovery dump, and issue-triage's sweep and audit all need the whole board. They now use --limit 2000 and assert .items | length == .totalCount (item-list --format json already returns totalCount). They fail closed:

  • GHSA lookup: reports "incomplete or failed" instead of "no draft card".
  • Snapshot, recovery dump, triage dumps: an incomplete dump is deleted, so the next step fails on the missing file instead of running on partial data.

The same check catches a failed gh call, whose empty output has neither key.

A new short section, Finding a card without trusting --limit, states the rule once. The stale "~265 items" figure is gone, since the assertion replaces the manual check.

Verification

Each recipe was extracted from the edited Markdown and run against the live boards:

Recipe Case Result
GHSA lookup Real advisory id Found the draft's item id
GHSA lookup --limit 100 Reported incomplete, drew no conclusion
GHSA lookup Unknown id "no draft card"
Issue-side lookup #2451, #2450 Correct card ids
Issue-side lookup #2444 (a PR), #99999 Empty ITEM_ID plus a message; before the || guard, #99999 put the error JSON into ITEM_ID
Snapshot Live Complete, 534 of 534
Snapshot Truncated Refused
Triage sweep A real rate-limit failure mid-test Deleted both dumps and exited 2
Triage sweep Synthetic dumps (union, filtering) Correct: other-repo and draft cards excluded

Before this change, that same rate-limit failure made the sweep list every open issue as unboarded. npm run local:gate passes.

Not changed: gh issue list --state all --limit 2000 in the audit. That is the same class of problem, but the repo has 1,170 issues, and the lookup in issue-create is --search-filtered.

🤖 Generated with Claude Code

gh project item-list truncates silently past --limit, and board #28 now
holds more than the 500 the lookups asked for, so existing cards read as
missing. Issue cards are now looked up from the issue's projectItems,
which is independent of board size. Draft-card lookups and whole-board
dumps (GHSA lookup, snapshot, recovery, triage sweep and audit) use
--limit 2000 and assert .items|length == .totalCount, failing closed on
a truncated listing or a failed gh call.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall cliffhall added the v2 Issues and PRs for v2 label Sep 23, 2026
@cliffhall
cliffhall requested a balanced review from Copilot September 23, 2026 04:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Moderate issues could permit stale IDs, invalid mutations, successful failure paths, or truncated lookups.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 3 Medium severity

Open (3)
What changed in this PR

Hardens board and triage recipes against silently truncated project listings and unreliable card lookups.

Changes:

  • Adds completeness checks for board dumps.
  • Uses issue-side GraphQL card lookup.
  • Improves GHSA, snapshot, recovery, and triage handling.

Review findings:

  • Moderate (2 votes): Clear stale ITEM_ID values when lookup fails.
  • Moderate (4 votes): Prevent mutations when ITEM_ID is empty.
  • Moderate (2 votes): Snapshot failure guards at lines 283 and 308 must exit non-zero.
  • Moderate (1 vote): Paginate projectItems(first:20) to avoid silent truncation.
File Description
.claude/​skills/​issue-triage/​SKILL.md Validates complete board listings during triage and audits.
.claude/​skills/​board-ops/​SKILL.md Adds safer card lookups and dump validation, with unresolved fail-closed and pagination issues.

Comment thread .claude/skills/board-ops/SKILL.md
Comment thread .claude/skills/board-ops/SKILL.md Outdated
Comment thread .claude/skills/board-ops/SKILL.md Outdated
…#2452 review)

Clear ITEM_ID before the GHSA lookup so a failed listing cannot leave an
earlier id in place; guard item-edit and item-delete on a non-empty id,
and split the issue-side lookup from the Status edit so the delete
recipe does not inherit it; end every dump guard with false so an
incomplete dump returns non-zero; widen projectItems to first:100.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review, round 1: 3 comments, all fixed in eabbfc4. Each thread has its own reply.

  • Stale ITEM_ID after a failed GHSA lookup: fixed. It is now cleared before the listing.
  • item-edit runs on an empty id: fixed. The edit and the delete are both guarded on a non-empty id. The lookup now has its own block, so the delete recipe no longer drags a Status edit along with it.
  • Dump guards exit 0: fixed. Every guard ends with false: the snapshot and recovery dumps here, and both triage dumps.
  • Review body only (1 vote): paginate projectItems(first:20): widened to first:100, the connection's maximum. That connection counts the boards one issue is on, not the cards on a board, so it has no exposure to board size. A cursor loop over it isn't justified.

@cliffhall
cliffhall requested a balanced review from Copilot September 23, 2026 04:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The project #11 recipe can mutate or delete against the wrong project configuration.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Resolved since last review (3)

Comment thread .claude/skills/board-ops/SKILL.md Outdated
…2452 review)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

cliffhall commented Sep 23, 2026

Copy link
Copy Markdown
Member Author

Copilot review, round 2: 1 comment, fixed in 4964bb6. It has a reply in its thread.

  • # 11 recipe mixes a v1 lookup with v2 mutation ids: fixed. The # 11 note now names every id to swap: the node id in both the lookup and --project-id, the Status field, an option id from # 11's table, and item-delete 11.

The 3 round-1 findings show as resolved.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

The recovery recipe’s critical failure path does not reliably stop subsequent steps.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Resolved since last review (1)

Comment thread .claude/skills/board-ops/SKILL.md Outdated
A deleted dump still let the redirect create an empty lost-ids.json, so
the re-apply loop ran zero times and exited 0. lost-ids.json is now
written only inside the completeness check, and step 3 refuses to run
without it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review, round 3: 1 comment, fixed in 68dc5f5. It has a reply in its thread.

  • Recovery continues after a failed dump: fixed. lost-ids.json is written only from a complete dump, and the re-apply step refuses to run without it. The redirect was creating an empty file, so the loop ran zero times and exited 0.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The recovery workflow can retain lost-ids.json after validation failure and permit an unconfirmed mutation.

Review effort: Balanced
Findings: None

Resolved since last review (1)

…iew)

The snapshot is the only record of what the orphaned cards held, and an
incomplete one is now deleted, so step 1 drops lost-ids.json when the
snapshot report cannot run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review, round 4: no inline comments, but the headline raised a concern ("can retain lost-ids.json after validation failure and permit an unconfirmed mutation"). With no thread to reply in, it's answered here. Fixed in 24b1a12.

  • The concern was real. This PR deletes an incomplete snapshot, so the snapshot can now be missing. Step 1 would still keep lost-ids.json from a complete broken-board dump. The "was X" report would then fail, but step 3 re-applied anyway, and that report is the only confirmation of what those cards held. Now, when the report can't run, step 1 drops lost-ids.json and says why, and step 3 refuses to run.
  • Tested with the gh calls stubbed. Missing snapshot: nothing re-applied. Complete: re-applied to the lost card. Truncated dump: stopped at step 1.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Recovery must verify every lost ID before retaining lost-ids.json and reassigning cards.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity

Open (1)

Comment thread .claude/skills/board-ops/SKILL.md
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review, round 5: 1 comment, declined; the reasoning is in its thread.

No actionable findings remain, so the review cycle ends here.

@cliffhall
cliffhall merged commit de44e97 into v2/main Sep 23, 2026
5 checks passed
@cliffhall
cliffhall deleted the v2/fix/2451-board-lookup-limits branch September 23, 2026 05:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

board-ops: card lookups silently miss cards now that board #28 exceeds --limit 500

2 participants