Skip to content

feat(dispatcher): support cross-repo deps in check_deps_resolved (closes #157)#160

Merged
zxkane merged 2 commits into
mainfrom
feat/cross-repo-deps
May 27, 2026
Merged

feat(dispatcher): support cross-repo deps in check_deps_resolved (closes #157)#160
zxkane merged 2 commits into
mainfrom
feat/cross-repo-deps

Conversation

@zxkane
Copy link
Copy Markdown
Owner

@zxkane zxkane commented May 27, 2026

Summary

  • Fix check_deps_resolved two-bug class (feat(dispatcher): support cross-repo dependency references in check_deps_resolved #157): cross-repo owner/repo#N refs were collapsing to bare N queried in the wrong repo, and prose/blockquote #N mentions were greedy-extracted — both ending in the same silent-block-forever path.
  • Restrict extraction to list-item lines only; recognize owner/repo#N (cross-repo) and #N (same-repo) with left-boundary anchors so URL fragments and inline punctuation don't misparse.
  • On lookup failure (empty $state from gh issue view), fail-safe block AND emit a stderr warning naming the failed ref — without that, a typo would silently recreate the original bug class.

Spec & docs

  • Design doc: docs/superpowers/specs/2026-05-27-cross-repo-deps-design.md
  • New invariant: INV-39 — list-item scope, cross-repo support, lookup-failure semantics.
  • Updated invariant: INV-11 cross-references INV-39 (state ∉ {CLOSED, MERGED} rule applies to both same-repo and cross-repo refs).
  • Flow doc: docs/pipeline/dispatcher-flow.md Step 2 description updated.
  • User-facing: skills/create-issue/SKILL.md and references/issue-templates.md document list-item scope + owner/repo#N syntax.

Test plan

  • All existing #61/#73 regression cases continue to pass (no behavior change for bare-#N-on-list-item).
  • Cross-repo owner/repo#N: CLOSED/MERGED → resolved; OPEN → blocked.
  • Same number in two repos resolves independently (#42 OPEN in this repo + other/other#42 CLOSED → resolved).
  • Mixed list items: same-repo CLOSED + cross-repo OPEN → blocked.
  • Prose-embedded #N between headings → ignored (was the silent-block bug).
  • Blockquote > ... owner/repo#N ... → ignored.
  • URL fragment https://github.com/.../issues/123 → ignored.
  • Numbered list (1. / 2.) → extracted correctly.
  • Failed gh issue view (404 / unauthorized) → blocks AND emits stderr warning naming the failed ref.

bash tests/unit/test-check-deps-resolved.sh — 20/20 PASS.
bash tests/unit/test-create-issue-dependencies-guidance.sh — 10/10 PASS.
bash tests/unit/test-lib-dispatch.sh — 21/21 PASS.

Closes #157.

 #157)

`check_deps_resolved` greedy-extracted every `#NNN` between `## Dependencies`
and the next `## ` heading via `grep -oE '#[0-9]+'`, then queried each in
$REPO. Two related bugs fell out:

1. `owner/repo#NNN` cross-repo refs collapsed to bare `NNN` and were looked
   up in the wrong repo. When the lookup failed, `|| true` swallowed the
   error, $state was empty, the != "CLOSED" check was true, and the issue
   was silently blocked forever.
2. The same greedy match swept up `#NNN` tokens inside prose, blockquotes,
   and inline references — same silent-block path.

Fix:
- Restrict extraction to list-item lines (`-`, `*`, `1.`) only.
- Recognize two ref shapes per item: `owner/repo#N` (cross-repo, longer-
  first match-and-strip) and bare `#N` (same-repo). Both require a left
  boundary so URL fragments and inline punctuation don't misparse.
- On lookup failure (empty state from `gh issue view`), fail-safe block
  AND emit a stderr warning naming the failed `<repo>#N`. Without the
  warning, a typo would silently recreate the original bug class.

Documentation:
- New INV-39 in invariants.md with the parsing rule + lookup-failure
  semantics; INV-11 cross-references it.
- dispatcher-flow.md Step 2 updated to reflect list-only + cross-repo.
- create-issue SKILL.md and templates document the user-facing rules.

Tests (tests/unit/test-check-deps-resolved.sh, 20 cases):
- All existing #61/#73 cases still pass.
- Cross-repo CLOSED/MERGED/OPEN; same-repo + cross-repo mixed.
- Same number, different repos resolves independently.
- Prose, blockquote, URL-fragment refs ignored.
- Numbered list extraction.
- Lookup-failure blocks AND emits the stderr warning.
Copy link
Copy Markdown

@amazon-q-developer amazon-q-developer Bot left a comment

Choose a reason for hiding this comment

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

This PR successfully implements cross-repo dependency support and eliminates false positives from prose/blockquotes. The implementation is well-designed and thoroughly tested.

Key strengths:

  • Two-stage parsing correctly restricts to list items only, eliminating false positives from prose/blockquotes
  • Longest-first matching prevents double-counting of owner/repo#N refs
  • Comprehensive test coverage (20/20 tests passing) including cross-repo, mixed dependencies, and edge cases
  • Proper error handling with stderr warnings for lookup failures
  • Documentation updated with new INV-39 invariant and cross-references

Implementation verified:

  • Stage 1 filters to list-item lines only using grep -E '^[[:space:]]*([-*]|[0-9]+\.)[[:space:]]'
  • Stage 2a matches cross-repo refs first with left boundary protection
  • Stage 2b matches bare #N refs on the residue
  • Both stages correctly check state ∉ {CLOSED, MERGED} per INV-11
  • Failed lookups emit observable warnings and block dispatch (fail-safe)

All acceptance criteria from #157 are met. No defects found.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.

…#157)

Address agy review on PR #160:

1. Restore `(` to the left-boundary anchor in both Stage 2a (cross-repo)
   and Stage 2b (bare #N) regexes — `(^|[[:space:]\(])` matches the
   approved spec at docs/superpowers/specs/2026-05-27-cross-repo-deps-design.md.
   Without `(`, parenthesized refs like `- (owner/repo#42)` and `- (#7)`
   were silently ignored.

2. Strengthen the URL-fragment regression test to put the URL on a
   list-item line so Stage 2's boundary logic actually runs (the previous
   prose-only variant was filtered out at Stage 1). Register competing
   OPEN states for the would-be-extracted numbers so a future greedy-
   extraction regression would flip the test to BLOCKED.

3. Add explicit parenthesized-ref tests covering both CLOSED → resolved
   and OPEN → blocked.

INV-39 updated to document the `(`-boundary in both the rule statement
and the regex citation.

Tests: 23/23 PASS in test-check-deps-resolved.sh.
@zxkane
Copy link
Copy Markdown
Owner Author

zxkane commented May 27, 2026

agy review

Verdict: COMMENT (now addressed in 0aaf0df)

Findings

  1. Left-boundary anchor drifted from speclib-dispatch.sh:312 and :330 shipped (^|[[:space:]]) but the approved design spec specified (^|[[:space:]\(]) to allow parenthesized refs like - (owner/repo#42). Without (, those were silently ignored. ✅ Fixed: both regexes now use the spec-aligned anchor; INV-39 updated.

  2. URL-fragment test was weaktests/unit/test-check-deps-resolved.sh had the URL on a prose line, so Stage 1's list-item filter dropped it before Stage 2's boundary logic could run. Stage 2's URL-fragment protection was therefore untested. ✅ Fixed: added a list-item URL test with competing OPEN states for the would-be-extracted numbers, so a future greedy-extraction regression would flip the test red.

  3. No coverage for parenthesized refs — neither in tests nor docs. ✅ Fixed: two new test cases (- (owner/repo#42), - (#7)) covering CLOSED → resolved and OPEN → blocked.

Confirmed (no change needed)

  • Loop safetyline="${line/"$matched"/ }" is safe (the quoted substitution treats / and # as literals; BASH_REMATCH[0] always contains a #NNN portion the regex requires; replacing it makes guaranteed forward progress).
  • Fail-safe lookup-failure semantics — block + stderr warning is the right call. (Commenting on the issue would spam on every dispatcher tick.)

Suggestions not adopted

  • Right-boundary anchor (e.g., \b after #NNN) — would reject #123foo. Real-world hit rate is low (refs are typically followed by whitespace or punctuation), and adding it complicates the regex. Not adopted.

Test count: 23/23 PASS in test-check-deps-resolved.sh.

@zxkane
Copy link
Copy Markdown
Owner Author

zxkane commented May 27, 2026

agy review (second pass — verdict: ✅ APPROVE)

All three findings from the prior review confirmed resolved by 0aaf0df:

  1. Left-boundary anchor — Stage 2a + 2b both use (^|[[:space:]\(]) per spec.
  2. URL-fragment test on a list item — competing OPEN states registered for 123 and 456 in both repos so a regex regression flips the test red.
  3. Parenthesized-ref tests — CLOSED → resolved + OPEN → blocked covered for both (owner/repo#42) and (#7).
  4. INV-39 docs( documented in both the boundary prose and the regex citation.

Regression checks

  • \( escape inside [[:space:]\(]: bash word-parses \( to literal ( during shell expansion; the regex engine receives a literal ( (not a metacharacter, not a literal backslash). Correct.
  • URL-fragment isolation: on - See https://github.com/.../issues/123#456 for context, 123 is preceded by / and 456 by # — neither adjacent to a left-boundary char (^, space, or (). Both correctly ignored.
  • Strip preserves closing paren: for - (owner/repo#42), BASH_REMATCH[0] captures (owner/repo#42. The strip leaves the trailing ) intact, so subsequent regex passes don't misparse residue.

23/23 tests pass. No new findings.

@zxkane zxkane merged commit 70a67f4 into main May 27, 2026
3 checks passed
@zxkane zxkane deleted the feat/cross-repo-deps branch May 27, 2026 13:39
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.

feat(dispatcher): support cross-repo dependency references in check_deps_resolved

1 participant