Skip to content

fix: link a PR to its issue on any #N reference, not just closing keywords (#652) - #679

Merged
johanzander merged 2 commits into
mainfrom
fix/issue-652-backlog-digest-link-any-ref
Aug 22, 2026
Merged

fix: link a PR to its issue on any #N reference, not just closing keywords (#652)#679
johanzander merged 2 commits into
mainfrom
fix/issue-652-backlog-digest-link-any-ref

Conversation

@johanzander

Copy link
Copy Markdown
Owner

Summary

  • The backlog digest now links an open PR to its issue on any #N body reference, not just closing keywords (fixes/closes/resolves/refs #N). A no-auto-close PR that says "Part of #N", "tracking #N", or a bare #N is visible on the board instead of invisible.
  • Documented cross-ref phrases (Blocked by #N, Depends on, Unblocks/Unblocking, Related to, Relationship to, See/See also, Not part of) are phrase-stripped before matching, so a PR that merely names another issue never links to it.
  • The merged-PR scan uses work verbs only (fixes/closes/resolves/refs/part of/tracking/tracks): a merged intermediate PR keeps its issue In Verification (never re-dispatchable), while a merged PR that names another issue in prose does not flip it. A new merged_prs field exposes every merged work-referencing PR.
  • GitHub's lazily-computed mergeable is re-queried until it leaves UNKNOWN (budget 6, covering the Consolidate PredictionSnapshotStore into the unified per-day DailyView format #490 six-pass measurement) and emitted null when still UNKNOWN.

Root cause

pr_matches_issue in scripts/backlog-digest.sh matched (fixes|closes|resolves|refs) #N only. The no-auto-close rule forbids closing verbs on intermediate PRs — they carry Part of #N / tracking #N / a bare #N — so those PRs resolved to no issue and the issue's column fell through to the live worktree: issue #409 reported In Progress while its approved PR #490 sat open. The merged-PR scan had the same closing-keyword-only blind spot in reverse: narrowing it (during this fix's first pass) flipped #643/#542/#571/#592/#666 from In Verification to Backlog / Ready for Dev on the live board, because their merged PRs (#675/#591/#584/#619/#672) used Refs #N-style references.

Fix

Test plan

Evidence the test discriminates

The RED tests were written first and observed failing on the pre-fix script; the mutations below confirm they still discriminate on the final tree.

Outcome-level coverage

  • none, because this is a bash tooling fix — the outcomes are board columns (In Review / In Verification / Backlog), pinned by the test harness's _gh_shim-driven digest runs above; there is no optimizer/execution model involved.

Refs #652

johanzander and others added 2 commits August 22, 2026 15:48
…words (#652)

The digest linked an open PR to its issue only when the PR body used a
closing keyword (fixes/closes/resolves/refs #N). The no-auto-close rule
forbids those on intermediate PRs -- they say "Part of #N", "tracking #N",
or a bare "#N" -- so such a PR was invisible: issue #409 reported In
Progress while its approved PR (#490) sat open. Linkage now matches any #N
reference, with documented cross-ref phrases (Blocked by, Depends on,
Unblocks, Related to, Relationship to, See also, See, Not part of) stripped
first so they never link.

The merged-PR scan is deliberately narrower (work verbs: fixes/closes/
resolves/refs/part of/tracking/tracks): a merged intermediate PR keeps its
issue In Verification (a narrowed scan had flipped #643/#542/#571/#592/#666
back to Backlog/Ready for Dev on the live board), while a merged PR that
merely names another issue in prose does not. mergeable is re-queried until
it leaves UNKNOWN (budget 6) and emitted null if it never resolves.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@bess-agent

Copy link
Copy Markdown
Collaborator

@claude-bot review

@bess-manager-claude-bot bess-manager-claude-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verdict: APPROVE

Matches linked issue's root cause (#652): Yes, exactly. #652 diagnosed two independent defects and prescribed both fixes verbatim:

  1. pr_matches_issue matched only (fixes|closes|resolves) #N, which the no-auto-close convention forbids on intermediate PRs — so a "Part of #409" PR resolved to no issue and #409's column fell through to the live-worktree branch, reporting In Progress for an approved, mergeable PR.
  2. mergeable: UNKNOWN (GitHub's lazily-computed first-query value) was passed through as if final.

scripts/backlog-digest.sh's new linkage_body/pr_matches_issue (any #N, with documented cross-ref phrases like Blocked by/Related to/Unblocks stripped first) and the bounded MERGE_RETRY_LIMIT/MERGE_RETRY_SLEEP re-query loop implement exactly what #652's "Proposed fix" section asked for. The widened merged-PR regex (fixes|closes|resolves|refs|part of|tracking|tracks, still deliberately excluding bare #N) fixes a real regression the PR's own root-cause section documents was introduced mid-fix (narrowing it flipped #643/#542/#571/#592/#666 off In Verification on the live board) — same underlying defect class as #652, not unrelated scope.

Would the tests catch a regression? Yes, verified independently, not just taken on the PR's word. I checked out the branch, ran the full test_backlog_digest.py suite (68 passed), then mutated pr_matches_issue back to the pre-fix closing-keyword-only regex and re-ran: test_a_bare_number_reference_links_a_pr_to_its_issue, test_a_blocked_by_side_reference_still_links_the_prs_own_issue, and one other failed as expected (3 failed / 65 passed), then restored to green. The tests assert board-visible outcomes (item[\"column\"], item[\"prs\"], orphan lists) rather than jq internals, consistent with docs/agents/testing.md. I also hand-traced the linkage_body regex against every parametrized non-work-reference case (Related to, Unrelated to, Unblocks/Unblocking, See/See also, Not part of) and the boundary regex (#2409 vs issue 409, #4095 vs issue 409) — all correct, including the accidental-but-correct substring behavior on Unrelated to #900.

Minimal / no scope creep: Yes. Three files touched (CHANGELOG.md, the script, its test file), all load-bearing for #652. The new merged_prs (plural) field is the one piece not explicitly asked for in #652, but it falls directly out of widening the merged-PR regex to work-verb spellings (now multiple merged PRs can legitimately match one issue) and is cheap, tested, additive visibility data — not a separate feature.

Rule violations: None found. No Python/API-layer/architecture rules apply (pure bash/jq + test file). No secrets, no injection vectors, no new classes. mergeable's null-on-still-UNKNOWN change doesn't affect backlog-rhythm.sh, which queries mergeable independently via its own gh pr view call and never reads the digest's prs[].mergeable field — confirmed by grep.

Minor observation (non-blocking): The PR description doesn't include an explicit "local fix / structural fix / escalated" scope-assessment line per rules.md Debugging Protocol step 9. I judged this a local fix — confined to one script's existing linkage/merge-scan responsibilities, no new cross-module ownership — so I'm not treating the missing statement as a blocker, but flagging it since the checklist calls for it explicitly.

CI: all checks green (Fast tests, E2E, Docker build, Frontend, Code quality, Merge gate; Algorithm tests skipped as expected for this diff).

@johanzander
johanzander marked this pull request as ready for review August 22, 2026 14:05
@johanzander
johanzander merged commit 064e7f3 into main Aug 22, 2026
8 checks passed
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