@unbrained/pm-cli 2026.8.13 → 2026.8.14

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 (136) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +141 -112
  3. package/dist/cli/main.js +39 -3
  4. package/dist/cli-bundle/bundle-manifest.json +144 -176
  5. package/dist/cli-bundle/chunks/{chunk-DEDU3DG7.js → chunk-BBOFSVAK.js} +66 -65
  6. package/dist/cli-bundle/chunks/chunk-BFALV3YP.js +5 -0
  7. package/dist/cli-bundle/chunks/{chunk-Q47C67TQ.js → chunk-FIW4P64F.js} +2 -2
  8. package/dist/cli-bundle/chunks/{chunk-QGTUPEU5.js → chunk-G5JUB66K.js} +41 -41
  9. package/dist/cli-bundle/chunks/{chunk-3ZMOWAFM.js → chunk-SBRKH6OR.js} +2 -2
  10. package/dist/cli-bundle/chunks/chunk-TMJ7URWS.js +13 -0
  11. package/dist/cli-bundle/chunks/{chunk-F7FJYGK3.js → chunk-TXMEUUUY.js} +2 -2
  12. package/dist/cli-bundle/chunks/{chunk-YLBAPY22.js → chunk-XAVMOK6B.js} +2 -2
  13. package/dist/cli-bundle/chunks/{chunk-TF3TPKPR.js → chunk-YAMTJL6Y.js} +33 -33
  14. package/dist/cli-bundle/chunks/{chunk-IMGIN7R6.js → chunk-YSVSMJ2B.js} +2 -2
  15. package/dist/cli-bundle/chunks/{register-list-query-4HIZ7EA3.js → register-list-query-T3EHHNNV.js} +2 -2
  16. package/dist/cli-bundle/chunks/{register-mutation-W64FZ5HN.js → register-mutation-E27WCLSZ.js} +2 -2
  17. package/dist/cli-bundle/chunks/{register-operations-C44ET7R5.js → register-operations-4R6I7CPY.js} +2 -2
  18. package/dist/cli-bundle/chunks/{register-setup-634MFRXU.js → register-setup-3YXZ444E.js} +2 -2
  19. package/dist/cli-bundle/focused-chunks/{chunk-OOYYKQWX.js → chunk-4DQ2YERC.js} +2 -2
  20. package/dist/cli-bundle/focused-chunks/chunk-F43TT2QQ.js +8 -0
  21. package/dist/cli-bundle/focused-chunks/{chunk-2RI2FESN.js → chunk-K7RWWOAG.js} +2 -2
  22. package/dist/cli-bundle/focused-chunks/chunk-KFSZ3BP6.js +16 -0
  23. package/dist/cli-bundle/focused-chunks/{chunk-3DJSGWVB.js → chunk-KSEDUWVZ.js} +2 -2
  24. package/dist/cli-bundle/focused-chunks/{chunk-NFHFZH2Z.js → chunk-KYUQGTSB.js} +2 -2
  25. package/dist/cli-bundle/focused-chunks/{chunk-IIS2FRKL.js → chunk-LZ4MV3RH.js} +2 -2
  26. package/dist/cli-bundle/focused-chunks/chunk-PGXJQLCT.js +155 -0
  27. package/dist/cli-bundle/focused-chunks/{chunk-E3AVJ655.js → chunk-PPFGQDSI.js} +2 -2
  28. package/dist/cli-bundle/focused-chunks/chunk-Q4YY3XNF.js +2 -0
  29. package/dist/cli-bundle/focused-chunks/chunk-QK753U3U.js +46 -0
  30. package/dist/cli-bundle/focused-chunks/{chunk-QDZUABWL.js → chunk-QUMB2J27.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/chunk-SM7MTG27.js +2 -0
  32. package/dist/cli-bundle/focused-chunks/{chunk-I75MANL7.js → chunk-WCVE2NIG.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/chunk-XDNAW5OI.js +18 -0
  34. package/dist/cli-bundle/focused-chunks/{chunk-2JP7W7GO.js → chunk-YOOI3UZX.js} +2 -2
  35. package/dist/cli-bundle/focused-chunks/chunk-ZM6TZVHC.js +2 -0
  36. package/dist/cli-bundle/main.js +13 -13
  37. package/dist/cli-bundle/sdk-authoring.js +1 -1
  38. package/dist/cli-bundle/sdk-contracts.js +1 -1
  39. package/dist/cli-bundle/sdk-core.js +44 -41
  40. package/dist/cli-bundle/sdk-governance.js +1 -1
  41. package/dist/cli-bundle/sdk-graph.js +1 -1
  42. package/dist/cli-bundle/sdk-merge.js +109 -1
  43. package/dist/cli-bundle/sdk-query.js +1 -1
  44. package/dist/cli-bundle/sdk-runtime.js +1 -1
  45. package/dist/cli-bundle/sdk-testing.js +1 -1
  46. package/dist/cli-bundle/sdk.js +2 -2
  47. package/dist/core/history/drift-scan.d.ts +6 -0
  48. package/dist/core/history/drift-scan.js +74 -50
  49. package/dist/core/history/workspace-history.d.ts +59 -0
  50. package/dist/core/history/workspace-history.js +197 -10
  51. package/dist/core/output/output.js +12 -4
  52. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +6 -1
  53. package/dist/sdk/cli-contracts/runtime-contracts.js +155 -60
  54. package/dist/sdk/cli-program.js +3 -3
  55. package/dist/sdk/context-relevance.js +12 -4
  56. package/dist/sdk/governance/assurance.js +4 -4
  57. package/dist/sdk/governance/health.js +15 -3
  58. package/dist/sdk/governance/validate-history-drift.d.ts +7 -0
  59. package/dist/sdk/governance/validate-history-drift.js +68 -0
  60. package/dist/sdk/governance/validate.js +4 -46
  61. package/dist/sdk/graph/assembly.d.ts +23 -0
  62. package/dist/sdk/graph/assembly.js +54 -2
  63. package/dist/sdk/graph/durable-cache.js +50 -20
  64. package/dist/sdk/graph/governance-contracts.d.ts +1 -1
  65. package/dist/sdk/graph/governance-contracts.js +4 -2
  66. package/dist/sdk/graph/governance.d.ts +21 -1
  67. package/dist/sdk/graph/governance.js +94 -32
  68. package/dist/sdk/graph/index.d.ts +2 -2
  69. package/dist/sdk/graph/index.js +4 -4
  70. package/dist/sdk/graph/mutation-advisory.js +15 -7
  71. package/dist/sdk/graph/remediation.js +12 -2
  72. package/dist/sdk/history-read.d.ts +8 -0
  73. package/dist/sdk/history-read.js +2 -2
  74. package/dist/sdk/index.d.ts +1 -1
  75. package/dist/sdk/index.js +3 -3
  76. package/dist/sdk/query/history.js +20 -3
  77. package/dist/sdk/read-output-budget.d.ts +2 -0
  78. package/dist/sdk/read-output-budget.js +12 -5
  79. package/dist/sdk/read-output-contracts.d.ts +61 -5
  80. package/dist/sdk/read-output-contracts.js +210 -28
  81. package/dist/sdk/read-output-rows.d.ts +11 -0
  82. package/dist/sdk/read-output-rows.js +47 -2
  83. package/dist/sdk/runtime-primitives.d.ts +1 -1
  84. package/dist/sdk/runtime-primitives.js +3 -3
  85. package/dist/sdk/runtime.js +5 -3
  86. package/docs/ASSURANCE.md +10 -1
  87. package/docs/COMMANDS.md +31 -2
  88. package/docs/READ_OUTPUT_CONTRACTS.md +44 -8
  89. package/docs/RELATIONSHIP_GRAPH.md +20 -5
  90. package/docs/SDK.md +12 -5
  91. package/docs/SDK_CONTEXT_INTEGRITY.md +32 -1
  92. package/docs/TESTING.md +23 -1
  93. package/docs/performance/sdk-entrypoint-import-costs.md +20 -13
  94. package/marketplace.json +2 -2
  95. package/package.json +6 -6
  96. package/packages/pm-beads/extensions/beads/index.ts +1 -0
  97. package/packages/pm-beads/package.json +1 -1
  98. package/packages/pm-calendar/extensions/calendar/index.ts +1 -0
  99. package/packages/pm-calendar/package.json +1 -1
  100. package/packages/pm-command-kit/package.json +1 -1
  101. package/packages/pm-digital-twin/extensions/digital-twin/index.ts +7 -0
  102. package/packages/pm-digital-twin/package.json +1 -1
  103. package/packages/pm-governance-audit/extensions/governance-audit/index.ts +4 -0
  104. package/packages/pm-governance-audit/package.json +1 -1
  105. package/packages/pm-guide-shell/extensions/guide-shell/index.ts +5 -0
  106. package/packages/pm-guide-shell/package.json +1 -1
  107. package/packages/pm-kanban/package.json +1 -1
  108. package/packages/pm-lifecycle-hooks/package.json +1 -1
  109. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/index.ts +6 -0
  110. package/packages/pm-linked-test-adapters/package.json +1 -1
  111. package/packages/pm-search-advanced/extensions/search-advanced/index.ts +2 -0
  112. package/packages/pm-search-advanced/package.json +1 -1
  113. package/packages/pm-templates/extensions/templates/index.ts +4 -0
  114. package/packages/pm-templates/package.json +1 -1
  115. package/packages/pm-todos/extensions/todos/index.ts +2 -0
  116. package/packages/pm-todos/package.json +1 -1
  117. package/packages/pm-vcs/extensions/vcs/index.ts +7 -0
  118. package/packages/pm-vcs/package.json +1 -1
  119. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  120. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  121. package/scripts/bundle-cli.mjs +17 -4
  122. package/sdk/public-surface.json +209 -29
  123. package/dist/cli-bundle/chunks/chunk-DL5M5J3V.js +0 -13
  124. package/dist/cli-bundle/chunks/chunk-HIUZVCMN.js +0 -5
  125. package/dist/cli-bundle/focused-chunks/chunk-27N23W6M.js +0 -31
  126. package/dist/cli-bundle/focused-chunks/chunk-3BNVU6LC.js +0 -8
  127. package/dist/cli-bundle/focused-chunks/chunk-6MLIRBLV.js +0 -5
  128. package/dist/cli-bundle/focused-chunks/chunk-6XYLENDV.js +0 -155
  129. package/dist/cli-bundle/focused-chunks/chunk-CP4K4WFS.js +0 -2
  130. package/dist/cli-bundle/focused-chunks/chunk-EBTNSFYE.js +0 -2
  131. package/dist/cli-bundle/focused-chunks/chunk-HC2OL2H2.js +0 -2
  132. package/dist/cli-bundle/focused-chunks/chunk-OGC4XSBC.js +0 -17
  133. package/dist/cli-bundle/focused-chunks/chunk-PKPOZXLL.js +0 -2
  134. package/dist/cli-bundle/focused-chunks/chunk-QQX5TDFT.js +0 -16
  135. package/dist/cli-bundle/focused-chunks/chunk-TEZIXMTH.js +0 -2
  136. package/dist/cli-bundle/focused-chunks/chunk-WEH6NSL6.js +0 -18
@@ -77,6 +77,19 @@ export interface DuplicateDependencyRow {
77
77
  /** Whether the holder is terminal and the duplication is historical debt. */
78
78
  legacy_terminal: boolean;
79
79
  }
80
+ /** One holder whose scalar blocker and structured ordering row assert opposite precedence. */
81
+ export interface OrderingStorageContradiction {
82
+ /** Item storing both contradictory representations. */
83
+ holder_id: string;
84
+ /** Target named by both the scalar blocker and structured dependency row. */
85
+ target_id: string;
86
+ /** Structured ordering kind that places the holder before the target. */
87
+ dependency_kind: string;
88
+ /** Current lifecycle status of the holder. */
89
+ holder_status: ItemStatus;
90
+ /** Whether the holder is terminal and the contradiction is historical debt. */
91
+ legacy_terminal: boolean;
92
+ }
80
93
  /**
81
94
  * Collect raw stored dependency rows whose exact identity — holder, kind, and
82
95
  * case-insensitive target — appears more than once on one item. Graph
@@ -85,6 +98,14 @@ export interface DuplicateDependencyRow {
85
98
  * only surface that reports the storage-layer defect.
86
99
  */
87
100
  export declare function collectDuplicateDependencyRows(items: readonly DependencyReferenceHolder[], isTerminal?: (status: ItemStatus) => boolean): DuplicateDependencyRow[];
101
+ /**
102
+ * Collect storage rows where `blocked_by: target` places the target before the
103
+ * holder while a same-target structured ordering dependency places the holder
104
+ * before the target. The contradictory rows form an artificial two-node cycle
105
+ * after graph assembly, so this pre-assembly evidence identifies the exact row
106
+ * to remove instead of reporting only strongly connected component members.
107
+ */
108
+ export declare function collectOrderingStorageContradictions(items: readonly DependencyReferenceHolder[], isTerminal?: (status: ItemStatus) => boolean, registry?: RelationshipKindRegistry): OrderingStorageContradiction[];
88
109
  /**
89
110
  * Classify missing hierarchy and dependency targets without mutating their holders.
90
111
  *
@@ -127,6 +148,8 @@ export interface WorkspaceRelationshipAssembly {
127
148
  dangling: DanglingDependencyReferenceSummary;
128
149
  /** Raw same-identity duplicated dependency rows found before graph dedup. */
129
150
  duplicateRows: DuplicateDependencyRow[];
151
+ /** Scalar-versus-structured ordering contradictions found before graph normalization. */
152
+ orderingContradictions?: OrderingStorageContradiction[];
130
153
  /** Raw legacy alias rows grouped by accepted spelling before graph canonicalization. */
131
154
  legacyAliasCounts: Record<string, number>;
132
155
  }
@@ -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]="62ec8e0e-658e-5a32-b458-439d5ffd1229")}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]="a6fc5da1-b7d1-5b3c-8033-cecccc7861c3")}catch(e){}}();
3
3
  import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
4
4
  import { RelationshipGraph, createRelationshipKindRegistry, } from "../relationships.js";
5
5
  import { isExternalDependencySourceKind } from "../dependency-provenance.js";
@@ -104,6 +104,57 @@ export function collectDuplicateDependencyRows(items, isTerminal = (status) => s
104
104
  return compareCaseFoldedText(left.kind, right.kind);
105
105
  });
106
106
  }
107
+ /** Decode one dependency row only when it contradicts the holder's scalar blocker. */
108
+ function decodeOrderingStorageContradiction(item, blocker, dependency, isTerminal, registry) {
109
+ if (typeof dependency !== "object" || dependency === null)
110
+ return undefined;
111
+ const target = normalizeDependencyReferenceTarget(dependency.id);
112
+ if (!target || target.toLowerCase() !== blocker.toLowerCase())
113
+ return undefined;
114
+ const definition = registry.resolve(typeof dependency.kind === "string" ? dependency.kind : "related");
115
+ if (definition?.ordering !== true ||
116
+ (definition.precedence ?? "source_before_target") !== "source_before_target")
117
+ return undefined;
118
+ return {
119
+ holder_id: item.id.trim(),
120
+ target_id: target,
121
+ dependency_kind: definition.kind,
122
+ holder_status: item.status,
123
+ legacy_terminal: isTerminal(item.status),
124
+ };
125
+ }
126
+ /**
127
+ * Collect storage rows where `blocked_by: target` places the target before the
128
+ * holder while a same-target structured ordering dependency places the holder
129
+ * before the target. The contradictory rows form an artificial two-node cycle
130
+ * after graph assembly, so this pre-assembly evidence identifies the exact row
131
+ * to remove instead of reporting only strongly connected component members.
132
+ */
133
+ export function collectOrderingStorageContradictions(items, isTerminal = (status) => status === "closed" || status === "canceled", registry = resolveWorkspaceRelationshipKindRegistry()) {
134
+ const contradictions = new Map();
135
+ for (const item of items) {
136
+ if (typeof item?.id !== "string" || item.id.trim().length === 0)
137
+ continue;
138
+ const blocker = normalizeDependencyReferenceTarget(item.blocked_by);
139
+ if (!blocker)
140
+ continue;
141
+ for (const dependency of item.dependencies ?? []) {
142
+ const row = decodeOrderingStorageContradiction(item, blocker, dependency, isTerminal, registry);
143
+ if (!row)
144
+ continue;
145
+ contradictions.set(`${row.holder_id.toLowerCase()}\u0000${row.target_id.toLowerCase()}\u0000${row.dependency_kind}`, row);
146
+ }
147
+ }
148
+ return [...contradictions.values()].sort((left, right) => {
149
+ const holderCompare = compareCaseFoldedText(left.holder_id, right.holder_id);
150
+ if (holderCompare !== 0)
151
+ return holderCompare;
152
+ const targetCompare = compareCaseFoldedText(left.target_id, right.target_id);
153
+ if (targetCompare !== 0)
154
+ return targetCompare;
155
+ return compareCaseFoldedText(left.dependency_kind, right.dependency_kind);
156
+ });
157
+ }
107
158
  /**
108
159
  * Classify missing hierarchy and dependency targets without mutating their holders.
109
160
  *
@@ -296,8 +347,9 @@ export function assembleWorkspaceRelationshipGraph(items, isTerminal, registry)
296
347
  missingIdSet: new Set(missingIds.map((id) => id.toLowerCase())),
297
348
  dangling,
298
349
  duplicateRows: collectDuplicateDependencyRows(safeItems, isTerminal),
350
+ orderingContradictions: collectOrderingStorageContradictions(safeItems, isTerminal, relationshipRegistry),
299
351
  legacyAliasCounts: collectLegacyDependencyAliasCounts(safeItems, relationshipRegistry),
300
352
  };
301
353
  }
302
354
  //# sourceMappingURL=assembly.js.map
303
- //# debugId=62ec8e0e-658e-5a32-b458-439d5ffd1229
355
+ //# debugId=a6fc5da1-b7d1-5b3c-8033-cecccc7861c3
@@ -15,7 +15,7 @@
15
15
  * threshold or after an explicit `pm graph index --rebuild` opt-in.
16
16
  */
17
17
 
18
- !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]="2f7f14e3-6d41-5f45-a560-ebfbb8aa5828")}catch(e){}}();
18
+ !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]="9e4aa41d-fca4-5e55-ab2b-d99f06d90ae2")}catch(e){}}();
19
19
  import path from "node:path";
20
20
  import { readFileIfExists, removeFileIfExists, writeFileAtomic, } from "../../core/fs/fs-utils.js";
21
21
  import { acquireLock } from "../../core/lock/lock.js";
@@ -174,8 +174,52 @@ function isNonnegativeCoverageByTypeRecord(value) {
174
174
  return Object.values(value).every((entry) => isRecord(entry) &&
175
175
  [entry.active, entry.isolated, entry.degree_leq_one].every(isNonnegativeInteger));
176
176
  }
177
+ /** Decode the additive information-bearing census as one coherent field group. */
178
+ function decodeInformativeProfile(profile, nodes, edges) {
179
+ const fields = [
180
+ "recorded_nodes",
181
+ "informative_edges",
182
+ "redundant_edges",
183
+ "ordering_contradiction_edges",
184
+ ];
185
+ const presentCount = fields.filter((field) => profile[field] !== undefined).length;
186
+ if (presentCount !== 0 && presentCount !== fields.length)
187
+ return undefined;
188
+ if (!fields.every((field) => isOptionalValid(profile[field], isNonnegativeInteger)))
189
+ return undefined;
190
+ const decoded = {
191
+ recorded_nodes: profile.recorded_nodes ?? nodes,
192
+ informative_edges: profile.informative_edges ?? edges,
193
+ redundant_edges: profile.redundant_edges ?? 0,
194
+ ordering_contradiction_edges: profile.ordering_contradiction_edges ?? 0,
195
+ };
196
+ return decoded.recorded_nodes <= nodes &&
197
+ decoded.informative_edges <= edges &&
198
+ decoded.redundant_edges <= edges &&
199
+ decoded.ordering_contradiction_edges <= edges
200
+ ? decoded
201
+ : undefined;
202
+ }
203
+ /** Validate the optional structural census fields as one complete version group. */
204
+ function hasValidStructuralFields(profile, countFields, rateFields) {
205
+ const introducedFields = [
206
+ ...countFields,
207
+ ...rateFields,
208
+ "finding_subjects_by_code",
209
+ ];
210
+ const presentCount = introducedFields.filter((field) => profile[field] !== undefined).length;
211
+ if (presentCount !== 0 && presentCount !== introducedFields.length)
212
+ return false;
213
+ return (countFields.every((field) => isOptionalValid(profile[field], isNonnegativeInteger)) &&
214
+ rateFields.every((field) => isOptionalValid(profile[field], isNonnegativeInteger) &&
215
+ (profile[field] === undefined || Number(profile[field]) <= 10_000)) &&
216
+ isOptionalValid(profile.finding_subjects_by_code, isNonnegativeCountRecord));
217
+ }
177
218
  /** Decode optional structural fields while normalizing pre-structure baselines. */
178
- function decodeStructuralProfile(profile, affectedSubjectsByCode) {
219
+ function decodeStructuralProfile(profile, affectedSubjectsByCode, nodes, edges) {
220
+ const informative = decodeInformativeProfile(profile, nodes, edges);
221
+ if (informative === undefined)
222
+ return undefined;
179
223
  const countFields = [
180
224
  "articulation_points",
181
225
  "bridge_edges",
@@ -193,31 +237,17 @@ function decodeStructuralProfile(profile, affectedSubjectsByCode) {
193
237
  "terminal_outcome_reachability_basis_points",
194
238
  "outcome_reachability_basis_points",
195
239
  ];
196
- const introducedStructuralFields = [
197
- ...countFields,
198
- ...rateFields,
199
- "finding_subjects_by_code",
200
- ];
201
- const introducedStructuralFieldCount = introducedStructuralFields.filter((field) => profile[field] !== undefined).length;
202
- if (introducedStructuralFieldCount !== 0 &&
203
- introducedStructuralFieldCount !== introducedStructuralFields.length) {
204
- return undefined;
205
- }
206
- const validCounts = countFields.every((field) => profile[field] === undefined || isNonnegativeInteger(profile[field]));
207
- const validRates = rateFields.every((field) => profile[field] === undefined ||
208
- (isNonnegativeInteger(profile[field]) && Number(profile[field]) <= 10_000));
209
- if (!validCounts || !validRates)
240
+ if (!hasValidStructuralFields(profile, countFields, rateFields))
210
241
  return undefined;
211
242
  if (profile.edge_basis !== undefined &&
212
243
  profile.edge_basis !== "deduplicated_directed")
213
244
  return undefined;
214
- if (!isOptionalValid(profile.finding_subjects_by_code, isNonnegativeCountRecord))
215
- return undefined;
216
245
  const findingSubjects = isNonnegativeCountRecord(profile.finding_subjects_by_code)
217
246
  ? profile.finding_subjects_by_code
218
247
  : {};
219
248
  return {
220
249
  edge_basis: "deduplicated_directed",
250
+ ...informative,
221
251
  ...Object.fromEntries(countFields.map((field) => [field, profile[field] ?? 0])),
222
252
  ...Object.fromEntries(rateFields.map((field) => [field, profile[field] ?? 0])),
223
253
  finding_subjects_by_code: Object.fromEntries(RELATIONSHIP_AUDIT_FINDING_CODES.map((code) => [
@@ -302,7 +332,7 @@ function decodeBaseline(raw) {
302
332
  const composition = decodeGraphComposition(profile.edges, profile.edges_by_kind, profile.edge_share_by_kind, profile.semantic_edges, profile.semantic_edge_share);
303
333
  if (composition === undefined)
304
334
  return undefined;
305
- const structural = decodeStructuralProfile(profile, affectedSubjectsByCode);
335
+ const structural = decodeStructuralProfile(profile, affectedSubjectsByCode, profile.nodes, profile.edges);
306
336
  if (structural === undefined)
307
337
  return undefined;
308
338
  const { coverage_by_type = {} } = profile;
@@ -329,4 +359,4 @@ export async function saveGraphAuditBaseline(pmRoot, snapshot) {
329
359
  await writeFileAtomic(graphAuditBaselinePath(pmRoot), JSON.stringify(snapshot));
330
360
  }
331
361
  //# sourceMappingURL=durable-cache.js.map
332
- //# debugId=2f7f14e3-6d41-5f45-a560-ebfbb8aa5828
362
+ //# debugId=9e4aa41d-fca4-5e55-ab2b-d99f06d90ae2
@@ -7,6 +7,6 @@
7
7
  * drifting when a finding family is added.
8
8
  */
9
9
  /** Stable machine-readable relationship audit finding families. */
10
- export declare const RELATIONSHIP_AUDIT_FINDING_CODES: readonly ["missing_reference_active", "missing_reference_terminal", "legacy_no_blocker_sentinel", "ordering_cycle", "legacy_ordering_cycle", "duplicate_edge", "legacy_duplicate_edge", "duplicate_dependency_row", "legacy_duplicate_dependency_row", "stale_lifecycle_block", "isolated_active_node", "sparse_active_node"];
10
+ export declare const RELATIONSHIP_AUDIT_FINDING_CODES: readonly ["missing_reference_active", "missing_reference_terminal", "legacy_no_blocker_sentinel", "ordering_cycle", "legacy_ordering_cycle", "ordering_storage_contradiction", "legacy_ordering_storage_contradiction", "duplicate_edge", "legacy_duplicate_edge", "duplicate_dependency_row", "legacy_duplicate_dependency_row", "stale_lifecycle_block", "isolated_active_node", "sparse_active_node"];
11
11
  /** Machine-readable identifier for one relationship audit finding family. */
12
12
  export type RelationshipAuditFindingCode = (typeof RELATIONSHIP_AUDIT_FINDING_CODES)[number];
@@ -8,13 +8,15 @@
8
8
  */
9
9
  /** Stable machine-readable relationship audit finding families. */
10
10
 
11
- !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]="a2043b27-3dfe-5da8-a10f-d92ff33f3c28")}catch(e){}}();
11
+ !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]="bc561e73-75b8-5ea7-a18c-da70fb991b69")}catch(e){}}();
12
12
  export const RELATIONSHIP_AUDIT_FINDING_CODES = [
13
13
  "missing_reference_active",
14
14
  "missing_reference_terminal",
15
15
  "legacy_no_blocker_sentinel",
16
16
  "ordering_cycle",
17
17
  "legacy_ordering_cycle",
18
+ "ordering_storage_contradiction",
19
+ "legacy_ordering_storage_contradiction",
18
20
  "duplicate_edge",
19
21
  "legacy_duplicate_edge",
20
22
  "duplicate_dependency_row",
@@ -24,4 +26,4 @@ export const RELATIONSHIP_AUDIT_FINDING_CODES = [
24
26
  "sparse_active_node",
25
27
  ];
26
28
  //# sourceMappingURL=governance-contracts.js.map
27
- //# debugId=a2043b27-3dfe-5da8-a10f-d92ff33f3c28
29
+ //# debugId=bc561e73-75b8-5ea7-a18c-da70fb991b69
@@ -13,7 +13,7 @@
13
13
  * agents can plan remediation without re-deriving context.
14
14
  */
15
15
  import type { RelationshipEdge } from "../relationships.js";
16
- import type { WorkspaceRelationshipAssembly } from "./assembly.js";
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";
19
19
  /** Severity ladder shared by every relationship audit finding. */
@@ -32,6 +32,8 @@ export interface RelationshipAuditFinding {
32
32
  count: number;
33
33
  /** Deterministic bounded sample of affected subjects. */
34
34
  sample: string[];
35
+ /** Optional exact evidence that explains why the sampled subjects were selected. */
36
+ evidence?: string[];
35
37
  /** Whether {@link sample} was truncated by the configured sample bound. */
36
38
  sample_truncated: boolean;
37
39
  /** Safe machine-actionable next step; audits never invent or auto-apply edges. */
@@ -50,8 +52,16 @@ export interface RelationshipCoverageTypeProfile {
50
52
  export interface RelationshipCoverageProfile {
51
53
  /** Total indexed nodes including materialized missing placeholders. */
52
54
  nodes: number;
55
+ /** Tracker-recorded nodes, excluding synthesized missing and external placeholders. */
56
+ recorded_nodes?: number;
53
57
  /** Total deduplicated indexed edges. */
54
58
  edges: number;
59
+ /** Edges that remain after excluding redundant and contradictory storage rows. */
60
+ informative_edges?: number;
61
+ /** Stored edges implied by a bounded longer path in the same semantic family. */
62
+ redundant_edges?: number;
63
+ /** Structured ordering edges that contradict a same-target scalar blocker. */
64
+ ordering_contradiction_edges?: number;
55
65
  /** Counting convention used by edges and edges_by_kind. */
56
66
  edge_basis: "deduplicated_directed";
57
67
  /** Deterministic per-kind edge counts. */
@@ -134,6 +144,8 @@ export declare function isSemanticContextKind(kind: string): boolean;
134
144
  * advisories) share one cycle semantics with the workspace audit.
135
145
  */
136
146
  export declare function collectOrderingCycles(successors: Map<string, string[]>): string[][];
147
+ /** Format the exact contradictory storage pair that manufactures an ordering cycle. */
148
+ export declare function formatOrderingStorageContradiction(contradiction: Pick<OrderingStorageContradiction, "holder_id" | "target_id" | "dependency_kind">): string;
137
149
  /** One duplicate-edge group in semantic orientation with its stored spellings. */
138
150
  export interface DuplicateRelationshipEdgeGroup {
139
151
  /** Semantic tail node shared by every stored spelling. */
@@ -189,8 +201,16 @@ export interface RelationshipAuditDelta {
189
201
  profile: {
190
202
  /** Node-count change including missing placeholders. */
191
203
  nodes: number;
204
+ /** Tracker-recorded node-count change excluding synthesized placeholders. */
205
+ recorded_nodes?: number;
192
206
  /** Deduplicated edge-count change. */
193
207
  edges: number;
208
+ /** Informative edge-count change after non-information deductions. */
209
+ informative_edges?: number;
210
+ /** Redundant edge-count change. */
211
+ redundant_edges?: number;
212
+ /** Ordering contradiction edge-count change. */
213
+ ordering_contradiction_edges?: number;
194
214
  /** Active-node-count change. */
195
215
  active_nodes: number;
196
216
  /** Missing-placeholder-count change. */
@@ -1,6 +1,6 @@
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]="ab8a4904-0302-5e36-9963-750b3ba79876")}catch(e){}}();
3
- import { isTransitiveKind, orientTransitiveEdge, transitiveFamilyKey, } from "./analytics.js";
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]="1955b7a4-385d-5a5d-8856-6db9f94814aa")}catch(e){}}();
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";
6
6
  /** Default bounded sample size applied to every finding family. */
@@ -25,8 +25,14 @@ const SEVERITY_RANK = {
25
25
  warning: 1,
26
26
  info: 2,
27
27
  };
28
+ /** Normalize optional exemption identifiers into a case-insensitive lookup set. */
29
+ function normalizeExemptionSet(values) {
30
+ return new Set((values ?? [])
31
+ .filter((value) => typeof value === "string")
32
+ .map((value) => value.trim().toLowerCase()));
33
+ }
28
34
  /** Build one finding with deterministic bounded sampling over sorted subjects. */
29
- function buildFinding(code, severity, policy, describe, subjects, maxSampleSize, remediation) {
35
+ function buildFinding(code, severity, policy, describe, subjects, maxSampleSize, remediation, evidence) {
30
36
  const sorted = [...subjects].sort((left, right) => left.localeCompare(right));
31
37
  return {
32
38
  code,
@@ -37,6 +43,13 @@ function buildFinding(code, severity, policy, describe, subjects, maxSampleSize,
37
43
  sample: sorted.slice(0, maxSampleSize),
38
44
  sample_truncated: sorted.length > maxSampleSize,
39
45
  remediation,
46
+ ...(evidence === undefined
47
+ ? {}
48
+ : {
49
+ evidence: [...evidence]
50
+ .sort((left, right) => left.localeCompare(right))
51
+ .slice(0, maxSampleSize),
52
+ }),
40
53
  };
41
54
  }
42
55
  /** Resolve the ordering-only successor adjacency for cycle analysis. */
@@ -177,6 +190,21 @@ function isActiveAuditMember(member, nodeStates) {
177
190
  return true;
178
191
  return !state.terminal;
179
192
  }
193
+ /** Format the exact contradictory storage pair that manufactures an ordering cycle. */
194
+ export function formatOrderingStorageContradiction(contradiction) {
195
+ return `${contradiction.holder_id} -> ${contradiction.target_id} (blocked_by scalar + ${contradiction.dependency_kind} dependency)`;
196
+ }
197
+ /** Report active and historical scalar-versus-structured ordering contradictions. */
198
+ function collectOrderingStorageContradictionFindings(assembly, maxSampleSize) {
199
+ const active = [];
200
+ const legacy = [];
201
+ for (const contradiction of assembly.orderingContradictions ?? [])
202
+ (contradiction.legacy_terminal ? legacy : active).push(formatOrderingStorageContradiction(contradiction));
203
+ const findings = [];
204
+ appendFinding(findings, active, maxSampleSize, "ordering_storage_contradiction", "error", "A scalar blocker and same-target structured ordering row must not assert opposite precedence.", (count) => `${count} active scalar-versus-structured ordering contradiction(s)`, "Remove the structured dependency row that points the holder before its scalar blocker, or replace both representations with one unambiguous ordering edge.");
205
+ appendFinding(findings, legacy, maxSampleSize, "legacy_ordering_storage_contradiction", "info", "Terminal scalar-versus-structured ordering contradictions are exact historical storage defects with no live scheduling effect.", (count) => `${count} terminal scalar-versus-structured ordering contradiction(s)`, "Remove the contradictory blocks dependency row in a dedicated changelog-safe closed-item batch; preserve the scalar blocker as the historical precedence record.");
206
+ return findings;
207
+ }
180
208
  /** Collect ordering-cycle and lifecycle-block governance findings. */
181
209
  function collectOrderingFindings(assembly, nodeStates, isBlocked, maxSampleSize) {
182
210
  const findings = [];
@@ -186,9 +214,18 @@ function collectOrderingFindings(assembly, nodeStates, isBlocked, maxSampleSize)
186
214
  // it cannot make live work unschedulable, and "repairing" it would touch
187
215
  // closed items (changelog drag), so it downgrades to informational debt.
188
216
  const active = cycle.some((member) => isActiveAuditMember(member, nodeStates));
217
+ const cycleMembers = new Set(cycle.map((member) => member.toLowerCase()));
218
+ const contradictionEvidence = (assembly.orderingContradictions ?? [])
219
+ .filter((row) => cycleMembers.has(row.holder_id.toLowerCase()) &&
220
+ cycleMembers.has(row.target_id.toLowerCase()))
221
+ .map(formatOrderingStorageContradiction);
189
222
  findings.push(active
190
- ? buildFinding("ordering_cycle", "error", "Order-bearing relationship kinds must stay acyclic; a cycle makes every member unschedulable.", (count) => `execution-order cycle across ${count} item(s)`, cycle, maxSampleSize, "Remove or retype one ordering edge inside the cycle, or split the work so precedence is linear.")
191
- : buildFinding("legacy_ordering_cycle", "info", "Ordering cycles between exclusively terminal items are historical contradictions with no scheduling effect.", (count) => `terminal-only execution-order cycle across ${count} item(s)`, cycle, maxSampleSize, "Leave as history debt, or clean up in a dedicated changelog-safe closed-item batch; never repair closed items ad hoc."));
223
+ ? buildFinding("ordering_cycle", "error", "Order-bearing relationship kinds must stay acyclic; a cycle makes every member unschedulable.", (count) => `execution-order cycle across ${count} item(s)`, cycle, maxSampleSize, "Remove or retype one ordering edge inside the cycle, or split the work so precedence is linear.", contradictionEvidence.length === 0
224
+ ? undefined
225
+ : contradictionEvidence)
226
+ : buildFinding("legacy_ordering_cycle", "info", "Ordering cycles between exclusively terminal items are historical contradictions with no scheduling effect.", (count) => `terminal-only execution-order cycle across ${count} item(s)`, cycle, maxSampleSize, "Leave as history debt, or clean up in a dedicated changelog-safe closed-item batch; never repair closed items ad hoc.", contradictionEvidence.length === 0
227
+ ? undefined
228
+ : contradictionEvidence));
192
229
  }
193
230
  const predecessorsByNode = new Map();
194
231
  for (const [predecessor, adjacent] of orderingAdjacency)
@@ -448,6 +485,12 @@ function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExem
448
485
  appendFinding(findings, isolates, maxSampleSize, "isolated_active_node", "warning", "Active work should be reachable from the graph unless explicitly declared a valid isolate.", (count) => `${count} active item(s) with no relationships`, "Link the item to its parent, prerequisite, or origin — or register it as an exempt isolate.");
449
486
  appendFinding(findings, sparse, maxSampleSize, "sparse_active_node", "info", "Active items with a single edge often miss an honest semantic partner; sparse is not automatically defective.", (count) => `${count} active item(s) with exactly one relationship`, "Investigate for an honest second edge (story->task, defect family, cross-epic complement); do not fabricate one.");
450
487
  const edgeCount = assembly.graph.edges().length;
488
+ const redundantEdges = findRedundantRelationshipEdges(assembly.graph, {
489
+ signal,
490
+ }).value;
491
+ const nonInformativeEdgeKeys = new Set(redundantEdges.map(({ edge }) => `${edge.source.toLowerCase()}\u0000${edge.target.toLowerCase()}\u0000${edge.kind}`));
492
+ for (const contradiction of assembly.orderingContradictions ?? [])
493
+ nonInformativeEdgeKeys.add(`${contradiction.holder_id.toLowerCase()}\u0000${contradiction.target_id.toLowerCase()}\u0000${contradiction.dependency_kind}`);
451
494
  const sortedEdgesByKind = Object.fromEntries(Object.entries(edgesByKind).sort(([left], [right]) => left.localeCompare(right)));
452
495
  const semanticEdges = Object.entries(sortedEdgesByKind).reduce((count, [kind, value]) => count + (isSemanticContextKind(kind) ? value : 0), 0);
453
496
  const cutStructure = findRelationshipCutStructure(assembly.graph, {
@@ -458,7 +501,11 @@ function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExem
458
501
  findings,
459
502
  profile: {
460
503
  nodes: assembly.graph.nodes().length,
504
+ recorded_nodes: assembly.details.filter((detail) => detail.status !== "missing" && detail.status !== "external").length,
461
505
  edges: edgeCount,
506
+ informative_edges: edgeCount - nonInformativeEdgeKeys.size,
507
+ redundant_edges: redundantEdges.length,
508
+ ordering_contradiction_edges: assembly.orderingContradictions?.length ?? 0,
462
509
  edge_basis: "deduplicated_directed",
463
510
  edges_by_kind: sortedEdgesByKind,
464
511
  edge_share_by_kind: Object.fromEntries(Object.entries(sortedEdgesByKind).map(([kind, count]) => [
@@ -496,12 +543,8 @@ export function auditWorkspaceRelationshipGraph(assembly, options = {}) {
496
543
  const maxSampleSize = options.maxSampleSize ?? DEFAULT_MAX_SAMPLE_SIZE;
497
544
  if (!Number.isInteger(maxSampleSize) || maxSampleSize < 1)
498
545
  throw new TypeError(`Invalid audit sample bound: ${String(options.maxSampleSize)}`);
499
- const exemptIsolates = new Set((options.exemptIsolates ?? [])
500
- .filter((id) => typeof id === "string")
501
- .map((id) => id.trim().toLowerCase()));
502
- const isolateExemptTypes = new Set((options.isolateExemptTypes ?? [])
503
- .filter((type) => typeof type === "string")
504
- .map((type) => type.trim().toLowerCase()));
546
+ const exemptIsolates = normalizeExemptionSet(options.exemptIsolates);
547
+ const isolateExemptTypes = normalizeExemptionSet(options.isolateExemptTypes);
505
548
  const nodeStates = new Map(assembly.details.map((detail) => [
506
549
  detail.id,
507
550
  {
@@ -518,6 +561,8 @@ export function auditWorkspaceRelationshipGraph(assembly, options = {}) {
518
561
  edgesByKind[edge.kind] = (edgesByKind[edge.kind] ?? 0) + 1;
519
562
  const findings = collectIntegrityFindings(assembly, isTerminal, maxSampleSize);
520
563
  options.signal?.throwIfAborted();
564
+ findings.push(...collectOrderingStorageContradictionFindings(assembly, maxSampleSize));
565
+ options.signal?.throwIfAborted();
521
566
  findings.push(...collectOrderingFindings(assembly, nodeStates, isBlocked, maxSampleSize));
522
567
  options.signal?.throwIfAborted();
523
568
  findings.push(...collectDuplicateEdgeFindings(assembly, nodeStates, maxSampleSize), ...collectDuplicateRowFindings(assembly, maxSampleSize));
@@ -556,45 +601,62 @@ function diffCountRecords(baseline, current) {
556
601
  function readSnapshotCoverageByType(snapshot) {
557
602
  return snapshot.profile.coverage_by_type ?? {};
558
603
  }
559
- /**
560
- * Compare two point-in-time audit snapshots and return the signed change in
561
- * findings and structural coverage. This is the temporal primitive behind
562
- * change-since-baseline audit reporting: agents track census drift across
563
- * sessions without re-deriving or storing full finding collections.
564
- */
565
- export function diffRelationshipAuditSnapshots(baseline, current) {
566
- const coverageByType = {};
567
- // Public SDK callers may compare legacy or JSON-decoded snapshots created
568
- // before per-type coverage was added, even though current typed snapshots
569
- // always carry this field.
570
- const baselineCoverageByType = readSnapshotCoverageByType(baseline);
571
- const currentCoverageByType = readSnapshotCoverageByType(current);
572
- const typeKeys = [
604
+ /** Diff per-type coverage while omitting unchanged type rows. */
605
+ function diffCoverageByType(baseline, current) {
606
+ const deltas = {};
607
+ const baselineCoverage = readSnapshotCoverageByType(baseline);
608
+ const currentCoverage = readSnapshotCoverageByType(current);
609
+ const types = [
573
610
  ...new Set([
574
- ...Object.keys(baselineCoverageByType),
575
- ...Object.keys(currentCoverageByType),
611
+ ...Object.keys(baselineCoverage),
612
+ ...Object.keys(currentCoverage),
576
613
  ]),
577
614
  ].sort();
578
- for (const type of typeKeys) {
579
- const before = Object.assign({ active: 0, isolated: 0, degree_leq_one: 0 }, baselineCoverageByType[type]);
580
- const after = Object.assign({ active: 0, isolated: 0, degree_leq_one: 0 }, currentCoverageByType[type]);
615
+ for (const type of types) {
616
+ const before = Object.assign({ active: 0, isolated: 0, degree_leq_one: 0 }, baselineCoverage[type]);
617
+ const after = Object.assign({ active: 0, isolated: 0, degree_leq_one: 0 }, currentCoverage[type]);
581
618
  const delta = {
582
619
  active: after.active - before.active,
583
620
  isolated: after.isolated - before.isolated,
584
621
  degree_leq_one: after.degree_leq_one - before.degree_leq_one,
585
622
  };
586
623
  if (Object.values(delta).some((value) => value !== 0))
587
- coverageByType[type] = delta;
624
+ deltas[type] = delta;
588
625
  }
626
+ return deltas;
627
+ }
628
+ /**
629
+ * Compare two point-in-time audit snapshots and return the signed change in
630
+ * findings and structural coverage. This is the temporal primitive behind
631
+ * change-since-baseline audit reporting: agents track census drift across
632
+ * sessions without re-deriving or storing full finding collections.
633
+ */
634
+ export function diffRelationshipAuditSnapshots(baseline, current) {
635
+ // Public SDK callers may compare legacy or JSON-decoded snapshots created
636
+ // before per-type coverage was added, even though current typed snapshots
637
+ // always carry this field.
638
+ const coverageByType = diffCoverageByType(baseline, current);
589
639
  const { edge_share_by_kind: baselineEdgeShareByKind = {}, semantic_edges: baselineSemanticEdges = 0, semantic_edge_share: baselineSemanticEdgeShare = 0, } = baseline.profile;
590
640
  const { edge_share_by_kind: currentEdgeShareByKind = {}, semantic_edges: currentSemanticEdges = 0, semantic_edge_share: currentSemanticEdgeShare = 0, } = current.profile;
641
+ const baselineRecordedNodes = baseline.profile.recorded_nodes ?? baseline.profile.nodes;
642
+ const currentRecordedNodes = current.profile.recorded_nodes ?? current.profile.nodes;
643
+ const baselineInformativeEdges = baseline.profile.informative_edges ?? baseline.profile.edges;
644
+ const currentInformativeEdges = current.profile.informative_edges ?? current.profile.edges;
645
+ const baselineRedundantEdges = baseline.profile.redundant_edges ?? 0;
646
+ const currentRedundantEdges = current.profile.redundant_edges ?? 0;
647
+ const baselineOrderingContradictionEdges = baseline.profile.ordering_contradiction_edges ?? 0;
648
+ const currentOrderingContradictionEdges = current.profile.ordering_contradiction_edges ?? 0;
591
649
  return {
592
650
  baseline_saved_at: baseline.saved_at,
593
651
  same_snapshot: baseline.fingerprint === current.fingerprint,
594
652
  affected_subjects_by_code: diffCountRecords(baseline.affected_subjects_by_code, current.affected_subjects_by_code),
595
653
  profile: {
596
654
  nodes: current.profile.nodes - baseline.profile.nodes,
655
+ recorded_nodes: currentRecordedNodes - baselineRecordedNodes,
597
656
  edges: current.profile.edges - baseline.profile.edges,
657
+ informative_edges: currentInformativeEdges - baselineInformativeEdges,
658
+ redundant_edges: currentRedundantEdges - baselineRedundantEdges,
659
+ ordering_contradiction_edges: currentOrderingContradictionEdges - baselineOrderingContradictionEdges,
598
660
  active_nodes: current.profile.active_nodes - baseline.profile.active_nodes,
599
661
  missing_nodes: current.profile.missing_nodes - baseline.profile.missing_nodes,
600
662
  isolated_active_nodes: current.profile.isolated_active_nodes -
@@ -610,4 +672,4 @@ export function diffRelationshipAuditSnapshots(baseline, current) {
610
672
  };
611
673
  }
612
674
  //# sourceMappingURL=governance.js.map
613
- //# debugId=ab8a4904-0302-5e36-9963-750b3ba79876
675
+ //# debugId=1955b7a4-385d-5a5d-8856-6db9f94814aa
@@ -12,8 +12,8 @@ export { computeRelationshipCentrality, findRelationshipCutStructure, type Graph
12
12
  export { createRelationshipGraphSnapshot, federateRelationshipGraphSnapshots, loadRelationshipGraphAdapter, MemoryRelationshipGraphAdapter, parseRelationshipGraphSnapshot, RELATIONSHIP_GRAPH_SNAPSHOT_VERSION, syncRelationshipGraphAdapter, type LoadedRelationshipGraphSnapshot, type RelationshipGraphAdapter, type RelationshipGraphAdapterContext, type RelationshipGraphAdapterReplaceContext, type RelationshipGraphAdapterSyncResult, type RelationshipGraphSnapshot, } from "./adapter.js";
13
13
  export { assertMemoryRelationshipGraphAdapterConformance, assertRelationshipGraphAdapterConformance, createRelationshipGraphScaleFixture, type RelationshipGraphAdapterConformanceCase, type RelationshipGraphAdapterConformanceReport, type RelationshipGraphScaleFixture, type RelationshipGraphScaleFixtureOptions, type RelationshipGraphScaleTopology, } from "./conformance.js";
14
14
  export { analyzeRelationshipSchedule, type GraphScheduleOptions, type RelationshipScheduleAnalysis, type RelationshipScheduleRow, } from "./scheduling.js";
15
- export { assembleWorkspaceRelationshipGraph, collectDanglingDependencyReferences, collectDuplicateDependencyRows, collectMissingDependencyTargetIds, normalizeDependencyGraphTarget, resolveWorkspaceRelationshipKindRegistry, type DanglingDependencyReference, type DanglingDependencyReferenceSummary, type DependencyReferenceHolder, type DependencyReferenceSource, type DuplicateDependencyRow, type WorkspaceRelationshipAssembly, type WorkspaceRelationshipItem, type WorkspaceRelationshipNodeDetails, } from "./assembly.js";
16
- export { auditWorkspaceRelationshipGraph, collectDuplicateRelationshipEdgeGroups, collectOrderingCycles, diffRelationshipAuditSnapshots, formatDuplicateEdgeGroup, type DuplicateRelationshipEdgeGroup, type RelationshipAuditDelta, type RelationshipAuditFinding, type RelationshipAuditFindingCode, type RelationshipAuditOptions, type RelationshipAuditReport, type RelationshipAuditSeverity, type RelationshipAuditSnapshot, type RelationshipCoverageProfile, type RelationshipCoverageTypeProfile, } from "./governance.js";
15
+ export { assembleWorkspaceRelationshipGraph, collectDanglingDependencyReferences, collectDuplicateDependencyRows, collectMissingDependencyTargetIds, collectOrderingStorageContradictions, normalizeDependencyGraphTarget, resolveWorkspaceRelationshipKindRegistry, type DanglingDependencyReference, type DanglingDependencyReferenceSummary, type DependencyReferenceHolder, type DependencyReferenceSource, type DuplicateDependencyRow, type OrderingStorageContradiction, type WorkspaceRelationshipAssembly, type WorkspaceRelationshipItem, type WorkspaceRelationshipNodeDetails, } from "./assembly.js";
16
+ export { auditWorkspaceRelationshipGraph, collectDuplicateRelationshipEdgeGroups, collectOrderingCycles, diffRelationshipAuditSnapshots, formatDuplicateEdgeGroup, formatOrderingStorageContradiction, type DuplicateRelationshipEdgeGroup, type RelationshipAuditDelta, type RelationshipAuditFinding, type RelationshipAuditFindingCode, type RelationshipAuditOptions, type RelationshipAuditReport, type RelationshipAuditSeverity, type RelationshipAuditSnapshot, type RelationshipCoverageProfile, type RelationshipCoverageTypeProfile, } from "./governance.js";
17
17
  export { clearDurableGraphCache, durableGraphCachePath, durableGraphCacheStatus, GRAPH_DURABLE_CACHE_MIN_ITEMS, GRAPH_DURABLE_CACHE_VERSION, graphAuditBaselinePath, loadGraphAuditBaseline, openDurableGraphCache, persistDurableGraphResult, saveGraphAuditBaseline, shouldPersistDurableGraphCache, type DurableGraphCacheEnvelope, type DurableGraphCacheStatus, type DurableGraphCacheView, } from "./durable-cache.js";
18
18
  export { enumerateRelationshipPaths, hierarchyAncestors, hierarchyDescendants, orderingPredecessors, orderingSuccessors, type GraphPathOptions, type GraphTraversalOptions, type RelationshipPath, } from "./traversal.js";
19
19
  export { computeWorkspaceGraphFingerprint, resetWorkspaceGraphCache, workspaceGraphCache, WorkspaceGraphCache, type GraphCacheMetadata, type WorkspaceGraphCacheLookup, } from "./cache.js";
@@ -8,14 +8,14 @@
8
8
  * `sdk/relationships` and is safe for CLI, MCP, extension, and non-PM callers.
9
9
  */
10
10
 
11
- !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]="2c3df51e-6b10-5da6-8340-126465d9c434")}catch(e){}}();
11
+ !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]="b5509c6e-1431-5316-a563-16681ced4f33")}catch(e){}}();
12
12
  export { computeRelationshipDominators, detectRelationshipCommunities, findRedundantRelationshipEdges, forEachMatchedRelationshipEdge, } from "./analytics.js";
13
13
  export { computeRelationshipCentrality, findRelationshipCutStructure, } from "./centrality.js";
14
14
  export { createRelationshipGraphSnapshot, federateRelationshipGraphSnapshots, loadRelationshipGraphAdapter, MemoryRelationshipGraphAdapter, parseRelationshipGraphSnapshot, RELATIONSHIP_GRAPH_SNAPSHOT_VERSION, syncRelationshipGraphAdapter, } from "./adapter.js";
15
15
  export { assertMemoryRelationshipGraphAdapterConformance, assertRelationshipGraphAdapterConformance, createRelationshipGraphScaleFixture, } from "./conformance.js";
16
16
  export { analyzeRelationshipSchedule, } from "./scheduling.js";
17
- export { assembleWorkspaceRelationshipGraph, collectDanglingDependencyReferences, collectDuplicateDependencyRows, collectMissingDependencyTargetIds, normalizeDependencyGraphTarget, resolveWorkspaceRelationshipKindRegistry, } from "./assembly.js";
18
- export { auditWorkspaceRelationshipGraph, collectDuplicateRelationshipEdgeGroups, collectOrderingCycles, diffRelationshipAuditSnapshots, formatDuplicateEdgeGroup, } from "./governance.js";
17
+ export { assembleWorkspaceRelationshipGraph, collectDanglingDependencyReferences, collectDuplicateDependencyRows, collectMissingDependencyTargetIds, collectOrderingStorageContradictions, normalizeDependencyGraphTarget, resolveWorkspaceRelationshipKindRegistry, } from "./assembly.js";
18
+ export { auditWorkspaceRelationshipGraph, collectDuplicateRelationshipEdgeGroups, collectOrderingCycles, diffRelationshipAuditSnapshots, formatDuplicateEdgeGroup, formatOrderingStorageContradiction, } from "./governance.js";
19
19
  export { clearDurableGraphCache, durableGraphCachePath, durableGraphCacheStatus, GRAPH_DURABLE_CACHE_MIN_ITEMS, GRAPH_DURABLE_CACHE_VERSION, graphAuditBaselinePath, loadGraphAuditBaseline, openDurableGraphCache, persistDurableGraphResult, saveGraphAuditBaseline, shouldPersistDurableGraphCache, } from "./durable-cache.js";
20
20
  export { enumerateRelationshipPaths, hierarchyAncestors, hierarchyDescendants, orderingPredecessors, orderingSuccessors, } from "./traversal.js";
21
21
  export { computeWorkspaceGraphFingerprint, resetWorkspaceGraphCache, workspaceGraphCache, WorkspaceGraphCache, } from "./cache.js";
@@ -23,4 +23,4 @@ export { planRelationshipRemediation, } from "./remediation.js";
23
23
  export { collectNewOrderingCycleWarnings } from "./mutation-advisory.js";
24
24
  export { GRAPH_SUBCOMMAND_VALUES, parseGraphSubcommand, runGraph, } from "./run.js";
25
25
  //# sourceMappingURL=index.js.map
26
- //# debugId=2c3df51e-6b10-5da6-8340-126465d9c434
26
+ //# debugId=b5509c6e-1431-5316-a563-16681ced4f33
@@ -1,7 +1,7 @@
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]="4198a3b2-2541-50eb-bec5-93ac58601f40")}catch(e){}}();
3
- import { normalizeDependencyGraphTarget, resolveWorkspaceRelationshipKindRegistry, } from "./assembly.js";
4
- import { collectOrderingCycles } from "./governance.js";
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]="94e8b95b-35fa-5fc7-843a-481497e09b54")}catch(e){}}();
3
+ import { collectOrderingStorageContradictions, normalizeDependencyGraphTarget, resolveWorkspaceRelationshipKindRegistry, } from "./assembly.js";
4
+ import { collectOrderingCycles, formatOrderingStorageContradiction, } from "./governance.js";
5
5
  function cycleKey(component) {
6
6
  return [...component].sort().join("\u0000");
7
7
  }
@@ -153,9 +153,17 @@ export function collectNewOrderingCycleWarnings(beforeItems, afterItems, changed
153
153
  const before = collectScopedCycles(beforeItems, registry, changedItemId);
154
154
  const after = collectScopedCycles(afterItems, registry, changedItemId);
155
155
  const beforeCycles = new Set(before.cycles.map(cycleKey));
156
- return after.cycles
157
- .filter((component) => !beforeCycles.has(cycleKey(component)))
158
- .map((component) => `ordering_cycle_created:${findCyclePath(after.successors, component, after.canonical).join(" -> ")}:items_will_not_be_ready:run_pm_graph_audit`);
156
+ const beforeContradictions = new Set(collectOrderingStorageContradictions(beforeItems, undefined, registry).map((row) => `${row.holder_id.toLowerCase()}\u0000${row.target_id.toLowerCase()}\u0000${row.dependency_kind}`));
157
+ const contradictionWarnings = collectOrderingStorageContradictions(afterItems, undefined, registry)
158
+ .filter((row) => row.holder_id.toLowerCase() === changedItemId.trim().toLowerCase() &&
159
+ !beforeContradictions.has(`${row.holder_id.toLowerCase()}\u0000${row.target_id.toLowerCase()}\u0000${row.dependency_kind}`))
160
+ .map((row) => `ordering_storage_contradiction_created:${formatOrderingStorageContradiction(row)}:remove_contradicting_dependency_row:run_pm_graph_audit`);
161
+ return [
162
+ ...contradictionWarnings,
163
+ ...after.cycles
164
+ .filter((component) => !beforeCycles.has(cycleKey(component)))
165
+ .map((component) => `ordering_cycle_created:${findCyclePath(after.successors, component, after.canonical).join(" -> ")}:items_will_not_be_ready:run_pm_graph_audit`),
166
+ ];
159
167
  }
160
168
  /** White-box graph-path helpers for exhaustive SDK primitive verification. */
161
169
  export const mutationAdvisoryTestOnly = {
@@ -166,4 +174,4 @@ export const mutationAdvisoryTestOnly = {
166
174
  findPathBackToStart,
167
175
  };
168
176
  //# sourceMappingURL=mutation-advisory.js.map
169
- //# debugId=4198a3b2-2541-50eb-bec5-93ac58601f40
177
+ //# debugId=94e8b95b-35fa-5fc7-843a-481497e09b54