Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .agents/pm/features/pm-github-hdai.toon
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
id: pm-github-hdai
title: "Import --link-deps: map GitHub issue-body dependency references (Blocked by/Depends on/Blocks #N) into pm dependency edges + emit ordering-cycle advisory via collectNewOrderingCycleWarnings"
description: "Opt-in second pass over imported issues that parses dependency references from issue bodies and materializes them as pm dependency edges between the corresponding pm items (resolved via the existing gh:owner/repo#N provenance index). Preserves the declared blocker graph so agents see real dependencies instead of flat items (project management = context management). Rejects self-references. Idempotent (pm update --dep dedupes). Works with and without --atomic. Non-atomic path surfaces the native pm update ordering_cycle_created warning; atomic path calls the SDK export collectNewOrderingCycleWarnings(before,after,changedId) to restore the advisory that commitItemMutations drops (its BulkItemMutationOutcome carries only {id,op}). Substantively resolves companion 7pnx part-2 (adopt collectNewOrderingCycleWarnings)."
type: Feature
status: open
priority: 2
tags[4]: dependencies,feature,import,sdk-adoption
created_at: "2026-07-22T21:41:46.678Z"
updated_at: "2026-07-22T21:56:09.789Z"
author: codex
acceptance_criteria: "Ref parser unit-tested (Blocked by/Depends on/Blocks, cross-repo owner/repo#N, case-insensitive, dedupe, self-ref rejected, dangling refs reported not errored); edges resolved via provenance index; both atomic + non-atomic paths apply edges; ordering-cycle warnings surfaced in summary+JSON; re-import creates no duplicate edges; README + CHANGELOG updated; CI green; full bot loop clean"
notes[1]{created_at,author,text}:
"2026-07-22T21:56:09.788Z",codex,"IMPLEMENTED (branch pending). Added opt-in --link-deps second pass to pm github import: parseDependencyReferences (pure; Blocked by/Depends on→blocked_by, Blocks→blocks; bare #N + owner/repo#N; case/hyphen/colon tolerant; multi-ref; code-span stripping; dedupe), buildProvenanceIndexFromMetadata, planDependencyLinks (self-ref + dangling + missing-source skips, dedupe), linkImportedDependencies (best-effort apply via pm update --dep, path-agnostic, idempotent). Ordering-cycle advisory via SDK collectNewOrderingCycleWarnings over before/after listAllItemMetadata snapshots (restores the advisory commitItemMutations drops → resolves companion 7pnx part-2). Result gains linkedDependencies/unresolvedDependencyRefs/orderingCycleWarnings/dependencyLinkFailures; dry-run reports wouldLinkDependencyCandidates. peerDep floor unchanged (>=2026.7.20 already covers both SDK exports). 25 new tests (parser/planner/provenance units + hermetic DI orchestration + 3 real end-to-end runImport tests) — full suite 164 green, typecheck clean. REAL-DATA VERIFIED: created private throwaway repo with 3 dependency-phrased issues, imported via live REST → 3 edges (#2 blocked_by #1; #3 blocked_by #2 + #1), code-block #999 correctly ignored (0 unresolved), pm next correctly gated #2/#3 behind #1; repo deleted after."
body: ""
2 changes: 2 additions & 0 deletions .agents/pm/history/pm-github-hdai.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"ts":"2026-07-22T21:41:46.678Z","author":"codex","op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-hdai"},{"op":"add","path":"/metadata/title","value":"Import --link-deps: map GitHub issue-body dependency references (Blocked by/Depends on/Blocks #N) into pm dependency edges + emit ordering-cycle advisory via collectNewOrderingCycleWarnings"},{"op":"add","path":"/metadata/description","value":"Opt-in second pass over imported issues that parses dependency references from issue bodies and materializes them as pm dependency edges between the corresponding pm items (resolved via the existing gh:owner/repo#N provenance index). Preserves the declared blocker graph so agents see real dependencies instead of flat items (project management = context management). Rejects self-references. Idempotent (pm update --dep dedupes). Works with and without --atomic. Non-atomic path surfaces the native pm update ordering_cycle_created warning; atomic path calls the SDK export collectNewOrderingCycleWarnings(before,after,changedId) to restore the advisory that commitItemMutations drops (its BulkItemMutationOutcome carries only {id,op}). Substantively resolves companion 7pnx part-2 (adopt collectNewOrderingCycleWarnings)."},{"op":"add","path":"/metadata/type","value":"Feature"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":["dependencies","feature","import","sdk-adoption"]},{"op":"add","path":"/metadata/created_at","value":"2026-07-22T21:41:46.678Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-07-22T21:41:46.678Z"},{"op":"add","path":"/metadata/author","value":"codex"},{"op":"add","path":"/metadata/acceptance_criteria","value":"Ref parser unit-tested (Blocked by/Depends on/Blocks, cross-repo owner/repo#N, case-insensitive, dedupe, self-ref rejected, dangling refs reported not errored); edges resolved via provenance index; both atomic + non-atomic paths apply edges; ordering-cycle warnings surfaced in summary+JSON; re-import creates no duplicate edges; README + CHANGELOG updated; CI green; full bot loop clean"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"7a56d6b54c6742ccf7f2d5245e704bee24121830bc57b64905f2caea0b34e4a4","message":""}
{"ts":"2026-07-22T21:56:09.789Z","author":"codex","op":"note_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-07-22T21:56:09.789Z"},{"op":"add","path":"/metadata/notes","value":[{"created_at":"2026-07-22T21:56:09.788Z","author":"codex","text":"IMPLEMENTED (branch pending). Added opt-in --link-deps second pass to pm github import: parseDependencyReferences (pure; Blocked by/Depends on→blocked_by, Blocks→blocks; bare #N + owner/repo#N; case/hyphen/colon tolerant; multi-ref; code-span stripping; dedupe), buildProvenanceIndexFromMetadata, planDependencyLinks (self-ref + dangling + missing-source skips, dedupe), linkImportedDependencies (best-effort apply via pm update --dep, path-agnostic, idempotent). Ordering-cycle advisory via SDK collectNewOrderingCycleWarnings over before/after listAllItemMetadata snapshots (restores the advisory commitItemMutations drops → resolves companion 7pnx part-2). Result gains linkedDependencies/unresolvedDependencyRefs/orderingCycleWarnings/dependencyLinkFailures; dry-run reports wouldLinkDependencyCandidates. peerDep floor unchanged (>=2026.7.20 already covers both SDK exports). 25 new tests (parser/planner/provenance units + hermetic DI orchestration + 3 real end-to-end runImport tests) — full suite 164 green, typecheck clean. REAL-DATA VERIFIED: created private throwaway repo with 3 dependency-phrased issues, imported via live REST → 3 edges (#2 blocked_by #1; #3 blocked_by #2 + #1), code-block #999 correctly ignored (0 unresolved), pm next correctly gated #2/#3 behind #1; repo deleted after."}]}],"before_hash":"7a56d6b54c6742ccf7f2d5245e704bee24121830bc57b64905f2caea0b34e4a4","after_hash":"b75738d7177a92b035569a7efcbacf08a4c7a113c3cc443248fc5bc13668e3f4"}
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pm github import owner/repo --assignee octocat
pm github import owner/repo --milestone "v1.0"
pm github import owner/repo --include-prs
pm github import owner/repo --atomic
pm github import owner/repo --link-deps # map issue-body dependencies to pm edges
pm github import owner/repo --dry-run
```

Expand All @@ -55,6 +56,7 @@ pm github import owner/repo --dry-run
| `--with-comments` | boolean | Fetch issue comments and append them to the item body |
| `--comments-mode <mode>` | `body`\|`annotations`\|`both` | How fetched GitHub comments are persisted (default `body`). `annotations` syncs comments into the pm item's native comments collection via the SDK; `both` writes the body section AND native comments. `annotations`/`both` are idempotent on re-import (dedupe by GitHub comment id) |
| `--atomic` | boolean | Commit every create, update, close, and reopen in one workspace-writer-locked, crash-resumable transaction (requires pm CLI/SDK >=2026.7.20). Normal failure compensation restores updated/closed items and deletes newly created items; an incomplete compensation is reported explicitly for retry or repair. |
| `--link-deps` | boolean | After import, map dependency references in issue **bodies** (`Blocked by #N`, `Depends on owner/repo#N`, `Blocks #N`) to pm dependency edges between the linked items. Idempotent, best-effort, and re-runnable; see [Dependency linking](#dependency-linking---link-deps) below. |
| `--dry-run` | boolean | Preview without writing |
| `--type <type>` | string | Override pm item type (default: Issue) |

Expand All @@ -77,6 +79,37 @@ pm github import owner/repo --with-comments # legacy body embedd
pm github import owner/repo --with-comments --comments-mode annotations # same as --comments-mode both
```

### Dependency linking (`--link-deps`)

GitHub issue authors declare cross-issue dependencies in prose — `Blocked by #12`, `Depends on owner/repo#5`, `Blocks #9`. A flat import throws that structure away, leaving pm items with no blocker graph. `--link-deps` runs an opt-in second pass that parses those references from each issue's **body** and materializes them as pm dependency edges between the corresponding pm items, resolved through the same `gh:owner/repo#N` provenance tags the import writes.

The effect is context you can act on: `pm next` and `pm deps` surface the real ready/blocked ordering instead of an undifferentiated list.

```bash
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; multiple refs like `#1, #2 and #3`):

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

Both bare `#N` (resolved against the imported repo) and explicit `owner/repo#N` cross-repo references are supported, the latter only when that issue is also present in the workspace.

**Guarantees**

- **Idempotent** — edges dedupe by id + kind, so re-running import never duplicates them.
- **Path-agnostic** — runs identically after the normal and `--atomic` import.
- **Safe** — references inside fenced/inline code spans are ignored; self-references and references to issues not in the workspace are skipped (the latter counted as `unresolvedDependencyRefs`); a failed individual edge never fails the import (it is reported in `dependencyLinkFailures` and the pass is re-runnable).
- **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) rather than rejected, mirroring the SDK's warn-don't-reject contract for legacy graph debt.

The import result gains `linkedDependencies`, `unresolvedDependencyRefs`, `orderingCycleWarnings` (and `dependencyLinkFailures` when non-empty); a `--dry-run --link-deps` result reports `wouldLinkDependencyCandidates`.

## Export (pm → GitHub)

### `pm github export`
Expand Down
Loading