Skip to content

feat(import): --link-deps maps GitHub issue-body dependencies to pm edges#9

Merged
unbraind merged 2 commits into
mainfrom
feat/import-link-deps
Jul 22, 2026
Merged

feat(import): --link-deps maps GitHub issue-body dependencies to pm edges#9
unbraind merged 2 commits into
mainfrom
feat/import-link-deps

Conversation

@unbraind

@unbraind unbraind commented Jul 22, 2026

Copy link
Copy Markdown
Owner

What

Adds an opt-in --link-deps flag to pm github import that maps dependency references declared in GitHub issue bodies into pm dependency edges between the imported items.

GitHub authors express dependencies in prose — Blocked by #12, Depends on owner/repo#5, Blocks #9. A flat import discards that structure, so agents see an undifferentiated list of items with no blocker graph. --link-deps recovers it: after the items are imported, a second pass resolves those references (through the existing gh:owner/repo#N provenance tags) and writes the corresponding blocked_by / blocks edges. pm next and pm deps then reflect the real ready/blocked ordering — project management = context management.

pm github import owner/repo --link-deps
pm github import owner/repo --atomic --link-deps
pm github import owner/repo --link-deps --dry-run   # reports candidate reference count only

Reference grammar

Case-insensitive; -/: glue tolerated; multi-ref runs like #1, #2 and #3; bare #N (resolved against the imported repo) and explicit owner/repo#N.

Phrase pm edge on the source item
Blocked by #N / Depends on #N blocked_by → referenced item
Blocks #N blocks → referenced item

Guarantees

  • Idempotentpm update --dep dedupes by id+kind; re-import never duplicates edges.
  • Path-agnostic — runs identically after the normal and --atomic import.
  • Safe — refs inside fenced/inline code spans are ignored; self-references and refs to issues absent from the workspace are skipped (the latter counted as unresolvedDependencyRefs); an individual failed edge never fails the import (reported in dependencyLinkFailures; the pass is re-runnable).
  • ReDoS-free parser — phrase + reference scanning is linear via sticky (y) regexes anchored at the exact position; no nested quantifier over unbounded input.
  • Cycle-aware, not cycle-blocking — ordering cycles the mapped edges introduce are reported in orderingCycleWarnings, computed via the pm SDK collectNewOrderingCycleWarnings advisory over the workspace before/after the pass. This restores the advisory that the commitItemMutations atomic path drops (its outcome carries only {id,op}), matching the SDK's warn-don't-reject contract for legacy graph debt.

Import result gains linkedDependencies, unresolvedDependencyRefs, orderingCycleWarnings (+ dependencyLinkFailures when non-empty); --dry-run --link-deps reports wouldLinkDependencyCandidates. The peerDependency floor is unchanged (>=2026.7.20 already exports both SDK primitives).

Tests

25 new tests (full suite 164 green), typecheck clean, npm audit --omit=dev clean, changelog:check up to date:

  • Pure units: parseDependencyReferences (grammar, cross-repo, multi-ref, code-span stripping, dedupe, roadblocks non-match), planDependencyLinks (self-ref / dangling / absent-source skips, dedupe), buildProvenanceIndexFromMetadata (first-writer-wins), countDependencyRefCandidates.
  • Hermetic DI orchestration for linkImportedDependencies (apply, failures, no-op short-circuit, warning dedupe).
  • 3 real end-to-end runImport --link-deps cases against a live pm tracker + SDK.

Real-data verification: imported a private throwaway repo over live GitHub REST with 3 dependency-phrased issues → 3 edges written (#2 blocked_by #1; #3 blocked_by #2 + #1), the #999 inside a code block correctly ignored (0 unresolved), and pm next correctly gated #2/#3 behind #1. Repo deleted after.

pm items

  • Feature: pm-github-hdai
  • Companion tracker: pm-cli-website-096t (relates to absorption epic pm-cli-website-7pnx — this PR substantively resolves its part-2, "adopt collectNewOrderingCycleWarnings fleet-wide", by giving the SDK export a real use site).

🤖 Generated with Claude Code


Summary by cubic

Adds an opt-in --link-deps flag to pm github import that parses dependency phrases in GitHub issue bodies and writes pm blocked_by/blocks edges so pm next and pm deps reflect real ready/blocked order. The pass is now hardened so SDK load/snapshot/advisory failures never reject a successful import; they’re reported and linking is skipped.

  • New Features

    • Maps “Blocked by/Depends on/Blocks” refs (bare #N or owner/repo#N) to edges; case-insensitive, allows -/:, supports multi-refs; ignores refs in code.
    • Idempotent and best-effort: skips self and missing targets; works with or without --atomic; --dry-run reports candidate count.
    • Emits ordering-cycle warnings via collectNewOrderingCycleWarnings from @unbrained/pm-cli; result fields: linkedDependencies, unresolvedDependencyRefs, orderingCycleWarnings (and dependencyLinkFailures when present).
    • README updated; 27 tests added (incl. end-to-end); full suite 166 green.
  • Bug Fixes

    • --link-deps infra errors (SDK import, pre/after snapshots, cycle advisory) no longer fail the command post-import; edges already written are preserved and a clear note is returned.

Written for commit d96512c. Summary will update on new commits.

Review in cubic

…dges

Opt-in second pass over `pm github import` that parses dependency
references from issue BODIES (`Blocked by #N`, `Depends on owner/repo#N`,
`Blocks #N`) and materializes them as pm dependency edges between the
imported items, resolved through the existing `gh:owner/repo#N` provenance
tags. Agents get the real ready/blocked ordering (`pm next`, `pm deps`)
instead of a flat list — project management = context management.

Implementation (index.ts):
- parseDependencyReferences (pure): case/hyphen/colon-tolerant phrase
  grammar; bare `#N` + explicit `owner/repo#N`; multi-ref runs
  (`#1, #2 and #3`); fenced/inline code-span stripping; in-body dedupe.
  "Blocked by"/"Depends on" → blocked_by; "Blocks" → blocks.
- buildProvenanceIndexFromMetadata + planDependencyLinks (pure): resolve
  refs to concrete edges; skip self-references, unresolved targets
  (counted), and issues whose source item is absent; dedupe edges.
- linkImportedDependencies: best-effort, idempotent (`pm update --dep`
  dedupes by id+kind), path-agnostic (runs after the normal AND --atomic
  import). Ordering cycles the mapped edges introduce are reported, not
  rejected, via the SDK `collectNewOrderingCycleWarnings` advisory over the
  workspace before/after the pass — restoring the advisory that the
  `commitItemMutations` atomic path drops (its outcome carries only
  {id,op}).

Result surface gains linkedDependencies / unresolvedDependencyRefs /
orderingCycleWarnings (+ dependencyLinkFailures when non-empty); a
`--dry-run --link-deps` result reports wouldLinkDependencyCandidates.
peerDependency floor unchanged (>=2026.7.20 already exports both SDK fns).

Tests: 25 new (parser/planner/provenance units, hermetic DI orchestration,
3 real end-to-end runImport cases) — full suite 164 green, typecheck clean,
audit --omit=dev clean, changelog:check up to date. Verified against a
real private repo over live REST: 3 dependency-phrased issues → 3 edges,
code-block `#999` correctly ignored, `pm next` gating confirmed.

Tracks pm item pm-github-hdai.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@sourcery-ai sourcery-ai Bot 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.

Sorry @unbraind, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds an opt-in --link-deps second pass to GitHub imports. It parses dependency references from issue bodies, resolves them through GitHub provenance metadata, applies PM dependency edges, reports unresolved references and cycle warnings, and adds unit, integration, and end-to-end coverage.

Changes

GitHub dependency linking

Layer / File(s) Summary
Dependency contracts and planning
index.ts, test/link-deps.test.ts
Adds dependency-linking types and pure functions for parsing references, indexing provenance, counting candidates, and planning deduplicated edges.
Dependency application and import wiring
index.ts, test/link-deps.test.ts
Runs dependency linking after atomic and non-atomic imports, applies edges through injectable operations, reports failures and unresolved references, and surfaces ordering-cycle warnings.
CLI documentation and feature records
index.ts, README.md, .agents/pm/...
Registers --link-deps, updates importer examples and documentation, and records the feature implementation details.
End-to-end import validation
test/link-deps.test.ts
Tests live dependency linking, idempotent re-imports, self-reference skipping, unresolved references, and disabled linking.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • unbraind/pm-github#5: Both changes modify atomic GitHub import behavior around commitItemMutations.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly states the new opt-in link-deps import behavior and GitHub issue dependency mapping.
Description check ✅ Passed The description matches the PR by explaining the --link-deps import flow, grammar, guarantees, and tests.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/import-link-deps

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@unbraind

Copy link
Copy Markdown
Owner Author

@coderabbitai full review
@greptileai review
/gemini review

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

@unbraind I’ll perform a full review of the PR, including the dependency-linking flow, parser safety, atomic/dry-run behavior, and test coverage.

✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 37 minutes.

@unbraind

Copy link
Copy Markdown
Owner Author

@greptileai review

@unbraind

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

Adversarial review found the second-pass call sites awaited
linkImportedDependencies without guarding SDK-load / snapshot / advisory
errors. On a host whose CLI predates the required SDK exports (or on a
transient workspace-read error), the items commit, then the pass throws
and runImport rejects — the caller sees a FAILED command despite a fully
successful import, contradicting the feature's best-effort contract.

Fix: linkImportedDependencies now wraps (1) SDK resolution + pre-edge
snapshot — a failure returns linked:0 with a 'dependency linking skipped'
note instead of throwing; and (2) the after-snapshot + ordering-cycle
detector — a failure preserves the edges already written and records an
'ordering-cycle advisory skipped' note. Per-edge failures were already
captured. +2 tests (27 link-deps / 166 total, all green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@unbraind

Copy link
Copy Markdown
Owner Author

Pushed d96512c addressing a robustness gap surfaced in review: the --link-deps second pass now folds SDK-load / snapshot / ordering-cycle-advisory failures into the reported dependencyLinkFailures instead of throwing, so an infra error (e.g. an older CLI missing the SDK export) can never discard an already-committed import. +2 tests (166 total, all green).

@coderabbitai full review
@greptileai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

@unbraind I’ll perform a full review, with particular attention to the new best-effort error handling in the --link-deps second pass, atomic/non-atomic import preservation, and the added regression tests.

✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 38 minutes.

@unbraind

Copy link
Copy Markdown
Owner Author

Review trail (merging)

All checks green on both commits (42e3906, d96512c): CI test (166 tests), semgrep clean, cubic reviewed both commits → NEUTRAL / 0 findings. CodeRabbit performed full reviews on both commits but its OSS Fair-Usage quota throttled the visible walkthrough (0 inline comments emitted). Greptile (100 OSS credits), Sourcery (weekly 500k-diff budget), and Gemini (sunset) were unavailable this cycle.

To compensate for the throttled/unavailable bots, an independent adversarial review was run over the diff; it surfaced one MEDIUM robustness gap — the second pass could throw after a committed import on an older-CLI host — which is fixed in d96512c (SDK-load / snapshot / advisory failures now fold into dependencyLinkFailures instead of rejecting) with 2 added regression tests.

Merging on the green gate; happy to follow up on any findings CodeRabbit emits once its window reopens.

@unbraind
unbraind merged commit 5d59cc7 into main Jul 22, 2026
5 checks passed
@unbraind
unbraind deleted the feat/import-link-deps branch July 22, 2026 23:08
unbraind added a commit that referenced this pull request Jul 22, 2026
…review loop complete

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant