Skip to content

fix: idd-issue baseline-tag guard and exact label lookup; idd-update blank-line splice (#411, #412, #413) - #442

Open
kiki830621 wants to merge 7 commits into
mainfrom
idd/cluster-411-412-413
Open

kiki830621 wants to merge 7 commits into
mainfrom
idd/cluster-411-412-413

Conversation

@kiki830621

@kiki830621 kiki830621 commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Refs #411
Refs #412
Refs #413

Summary

Three Simple-tier bugs from the 2026-10-26 batch, in one cluster PR (the maintainer asked for one PR per batch, the #374 decision). #411 and #412 are in idd-issue; #413 is in idd-update.

  • idd-issue: Step 3.6 baseline tag 未檢查 issue 號非空,建立失敗時會推出 idd--baseline #412 — idd-issue no longer tags idd--baseline when the issue was not created. Step 3.A captures the URL from gh-egress.sh, checks that it ends in an issue number, and stops otherwise. It also sets NEW_ISSUE_NUMBER, which Step 4.6 reads, and says "the issue may exist" when a URL was printed with a non-zero exit, so it is not retried into a duplicate. Step 3.6 tags only a numeric number and prints a graceful-skip reason otherwise.
  • idd-issue: label_exists() 用 --search 判斷存在,短 label 名稱(如 P0)查不到 #411 — label_exists() finds labels that exist. It is now an exact REST lookup (repos/$GITHUB_REPO/labels/<encoded>) instead of gh label list --search … | grep -qx, which missed labels outside the 30 best matches, read the name as a regex and is GraphQL (blocked in cloud sessions). A failed lookup returns 2 with gh's message instead of "missing". Step 3.5 (b) uses $GITHUB_REPO instead of the bare repo name.
  • idd-update Branch B 在正文結尾沒有空行時寫出 setext 標題,使上一節無法就地更正 #413 — idd-update never writes a setext heading above Current Status. Step 5 has one executable splice for both branches. It strips the body's trailing newlines and joins with one blank line. It reads the body itself, in the same call, and sends it through gh-egress.sh there too. The ## Current Status anchor follows CommonMark fences. Branch A also repairs the 23 bodies an older Branch B wrote as setext; that blank line is the one stated exception to the managed-zone rule (maintainer decision 2026-10-26).

No version bump: PR #426 and #424 both claim 3.6.0 and PR #418 claims 3.5.1, so the CHANGELOG entry is under [Unreleased].

Fixed before merge (verify)

Two independent reviewers (requirements + logic; security + regression + devil's advocate), Claude-only. Reports: #411 Verify(cluster 報告);#412、#413 有指向它的 pointer。

  • Blocking, fixed: the first version of the splice used a BODY nothing in the block assigned. If it was lost between Bash calls, the issue was overwritten with the status block alone; this was confirmed through the real gh-egress.sh. The block now reads the body via REST and stops when the read fails.
  • Fences: ``` and ~~~, fence length, info string. An unclosed trailing fence no longer grows one Current Status block per run (idd-close 的 checklist gate 對 Spectra path 永遠 fallback 掃 Strategy——那些 checkbox 沒有任何一步會勾 #290).
  • label_exists refuses ./.. and empty path parts. TAG is safe under set -u. A CR is stripped from the URL. Safeguard 1 uses exit 1.
  • Tests were strengthened after mutation testing. Every new suite fails on origin/main.

Test plan

  • New suites: baseline-tag-guard (40), label-exists (40), idd-update-splice (91). Each runs the changed SKILL.md blocks against stubs, with positive controls.
  • bash plugins/issue-driven-dev/scripts/run-all-tests.sh: 66 suites, 63 pass. The 3 failures are environment-only and also fail on origin/main under the same conditions: idd-repo-map and idd-tree-lock (run as root), verify-scratch-paths (checkout under /tmp).
  • Splice run over all 337 real issue bodies (read-only): setext above Current Status 23 → 0, idempotent on a second run, no lines lost.
  • Codex cross-model verify was not run (cloud session); run /idd-verify --pr <this PR> locally before merging.

After merge: /idd-close 411 412 413.

https://claude.ai/code/session_01PJZJ8sbcVVqqLngBfkGNUq


Generated by Claude Code

…dd--baseline (#412)

Step 3.A now captures the URL from gh-egress, checks that it ends in an
issue number, and stops when it does not: every failure (gh's error, a
missing label, a gate refusal at exit 10-15) leaves stdout empty, and an
unchecked capture used to carry an empty NUMBER into Step 3.6. It also
sets NEW_ISSUE_NUMBER, the name Step 4.6 reads.

Step 3.6 tags only a numeric NUMBER and otherwise prints a graceful-skip
reason, so an empty number can no longer tag and push idd--baseline (and
hide later failures behind "already exists").

New suite baseline-tag-guard runs both snippets out of SKILL.md against a
stub gh-egress and a temp repo with a bare remote, with a positive control
that neutralises the guard.

Refs #412

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJZJ8sbcVVqqLngBfkGNUq
`gh label list --search "$1" | grep -qx "$1"` answered "missing" for
labels that exist: the search is best-match and capped at 30 results,
`gh label list` is GraphQL (blocked in cloud sessions), and grep read
the name as a pattern ([RFC], -wip). It also queried $REPO, which Step
2.6 sets to the bare repo name.

label_exists() now GETs repos/$GITHUB_REPO/labels/<encoded name> (exit 0
exists, 1 missing on 404, 2 when the lookup itself failed, with gh's
message), refuses `.`/`..` (which resolve to the list endpoint), and
Step 3.5 (b) uses $GITHUB_REPO throughout.

New suite label-exists runs the function out of SKILL.md against a stub
gh, with a control that shows the old probe missing P0 on the same stub.

Refs #411

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJZJ8sbcVVqqLngBfkGNUq
…t heading (#413)

Branch B appended `\n---\n\n## Current Status…`; a body ending without a
newline (common for GitHub-edited bodies, and every body read through
`$(...)`) put its last line directly on the `---`, which CommonMark reads
as a setext h2, and /idd-edit --correct then refused that section.

Step 5 now has one executable splice for both branches: strip the
body's trailing newlines, join with exactly one blank line before the
`---` block from Step 4. Branch A drops the `---` right above
`## Current Status` before the same join, so the 23 bodies an older
Branch B wrote as setext are repaired on their next update (maintainer
decision 2026-10-26; the iron rule names this one exception). The block
refuses to run with an empty NEW_STATUS.

New suite idd-update-splice runs the splice out of SKILL.md and parses
the result with the pinned markdown-it-py, across trailing-newline, CRLF,
footer, list, table, fence and Branch A shapes.

Refs #413

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJZJ8sbcVVqqLngBfkGNUq
Version left to the merge: PR #426 and #424 both claim 3.6.0, PR #418
claims 3.5.1.

Refs #411, #412, #413

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJZJ8sbcVVqqLngBfkGNUq
…, label path parts (#411, #412, #413)

Adversarial review of the cluster branch:

- idd-update Step 5 (blocking): the splice spliced a BODY nothing in
  the block assigned; lost between Bash calls, it was empty, and the
  issue was overwritten with the status block alone (confirmed through
  the real gh-egress). The block now checks NUMBER and GITHUB_REPO,
  reads the body itself via REST and stops when the read fails.
- The Current Status anchor follows CommonMark fences (``` and ~~~,
  length, indent, info string), and an unclosed trailing fence reuses
  the status an earlier run appended (#290 grew one block per run).
- label_exists refuses names with a `.`/`..` path part (a proxy that
  decodes %2F normalised ./bug to bug).
- Step 3.A says "the issue may exist" when a URL was printed with a
  non-zero exit, so it is not retried into a duplicate.
- CHANGELOG states the behaviour changes: case-insensitive labels,
  group mode skipping the baseline tag until #438, fenced anchors.

Refs #411, #412, #413

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJZJ8sbcVVqqLngBfkGNUq
Non-blocking points from the requirements/logic review:

- idd-update Step 5 sends the spliced body through gh-egress in the same
  block; UPDATED_BODY does not survive into a second Bash call.
- idd-issue Step 3.6 builds TAG from ${NUMBER:-}, so an unset NUMBER
  under `set -u` still skips gracefully; Step 3.A strips a CR from the
  printed URL; Safeguard 1 says label_exists() must be defined in the
  same call and stops with `exit 1` (a top-level `return 1` errored).
- Tests, strengthened after mutation: the stale-number check reads the
  numbers on exit, the inline-backtick case now fails if the info-string
  rule is dropped, plus first-anchor merging, a lost GITHUB_REPO, the
  sent body, a CR URL and Step 3.6 under `set -u`.

Refs #411, #412, #413

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJZJ8sbcVVqqLngBfkGNUq
Re-check of the cluster: through a proxy that decodes %2F, /bug and bug/
collapse to labels/bug and answered "exists". The "/$1/" check now
refuses any empty part as well as . and ..

Refs #411

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJZJ8sbcVVqqLngBfkGNUq
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants