Repository navigation
Scale pm-graph item exports and expose pure graph projection #122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
503ff86
perf(pm-graph): build large item graphs with indexed edges
unbraind 6aa1627
test(pm-graph): pin export order for duplicate and external edges
unbraind e7d30d4
docs(graph): record resumed PR #122 verification
unbraind 3d97a75
Merge branch 'main' into perf/pm-graph-linear-export-2026-09-29
unbraind File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| id: pm-graph-3a1p | ||
| title: Graph export uses quadratic item and edge scans on large trackers | ||
| description: "The pm-graph graphFromItems builder calls items.some for relationship targets and deduplicates all edges with a final filter/findIndex. Large workspaces with many relations therefore perform repeated full scans. Replace both with indexed membership and insertion-time edge keys while preserving first-edge properties, ordering, external nodes, and export shape." | ||
| type: Issue | ||
| status: blocked | ||
| priority: 1 | ||
| tags: [] | ||
| created_at: "2026-09-29T09:15:55.866Z" | ||
| updated_at: "2026-10-02T23:07:56.404Z" | ||
| author: codex | ||
| acceptance_criteria: Real export shape and duplicate-edge semantics are unchanged; a representative multi-thousand-item export completes within a measured bound; release and packed gates pass; all evidence is linked to this item. | ||
| repro_steps: "Inspect src/index.ts graphFromItems: items.some in addRelationship; relationships.filter with all.findIndex on every edge." | ||
| expected_result: "Graph construction scales with item and edge counts, preserving the existing export contract." | ||
| actual_result: Graph construction has O(items x edges + edges squared) scans. | ||
| dependencies[1]{id,kind,created_at,author,source_kind,author_source}: | ||
| pm-graph-6zil,related,"2026-09-29T09:31:10.155Z",codex,"cli:update:dep",detected | ||
| comments[4]{created_at,author,text}: | ||
| "2026-10-02T22:10:50.898Z",codex-sol-land,"Resumed PR #122 from d27eefcd1048f0b8e30efe9e08be908aa3c3586e. Rebase onto current fix/pm-graph-github-extension-cli-compat-2026-09-27 yields 64f2abe3b138cbd8bb4c9d4a77e55758bf6256ec. All existing bot artifacts and restart-era owner replies inspected; no new actionable finding. Preserve earlier fixes and technical refusals. Verifying unchanged CI gates under the shared heavy lock; no merge, release or closure." | ||
| "2026-10-02T22:13:02.054Z",codex-sol-land,"The original focused test is retained at its 30-second timeout. Its first linked attempt refused the historical branch provenance after the necessary isolated worktree branch rename; the newly linked identical command itself passed 2/2. Reviewed and acknowledged the existing command for this clone, without changing trust policy or test gates, and removed only the duplicate command added by this restart." | ||
| "2026-10-02T22:30:02.207Z",codex-sol-land,"Parent #116 received new workflow duplication and current-metadata findings in its resumed review. It now has a test-first shared installer fix queued for full verification. Stopped the redundant child full gate against the earlier parent after focused tests, strict health and fresh-build comparison passed; the child must rebase onto that final parent and run its full gate once, preserving all local tracker work. No stopped run is counted as a pass." | ||
| "2026-10-02T23:07:53.000Z",codex-sol-land,"Resumed verification: npm ci, current-base rebase, fresh committed-dist comparison, strict local tracker health with required merge drivers, npm run release:check, and bun install --no-save all passed. Full gate: 300 tests, 300 pass, 0 skips; configured coverage thresholds unchanged. PM-linked test/graph-builder-scale.test.ts passed. Earlier findings and technical refusals retained; no new source fix was needed in this restart. Exact pushed-head CI and substantive reviewer availability remain separate checks; no merge, release, publication or item closure." | ||
| notes[7]{created_at,author,text}: | ||
| "2026-09-29T09:31:10.155Z",codex,"2026-09-29: graph projection uses indexed item IDs and insertion-time edge keys. A synthetic 3000-item graph with parent blocker duplicate dependency and two tags completed in 61.59 ms under the full coverage run. First-edge properties and external node semantics passed focused tests." | ||
| "2026-09-29T09:31:10.155Z",codex,"Exact local npm run release:check passed 294 tests with zero failures and skips; 0 duplicated lines; 90 documented declarations; production audit and changelog checks passed. Measured coverage 99.65% lines 94.07% branches 100% functions; pm-graph-6zil owns the remaining 100% gap." | ||
| "2026-09-29T09:31:10.155Z",codex,Installed pm-ops 2026.9.28 canonical merge-driver launcher copied byte-identically after the first full gate caught template drift. Fresh isolated npm/Node and Bun 1.3.5 installs of the packed artifact both loaded graphFromItems and projected a graph. Local pm health still reports five merge-driver config drift keys even after pm merge install with pinned CLI 2026.9.27; investigate separately. | ||
| "2026-09-29T09:32:35.884Z",codex,An isolated fresh npm Git workspace with pinned CLI 2026.9.27 passes strict health after init and merge install. The five-key drift reproduces only in this existing checkout so no upstream issue is asserted from this evidence. | ||
| "2026-09-29T09:34:25.815Z",codex,Stacked this change on pm-graph PR #116 to inherit its CLI SDK and pm-ops certification. The new branch initially showed two chain mismatches in this item history; pm history-repair dry-run proved item content already matched and an audited repair rehashed two entries with zero skipped operations. Strict health now passes with two stale-item advisories. | ||
| "2026-09-29T09:40:31.819Z",codex,"Greptile on PR #122 head baabeef identified an untested output-order contract. Accepted: the small duplicate-blocker/external-target acceptance now asserts exact node and edge insertion order; focused Node test and linked pm test both pass. Full exact-head gate and renewed bot reviews follow the next push." | ||
| "2026-09-29T09:46:35.665Z",codex,"Greptile order finding fix exact local gate: npm run release:check passed 295 tests with zero failures/skips; 0 duplicate lines; 90 documented declarations; 0 production vulnerabilities. Coverage remains 99.65 lines 94.07 branches 100 functions. PR #122 remains open for new-head CI and bot review." | ||
| files[4]{path,scope,note}: | ||
| README.md,project,Pure graph projection API and current SDK read path | ||
| scripts/prepare-merge-driver.ts,project,Canonical pm-ops 2026.9.28 launcher | ||
| src/index.ts,project,Linear graph projection | ||
| test/graph-builder-scale.test.ts,project,Contract and scale acceptance | ||
| tests[1]{command,scope,timeout_seconds,pm_context_mode,provenance{author,created_at,source_kind,source_ref}}: | ||
| node --test test/graph-builder-scale.test.ts,project,30,schema,codex,"2026-09-29T09:31:41.849Z",local_mutation,perf/pm-graph-linear-export-2026-09-29 | ||
| docs[3]: | ||
| - path: "https://github.com/unbraind/pm-graph/pull/122#discussion_r4131898043" | ||
| scope: global | ||
| note: Accepted Greptile output-order finding | ||
| - path: "https://github.com/unbraind/pm-web/blob/main/.agents/pm/features/pm-web-38n5.toon" | ||
| scope: global | ||
| note: Potential pure graph API consumer for observational reads | ||
| - path: "https://github.com/unbraind/pm-graph/pull/122" | ||
| scope: project | ||
| body: "" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| /** Contract and scale checks for the pure graph projection used by exports. */ | ||
| import assert from "node:assert/strict"; | ||
| import { performance } from "node:perf_hooks"; | ||
| import test from "node:test"; | ||
| import type { ItemMetadata } from "@unbrained/pm-cli/sdk"; | ||
|
|
||
| import { graphFromItems } from "../src/index.ts"; | ||
|
|
||
| test("graph projection retains the first dependency edge and external targets", () => { | ||
| const item = { | ||
| id: "item-1", title: "Example", description: "", type: "Task", status: "open", | ||
| priority: 2, created_at: "2026-09-29T00:00:00.000Z", updated_at: "2026-09-29T00:00:00.000Z", | ||
| blocked_by: "external-1", blocked_reason: "waiting", | ||
| dependencies: [{ id: "external-1", kind: "blocked_by", created_at: "2026-09-29T00:00:00.000Z" }], | ||
| tags: [], | ||
| } satisfies ItemMetadata; | ||
| const graph = graphFromItems([item], "/tmp/pm-graph-contract", new Map()); | ||
| assert.deepEqual(graph.nodes.map((node) => node.id), [ | ||
| "item-1", "external-1", "type:task", "status:open", | ||
| ]); | ||
| assert.deepEqual(graph.relationships.map((edge) => [edge.from, edge.to, edge.type]), [ | ||
| ["item-1", "external-1", "BLOCKED_BY"], | ||
| ["item-1", "type:task", "HAS_TYPE"], | ||
| ["item-1", "status:open", "HAS_STATUS"], | ||
| ]); | ||
| const edges = graph.relationships.filter((edge) => | ||
| edge.from === "item-1" && edge.to === "external-1" && edge.type === "BLOCKED_BY"); | ||
| assert.equal(edges.length, 1); | ||
| assert.deepEqual(edges[0]?.properties, { source: "blocked_by", reason: "waiting" }); | ||
| assert.deepEqual(graph.nodes.find((node) => node.id === "external-1")?.labels, ["ExternalPmItem"]); | ||
| }); | ||
|
|
||
| test("a multi-thousand-item graph with dense facet and dependency edges builds within the export budget", () => { | ||
| const count = 3_000; | ||
| const items = Array.from({ length: count }, (_, index) => ({ | ||
| id: `item-${index}`, | ||
| title: `Item ${index}`, | ||
| description: "", | ||
| type: "Task" as const, | ||
| status: "open" as const, | ||
| priority: 2 as const, | ||
| created_at: "2026-09-29T00:00:00.000Z", | ||
| updated_at: "2026-09-29T00:00:00.000Z", | ||
| tags: ["agent", "shared"], | ||
| ...(index > 0 ? { | ||
| parent: `item-${index - 1}`, | ||
| blocked_by: `item-${index - 1}`, | ||
| dependencies: [{ id: `item-${index - 1}`, kind: "blocked_by" as const, created_at: "2026-09-29T00:00:00.000Z" }], | ||
| } : {}), | ||
| })) satisfies ItemMetadata[]; | ||
| const start = performance.now(); | ||
| const graph = graphFromItems(items, "/tmp/pm-graph-scale", new Map()); | ||
| const elapsedMs = performance.now() - start; | ||
| assert.equal(graph.nodes.filter((node) => node.labels.includes("PmItem")).length, count); | ||
| assert.equal(graph.relationships.filter((edge) => edge.type === "BLOCKED_BY").length, count - 1); | ||
| assert.equal(graph.relationships.filter((edge) => edge.type === "CHILD_OF").length, count - 1); | ||
| assert.ok(elapsedMs < 5_000, `3,000-item graph projection took ${elapsedMs.toFixed(0)} ms`); | ||
| }); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.