@unbrained/pm-cli 2026.8.12 → 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.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +162 -111
- package/dist/cli/error-guidance.js +4 -8
- package/dist/cli/main.js +40 -3
- package/dist/cli/register-assurance.js +28 -17
- package/dist/cli-bundle/bundle-manifest.json +141 -173
- package/dist/cli-bundle/chunks/chunk-BBOFSVAK.js +197 -0
- package/dist/cli-bundle/chunks/chunk-BFALV3YP.js +5 -0
- package/dist/cli-bundle/chunks/{chunk-WLAHPSOX.js → chunk-FIW4P64F.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-BM5YJ2UW.js → chunk-G5JUB66K.js} +52 -52
- package/dist/cli-bundle/chunks/chunk-SBRKH6OR.js +2 -0
- package/dist/cli-bundle/chunks/chunk-TMJ7URWS.js +13 -0
- package/dist/cli-bundle/chunks/chunk-TXMEUUUY.js +8 -0
- package/dist/cli-bundle/chunks/{chunk-KOQMGCTA.js → chunk-XAVMOK6B.js} +50 -50
- package/dist/cli-bundle/chunks/chunk-YAMTJL6Y.js +34 -0
- package/dist/cli-bundle/chunks/chunk-YSVSMJ2B.js +2 -0
- package/dist/cli-bundle/chunks/{register-list-query-XPCJRUUD.js → register-list-query-T3EHHNNV.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-4RJCBKRS.js → register-mutation-E27WCLSZ.js} +2 -2
- package/dist/cli-bundle/chunks/register-operations-4R6I7CPY.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-LLHAKP2V.js → register-setup-3YXZ444E.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-JAFRIWVF.js → chunk-4DQ2YERC.js} +4 -4
- package/dist/cli-bundle/focused-chunks/chunk-F43TT2QQ.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-K7RWWOAG.js +4 -0
- package/dist/cli-bundle/focused-chunks/chunk-KFSZ3BP6.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-KHM2CS2C.js → chunk-KSEDUWVZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-KYUQGTSB.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-ZMGWAYH7.js → chunk-LZ4MV3RH.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-PGXJQLCT.js +155 -0
- package/dist/cli-bundle/focused-chunks/{chunk-RWPAWUOT.js → chunk-PPFGQDSI.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-Q4YY3XNF.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-QK753U3U.js +46 -0
- package/dist/cli-bundle/focused-chunks/chunk-QUMB2J27.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-SM7MTG27.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-GQW4BPUT.js → chunk-WCVE2NIG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-XDNAW5OI.js +18 -0
- package/dist/cli-bundle/focused-chunks/{chunk-YIAXMC3T.js → chunk-YOOI3UZX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZM6TZVHC.js +2 -0
- package/dist/cli-bundle/main.js +13 -13
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +45 -41
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +109 -1
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +2 -2
- package/dist/core/checkpoint/checkpoint-gc.js +7 -12
- package/dist/core/extensions/activation-summary-markdown.js +5 -4
- package/dist/core/extensions/activation-summary.d.ts +2 -0
- package/dist/core/extensions/activation-summary.js +6 -2
- package/dist/core/extensions/capability-usage.d.ts +1 -1
- package/dist/core/extensions/capability-usage.js +4 -3
- package/dist/core/extensions/contribution-inventory.d.ts +1 -0
- package/dist/core/extensions/contribution-inventory.js +6 -2
- package/dist/core/extensions/extension-registries.js +3 -2
- package/dist/core/extensions/extension-types.d.ts +83 -1
- package/dist/core/extensions/extension-types.js +3 -2
- package/dist/core/extensions/loader.d.ts +2 -8
- package/dist/core/extensions/loader.js +53 -144
- package/dist/core/extensions/registration-values.d.ts +43 -0
- package/dist/core/extensions/registration-values.js +210 -0
- package/dist/core/extensions/runtime-registrations.d.ts +3 -1
- package/dist/core/extensions/runtime-registrations.js +12 -2
- package/dist/core/fs/fs-utils.d.ts +2 -0
- package/dist/core/fs/fs-utils.js +7 -3
- package/dist/core/history/drift-cache.js +4 -3
- package/dist/core/history/drift-scan.d.ts +6 -0
- package/dist/core/history/drift-scan.js +76 -58
- package/dist/core/history/workspace-history.d.ts +59 -0
- package/dist/core/history/workspace-history.js +197 -10
- package/dist/core/lock/lock-gc.js +8 -13
- package/dist/core/lock/lock.js +5 -4
- package/dist/core/output/output.js +12 -4
- package/dist/core/search/vector-stores.js +6 -11
- package/dist/core/store/item-metadata-cache.js +4 -4
- package/dist/core/telemetry/runtime.d.ts +6 -0
- package/dist/core/telemetry/runtime.js +101 -30
- package/dist/sdk/agent/command-recovery.d.ts +2 -0
- package/dist/sdk/agent/command-recovery.js +10 -2
- package/dist/sdk/annotations.js +4 -4
- package/dist/sdk/cli-contracts/completeness.js +9 -3
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts/flag-contracts.js +6 -3
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +6 -1
- package/dist/sdk/cli-contracts/runtime-contracts.js +155 -60
- package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +32 -0
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +25 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +35 -5
- package/dist/sdk/cli-contracts/tool-schema.js +17 -2
- package/dist/sdk/cli-program.js +3 -3
- package/dist/sdk/comments.js +4 -3
- package/dist/sdk/compile-cache.js +4 -3
- package/dist/sdk/compose.d.ts +3 -1
- package/dist/sdk/compose.js +16 -2
- package/dist/sdk/context-relevance.js +12 -4
- package/dist/sdk/context-signal-store.js +4 -3
- package/dist/sdk/extension/install-runtime.js +4 -4
- package/dist/sdk/extension/managed-state.js +4 -3
- package/dist/sdk/extension-contracts.d.ts +1 -1
- package/dist/sdk/flag-invocation-contracts.js +5 -6
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -2
- package/dist/sdk/governance/assurance-action.d.ts +27 -3
- package/dist/sdk/governance/assurance-action.js +112 -28
- package/dist/sdk/governance/assurance-mutation-error.d.ts +7 -0
- package/dist/sdk/governance/assurance-mutation-error.js +25 -2
- package/dist/sdk/governance/assurance-presets.d.ts +54 -0
- package/dist/sdk/governance/assurance-presets.js +136 -0
- package/dist/sdk/governance/assurance-runtime.d.ts +4 -0
- package/dist/sdk/governance/assurance-runtime.js +109 -8
- package/dist/sdk/governance/assurance.d.ts +39 -0
- package/dist/sdk/governance/assurance.js +145 -6
- package/dist/sdk/governance/gc.js +5 -11
- package/dist/sdk/governance/health.js +18 -6
- package/dist/sdk/governance/validate-history-drift.d.ts +7 -0
- package/dist/sdk/governance/validate-history-drift.js +68 -0
- package/dist/sdk/governance/validate.js +6 -48
- package/dist/sdk/graph/assembly.d.ts +23 -0
- package/dist/sdk/graph/assembly.js +54 -2
- package/dist/sdk/graph/durable-cache.js +91 -3
- package/dist/sdk/graph/governance-contracts.d.ts +12 -0
- package/dist/sdk/graph/governance-contracts.js +29 -0
- package/dist/sdk/graph/governance.d.ts +51 -3
- package/dist/sdk/graph/governance.js +216 -35
- package/dist/sdk/graph/index.d.ts +2 -2
- package/dist/sdk/graph/index.js +4 -4
- package/dist/sdk/graph/mutation-advisory.js +15 -7
- package/dist/sdk/graph/remediation.js +12 -2
- package/dist/sdk/guide.js +4 -4
- package/dist/sdk/history-read.d.ts +8 -0
- package/dist/sdk/history-read.js +2 -2
- package/dist/sdk/index.d.ts +3 -2
- package/dist/sdk/index.js +5 -4
- package/dist/sdk/linked-artifacts.d.ts +2 -0
- package/dist/sdk/linked-artifacts.js +29 -4
- package/dist/sdk/merge/install.js +5 -4
- package/dist/sdk/query/activity.js +4 -3
- package/dist/sdk/query/history.js +20 -3
- package/dist/sdk/read-output-budget.d.ts +2 -0
- package/dist/sdk/read-output-budget.js +12 -5
- package/dist/sdk/read-output-contracts.d.ts +61 -5
- package/dist/sdk/read-output-contracts.js +210 -28
- package/dist/sdk/read-output-rows.d.ts +11 -0
- package/dist/sdk/read-output-rows.js +47 -2
- package/dist/sdk/relationship-history.js +5 -5
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.js +5 -3
- package/dist/sdk/schema-migration.js +4 -4
- package/dist/sdk/test/execution.js +4 -4
- package/dist/sdk/workspace-memory.js +4 -4
- package/dist/sdk/workspace-snapshot.js +8 -14
- package/dist/sdk/workspace-transaction-gc.js +4 -9
- package/dist/sdk/workspace-transaction.js +4 -4
- package/dist/sdk/workspace.js +4 -3
- package/docs/ASSURANCE.md +163 -3
- package/docs/COMMANDS.md +31 -2
- package/docs/CONFIGURATION.md +2 -0
- package/docs/EXTENSIONS.md +11 -12
- package/docs/READ_OUTPUT_CONTRACTS.md +44 -8
- package/docs/RELATIONSHIP_GRAPH.md +34 -4
- package/docs/SDK.md +29 -8
- package/docs/SDK_CONTEXT_INTEGRITY.md +32 -1
- package/docs/TESTING.md +47 -16
- package/docs/performance/sdk-entrypoint-import-costs.md +20 -13
- package/marketplace.json +2 -2
- package/package.json +6 -6
- package/packages/pm-beads/extensions/beads/index.ts +1 -0
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/extensions/calendar/index.ts +1 -0
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/extensions/digital-twin/index.ts +7 -0
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/extensions/governance-audit/index.ts +4 -0
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/extensions/guide-shell/index.ts +5 -0
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/index.ts +6 -0
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/extensions/search-advanced/index.ts +2 -0
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/extensions/templates/index.ts +4 -0
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/extensions/todos/index.ts +2 -0
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/extensions/vcs/index.ts +7 -0
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/scripts/bundle-cli.mjs +17 -4
- package/sdk/public-surface.json +390 -60
- package/dist/cli-bundle/chunks/chunk-3PS7X6GS.js +0 -8
- package/dist/cli-bundle/chunks/chunk-7KL6KMWF.js +0 -13
- package/dist/cli-bundle/chunks/chunk-D55A5AEN.js +0 -33
- package/dist/cli-bundle/chunks/chunk-KIKDWECH.js +0 -196
- package/dist/cli-bundle/chunks/chunk-R76342NV.js +0 -2
- package/dist/cli-bundle/chunks/chunk-RBTK5EZV.js +0 -5
- package/dist/cli-bundle/chunks/chunk-VLUQOIDT.js +0 -2
- package/dist/cli-bundle/chunks/register-operations-2OGISOVR.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-2DALMVF7.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-5OQIMELN.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-5TAGTDRE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-ECADZMVC.js +0 -18
- package/dist/cli-bundle/focused-chunks/chunk-EJGXRA6B.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-FFGSZCPK.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-ISKOBJCM.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-KPSXVBDV.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-KTLOKKCQ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-LGYK3NUF.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-NBLUKITQ.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-NYLOUPOB.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-Q4T463SD.js +0 -31
- package/dist/cli-bundle/focused-chunks/chunk-QVZVY53N.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-UTEWXDEQ.js +0 -17
|
@@ -13,11 +13,11 @@
|
|
|
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
|
+
import { type RelationshipAuditFindingCode } from "./governance-contracts.js";
|
|
18
|
+
export type { RelationshipAuditFindingCode } from "./governance-contracts.js";
|
|
17
19
|
/** Severity ladder shared by every relationship audit finding. */
|
|
18
20
|
export type RelationshipAuditSeverity = "error" | "warning" | "info";
|
|
19
|
-
/** Machine-readable identifier for one relationship audit finding family. */
|
|
20
|
-
export type RelationshipAuditFindingCode = "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";
|
|
21
21
|
/** One policy-aware relationship audit finding with bounded evidence. */
|
|
22
22
|
export interface RelationshipAuditFinding {
|
|
23
23
|
/** Machine-readable finding family identifier. */
|
|
@@ -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. */
|
|
@@ -72,6 +82,34 @@ export interface RelationshipCoverageProfile {
|
|
|
72
82
|
degree_leq_one_active_nodes: number;
|
|
73
83
|
/** Deterministic per-type connectivity coverage; untyped nodes bucket under `(untyped)`. */
|
|
74
84
|
coverage_by_type: Record<string, RelationshipCoverageTypeProfile>;
|
|
85
|
+
/** Undirected cut vertices whose removal increases the component count. */
|
|
86
|
+
articulation_points: number;
|
|
87
|
+
/** Undirected cut edges whose removal disconnects their endpoints. */
|
|
88
|
+
bridge_edges: number;
|
|
89
|
+
/** Milestone nodes whose title explicitly declares an outcome. */
|
|
90
|
+
outcome_nodes: number;
|
|
91
|
+
/** Active non-outcome nodes with a typed hierarchy or implements path to an outcome. */
|
|
92
|
+
active_outcome_reachable_nodes: number;
|
|
93
|
+
/** Active non-outcome nodes without a typed hierarchy or implements path to an outcome. */
|
|
94
|
+
active_outcome_unreachable_nodes: number;
|
|
95
|
+
/** Active typed-outcome reachability expressed as integer basis points. */
|
|
96
|
+
active_outcome_reachability_basis_points: number;
|
|
97
|
+
/** Terminal non-placeholder, non-outcome nodes included in the all-status census. */
|
|
98
|
+
terminal_nodes: number;
|
|
99
|
+
/** Terminal non-outcome nodes with a typed hierarchy or implements path to an outcome. */
|
|
100
|
+
terminal_outcome_reachable_nodes: number;
|
|
101
|
+
/** Terminal non-outcome nodes without a typed hierarchy or implements path to an outcome. */
|
|
102
|
+
terminal_outcome_unreachable_nodes: number;
|
|
103
|
+
/** Terminal typed-outcome reachability expressed as integer basis points. */
|
|
104
|
+
terminal_outcome_reachability_basis_points: number;
|
|
105
|
+
/** All active and terminal non-outcome nodes with a typed path to an outcome. */
|
|
106
|
+
outcome_reachable_nodes: number;
|
|
107
|
+
/** All active and terminal non-outcome nodes without a typed path to an outcome. */
|
|
108
|
+
outcome_unreachable_nodes: number;
|
|
109
|
+
/** All-status typed-outcome reachability expressed as integer basis points. */
|
|
110
|
+
outcome_reachability_basis_points: number;
|
|
111
|
+
/** Affected-subject census containing every known finding code, including zero populations. */
|
|
112
|
+
finding_subjects_by_code: Record<RelationshipAuditFindingCode, number>;
|
|
75
113
|
}
|
|
76
114
|
/** Tuning and policy inputs accepted by the relationship audit. */
|
|
77
115
|
export interface RelationshipAuditOptions {
|
|
@@ -106,6 +144,8 @@ export declare function isSemanticContextKind(kind: string): boolean;
|
|
|
106
144
|
* advisories) share one cycle semantics with the workspace audit.
|
|
107
145
|
*/
|
|
108
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;
|
|
109
149
|
/** One duplicate-edge group in semantic orientation with its stored spellings. */
|
|
110
150
|
export interface DuplicateRelationshipEdgeGroup {
|
|
111
151
|
/** Semantic tail node shared by every stored spelling. */
|
|
@@ -161,8 +201,16 @@ export interface RelationshipAuditDelta {
|
|
|
161
201
|
profile: {
|
|
162
202
|
/** Node-count change including missing placeholders. */
|
|
163
203
|
nodes: number;
|
|
204
|
+
/** Tracker-recorded node-count change excluding synthesized placeholders. */
|
|
205
|
+
recorded_nodes?: number;
|
|
164
206
|
/** Deduplicated edge-count change. */
|
|
165
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;
|
|
166
214
|
/** Active-node-count change. */
|
|
167
215
|
active_nodes: number;
|
|
168
216
|
/** Missing-placeholder-count change. */
|
|
@@ -1,8 +1,13 @@
|
|
|
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]="
|
|
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
|
+
import { findRelationshipCutStructure } from "./centrality.js";
|
|
5
|
+
import { RELATIONSHIP_AUDIT_FINDING_CODES, } from "./governance-contracts.js";
|
|
4
6
|
/** Default bounded sample size applied to every finding family. */
|
|
5
7
|
const DEFAULT_MAX_SAMPLE_SIZE = 25;
|
|
8
|
+
/** Canonical item type and title marker that identify explicit outcomes. */
|
|
9
|
+
const OUTCOME_MILESTONE_TYPE = "milestone";
|
|
10
|
+
const OUTCOME_MILESTONE_TITLE_PREFIX = "outcome milestone:";
|
|
6
11
|
/** Relationship kinds that preserve why work exists or how evidence supports it. */
|
|
7
12
|
const SEMANTIC_CONTEXT_KINDS = new Set([
|
|
8
13
|
"discovered_from",
|
|
@@ -20,8 +25,14 @@ const SEVERITY_RANK = {
|
|
|
20
25
|
warning: 1,
|
|
21
26
|
info: 2,
|
|
22
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
|
+
}
|
|
23
34
|
/** Build one finding with deterministic bounded sampling over sorted subjects. */
|
|
24
|
-
function buildFinding(code, severity, policy, describe, subjects, maxSampleSize, remediation) {
|
|
35
|
+
function buildFinding(code, severity, policy, describe, subjects, maxSampleSize, remediation, evidence) {
|
|
25
36
|
const sorted = [...subjects].sort((left, right) => left.localeCompare(right));
|
|
26
37
|
return {
|
|
27
38
|
code,
|
|
@@ -32,6 +43,13 @@ function buildFinding(code, severity, policy, describe, subjects, maxSampleSize,
|
|
|
32
43
|
sample: sorted.slice(0, maxSampleSize),
|
|
33
44
|
sample_truncated: sorted.length > maxSampleSize,
|
|
34
45
|
remediation,
|
|
46
|
+
...(evidence === undefined
|
|
47
|
+
? {}
|
|
48
|
+
: {
|
|
49
|
+
evidence: [...evidence]
|
|
50
|
+
.sort((left, right) => left.localeCompare(right))
|
|
51
|
+
.slice(0, maxSampleSize),
|
|
52
|
+
}),
|
|
35
53
|
};
|
|
36
54
|
}
|
|
37
55
|
/** Resolve the ordering-only successor adjacency for cycle analysis. */
|
|
@@ -172,6 +190,21 @@ function isActiveAuditMember(member, nodeStates) {
|
|
|
172
190
|
return true;
|
|
173
191
|
return !state.terminal;
|
|
174
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
|
+
}
|
|
175
208
|
/** Collect ordering-cycle and lifecycle-block governance findings. */
|
|
176
209
|
function collectOrderingFindings(assembly, nodeStates, isBlocked, maxSampleSize) {
|
|
177
210
|
const findings = [];
|
|
@@ -181,9 +214,18 @@ function collectOrderingFindings(assembly, nodeStates, isBlocked, maxSampleSize)
|
|
|
181
214
|
// it cannot make live work unschedulable, and "repairing" it would touch
|
|
182
215
|
// closed items (changelog drag), so it downgrades to informational debt.
|
|
183
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);
|
|
184
222
|
findings.push(active
|
|
185
|
-
? 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."
|
|
186
|
-
|
|
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));
|
|
187
229
|
}
|
|
188
230
|
const predecessorsByNode = new Map();
|
|
189
231
|
for (const [predecessor, adjacent] of orderingAdjacency)
|
|
@@ -290,6 +332,104 @@ function collectDuplicateRowFindings(assembly, maxSampleSize) {
|
|
|
290
332
|
appendFinding(findings, legacy, maxSampleSize, "legacy_duplicate_dependency_row", "info", "Identical repeated dependency rows on terminal holders are historical storage noise with no scheduling effect.", (count) => `${count} exactly duplicated stored dependency row(s) on terminal holder(s)`, "Leave as history debt or clean up in a dedicated changelog-safe closed-item batch.");
|
|
291
333
|
return findings;
|
|
292
334
|
}
|
|
335
|
+
/** Build the reverse typed paths that can carry context toward an outcome. */
|
|
336
|
+
function buildOutcomeReverseIndex(assembly, signal) {
|
|
337
|
+
const reverse = new Map();
|
|
338
|
+
for (const edge of assembly.graph.edges()) {
|
|
339
|
+
signal?.throwIfAborted();
|
|
340
|
+
const definition = assembly.graph.registry().require(edge.kind);
|
|
341
|
+
let oriented;
|
|
342
|
+
if (definition.hierarchy) {
|
|
343
|
+
oriented = orientTransitiveEdge(edge, definition);
|
|
344
|
+
}
|
|
345
|
+
else if (definition.kind === "implements") {
|
|
346
|
+
oriented = { from: edge.source, to: edge.target };
|
|
347
|
+
}
|
|
348
|
+
if (oriented === undefined)
|
|
349
|
+
continue;
|
|
350
|
+
const sources = reverse.get(oriented.to) ?? new Set();
|
|
351
|
+
sources.add(oriented.from);
|
|
352
|
+
reverse.set(oriented.to, sources);
|
|
353
|
+
}
|
|
354
|
+
return reverse;
|
|
355
|
+
}
|
|
356
|
+
/** Expand outcome nodes through every deterministic reverse typed path. */
|
|
357
|
+
function expandOutcomeReachability(outcomes, reverse, signal) {
|
|
358
|
+
const reachable = new Set(outcomes);
|
|
359
|
+
const queue = [...outcomes].sort();
|
|
360
|
+
for (let index = 0; index < queue.length; index += 1) {
|
|
361
|
+
signal?.throwIfAborted();
|
|
362
|
+
for (const source of [...(reverse.get(queue[index]) ?? [])].sort()) {
|
|
363
|
+
if (reachable.has(source))
|
|
364
|
+
continue;
|
|
365
|
+
reachable.add(source);
|
|
366
|
+
queue.push(source);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return reachable;
|
|
370
|
+
}
|
|
371
|
+
/** Count active and terminal nodes against the resolved outcome-reachable set. */
|
|
372
|
+
function tallyOutcomeReachability(nodeStates, outcomes, reachable, signal) {
|
|
373
|
+
let activeReachable = 0;
|
|
374
|
+
let activeUnreachable = 0;
|
|
375
|
+
let terminal = 0;
|
|
376
|
+
let terminalReachable = 0;
|
|
377
|
+
for (const state of nodeStates.values()) {
|
|
378
|
+
signal?.throwIfAborted();
|
|
379
|
+
if (outcomes.has(state.id))
|
|
380
|
+
continue;
|
|
381
|
+
if (state.missing || state.status === "external")
|
|
382
|
+
continue;
|
|
383
|
+
if (state.terminal) {
|
|
384
|
+
terminal += 1;
|
|
385
|
+
if (reachable.has(state.id))
|
|
386
|
+
terminalReachable += 1;
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
if (reachable.has(state.id))
|
|
390
|
+
activeReachable += 1;
|
|
391
|
+
else
|
|
392
|
+
activeUnreachable += 1;
|
|
393
|
+
}
|
|
394
|
+
const active = activeReachable + activeUnreachable;
|
|
395
|
+
const terminalUnreachable = terminal - terminalReachable;
|
|
396
|
+
const outcomeReachable = activeReachable + terminalReachable;
|
|
397
|
+
const outcomeUnreachable = activeUnreachable + terminalUnreachable;
|
|
398
|
+
const outcomePopulation = outcomeReachable + outcomeUnreachable;
|
|
399
|
+
return {
|
|
400
|
+
active_outcome_reachable_nodes: activeReachable,
|
|
401
|
+
active_outcome_unreachable_nodes: activeUnreachable,
|
|
402
|
+
active_outcome_reachability_basis_points: active === 0 ? 0 : Math.floor((activeReachable * 10_000) / active),
|
|
403
|
+
terminal_nodes: terminal,
|
|
404
|
+
terminal_outcome_reachable_nodes: terminalReachable,
|
|
405
|
+
terminal_outcome_unreachable_nodes: terminalUnreachable,
|
|
406
|
+
terminal_outcome_reachability_basis_points: terminal === 0 ? 0 : Math.floor((terminalReachable * 10_000) / terminal),
|
|
407
|
+
outcome_reachable_nodes: outcomeReachable,
|
|
408
|
+
outcome_unreachable_nodes: outcomeUnreachable,
|
|
409
|
+
outcome_reachability_basis_points: outcomePopulation === 0
|
|
410
|
+
? 0
|
|
411
|
+
: Math.floor((outcomeReachable * 10_000) / outcomePopulation),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Count nodes with an explicit typed path to an outcome milestone. Hierarchy
|
|
416
|
+
* edges flow child to parent and `implements` flows implementation to outcome;
|
|
417
|
+
* unrelated association edges deliberately contribute no reachability.
|
|
418
|
+
*/
|
|
419
|
+
function profileOutcomeReachability(assembly, nodeStates, signal) {
|
|
420
|
+
const outcomes = new Set(assembly.details
|
|
421
|
+
.filter((detail) => detail.type?.toLowerCase() === OUTCOME_MILESTONE_TYPE &&
|
|
422
|
+
detail.title
|
|
423
|
+
.trim()
|
|
424
|
+
.toLowerCase()
|
|
425
|
+
.startsWith(OUTCOME_MILESTONE_TITLE_PREFIX))
|
|
426
|
+
.map((detail) => detail.id));
|
|
427
|
+
const reachable = expandOutcomeReachability(outcomes, buildOutcomeReverseIndex(assembly, signal), signal);
|
|
428
|
+
return {
|
|
429
|
+
outcome_nodes: outcomes.size,
|
|
430
|
+
...tallyOutcomeReachability(nodeStates, outcomes, reachable, signal),
|
|
431
|
+
};
|
|
432
|
+
}
|
|
293
433
|
/** Fold one active node's degree into the aggregate and per-type coverage tallies. */
|
|
294
434
|
function tallyActiveCoverageNode(tallies, state, degree, exemptIsolates, isolateExemptTypes) {
|
|
295
435
|
tallies.active += 1;
|
|
@@ -316,7 +456,7 @@ function tallyActiveCoverageNode(tallies, state, degree, exemptIsolates, isolate
|
|
|
316
456
|
else
|
|
317
457
|
tallies.sparse.push(state.id);
|
|
318
458
|
}
|
|
319
|
-
function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExemptTypes, maxSampleSize, edgesByKind) {
|
|
459
|
+
function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExemptTypes, maxSampleSize, edgesByKind, signal) {
|
|
320
460
|
const tallies = {
|
|
321
461
|
active: 0,
|
|
322
462
|
missing: 0,
|
|
@@ -327,6 +467,7 @@ function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExem
|
|
|
327
467
|
byType: new Map(),
|
|
328
468
|
};
|
|
329
469
|
for (const id of assembly.graph.nodes()) {
|
|
470
|
+
signal?.throwIfAborted();
|
|
330
471
|
const state = nodeStates.get(id);
|
|
331
472
|
/* c8 ignore next -- every graph node originates from assembly details by construction */
|
|
332
473
|
if (!state)
|
|
@@ -344,13 +485,27 @@ function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExem
|
|
|
344
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.");
|
|
345
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.");
|
|
346
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}`);
|
|
347
494
|
const sortedEdgesByKind = Object.fromEntries(Object.entries(edgesByKind).sort(([left], [right]) => left.localeCompare(right)));
|
|
348
495
|
const semanticEdges = Object.entries(sortedEdgesByKind).reduce((count, [kind, value]) => count + (isSemanticContextKind(kind) ? value : 0), 0);
|
|
496
|
+
const cutStructure = findRelationshipCutStructure(assembly.graph, {
|
|
497
|
+
signal,
|
|
498
|
+
}).value;
|
|
499
|
+
const outcomeReachability = profileOutcomeReachability(assembly, nodeStates, signal);
|
|
349
500
|
return {
|
|
350
501
|
findings,
|
|
351
502
|
profile: {
|
|
352
503
|
nodes: assembly.graph.nodes().length,
|
|
504
|
+
recorded_nodes: assembly.details.filter((detail) => detail.status !== "missing" && detail.status !== "external").length,
|
|
353
505
|
edges: edgeCount,
|
|
506
|
+
informative_edges: edgeCount - nonInformativeEdgeKeys.size,
|
|
507
|
+
redundant_edges: redundantEdges.length,
|
|
508
|
+
ordering_contradiction_edges: assembly.orderingContradictions?.length ?? 0,
|
|
354
509
|
edge_basis: "deduplicated_directed",
|
|
355
510
|
edges_by_kind: sortedEdgesByKind,
|
|
356
511
|
edge_share_by_kind: Object.fromEntries(Object.entries(sortedEdgesByKind).map(([kind, count]) => [
|
|
@@ -364,6 +519,10 @@ function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExem
|
|
|
364
519
|
isolated_active_nodes: tallies.isolated,
|
|
365
520
|
degree_leq_one_active_nodes: tallies.degreeLeqOne,
|
|
366
521
|
coverage_by_type: Object.fromEntries([...tallies.byType.entries()].sort(([left], [right]) => left < right ? -1 : 1)),
|
|
522
|
+
articulation_points: cutStructure.articulationPoints.length,
|
|
523
|
+
bridge_edges: cutStructure.bridges.length,
|
|
524
|
+
...outcomeReachability,
|
|
525
|
+
finding_subjects_by_code: Object.fromEntries(RELATIONSHIP_AUDIT_FINDING_CODES.map((code) => [code, 0])),
|
|
367
526
|
},
|
|
368
527
|
};
|
|
369
528
|
}
|
|
@@ -384,12 +543,8 @@ export function auditWorkspaceRelationshipGraph(assembly, options = {}) {
|
|
|
384
543
|
const maxSampleSize = options.maxSampleSize ?? DEFAULT_MAX_SAMPLE_SIZE;
|
|
385
544
|
if (!Number.isInteger(maxSampleSize) || maxSampleSize < 1)
|
|
386
545
|
throw new TypeError(`Invalid audit sample bound: ${String(options.maxSampleSize)}`);
|
|
387
|
-
const exemptIsolates =
|
|
388
|
-
|
|
389
|
-
.map((id) => id.trim().toLowerCase()));
|
|
390
|
-
const isolateExemptTypes = new Set((options.isolateExemptTypes ?? [])
|
|
391
|
-
.filter((type) => typeof type === "string")
|
|
392
|
-
.map((type) => type.trim().toLowerCase()));
|
|
546
|
+
const exemptIsolates = normalizeExemptionSet(options.exemptIsolates);
|
|
547
|
+
const isolateExemptTypes = normalizeExemptionSet(options.isolateExemptTypes);
|
|
393
548
|
const nodeStates = new Map(assembly.details.map((detail) => [
|
|
394
549
|
detail.id,
|
|
395
550
|
{
|
|
@@ -406,18 +561,27 @@ export function auditWorkspaceRelationshipGraph(assembly, options = {}) {
|
|
|
406
561
|
edgesByKind[edge.kind] = (edgesByKind[edge.kind] ?? 0) + 1;
|
|
407
562
|
const findings = collectIntegrityFindings(assembly, isTerminal, maxSampleSize);
|
|
408
563
|
options.signal?.throwIfAborted();
|
|
564
|
+
findings.push(...collectOrderingStorageContradictionFindings(assembly, maxSampleSize));
|
|
565
|
+
options.signal?.throwIfAborted();
|
|
409
566
|
findings.push(...collectOrderingFindings(assembly, nodeStates, isBlocked, maxSampleSize));
|
|
410
567
|
options.signal?.throwIfAborted();
|
|
411
568
|
findings.push(...collectDuplicateEdgeFindings(assembly, nodeStates, maxSampleSize), ...collectDuplicateRowFindings(assembly, maxSampleSize));
|
|
412
569
|
options.signal?.throwIfAborted();
|
|
413
|
-
const coverage = collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExemptTypes, maxSampleSize, edgesByKind);
|
|
570
|
+
const coverage = collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExemptTypes, maxSampleSize, edgesByKind, options.signal);
|
|
414
571
|
findings.push(...coverage.findings);
|
|
415
572
|
findings.sort((left, right) => SEVERITY_RANK[left.severity] - SEVERITY_RANK[right.severity] ||
|
|
416
573
|
left.code.localeCompare(right.code) ||
|
|
417
574
|
left.sample[0].localeCompare(right.sample[0]));
|
|
575
|
+
const findingSubjectsByCode = coverage.profile.finding_subjects_by_code;
|
|
576
|
+
for (const finding of findings) {
|
|
577
|
+
findingSubjectsByCode[finding.code] += finding.count;
|
|
578
|
+
}
|
|
418
579
|
return {
|
|
419
580
|
findings,
|
|
420
|
-
profile:
|
|
581
|
+
profile: {
|
|
582
|
+
...coverage.profile,
|
|
583
|
+
finding_subjects_by_code: findingSubjectsByCode,
|
|
584
|
+
},
|
|
421
585
|
};
|
|
422
586
|
}
|
|
423
587
|
/** Subtract two count records, keeping only non-zero signed deltas in sorted key order. */
|
|
@@ -437,45 +601,62 @@ function diffCountRecords(baseline, current) {
|
|
|
437
601
|
function readSnapshotCoverageByType(snapshot) {
|
|
438
602
|
return snapshot.profile.coverage_by_type ?? {};
|
|
439
603
|
}
|
|
440
|
-
/**
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
export function diffRelationshipAuditSnapshots(baseline, current) {
|
|
447
|
-
const coverageByType = {};
|
|
448
|
-
// Public SDK callers may compare legacy or JSON-decoded snapshots created
|
|
449
|
-
// before per-type coverage was added, even though current typed snapshots
|
|
450
|
-
// always carry this field.
|
|
451
|
-
const baselineCoverageByType = readSnapshotCoverageByType(baseline);
|
|
452
|
-
const currentCoverageByType = readSnapshotCoverageByType(current);
|
|
453
|
-
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 = [
|
|
454
610
|
...new Set([
|
|
455
|
-
...Object.keys(
|
|
456
|
-
...Object.keys(
|
|
611
|
+
...Object.keys(baselineCoverage),
|
|
612
|
+
...Object.keys(currentCoverage),
|
|
457
613
|
]),
|
|
458
614
|
].sort();
|
|
459
|
-
for (const type of
|
|
460
|
-
const before = Object.assign({ active: 0, isolated: 0, degree_leq_one: 0 },
|
|
461
|
-
const after = Object.assign({ active: 0, isolated: 0, degree_leq_one: 0 },
|
|
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]);
|
|
462
618
|
const delta = {
|
|
463
619
|
active: after.active - before.active,
|
|
464
620
|
isolated: after.isolated - before.isolated,
|
|
465
621
|
degree_leq_one: after.degree_leq_one - before.degree_leq_one,
|
|
466
622
|
};
|
|
467
623
|
if (Object.values(delta).some((value) => value !== 0))
|
|
468
|
-
|
|
624
|
+
deltas[type] = delta;
|
|
469
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);
|
|
470
639
|
const { edge_share_by_kind: baselineEdgeShareByKind = {}, semantic_edges: baselineSemanticEdges = 0, semantic_edge_share: baselineSemanticEdgeShare = 0, } = baseline.profile;
|
|
471
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;
|
|
472
649
|
return {
|
|
473
650
|
baseline_saved_at: baseline.saved_at,
|
|
474
651
|
same_snapshot: baseline.fingerprint === current.fingerprint,
|
|
475
652
|
affected_subjects_by_code: diffCountRecords(baseline.affected_subjects_by_code, current.affected_subjects_by_code),
|
|
476
653
|
profile: {
|
|
477
654
|
nodes: current.profile.nodes - baseline.profile.nodes,
|
|
655
|
+
recorded_nodes: currentRecordedNodes - baselineRecordedNodes,
|
|
478
656
|
edges: current.profile.edges - baseline.profile.edges,
|
|
657
|
+
informative_edges: currentInformativeEdges - baselineInformativeEdges,
|
|
658
|
+
redundant_edges: currentRedundantEdges - baselineRedundantEdges,
|
|
659
|
+
ordering_contradiction_edges: currentOrderingContradictionEdges - baselineOrderingContradictionEdges,
|
|
479
660
|
active_nodes: current.profile.active_nodes - baseline.profile.active_nodes,
|
|
480
661
|
missing_nodes: current.profile.missing_nodes - baseline.profile.missing_nodes,
|
|
481
662
|
isolated_active_nodes: current.profile.isolated_active_nodes -
|
|
@@ -491,4 +672,4 @@ export function diffRelationshipAuditSnapshots(baseline, current) {
|
|
|
491
672
|
};
|
|
492
673
|
}
|
|
493
674
|
//# sourceMappingURL=governance.js.map
|
|
494
|
-
//# debugId=
|
|
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";
|
package/dist/sdk/graph/index.js
CHANGED
|
@@ -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]="
|
|
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=
|
|
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]="
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
.
|
|
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=
|
|
177
|
+
//# debugId=94e8b95b-35fa-5fc7-843a-481497e09b54
|
|
@@ -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]="
|
|
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]="1eb0e2cb-084a-5a54-b41c-29dfdd6d2f34")}catch(e){}}();
|
|
3
3
|
import { findRedundantRelationshipEdges } from "./analytics.js";
|
|
4
4
|
import { auditWorkspaceRelationshipGraph, collectDuplicateRelationshipEdgeGroups, formatDuplicateEdgeGroup, } from "./governance.js";
|
|
5
5
|
/** Per-finding-code operation template applied to every sampled subject. */
|
|
@@ -29,6 +29,16 @@ const FINDING_STEP_TEMPLATES = {
|
|
|
29
29
|
confidence: "high",
|
|
30
30
|
rationale: "Terminal-only ordering cycles have no scheduling effect; repairing them would mutate closed history (changelog drag).",
|
|
31
31
|
},
|
|
32
|
+
ordering_storage_contradiction: {
|
|
33
|
+
op: "remove",
|
|
34
|
+
confidence: "high",
|
|
35
|
+
rationale: "The structured ordering row asserts the opposite precedence from the same-target scalar blocker; remove that exact dependency row or replace both representations with one unambiguous edge.",
|
|
36
|
+
},
|
|
37
|
+
legacy_ordering_storage_contradiction: {
|
|
38
|
+
op: "remove",
|
|
39
|
+
confidence: "high",
|
|
40
|
+
rationale: "The terminal holder contains a proven contradictory structured ordering row; remove it in a dedicated changelog-safe batch while preserving the scalar blocker as history.",
|
|
41
|
+
},
|
|
32
42
|
// duplicate_edge findings are expanded into per-stored-edge remove steps by
|
|
33
43
|
// the planner itself (see stepsFromDuplicateGroup); this template documents
|
|
34
44
|
// the family for exhaustiveness and backs any future sample-only fallback.
|
|
@@ -155,4 +165,4 @@ export function planRelationshipRemediation(assembly, options = {}) {
|
|
|
155
165
|
};
|
|
156
166
|
}
|
|
157
167
|
//# sourceMappingURL=remediation.js.map
|
|
158
|
-
//# debugId=
|
|
168
|
+
//# debugId=1eb0e2cb-084a-5a54-b41c-29dfdd6d2f34
|
package/dist/sdk/guide.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Implements the pm guide 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]="
|
|
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]="27be0fa5-1c6a-53de-a0e8-179aab7c795a")}catch(e){}}();
|
|
8
|
+
import { isFileAbsentError } from "../core/fs/fs-utils.js";
|
|
8
9
|
import { readFile } from "node:fs/promises";
|
|
9
10
|
import path from "node:path";
|
|
10
11
|
import { resolveConfiguredPmPackageRoot, EXIT_CODE, PmCliError, } from "./runtime-primitives.js";
|
|
@@ -119,8 +120,7 @@ async function renderGuideDocs(topic, depth, packageRoot) {
|
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
catch (error) {
|
|
122
|
-
const
|
|
123
|
-
const missing = code === "ENOENT";
|
|
123
|
+
const missing = isFileAbsentError(error);
|
|
124
124
|
docs.push({
|
|
125
125
|
path: doc.path,
|
|
126
126
|
purpose: doc.purpose,
|
|
@@ -277,4 +277,4 @@ export function renderGuideMarkdown(result) {
|
|
|
277
277
|
return lines.join("\n");
|
|
278
278
|
}
|
|
279
279
|
//# sourceMappingURL=guide.js.map
|
|
280
|
-
//# debugId=
|
|
280
|
+
//# debugId=27be0fa5-1c6a-53de-a0e8-179aab7c795a
|