@unbrained/pm-cli 2026.8.19 → 2026.8.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +41 -0
  3. package/dist/cli/error-guidance.d.ts +20 -0
  4. package/dist/cli/error-guidance.js +29 -30
  5. package/dist/cli/register-list-query.js +12 -10
  6. package/dist/cli/register-structured-mutation.d.ts +2 -0
  7. package/dist/cli/register-structured-mutation.js +29 -6
  8. package/dist/cli-bundle/bundle-manifest.json +156 -148
  9. package/dist/cli-bundle/chunks/chunk-2MA6ZQVZ.js +197 -0
  10. package/dist/cli-bundle/chunks/{chunk-4NRRH7AM.js → chunk-3AFAUHUE.js} +2 -2
  11. package/dist/cli-bundle/chunks/chunk-7VHZS727.js +5 -0
  12. package/dist/cli-bundle/chunks/chunk-BKYB45NQ.js +2092 -0
  13. package/dist/cli-bundle/chunks/{chunk-BHYMXLAE.js → chunk-BUNIEJNE.js} +2 -2
  14. package/dist/cli-bundle/chunks/{chunk-QXSH7BLM.js → chunk-JSLOFXGA.js} +3 -3
  15. package/dist/cli-bundle/chunks/chunk-LARJJ3RK.js +3 -0
  16. package/dist/cli-bundle/chunks/{chunk-TOXJM4WA.js → chunk-LOVTQ52Z.js} +2 -2
  17. package/dist/cli-bundle/chunks/chunk-N3DSV4CH.js +77 -0
  18. package/dist/cli-bundle/chunks/chunk-OCLPLFAY.js +35 -0
  19. package/dist/cli-bundle/chunks/chunk-S4IRYKBU.js +13 -0
  20. package/dist/cli-bundle/chunks/register-list-query-F57EWDEF.js +11 -0
  21. package/dist/cli-bundle/chunks/{register-mutation-AUWVCW4M.js → register-mutation-7IY2D5KO.js} +20 -20
  22. package/dist/cli-bundle/chunks/{register-operations-PZQPHXW5.js → register-operations-FALL3YTU.js} +2 -2
  23. package/dist/cli-bundle/chunks/{register-setup-I4LUHGVW.js → register-setup-HXU7IZZD.js} +2 -2
  24. package/dist/cli-bundle/focused-chunks/chunk-2NIY5NKG.js +18 -0
  25. package/dist/cli-bundle/focused-chunks/{chunk-US7VEYZG.js → chunk-4ERLO7QD.js} +2 -2
  26. package/dist/cli-bundle/focused-chunks/chunk-7WZRLCYF.js +50 -0
  27. package/dist/cli-bundle/focused-chunks/{chunk-MCZXYZAF.js → chunk-CKKQSJNN.js} +2 -2
  28. package/dist/cli-bundle/focused-chunks/chunk-EEFKYMDR.js +16 -0
  29. package/dist/cli-bundle/focused-chunks/{chunk-ZBIQQYMI.js → chunk-F2A56DHV.js} +2 -2
  30. package/dist/cli-bundle/focused-chunks/{chunk-ESISGDAY.js → chunk-F4YEW5I2.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/{chunk-ODHQEECS.js → chunk-FH6DYED3.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/chunk-FJ22HNRP.js +2 -0
  33. package/dist/cli-bundle/focused-chunks/chunk-FV5ACOK7.js +2 -0
  34. package/dist/cli-bundle/focused-chunks/chunk-JEAVFOWM.js +2 -0
  35. package/dist/cli-bundle/focused-chunks/{chunk-EXBCLIBU.js → chunk-KDNG7TKQ.js} +2 -2
  36. package/dist/cli-bundle/focused-chunks/chunk-NJ63LOP6.js +155 -0
  37. package/dist/cli-bundle/focused-chunks/chunk-NXRTQ7HI.js +2 -0
  38. package/dist/cli-bundle/focused-chunks/{chunk-JDOMQ7VQ.js → chunk-TJ7EMJ46.js} +3 -3
  39. package/dist/cli-bundle/focused-chunks/chunk-UZE7XUZK.js +2 -0
  40. package/dist/cli-bundle/focused-chunks/{chunk-DKPLYW3L.js → chunk-YKBKIEAJ.js} +2 -2
  41. package/dist/cli-bundle/focused-chunks/{chunk-VXDSU5MC.js → chunk-ZOSEELYJ.js} +2 -2
  42. package/dist/cli-bundle/main.js +12 -12
  43. package/dist/cli-bundle/sdk-authoring.js +1 -1
  44. package/dist/cli-bundle/sdk-contracts.js +2 -2
  45. package/dist/cli-bundle/sdk-core.js +41 -41
  46. package/dist/cli-bundle/sdk-governance.js +1 -1
  47. package/dist/cli-bundle/sdk-graph.js +1 -1
  48. package/dist/cli-bundle/sdk-merge.js +32 -32
  49. package/dist/cli-bundle/sdk-query.js +1 -1
  50. package/dist/cli-bundle/sdk-runtime.js +1 -1
  51. package/dist/cli-bundle/sdk-testing.js +1 -1
  52. package/dist/cli-bundle/sdk.js +5 -5
  53. package/dist/core/output/mutation-projection.js +26 -2
  54. package/dist/core/shared/constants.d.ts +1 -5
  55. package/dist/core/shared/constants.js +3 -81
  56. package/dist/core/shared/errors.d.ts +16 -0
  57. package/dist/core/shared/errors.js +2 -2
  58. package/dist/core/shared/item-metadata-contract.d.ts +14 -0
  59. package/dist/core/shared/item-metadata-contract.js +90 -0
  60. package/dist/core/store/item-store.d.ts +60 -0
  61. package/dist/core/store/item-store.js +26 -94
  62. package/dist/core/store/tracker-preflight.d.ts +7 -0
  63. package/dist/core/store/tracker-preflight.js +142 -0
  64. package/dist/sdk/agent/closed-domain-contracts.d.ts +25 -0
  65. package/dist/sdk/agent/closed-domain-contracts.js +140 -0
  66. package/dist/sdk/agent/refusal-closure.d.ts +13 -1
  67. package/dist/sdk/agent/refusal-closure.js +45 -3
  68. package/dist/sdk/agent/refusal-reachability.d.ts +26 -0
  69. package/dist/sdk/agent/refusal-reachability.js +26 -2
  70. package/dist/sdk/agent/tracker-preflight-contracts.d.ts +63 -0
  71. package/dist/sdk/agent/tracker-preflight-contracts.js +127 -0
  72. package/dist/sdk/agent-capability-contracts.js +6 -11
  73. package/dist/sdk/annotations.js +6 -7
  74. package/dist/sdk/cli-contracts/completeness.js +8 -2
  75. package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -2
  76. package/dist/sdk/cli-contracts/enum-contracts.js +16 -6
  77. package/dist/sdk/cli-contracts/flag-contracts.d.ts +2 -0
  78. package/dist/sdk/cli-contracts/flag-contracts.js +11 -2
  79. package/dist/sdk/cli-contracts/flag-lexicon-contracts.d.ts +19 -2
  80. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +105 -5
  81. package/dist/sdk/cli-contracts/grammar-contracts.d.ts +2 -2
  82. package/dist/sdk/cli-contracts/grammar-contracts.js +5 -2
  83. package/dist/sdk/cli-contracts/runtime-contracts.js +7 -3
  84. package/dist/sdk/cli-contracts/tool-schema.js +7 -2
  85. package/dist/sdk/cli-contracts.d.ts +2 -2
  86. package/dist/sdk/cli-contracts.js +4 -4
  87. package/dist/sdk/config.d.ts +5 -0
  88. package/dist/sdk/config.js +5 -5
  89. package/dist/sdk/context-intent-runtime.js +7 -4
  90. package/dist/sdk/contracts.d.ts +2 -0
  91. package/dist/sdk/contracts.js +4 -2
  92. package/dist/sdk/core.d.ts +1 -1
  93. package/dist/sdk/core.js +3 -3
  94. package/dist/sdk/dependencies.js +5 -7
  95. package/dist/sdk/dependency-flag-validation.d.ts +1 -1
  96. package/dist/sdk/dependency-flag-validation.js +10 -4
  97. package/dist/sdk/environment/tracker-preflight.d.ts +6 -0
  98. package/dist/sdk/environment/tracker-preflight.js +10 -0
  99. package/dist/sdk/eval.js +5 -7
  100. package/dist/sdk/files.js +6 -10
  101. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +110 -2
  102. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +179 -46
  103. package/dist/sdk/governance/assurance.d.ts +36 -2
  104. package/dist/sdk/governance/assurance.js +184 -10
  105. package/dist/sdk/governance/gc.js +5 -6
  106. package/dist/sdk/governance/health.js +5 -6
  107. package/dist/sdk/governance/reindex.js +5 -6
  108. package/dist/sdk/governance/validate.d.ts +1 -2
  109. package/dist/sdk/governance/validate.js +6 -12
  110. package/dist/sdk/graph/governance.d.ts +7 -5
  111. package/dist/sdk/graph/governance.js +32 -16
  112. package/dist/sdk/graph/run.js +5 -7
  113. package/dist/sdk/graph/traversal.js +14 -5
  114. package/dist/sdk/history-compact.js +6 -9
  115. package/dist/sdk/history-read.js +5 -7
  116. package/dist/sdk/history-redact.js +5 -6
  117. package/dist/sdk/history-repair.js +6 -9
  118. package/dist/sdk/improvement-ledger.js +7 -10
  119. package/dist/sdk/index.d.ts +7 -3
  120. package/dist/sdk/index.js +8 -4
  121. package/dist/sdk/init-agent-guidance.d.ts +5 -3
  122. package/dist/sdk/init-agent-guidance.js +69 -9
  123. package/dist/sdk/lifecycle/append.d.ts +0 -5
  124. package/dist/sdk/lifecycle/append.js +5 -6
  125. package/dist/sdk/lifecycle/claim.d.ts +0 -5
  126. package/dist/sdk/lifecycle/claim.js +6 -9
  127. package/dist/sdk/lifecycle/close-many.d.ts +0 -5
  128. package/dist/sdk/lifecycle/close-many.js +5 -6
  129. package/dist/sdk/lifecycle/close.d.ts +0 -5
  130. package/dist/sdk/lifecycle/close.js +5 -6
  131. package/dist/sdk/lifecycle/copy.d.ts +0 -5
  132. package/dist/sdk/lifecycle/copy.js +5 -6
  133. package/dist/sdk/lifecycle/create.d.ts +0 -5
  134. package/dist/sdk/lifecycle/create.js +5 -9
  135. package/dist/sdk/lifecycle/delete.js +5 -6
  136. package/dist/sdk/lifecycle/focus.d.ts +0 -5
  137. package/dist/sdk/lifecycle/focus.js +5 -6
  138. package/dist/sdk/lifecycle/mcp-actions.d.ts +18 -0
  139. package/dist/sdk/lifecycle/mcp-actions.js +52 -0
  140. package/dist/sdk/lifecycle/plan.d.ts +0 -5
  141. package/dist/sdk/lifecycle/plan.js +5 -6
  142. package/dist/sdk/lifecycle/reopen.d.ts +44 -0
  143. package/dist/sdk/lifecycle/reopen.js +69 -0
  144. package/dist/sdk/lifecycle/restore.js +5 -6
  145. package/dist/sdk/lifecycle/update-many.d.ts +0 -5
  146. package/dist/sdk/lifecycle/update-many.js +5 -6
  147. package/dist/sdk/lifecycle/update.d.ts +31 -5
  148. package/dist/sdk/lifecycle/update.js +140 -19
  149. package/dist/sdk/linked-artifacts.js +6 -7
  150. package/dist/sdk/merge/install.js +5 -6
  151. package/dist/sdk/mutation-events.js +5 -7
  152. package/dist/sdk/package-import-adapters.js +6 -8
  153. package/dist/sdk/profile.js +6 -7
  154. package/dist/sdk/query/activity.js +5 -6
  155. package/dist/sdk/query/calendar.js +5 -6
  156. package/dist/sdk/query/get.d.ts +1 -6
  157. package/dist/sdk/query/get.js +20 -55
  158. package/dist/sdk/query/history.d.ts +0 -5
  159. package/dist/sdk/query/history.js +5 -6
  160. package/dist/sdk/query/list.d.ts +7 -21
  161. package/dist/sdk/query/list.js +38 -54
  162. package/dist/sdk/query/projection-contracts.d.ts +33 -0
  163. package/dist/sdk/query/projection-contracts.js +185 -0
  164. package/dist/sdk/query/search-contracts.d.ts +2 -1
  165. package/dist/sdk/query/search-contracts.js +18 -87
  166. package/dist/sdk/query/search.d.ts +15 -0
  167. package/dist/sdk/query/search.js +34 -10
  168. package/dist/sdk/relationship-kinds/contract.d.ts +8 -0
  169. package/dist/sdk/relationship-kinds/contract.js +13 -13
  170. package/dist/sdk/relationships.d.ts +1 -1
  171. package/dist/sdk/relationships.js +20 -2
  172. package/dist/sdk/runtime-primitives.d.ts +1 -1
  173. package/dist/sdk/runtime-primitives.js +3 -3
  174. package/dist/sdk/runtime.d.ts +6 -0
  175. package/dist/sdk/runtime.js +18 -14
  176. package/dist/sdk/schema-migration.js +6 -7
  177. package/dist/sdk/schema.js +5 -6
  178. package/dist/sdk/similarity.d.ts +13 -0
  179. package/dist/sdk/similarity.js +32 -6
  180. package/dist/sdk/stats.js +5 -8
  181. package/dist/sdk/templates.js +5 -6
  182. package/dist/sdk/test/batch.js +5 -7
  183. package/dist/sdk/test/execution.js +4 -5
  184. package/dist/sdk/test/runs.js +5 -7
  185. package/docs/AGENT_UX_CONTRACTS.md +8 -1
  186. package/docs/COMMANDS.md +13 -1
  187. package/docs/DEPENDENCY_KIND_CONTRACT.md +12 -1
  188. package/docs/README.md +1 -0
  189. package/docs/RECURRENCE_RECOVERY_CONTRACTS.md +151 -0
  190. package/docs/RELATIONSHIP_GRAPH.md +92 -10
  191. package/docs/SDK.md +10 -2
  192. package/docs/SDK_CONTEXT_INTEGRITY.md +45 -0
  193. package/docs/SDK_PRIMITIVE_INVENTORY.md +15 -1
  194. package/docs/generated/AGENT_COMMAND_SURFACE.md +1 -1
  195. package/docs/performance/sdk-entrypoint-import-costs.md +14 -21
  196. package/marketplace.json +2 -2
  197. package/package.json +5 -5
  198. package/packages/pm-beads/package.json +1 -1
  199. package/packages/pm-calendar/package.json +1 -1
  200. package/packages/pm-command-kit/package.json +1 -1
  201. package/packages/pm-digital-twin/package.json +1 -1
  202. package/packages/pm-governance-audit/package.json +1 -1
  203. package/packages/pm-guide-shell/package.json +1 -1
  204. package/packages/pm-kanban/package.json +1 -1
  205. package/packages/pm-lifecycle-hooks/package.json +1 -1
  206. package/packages/pm-linked-test-adapters/package.json +1 -1
  207. package/packages/pm-search-advanced/package.json +1 -1
  208. package/packages/pm-templates/package.json +1 -1
  209. package/packages/pm-todos/package.json +1 -1
  210. package/packages/pm-vcs/package.json +1 -1
  211. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  212. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  213. package/sdk/public-surface.json +640 -44
  214. package/dist/cli-bundle/chunks/chunk-4THEB6PD.js +0 -13
  215. package/dist/cli-bundle/chunks/chunk-GWMXAQOD.js +0 -197
  216. package/dist/cli-bundle/chunks/chunk-HVFQTLYM.js +0 -35
  217. package/dist/cli-bundle/chunks/chunk-OI4XI562.js +0 -5
  218. package/dist/cli-bundle/chunks/chunk-OIOKV6NO.js +0 -2092
  219. package/dist/cli-bundle/chunks/chunk-SARFF5H5.js +0 -3
  220. package/dist/cli-bundle/chunks/chunk-YBMRWW4E.js +0 -77
  221. package/dist/cli-bundle/chunks/register-list-query-Y56KINDU.js +0 -11
  222. package/dist/cli-bundle/focused-chunks/chunk-34QBIYZI.js +0 -155
  223. package/dist/cli-bundle/focused-chunks/chunk-BJRYFVSH.js +0 -2
  224. package/dist/cli-bundle/focused-chunks/chunk-EF6ZS5GH.js +0 -50
  225. package/dist/cli-bundle/focused-chunks/chunk-L623ZPNK.js +0 -2
  226. package/dist/cli-bundle/focused-chunks/chunk-PRHY2IMX.js +0 -18
  227. package/dist/cli-bundle/focused-chunks/chunk-RZU5U6Q7.js +0 -2
  228. package/dist/cli-bundle/focused-chunks/chunk-YBMGXBFV.js +0 -16
  229. package/dist/cli-bundle/focused-chunks/chunk-YLVBJ6GF.js +0 -2
@@ -7,7 +7,7 @@
7
7
  * one deterministic SDK path.
8
8
  */
9
9
 
10
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="2bf52d6d-7e4f-5ec5-86bd-3e817ef521bb")}catch(e){}}();
10
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d4c380ce-031e-5b2d-aaa8-658bb4aa3087")}catch(e){}}();
11
11
  import { createHash } from "node:crypto";
12
12
  import path from "node:path";
13
13
  import { EXIT_CODE } from "../../core/shared/constants.js";
@@ -34,6 +34,7 @@ export const ASSURANCE_GATE_TRIGGERS = [
34
34
  export const ASSURANCE_MEASUREMENT_SOURCE_KINDS = [
35
35
  "items",
36
36
  "dependency_kind",
37
+ "prose_edge_gap",
37
38
  "graph",
38
39
  "validate",
39
40
  "health",
@@ -167,6 +168,53 @@ function validateItemsMeasurementSource(source) {
167
168
  throw new AssuranceMutationRefusalError("items source equals/state requires field");
168
169
  }
169
170
  }
171
+ /** Validate relationship-provenance predicates on a dependency-kind measurement. */
172
+ function validateDependencyKindMeasurementSource(source) {
173
+ if (typeof source.dependency_kind !== "string" ||
174
+ source.dependency_kind.trim().length === 0) {
175
+ throw new AssuranceMutationRefusalError("dependency_kind source requires dependency_kind");
176
+ }
177
+ const provenancePredicateCount = [
178
+ source.source_kind,
179
+ source.source_kind_prefix,
180
+ source.source_kind_state,
181
+ ].filter((value) => value !== undefined).length;
182
+ if (provenancePredicateCount > 1) {
183
+ throw new AssuranceMutationRefusalError("dependency_kind source accepts at most one source_kind predicate");
184
+ }
185
+ if ((source.source_kind !== undefined &&
186
+ source.source_kind.trim().length === 0) ||
187
+ (source.source_kind_prefix !== undefined &&
188
+ source.source_kind_prefix.trim().length === 0)) {
189
+ throw new AssuranceMutationRefusalError("dependency_kind source provenance values must not be empty");
190
+ }
191
+ if (source.source_kind_state !== undefined &&
192
+ source.source_kind_state !== "present" &&
193
+ source.source_kind_state !== "missing") {
194
+ throw new AssuranceMutationRefusalError("dependency_kind source source_kind_state must be present or missing");
195
+ }
196
+ }
197
+ /** Validate bounded, reasoned prose-parity exemptions. */
198
+ function validateProseEdgeGapSource(source) {
199
+ if (source.sample_limit !== undefined &&
200
+ (!Number.isInteger(source.sample_limit) || source.sample_limit < 1)) {
201
+ throw new AssuranceMutationRefusalError("prose_edge_gap sample_limit must be a positive integer");
202
+ }
203
+ for (const exemption of source.exemptions ?? []) {
204
+ if (typeof exemption.holder_id !== "string" ||
205
+ exemption.holder_id.trim().length === 0 ||
206
+ typeof exemption.reason !== "string" ||
207
+ exemption.reason.trim().length === 0) {
208
+ throw new AssuranceMutationRefusalError("prose_edge_gap exemptions require holder_id and reason");
209
+ }
210
+ if ((exemption.target_id !== undefined &&
211
+ exemption.target_id.trim().length === 0) ||
212
+ (exemption.text_contains !== undefined &&
213
+ exemption.text_contains.trim().length === 0)) {
214
+ throw new AssuranceMutationRefusalError("prose_edge_gap exemption selectors must not be empty");
215
+ }
216
+ }
217
+ }
170
218
  /** Validate and return one measurement declaration. */
171
219
  export function validateMeasurementDefinition(definition) {
172
220
  requireStableId(definition.id, "measurement.id");
@@ -185,11 +233,10 @@ export function validateMeasurementDefinition(definition) {
185
233
  if (source.kind === "items") {
186
234
  validateItemsMeasurementSource(source);
187
235
  }
188
- if (source.kind === "dependency_kind" &&
189
- (typeof source.dependency_kind !== "string" ||
190
- source.dependency_kind.trim().length === 0)) {
191
- throw new AssuranceMutationRefusalError("dependency_kind source requires dependency_kind");
192
- }
236
+ if (source.kind === "dependency_kind")
237
+ validateDependencyKindMeasurementSource(source);
238
+ if (source.kind === "prose_edge_gap")
239
+ validateProseEdgeGapSource(source);
193
240
  if ((source.kind === "graph" ||
194
241
  source.kind === "validate" ||
195
242
  source.kind === "health") &&
@@ -419,6 +466,24 @@ function itemsSourceResult(source, context) {
419
466
  contributors: matches.map((item) => item.id),
420
467
  };
421
468
  }
469
+ /** Match one normalized dependency provenance against an optional partition. */
470
+ function dependencyProvenanceMatches(source, sourceKind) {
471
+ if (source.source_kind !== undefined) {
472
+ return (sourceKind?.toLowerCase() === source.source_kind.trim().toLowerCase());
473
+ }
474
+ if (source.source_kind_prefix !== undefined) {
475
+ return (sourceKind
476
+ ?.toLowerCase()
477
+ .startsWith(source.source_kind_prefix.trim().toLowerCase()) === true);
478
+ }
479
+ if (source.source_kind_state === "present") {
480
+ return sourceKind !== undefined && sourceKind.length > 0;
481
+ }
482
+ if (source.source_kind_state === "missing") {
483
+ return sourceKind === undefined || sourceKind.length === 0;
484
+ }
485
+ return true;
486
+ }
422
487
  function dependencyKindSourceResult(source, context) {
423
488
  const contributors = [];
424
489
  const requestedKind = resolveCanonicalRelationshipKind(source.dependency_kind) ??
@@ -427,9 +492,10 @@ function dependencyKindSourceResult(source, context) {
427
492
  for (const dependency of item.dependencies ?? []) {
428
493
  const dependencyKind = resolveCanonicalRelationshipKind(dependency.kind) ??
429
494
  dependency.kind.trim().toLowerCase();
430
- if (dependencyKind === requestedKind) {
431
- contributors.push(`${item.id}->${dependency.id}`);
432
- }
495
+ const sourceKind = dependency.source_kind?.trim();
496
+ if (dependencyKind === requestedKind &&
497
+ dependencyProvenanceMatches(source, sourceKind))
498
+ contributors.push(`${item.id}->${dependency.id}${sourceKind ? `@${sourceKind}` : ""}`);
433
499
  }
434
500
  }
435
501
  return {
@@ -439,6 +505,109 @@ function dependencyKindSourceResult(source, context) {
439
505
  contributors,
440
506
  };
441
507
  }
508
+ /** Return every text segment whose item identifiers form the prose graph. */
509
+ function assuranceItemProseSegments(item) {
510
+ const segments = [item.description, item.body]
511
+ .filter((value) => typeof value === "string")
512
+ .map((value) => value.trim())
513
+ .filter(Boolean);
514
+ for (const key of ["comments", "notes", "learnings"]) {
515
+ const entries = item[key];
516
+ if (!Array.isArray(entries))
517
+ continue;
518
+ for (const entry of entries) {
519
+ if (typeof entry === "string")
520
+ segments.push(entry);
521
+ else if (typeof entry === "object" && entry !== null) {
522
+ const text = Reflect.get(entry, "text");
523
+ if (typeof text === "string")
524
+ segments.push(text);
525
+ }
526
+ }
527
+ }
528
+ return segments;
529
+ }
530
+ /** Return whether a reviewed exemption applies to one prose reference. */
531
+ function proseReferenceIsExempt(exemptions, holderId, targetId, segment) {
532
+ return exemptions.some((exemption) => exemption.holder_id.trim().toLowerCase() === holderId.toLowerCase() &&
533
+ (exemption.target_id === undefined ||
534
+ exemption.target_id.trim().toLowerCase() === targetId.toLowerCase()) &&
535
+ (exemption.text_contains === undefined ||
536
+ segment
537
+ .toLowerCase()
538
+ .includes(exemption.text_contains.trim().toLowerCase())));
539
+ }
540
+ /** Return the direction-independent identity of a prose or structured item pair. */
541
+ function prosePairKey(left, right) {
542
+ return [left.toLowerCase(), right.toLowerCase()].sort().join("\u0000");
543
+ }
544
+ /** Collect canonical ids, typed links, and raw prose mentions in one item pass. */
545
+ function collectProseEdgeCensusInputs(items) {
546
+ const canonicalIds = new Map();
547
+ const linkedPairs = new Set();
548
+ const proseMentions = [];
549
+ const mentionPattern = /\b[a-z][a-z0-9]*-[a-z0-9]+\b/giu;
550
+ let mentionCount = 0;
551
+ for (const item of items) {
552
+ canonicalIds.set(item.id.toLowerCase(), item.id);
553
+ for (const dependency of item.dependencies ?? [])
554
+ linkedPairs.add(prosePairKey(item.id, dependency.id));
555
+ for (const scalar of [item.parent, item.blocked_by])
556
+ if (typeof scalar === "string")
557
+ linkedPairs.add(prosePairKey(item.id, scalar));
558
+ for (const segment of assuranceItemProseSegments(item)) {
559
+ const mentionedIds = [...segment.matchAll(mentionPattern)].map((match) => match[0]);
560
+ mentionCount += mentionedIds.length;
561
+ proseMentions.push({
562
+ holder_id: item.id,
563
+ segment,
564
+ mentioned_ids: mentionedIds,
565
+ });
566
+ }
567
+ }
568
+ return {
569
+ canonical_ids: canonicalIds,
570
+ linked_pairs: linkedPairs,
571
+ prose_mentions: proseMentions,
572
+ mention_count: mentionCount,
573
+ };
574
+ }
575
+ /** Count distinct prose-named item pairs that have no typed edge in either direction. */
576
+ function proseEdgeGapSourceResult(source, context) {
577
+ const census = collectProseEdgeCensusInputs(context.items);
578
+ const gaps = new Map();
579
+ for (const proseMention of census.prose_mentions) {
580
+ const mentions = proseMention.mentioned_ids
581
+ .map((id) => census.canonical_ids.get(id.toLowerCase()))
582
+ .filter((id) => id !== undefined && id !== proseMention.holder_id);
583
+ const distinctMentions = [...new Set(mentions)];
584
+ for (const targetId of distinctMentions) {
585
+ const key = prosePairKey(proseMention.holder_id, targetId);
586
+ if (census.linked_pairs.has(key) ||
587
+ proseReferenceIsExempt(source.exemptions ?? [], proseMention.holder_id, targetId, proseMention.segment))
588
+ continue;
589
+ const explicit = distinctMentions.some((candidate) => candidate !== targetId);
590
+ if (gaps.get(key)?.explicit === true && !explicit)
591
+ continue;
592
+ gaps.set(key, {
593
+ contributor: `${proseMention.holder_id}->${targetId}|subject=${explicit ? "explicit" : "implicit"}`,
594
+ explicit,
595
+ });
596
+ }
597
+ }
598
+ const gapRows = [...gaps.values()];
599
+ const contributors = gapRows.map((entry) => entry.contributor).sort();
600
+ return {
601
+ value: contributors.length,
602
+ population_size: census.canonical_ids.size,
603
+ cost: context.items.length + census.linked_pairs.size + census.mention_count,
604
+ contributors: contributors.slice(0, source.sample_limit ?? 25),
605
+ partitions: {
606
+ explicit_subject: gapRows.filter((entry) => entry.explicit).length,
607
+ implicit_subject: gapRows.filter((entry) => !entry.explicit).length,
608
+ },
609
+ };
610
+ }
442
611
  function historySourceResult(source, context) {
443
612
  const matches = context.history.filter((entry) => (source.op === undefined || entry.op === source.op) &&
444
613
  (source.author === undefined || entry.author === source.author) &&
@@ -471,6 +640,8 @@ function sourceResult(definition, context) {
471
640
  if (source.kind === "dependency_kind") {
472
641
  return dependencyKindSourceResult(source, context);
473
642
  }
643
+ if (source.kind === "prose_edge_gap")
644
+ return proseEdgeGapSourceResult(source, context);
474
645
  if (source.kind === "history")
475
646
  return historySourceResult(source, context);
476
647
  if (source.kind === "links")
@@ -583,6 +754,7 @@ async function evaluateMeasurementInternal(definition, context, definitions, sta
583
754
  units: result.cost,
584
755
  items_scanned: definition.source.kind === "items" ||
585
756
  definition.source.kind === "dependency_kind" ||
757
+ definition.source.kind === "prose_edge_gap" ||
586
758
  definition.source.kind === "links"
587
759
  ? context.items.length
588
760
  : 0,
@@ -603,6 +775,7 @@ async function evaluateMeasurementInternal(definition, context, definitions, sta
603
775
  population_size: result.population_size,
604
776
  cost,
605
777
  contributors: result.contributors ?? [],
778
+ ...(result.partitions ? { partitions: result.partitions } : {}),
606
779
  };
607
780
  }
608
781
  function evaluateMeasurementCached(definition, context, definitions, stack, state) {
@@ -670,6 +843,7 @@ export function evaluateAssuranceAssertion(definition, measurement, options = {}
670
843
  negative_control_proven: proveNegativeControl(definition),
671
844
  cost: measurement.cost,
672
845
  contributors: measurement.contributors,
846
+ ...(measurement.partitions ? { partitions: measurement.partitions } : {}),
673
847
  };
674
848
  }
675
849
  function enforceGateProviderPolicy(gate, document, context, trigger) {
@@ -1006,4 +1180,4 @@ export async function listAssuranceVerdicts(pmRoot, options = {}) {
1006
1180
  .slice(0, limit);
1007
1181
  }
1008
1182
  //# sourceMappingURL=assurance.js.map
1009
- //# debugId=2bf52d6d-7e4f-5ec5-86bd-3e817ef521bb
1183
+ //# debugId=d4c380ce-031e-5b2d-aaa8-658bb4aa3087
@@ -4,7 +4,8 @@
4
4
  * Implements the pm gc command surface and its agent-facing runtime behavior.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e982158e-4a8d-57a9-bd0b-24bd73aef342")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="76f8405f-138d-5119-a300-f068354394a5")}catch(e){}}();
8
+ import { assertInitializedTracker } from "../environment/tracker-preflight.js";
8
9
  import fs from "node:fs/promises";
9
10
  import path from "node:path";
10
11
  import { runCheckpointGc } from "../../core/checkpoint/checkpoint-gc.js";
@@ -15,7 +16,7 @@ import { runLockGc } from "../../core/lock/lock-gc.js";
15
16
  import { EXIT_CODE } from "../../core/shared/constants.js";
16
17
  import { PmCliError } from "../../core/shared/errors.js";
17
18
  import { nowIso } from "../../core/shared/time.js";
18
- import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
19
+ import { resolvePmRoot } from "../../core/store/paths.js";
19
20
  import { readSettings } from "../../core/store/settings.js";
20
21
  const GC_SCOPE_VALUES = [
21
22
  "index",
@@ -234,9 +235,7 @@ function buildGcGuidance(params) {
234
235
  /** Implements run gc for the public runtime surface of this module. */
235
236
  export async function runGc(global, options = {}) {
236
237
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
237
- if (!(await pathExists(getSettingsPath(pmRoot)))) {
238
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
239
- }
238
+ await assertInitializedTracker(pmRoot);
240
239
  const settings = await readSettings(pmRoot);
241
240
  const dryRun = options.dryRun === true;
242
241
  const scopes = parseScopes(options.scope);
@@ -367,4 +366,4 @@ export async function runGc(global, options = {}) {
367
366
  };
368
367
  }
369
368
  //# sourceMappingURL=gc.js.map
370
- //# debugId=e982158e-4a8d-57a9-bd0b-24bd73aef342
369
+ //# debugId=76f8405f-138d-5119-a300-f068354394a5
@@ -4,11 +4,12 @@
4
4
  * Implements the pm health command surface and its agent-facing runtime behavior.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e7be701e-085c-5903-96da-61149452c673")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a7e3a41b-7d69-526d-aa3e-bc244ef8fe0c")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
+ import { assertInitializedTracker } from "../environment/tracker-preflight.js";
10
11
  import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
11
- import { isFileMissingError, pathExists, readFileIfExists, } from "../../core/fs/fs-utils.js";
12
+ import { isFileMissingError, readFileIfExists, } from "../../core/fs/fs-utils.js";
12
13
  import { activateExtensions, getActiveExtensionRegistrations, loadExtensions, runActiveOnReadHooks, } from "../../core/extensions/index.js";
13
14
  import { collectRegisteredItemFieldNames } from "../../core/extensions/item-fields.js";
14
15
  import { KNOWN_EXTENSION_CAPABILITIES, } from "../../core/extensions/loader.js";
@@ -1950,10 +1951,8 @@ function projectHealthResult(result, options, summaryMode) {
1950
1951
  /** Implements run health for the public runtime surface of this module. */
1951
1952
  export async function runHealth(global, options = {}) {
1952
1953
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
1954
+ await assertInitializedTracker(pmRoot);
1953
1955
  const settingsPath = getSettingsPath(pmRoot);
1954
- if (!(await pathExists(settingsPath))) {
1955
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
1956
- }
1957
1956
  const { settings, warnings: settingsReadWarnings } = await readSettingsWithMetadata(pmRoot);
1958
1957
  const normalizedSettingsReadWarnings = [...new Set(settingsReadWarnings)];
1959
1958
  const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
@@ -2111,4 +2110,4 @@ export const _testOnlyHealthCommand = {
2111
2110
  warningCode,
2112
2111
  };
2113
2112
  //# sourceMappingURL=health.js.map
2114
- //# debugId=e7be701e-085c-5903-96da-61149452c673
2113
+ //# debugId=a7e3a41b-7d69-526d-aa3e-bc244ef8fe0c
@@ -4,10 +4,11 @@
4
4
  * Implements the pm reindex command surface and its agent-facing runtime behavior.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fc124f85-8d28-508b-a3f7-2fe767382197")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1bcd20e1-2995-56ef-8d04-f265b8282c19")}catch(e){}}();
8
+ import { assertInitializedTracker } from "../environment/tracker-preflight.js";
8
9
  import fs from "node:fs/promises";
9
10
  import path from "node:path";
10
- import { toNonEmptyStringOrUndefined, getActiveExtensionRegistrations, runActiveOnIndexHooks, runActiveOnWriteHooks, collectRegisteredItemFieldNames, resolveRegisteredSearchProvider, resolveRegisteredVectorStoreAdapter, pathExists, writeFileAtomic, resolveItemTypeRegistry, parseItemDocument, acquireLock, buildSearchCorpus, buildSemanticCorpusInput, resolveSearchCorpusFields, resolveSemanticCorpusCharacterLimit, executeEmbeddingBatchesWithRetry, readVectorizationStatusLedger, writeVectorizationStatusLedger, REINDEX_LOCK_ID, resolveEmbeddingProviders, resolveSettingsWithSemanticRuntimeDefaults, executeVectorDelete, executeVectorReset, executeVectorUpsert, resolveVectorStores, buildVectorizationEmbeddingIdentity, buildVectorizationEmbeddingMetadata, hasVectorizationEmbeddingIdentityChanged, hasVectorizationVectorDimensionChanged, inferConsistentVectorDimension, EXIT_CODE, PmCliError, nowIso, listAllDocumentCandidatesCached, getSettingsPath, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
11
+ import { toNonEmptyStringOrUndefined, getActiveExtensionRegistrations, runActiveOnIndexHooks, runActiveOnWriteHooks, collectRegisteredItemFieldNames, resolveRegisteredSearchProvider, resolveRegisteredVectorStoreAdapter, writeFileAtomic, resolveItemTypeRegistry, parseItemDocument, acquireLock, buildSearchCorpus, buildSemanticCorpusInput, resolveSearchCorpusFields, resolveSemanticCorpusCharacterLimit, executeEmbeddingBatchesWithRetry, readVectorizationStatusLedger, writeVectorizationStatusLedger, REINDEX_LOCK_ID, resolveEmbeddingProviders, resolveSettingsWithSemanticRuntimeDefaults, executeVectorDelete, executeVectorReset, executeVectorUpsert, resolveVectorStores, buildVectorizationEmbeddingIdentity, buildVectorizationEmbeddingMetadata, hasVectorizationEmbeddingIdentityChanged, hasVectorizationVectorDimensionChanged, inferConsistentVectorDimension, EXIT_CODE, PmCliError, nowIso, listAllDocumentCandidatesCached, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
11
12
  const MANIFEST_PATH = "index/manifest.json";
12
13
  const EMBEDDINGS_PATH = "search/embeddings.jsonl";
13
14
  const EMBEDDING_MIGRATION_REINDEX_HINT = "Provider or model has changed since last index. Run pm reindex --mode semantic to rebuild.";
@@ -630,9 +631,7 @@ export async function runReindex(options, global) {
630
631
  const forceFullSemantic = options.full === true;
631
632
  emitReindexProgress(progressEnabled, `start mode=${requestedMode}`);
632
633
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
633
- if (!(await pathExists(getSettingsPath(pmRoot)))) {
634
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
635
- }
634
+ await assertInitializedTracker(pmRoot);
636
635
  const settings = resolveSettingsWithSemanticRuntimeDefaults(await readSettings(pmRoot)).settings;
637
636
  let releaseReindexLock = null;
638
637
  try {
@@ -760,4 +759,4 @@ export async function runReindex(options, global) {
760
759
  }
761
760
  }
762
761
  //# sourceMappingURL=reindex.js.map
763
- //# debugId=fc124f85-8d28-508b-a3f7-2fe767382197
762
+ //# debugId=1bcd20e1-2995-56ef-8d04-f265b8282c19
@@ -13,8 +13,7 @@ type ValidateDependencyCycleSeverity = "off" | "warn" | "error";
13
13
  type ValidateFileScanMode = "default" | "tracked-all" | "tracked-all-strict";
14
14
  type ItemWithBody = ValidateItem;
15
15
  type OrphanedPathClassification = "docs_unowned" | "tests_unowned" | "source_unowned" | "unlinked_existing";
16
- declare const LIFECYCLE_PATTERN_FIELD_KEYS: readonly ["blocked_reason", "resolution", "actual_result"];
17
- type LifecyclePatternFieldKey = (typeof LIFECYCLE_PATTERN_FIELD_KEYS)[number];
16
+ type LifecyclePatternFieldKey = "blocked_reason" | "resolution" | "actual_result";
18
17
  /** Documents the validate command options payload exchanged by command, SDK, and package integrations. */
19
18
  export interface ValidateCommandOptions {
20
19
  /** Value that configures or reports check metadata for this contract. */
@@ -4,7 +4,8 @@
4
4
  * Implements the pm validate command surface and its agent-facing runtime behavior.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b8c4707f-5445-5079-96e5-dc0dbd649b34")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1ed6b663-882a-5936-bd89-46bbbb17d806")}catch(e){}}();
8
+ import { assertInitializedTracker } from "../environment/tracker-preflight.js";
8
9
  import fs from "node:fs/promises";
9
10
  import { realpathSync } from "node:fs";
10
11
  import { execFile } from "node:child_process";
@@ -13,7 +14,7 @@ import { promisify } from "node:util";
13
14
  import { buildRemediationCommands } from "../../core/diagnostics/remediation.js";
14
15
  import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
15
16
  import { collectRegisteredItemFieldNames } from "../../core/extensions/item-fields.js";
16
- import { isFileMissingError, pathExists } from "../../core/fs/fs-utils.js";
17
+ import { isFileMissingError } from "../../core/fs/fs-utils.js";
17
18
  import { normalizeStatusInput } from "../../core/item/status.js";
18
19
  import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
19
20
  import { resolveRuntimeStatusRegistry, } from "../../core/schema/runtime-schema.js";
@@ -22,7 +23,7 @@ import { PmCliError } from "../../core/shared/errors.js";
22
23
  import { toNonEmptyStringOrUndefined } from "../../core/shared/primitives.js";
23
24
  import { nowIso } from "../../core/shared/time.js";
24
25
  import { CURRENT_ITEM_FORMAT_VERSION, effectiveItemFormatVersion, scanItemFormatVersions, } from "../../core/item/item-format-version.js";
25
- import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
26
+ import { resolvePmRoot } from "../../core/store/paths.js";
26
27
  import { readSettings } from "../../core/store/settings.js";
27
28
  import { partitionFixesByGrant, planCloseReasonBackfillFixes, planEstimateBackfillFixes, planResolutionBackfillFixes, planStaleLinkPruneFixes, planTerminalParentFixes, resolveGrantedFixScopes, toFixOutputRow, } from "../../core/validate/fix-planning.js";
28
29
  import { findDuplicateIssueCodes, } from "../../core/governance/issue-codes.js";
@@ -78,11 +79,6 @@ const VALIDATE_DEPENDENCY_CYCLE_SEVERITY_VALUES = [
78
79
  "warn",
79
80
  "error",
80
81
  ];
81
- const LIFECYCLE_PATTERN_FIELD_KEYS = [
82
- "blocked_reason",
83
- "resolution",
84
- "actual_result",
85
- ];
86
82
  const CORE_METADATA_REQUIRED_FIELDS = [
87
83
  "author",
88
84
  "acceptance_criteria",
@@ -2226,9 +2222,7 @@ export async function runValidate(options, global, services = {}) {
2226
2222
  // Resolved up-front so unknown --fix-scope values fail fast before any scan.
2227
2223
  const grantedFixScopes = resolveGrantedFixScopes(options.fixScope);
2228
2224
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
2229
- if (!(await pathExists(getSettingsPath(pmRoot)))) {
2230
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
2231
- }
2225
+ await assertInitializedTracker(pmRoot);
2232
2226
  const settings = await readSettings(pmRoot);
2233
2227
  const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
2234
2228
  const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
@@ -2313,4 +2307,4 @@ export async function runValidate(options, global, services = {}) {
2313
2307
  }
2314
2308
  /* c8 ignore stop */
2315
2309
  //# sourceMappingURL=validate.js.map
2316
- //# debugId=b8c4707f-5445-5079-96e5-dc0dbd649b34
2310
+ //# debugId=1ed6b663-882a-5936-bd89-46bbbb17d806
@@ -12,7 +12,7 @@
12
12
  * carries a deterministic bounded sample, and proposes a safe next action so
13
13
  * agents can plan remediation without re-deriving context.
14
14
  */
15
- import type { RelationshipEdge } from "../relationships.js";
15
+ import type { RelationshipEdge, RelationshipOutcomeTraversal } from "../relationships.js";
16
16
  import type { OrderingStorageContradiction, WorkspaceRelationshipAssembly } from "./assembly.js";
17
17
  import { type RelationshipAuditFindingCode } from "./governance-contracts.js";
18
18
  export type { RelationshipAuditFindingCode } from "./governance-contracts.js";
@@ -88,17 +88,19 @@ export interface RelationshipCoverageProfile {
88
88
  bridge_edges: number;
89
89
  /** Milestone nodes whose title explicitly declares an outcome. */
90
90
  outcome_nodes: number;
91
- /** Active non-outcome nodes with a typed hierarchy or implements path to an outcome. */
91
+ /** Declared edge kinds and directions admitted by typed outcome reachability. */
92
+ outcome_reachability_basis: Record<RelationshipOutcomeTraversal, string>;
93
+ /** Active non-outcome nodes with a path admitted by outcome_reachability_basis. */
92
94
  active_outcome_reachable_nodes: number;
93
- /** Active non-outcome nodes without a typed hierarchy or implements path to an outcome. */
95
+ /** Active non-outcome nodes without a path admitted by outcome_reachability_basis. */
94
96
  active_outcome_unreachable_nodes: number;
95
97
  /** Active typed-outcome reachability expressed as integer basis points. */
96
98
  active_outcome_reachability_basis_points: number;
97
99
  /** Terminal non-placeholder, non-outcome nodes included in the all-status census. */
98
100
  terminal_nodes: number;
99
- /** Terminal non-outcome nodes with a typed hierarchy or implements path to an outcome. */
101
+ /** Terminal non-outcome nodes with a path admitted by outcome_reachability_basis. */
100
102
  terminal_outcome_reachable_nodes: number;
101
- /** Terminal non-outcome nodes without a typed hierarchy or implements path to an outcome. */
103
+ /** Terminal non-outcome nodes without a path admitted by outcome_reachability_basis. */
102
104
  terminal_outcome_unreachable_nodes: number;
103
105
  /** Terminal typed-outcome reachability expressed as integer basis points. */
104
106
  terminal_outcome_reachability_basis_points: number;
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b63fba34-8ca1-5e3a-905d-772ea8ce0f11")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c5dbaccd-d0e5-5511-b659-4f0a5f45ccaf")}catch(e){}}();
3
3
  import { findRedundantRelationshipEdges, isTransitiveKind, orientTransitiveEdge, transitiveFamilyKey, } from "./analytics.js";
4
4
  import { findRelationshipCutStructure } from "./centrality.js";
5
5
  import { RELATIONSHIP_AUDIT_FINDING_CODES, } from "./governance-contracts.js";
@@ -336,23 +336,37 @@ function collectDuplicateRowFindings(assembly, maxSampleSize) {
336
336
  /** Build the reverse typed paths that can carry context toward an outcome. */
337
337
  function buildOutcomeReverseIndex(assembly, signal) {
338
338
  const reverse = new Map();
339
+ const basisKinds = {
340
+ source_to_target: [],
341
+ target_to_source: [],
342
+ both: [],
343
+ };
344
+ for (const definition of assembly.graph.registry().list()) {
345
+ if (definition.outcomeTraversal !== undefined) {
346
+ basisKinds[definition.outcomeTraversal].push(definition.kind);
347
+ }
348
+ }
349
+ const basis = {
350
+ source_to_target: basisKinds.source_to_target.join(","),
351
+ target_to_source: basisKinds.target_to_source.join(","),
352
+ both: basisKinds.both.join(","),
353
+ };
354
+ const append = (from, to) => {
355
+ const sources = reverse.get(to) ?? new Set();
356
+ sources.add(from);
357
+ reverse.set(to, sources);
358
+ };
339
359
  for (const edge of assembly.graph.edges()) {
340
360
  signal?.throwIfAborted();
341
361
  const definition = assembly.graph.registry().require(edge.kind);
342
- let oriented;
343
- if (definition.hierarchy) {
344
- oriented = orientTransitiveEdge(edge, definition);
345
- }
346
- else if (definition.kind === "implements") {
347
- oriented = { from: edge.source, to: edge.target };
348
- }
349
- if (oriented === undefined)
350
- continue;
351
- const sources = reverse.get(oriented.to) ?? new Set();
352
- sources.add(oriented.from);
353
- reverse.set(oriented.to, sources);
362
+ if (definition.outcomeTraversal === "source_to_target" ||
363
+ definition.outcomeTraversal === "both")
364
+ append(edge.source, edge.target);
365
+ if (definition.outcomeTraversal === "target_to_source" ||
366
+ definition.outcomeTraversal === "both")
367
+ append(edge.target, edge.source);
354
368
  }
355
- return reverse;
369
+ return { basis, reverse };
356
370
  }
357
371
  /** Expand outcome nodes through every deterministic reverse typed path. */
358
372
  function expandOutcomeReachability(outcomes, reverse, signal) {
@@ -425,9 +439,11 @@ function profileOutcomeReachability(assembly, nodeStates, signal) {
425
439
  .toLowerCase()
426
440
  .startsWith(OUTCOME_MILESTONE_TITLE_PREFIX))
427
441
  .map((detail) => detail.id));
428
- const reachable = expandOutcomeReachability(outcomes, buildOutcomeReverseIndex(assembly, signal), signal);
442
+ const { basis, reverse } = buildOutcomeReverseIndex(assembly, signal);
443
+ const reachable = expandOutcomeReachability(outcomes, reverse, signal);
429
444
  return {
430
445
  outcome_nodes: outcomes.size,
446
+ outcome_reachability_basis: basis,
431
447
  ...tallyOutcomeReachability(nodeStates, outcomes, reachable, signal),
432
448
  };
433
449
  }
@@ -673,4 +689,4 @@ export function diffRelationshipAuditSnapshots(baseline, current) {
673
689
  };
674
690
  }
675
691
  //# sourceMappingURL=governance.js.map
676
- //# debugId=b63fba34-8ca1-5e3a-905d-772ea8ce0f11
692
+ //# debugId=c5dbaccd-d0e5-5511-b659-4f0a5f45ccaf
@@ -11,9 +11,9 @@
11
11
  * queries in long-lived hosts are answered from the memoized snapshot.
12
12
  */
13
13
 
14
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6c8bfb7a-687a-5fbb-b408-ffdbab1187a9")}catch(e){}}();
14
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b7aa5929-ab87-5616-a749-1c353ae7b3c3")}catch(e){}}();
15
+ import { assertInitializedTracker } from "../environment/tracker-preflight.js";
15
16
  import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
16
- import { pathExists } from "../../core/fs/fs-utils.js";
17
17
  import { isTerminalStatus } from "../../core/item/status.js";
18
18
  import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
19
19
  import { resolveRuntimeStatusRegistry } from "../../core/schema/runtime-schema.js";
@@ -21,7 +21,7 @@ import { EXIT_CODE } from "../../core/shared/constants.js";
21
21
  import { PmCliError } from "../../core/shared/errors.js";
22
22
  import { createUnknownSubcommandError } from "../agent/subcommand-recovery.js";
23
23
  import { listAllItemMetadataLight } from "../../core/store/item-store.js";
24
- import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
24
+ import { resolvePmRoot } from "../../core/store/paths.js";
25
25
  import { readSettings } from "../../core/store/settings.js";
26
26
  import { parseDirection, parseKinds, parseMaxDepth, parsePositiveInteger, } from "../dependencies.js";
27
27
  import { analyzeGraphImpact, analyzeKnowledgeGraph, analyzeRelationshipExecution, } from "../relationship-analytics.js";
@@ -661,9 +661,7 @@ export async function runGraph(subcommandRaw, id, target, options, global) {
661
661
  const subcommand = parseGraphSubcommand(subcommandRaw, id, target);
662
662
  assertProjectionModeChoice(options.summary === true, options.full === true, "--summary");
663
663
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
664
- if (!(await pathExists(getSettingsPath(pmRoot)))) {
665
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
666
- }
664
+ await assertInitializedTracker(pmRoot);
667
665
  const settings = await readSettings(pmRoot);
668
666
  const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
669
667
  const items = await listAllItemMetadataLight(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema);
@@ -719,4 +717,4 @@ export async function runGraph(subcommandRaw, id, target, options, global) {
719
717
  return attachGraphProjection(value, invocation.summary, "result_rows");
720
718
  }
721
719
  //# sourceMappingURL=run.js.map
722
- //# debugId=6c8bfb7a-687a-5fbb-b408-ffdbab1187a9
720
+ //# debugId=b7aa5929-ab87-5616-a749-1c353ae7b3c3
@@ -1,6 +1,6 @@
1
1
  /** Default number of paths returned by bounded path enumeration. */
2
2
 
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c0fb747e-1f9f-55c4-808b-b77d3a881f87")}catch(e){}}();
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ac2b3cd9-5a98-5fea-888c-e96de8cd593d")}catch(e){}}();
4
4
  const DEFAULT_MAX_PATHS = 5;
5
5
  /** Default expansion-safety bound for bounded path enumeration. */
6
6
  const DEFAULT_MAX_VISITED_PATHS = 10_000;
@@ -50,8 +50,17 @@ function resolveFamilyKinds(graph, kinds, family) {
50
50
  const resolved = new Set();
51
51
  for (const kind of kinds) {
52
52
  const definition = registry.require(kind);
53
- if (!definition[family])
54
- throw new TypeError(`Relationship kind ${definition.kind} is not a ${family} kind`);
53
+ // Registry registration normalizes this optional compatibility field before
54
+ // definitions become queryable.
55
+ const traversal = definition.traversal;
56
+ if (traversal === "association")
57
+ throw new TypeError(`Relationship kind ${definition.kind} uses association traversal; use graph impact --direction both`);
58
+ if (traversal !== family && traversal !== "semantic") {
59
+ const redirect = traversal === "hierarchy"
60
+ ? "graph ancestors or graph descendants"
61
+ : "graph predecessors or graph successors";
62
+ throw new TypeError(`Relationship kind ${definition.kind} uses ${traversal} traversal; use ${redirect}`);
63
+ }
55
64
  resolved.add(definition.kind);
56
65
  }
57
66
  return resolved;
@@ -67,7 +76,7 @@ function expandSemanticNeighbors(graph, nodeId, familyKinds, family, matches) {
67
76
  const seen = new Set();
68
77
  for (const row of rows.value) {
69
78
  const definition = registry.require(row.edge.kind);
70
- if (!definition[family])
79
+ if (familyKinds === undefined && !definition[family])
71
80
  continue;
72
81
  if (!matches(row, definition, nodeId))
73
82
  continue;
@@ -273,4 +282,4 @@ export function enumerateRelationshipPaths(graph, source, target, options = {})
273
282
  return enumerateNonZeroRelationshipPaths(graph, source, target, options, maxPaths, maxVisitedPaths, maxDepth, direction);
274
283
  }
275
284
  //# sourceMappingURL=traversal.js.map
276
- //# debugId=c0fb747e-1f9f-55c4-808b-b77d3a881f87
285
+ //# debugId=ac2b3cd9-5a98-5fea-888c-e96de8cd593d