@unbrained/pm-cli 2026.8.13 → 2026.8.15
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 +165 -113
- package/dist/cli/commander-usage.js +17 -4
- package/dist/cli/error-guidance.d.ts +2 -0
- package/dist/cli/error-guidance.js +52 -25
- package/dist/cli/main.js +40 -3
- package/dist/cli/register-mutation.js +4 -2
- package/dist/cli/register-operations.js +5 -5
- package/dist/cli-bundle/bundle-manifest.json +146 -178
- package/dist/cli-bundle/chunks/{chunk-F7FJYGK3.js → chunk-24GAV7XL.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-AIM6VT2N.js +13 -0
- package/dist/cli-bundle/chunks/chunk-DSWDLTDR.js +197 -0
- package/dist/cli-bundle/chunks/{chunk-Q47C67TQ.js → chunk-J42EGKDK.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-KIEGUBYQ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-3ZMOWAFM.js → chunk-KLKYLSDX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-QGTUPEU5.js → chunk-LJHOAVGI.js} +59 -59
- package/dist/cli-bundle/chunks/chunk-MEM2ZS3O.js +5 -0
- package/dist/cli-bundle/chunks/chunk-QHPCJWEJ.js +35 -0
- package/dist/cli-bundle/chunks/{chunk-YLBAPY22.js → chunk-WLPDLNEZ.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-4HIZ7EA3.js → register-list-query-CT3LFDDN.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-W64FZ5HN.js → register-mutation-NWEVA5YS.js} +3 -3
- package/dist/cli-bundle/chunks/register-operations-AHIAG5KM.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-634MFRXU.js → register-setup-ZJZFVAKE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-4X57RE4U.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-6XKF3PGV.js +18 -0
- package/dist/cli-bundle/focused-chunks/chunk-7NJ4QYQ2.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-I75MANL7.js → chunk-EXZA4257.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ITAUHSO6.js +50 -0
- package/dist/cli-bundle/focused-chunks/{chunk-OOYYKQWX.js → chunk-KLVUMNXJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2RI2FESN.js → chunk-KT5XMYSX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-E3AVJ655.js → chunk-KTKH4IMG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-M67F5AIN.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3DJSGWVB.js → chunk-NSPYTG6G.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-OKA6ELTL.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-PUISBOPP.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-QLNMCESQ.js +155 -0
- package/dist/cli-bundle/focused-chunks/{chunk-IIS2FRKL.js → chunk-SLKC6QLJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-U65UC4G3.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-WTSER4WJ.js +16 -0
- package/dist/cli-bundle/focused-chunks/{chunk-2JP7W7GO.js → chunk-ZMFXQ7VF.js} +2 -2
- 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 +41 -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 +110 -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/diagnostics/remediation.js +7 -2
- package/dist/core/extensions/reserved-host-flags.js +3 -2
- package/dist/core/history/drift-scan.d.ts +6 -0
- package/dist/core/history/drift-scan.js +74 -50
- package/dist/core/history/replay.d.ts +14 -1
- package/dist/core/history/replay.js +45 -8
- package/dist/core/history/workspace-history.d.ts +59 -0
- package/dist/core/history/workspace-history.js +197 -10
- package/dist/core/output/output.d.ts +2 -0
- package/dist/core/output/output.js +13 -4
- package/dist/core/shared/command-types.d.ts +2 -0
- package/dist/core/shared/command-types.js +2 -2
- package/dist/core/shared/errors.d.ts +12 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/mcp/tool-definitions.js +9 -5
- package/dist/sdk/agent/refusal-reachability.d.ts +61 -0
- package/dist/sdk/agent/refusal-reachability.js +91 -3
- package/dist/sdk/cli-bootstrap.d.ts +2 -0
- package/dist/sdk/cli-bootstrap.js +7 -2
- package/dist/sdk/cli-contracts/completeness.js +3 -2
- package/dist/sdk/cli-contracts/flag-contracts.js +3 -2
- package/dist/sdk/cli-contracts/registration-helpers.js +3 -2
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +11 -1
- package/dist/sdk/cli-contracts/runtime-contracts.js +176 -65
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +15 -5
- package/dist/sdk/cli-contracts/tool-schema.js +10 -3
- package/dist/sdk/cli-program.js +4 -3
- package/dist/sdk/context-relevance.js +12 -4
- package/dist/sdk/core.d.ts +2 -2
- package/dist/sdk/core.js +3 -3
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +26 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -26
- package/dist/sdk/governance/assurance-action.d.ts +7 -1
- package/dist/sdk/governance/assurance-action.js +7 -6
- package/dist/sdk/governance/assurance-mutation-error.d.ts +42 -1
- package/dist/sdk/governance/assurance-mutation-error.js +27 -3
- package/dist/sdk/governance/assurance-runtime.js +12 -11
- package/dist/sdk/governance/assurance.d.ts +9 -0
- package/dist/sdk/governance/assurance.js +82 -16
- package/dist/sdk/governance/extension-host-version.d.ts +25 -0
- package/dist/sdk/governance/extension-host-version.js +105 -0
- package/dist/sdk/governance/health.d.ts +32 -1
- package/dist/sdk/governance/health.js +132 -28
- package/dist/sdk/governance/provenance-health.d.ts +27 -0
- package/dist/sdk/governance/provenance-health.js +95 -3
- 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 +9 -52
- package/dist/sdk/governance.d.ts +6 -0
- package/dist/sdk/governance.js +8 -2
- package/dist/sdk/graph/assembly.d.ts +23 -0
- package/dist/sdk/graph/assembly.js +54 -2
- package/dist/sdk/graph/durable-cache.js +50 -20
- package/dist/sdk/graph/governance-contracts.d.ts +1 -1
- package/dist/sdk/graph/governance-contracts.js +4 -2
- package/dist/sdk/graph/governance.d.ts +21 -1
- package/dist/sdk/graph/governance.js +94 -32
- 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/history-read.d.ts +8 -0
- package/dist/sdk/history-read.js +2 -2
- package/dist/sdk/history-repair.d.ts +13 -1
- package/dist/sdk/history-repair.js +62 -18
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +3 -3
- package/dist/sdk/linked-artifacts.js +16 -5
- package/dist/sdk/pagination.d.ts +15 -0
- package/dist/sdk/pagination.js +9 -5
- package/dist/sdk/query/context.d.ts +5 -1
- package/dist/sdk/query/context.js +14 -5
- package/dist/sdk/query/history.js +20 -3
- package/dist/sdk/read-output/continuation.d.ts +11 -0
- package/dist/sdk/read-output/continuation.js +132 -0
- package/dist/sdk/read-output-budget.d.ts +3 -1
- package/dist/sdk/read-output-budget.js +24 -13
- package/dist/sdk/read-output-contracts.d.ts +127 -7
- package/dist/sdk/read-output-contracts.js +381 -35
- package/dist/sdk/read-output-rows.d.ts +13 -0
- package/dist/sdk/read-output-rows.js +60 -2
- package/dist/sdk/runtime-input.js +4 -2
- 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/docs/ASSURANCE.md +68 -2
- package/docs/COMMANDS.md +39 -4
- package/docs/READ_OUTPUT_CONTRACTS.md +85 -8
- package/docs/RELATIONSHIP_GRAPH.md +20 -5
- package/docs/RELEASING.md +42 -5
- package/docs/SDK.md +12 -5
- package/docs/SDK_CONTEXT_INTEGRITY.md +94 -1
- package/docs/TESTING.md +23 -1
- package/docs/performance/sdk-entrypoint-import-costs.md +20 -13
- package/marketplace.json +2 -2
- package/package.json +7 -7
- 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 +1283 -157
- package/dist/cli-bundle/chunks/chunk-DEDU3DG7.js +0 -196
- package/dist/cli-bundle/chunks/chunk-DL5M5J3V.js +0 -13
- package/dist/cli-bundle/chunks/chunk-HIUZVCMN.js +0 -5
- package/dist/cli-bundle/chunks/chunk-IMGIN7R6.js +0 -2
- package/dist/cli-bundle/chunks/chunk-TF3TPKPR.js +0 -34
- package/dist/cli-bundle/chunks/register-operations-C44ET7R5.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-27N23W6M.js +0 -31
- package/dist/cli-bundle/focused-chunks/chunk-3BNVU6LC.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-6MLIRBLV.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-6XYLENDV.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-CP4K4WFS.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-EBTNSFYE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-HC2OL2H2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-NFHFZH2Z.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-OGC4XSBC.js +0 -17
- package/dist/cli-bundle/focused-chunks/chunk-PKPOZXLL.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QDZUABWL.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-QQX5TDFT.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-TEZIXMTH.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-WEH6NSL6.js +0 -18
|
@@ -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]="
|
|
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
|
-
|
|
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 =
|
|
500
|
-
|
|
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
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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(
|
|
575
|
-
...Object.keys(
|
|
611
|
+
...Object.keys(baselineCoverage),
|
|
612
|
+
...Object.keys(currentCoverage),
|
|
576
613
|
]),
|
|
577
614
|
].sort();
|
|
578
|
-
for (const type of
|
|
579
|
-
const before = Object.assign({ active: 0, isolated: 0, degree_leq_one: 0 },
|
|
580
|
-
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]);
|
|
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
|
-
|
|
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=
|
|
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
|
|
@@ -37,6 +37,14 @@ export interface HistoryVerificationResult {
|
|
|
37
37
|
current_item_hash?: string;
|
|
38
38
|
/** Whether the supplied document matches the newest history hash. */
|
|
39
39
|
current_matches_latest?: boolean;
|
|
40
|
+
/** Whether every governed workspace singleton matches the latest replayed state. */
|
|
41
|
+
workspace_state_matches_latest?: boolean;
|
|
42
|
+
/** Governed singleton paths whose JSON differs from the replayed value. */
|
|
43
|
+
workspace_state_mismatches?: string[];
|
|
44
|
+
/** Governed singleton paths absent from disk. */
|
|
45
|
+
workspace_state_missing?: string[];
|
|
46
|
+
/** Governed singleton paths unreadable as safe workspace-local JSON. */
|
|
47
|
+
workspace_state_unreadable?: string[];
|
|
40
48
|
}
|
|
41
49
|
/**
|
|
42
50
|
* Verify a history chain and optionally compare it with a current document.
|
package/dist/sdk/history-read.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* systems without acquiring locks or appending history.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
10
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="04f5d4d2-4021-5ce2-b35a-2134d98d2ad7")}catch(e){}}();
|
|
11
11
|
import { getActiveExtensionRegistrations } from "../core/extensions/index.js";
|
|
12
12
|
import { pathExists } from "../core/fs/fs-utils.js";
|
|
13
13
|
import { applyHistoryPatch, ensureMaterializedHistoryTarget, extractPatchFailureContext, replayHistoryToTarget, resolveHistoryTarget, } from "../core/history/projection.js";
|
|
@@ -85,4 +85,4 @@ export async function getItemAt(id, target, options = {}) {
|
|
|
85
85
|
}
|
|
86
86
|
export { applyHistoryPatch, ensureMaterializedHistoryTarget, extractPatchFailureContext, readHistoryEntries, replayHistoryToTarget, resolveHistoryTarget, };
|
|
87
87
|
//# sourceMappingURL=history-read.js.map
|
|
88
|
-
//# debugId=
|
|
88
|
+
//# debugId=04f5d4d2-4021-5ce2-b35a-2134d98d2ad7
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReplayDocument } from "../core/history/replay.js";
|
|
2
2
|
import type { GlobalOptions } from "../core/shared/command-types.js";
|
|
3
3
|
import type { HistoryEntry } from "../types/index.js";
|
|
4
|
+
import { type ProvenanceNormalizationReceipt } from "./governance/provenance-health.js";
|
|
4
5
|
/** Documents the history repair command options payload exchanged by command, SDK, and package integrations. */
|
|
5
6
|
export interface HistoryRepairCommandOptions {
|
|
6
7
|
/** Value that configures or reports dry run for this contract. */
|
|
@@ -19,6 +20,8 @@ export interface HistoryRepairCommandOptions {
|
|
|
19
20
|
auditContextById?: Record<string, Record<string, unknown>>;
|
|
20
21
|
/** Add an audit event even when replay and the current item already match. */
|
|
21
22
|
forceAuditEntry?: boolean;
|
|
23
|
+
/** Remove bounded-domain-invalid provenance observations and record an aggregate privacy-safe audit receipt. */
|
|
24
|
+
normalizeProvenance?: boolean;
|
|
22
25
|
}
|
|
23
26
|
/** Documents the history repair result payload exchanged by command, SDK, and package integrations. */
|
|
24
27
|
export interface HistoryRepairResult {
|
|
@@ -41,6 +44,9 @@ export interface HistoryRepairResult {
|
|
|
41
44
|
audit_entry_added: boolean;
|
|
42
45
|
verify_ok: boolean;
|
|
43
46
|
verify_errors: string[];
|
|
47
|
+
item_hash_version_before: number | null;
|
|
48
|
+
item_hash_version_after: number;
|
|
49
|
+
version_disposition: "preserved" | "selected_for_ambiguous_stream";
|
|
44
50
|
};
|
|
45
51
|
/** Value that configures or reports item for this contract. */
|
|
46
52
|
item: {
|
|
@@ -48,6 +54,10 @@ export interface HistoryRepairResult {
|
|
|
48
54
|
path: string | null;
|
|
49
55
|
matched_chain_before: boolean | null;
|
|
50
56
|
};
|
|
57
|
+
/** Privacy-safe receipt for the explicitly requested provenance normalization mode. */
|
|
58
|
+
provenance_normalization: ProvenanceNormalizationReceipt & {
|
|
59
|
+
requested: boolean;
|
|
60
|
+
};
|
|
51
61
|
/** Present when reconciling the chain with the on-disk item discards the replayed effect of earlier history events (GH-603): names the reverted fields and the authors whose mutations the reconciliation overwrites, so cross-author data loss after a lossy merge is loud instead of silent. */
|
|
52
62
|
reconciliation?: HistoryRepairReconciliationReport;
|
|
53
63
|
/** Value that configures or reports warnings for this contract. */
|
|
@@ -126,7 +136,9 @@ export interface HistoryRepairAllResult {
|
|
|
126
136
|
scanned_streams: number;
|
|
127
137
|
/** Value that configures or reports drifted streams for this contract. */
|
|
128
138
|
drifted_streams: number;
|
|
129
|
-
/**
|
|
139
|
+
/** Streams selected only because invalid provenance required normalization. */
|
|
140
|
+
provenance_invalid_streams: number;
|
|
141
|
+
/** One compact row per drifted or provenance-normalization target. */
|
|
130
142
|
streams: HistoryRepairAllStreamResult[];
|
|
131
143
|
/** Value that configures or reports totals for this contract. */
|
|
132
144
|
totals: {
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* Implements the pm history repair 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]="de9b7f82-0f51-599d-b1fa-2d54e3acbdbc")}catch(e){}}();
|
|
8
8
|
import jsonPatch from "fast-json-patch";
|
|
9
9
|
import { patchPathToChangedField } from "../core/history/history-diff.js";
|
|
10
10
|
import { pathExists, readFileIfExists } from "../core/fs/fs-utils.js";
|
|
11
11
|
import { executeHistoryRewrite, writeHistoryRawWithRollback, } from "../core/history/history-rewrite.js";
|
|
12
|
-
import { historyEntriesToRaw, normalizeReplayPatchOps, reanchorHistoryEntries, replayHash, toReplayDocument, verifyHistoryChain, } from "../core/history/replay.js";
|
|
12
|
+
import { historyEntriesToRaw, normalizeReplayPatchOps, reanchorHistoryEntries, replayHash, resolveHistoryRepairItemHashVersion, toReplayDocument, verifyHistoryChain, verifyHistoryChainWithVersion, } from "../core/history/replay.js";
|
|
13
13
|
import { scanHistoryDrift } from "../core/history/drift-scan.js";
|
|
14
14
|
import { invalidateHistoryDriftCache } from "../core/history/drift-cache.js";
|
|
15
15
|
import { readHistoryEntries } from "../core/history/read.js";
|
|
@@ -23,6 +23,7 @@ import { listAllItemMetadataWithBody, readLocatedItem, } from "../core/store/ite
|
|
|
23
23
|
import { getSettingsPath, resolvePmRoot } from "../core/store/paths.js";
|
|
24
24
|
import { readSettings } from "../core/store/settings.js";
|
|
25
25
|
import { resolveHistorySubject } from "./history-redact.js";
|
|
26
|
+
import { listInvalidProvenanceHistoryStreamIds, normalizeInvalidHistoryProvenance, } from "./governance/provenance-health.js";
|
|
26
27
|
function replayFieldValue(document, field) {
|
|
27
28
|
return field === "body"
|
|
28
29
|
? document.body
|
|
@@ -133,7 +134,7 @@ export function analyzeReconciliationDiscard(entries, finalReplay, currentItemRe
|
|
|
133
134
|
: null,
|
|
134
135
|
};
|
|
135
136
|
}
|
|
136
|
-
async function loadHistoryRepairItemReplay(subject, settings, historyEntries) {
|
|
137
|
+
async function loadHistoryRepairItemReplay(subject, settings, historyEntries, itemHashVersion) {
|
|
137
138
|
const currentItemPath = subject.located?.itemPath ?? null;
|
|
138
139
|
const loadedItem = subject.located
|
|
139
140
|
? await readLocatedItem(subject.located, { schema: settings.schema })
|
|
@@ -152,7 +153,7 @@ async function loadHistoryRepairItemReplay(subject, settings, historyEntries) {
|
|
|
152
153
|
return {
|
|
153
154
|
currentItemReplay,
|
|
154
155
|
currentItemPath,
|
|
155
|
-
matchedChainBefore: replayHash(currentItemReplay) === lastOriginalAfterHash,
|
|
156
|
+
matchedChainBefore: replayHash(currentItemReplay, itemHashVersion) === lastOriginalAfterHash,
|
|
156
157
|
currentItemRawBeforeLock: loadedItem.raw,
|
|
157
158
|
loadedItem,
|
|
158
159
|
};
|
|
@@ -180,16 +181,19 @@ function buildHistoryRepairEntries(params) {
|
|
|
180
181
|
patch: params.reconcileNeeded && params.currentItemReplay
|
|
181
182
|
? jsonPatch.compare(params.finalReplay, params.currentItemReplay)
|
|
182
183
|
: [],
|
|
183
|
-
before_hash: replayHash(params.finalReplay),
|
|
184
|
-
after_hash: replayHash(afterReplay),
|
|
184
|
+
before_hash: replayHash(params.finalReplay, params.itemHashVersion),
|
|
185
|
+
after_hash: replayHash(afterReplay, params.itemHashVersion),
|
|
185
186
|
message: params.message,
|
|
187
|
+
...(params.explicitItemHashVersion
|
|
188
|
+
? { item_hash_version: params.itemHashVersion }
|
|
189
|
+
: {}),
|
|
186
190
|
...(params.auditContext === undefined
|
|
187
191
|
? {}
|
|
188
192
|
: { context: params.auditContext }),
|
|
189
193
|
});
|
|
190
194
|
return { rewrittenEntries, auditEntryAdded: true };
|
|
191
195
|
}
|
|
192
|
-
function collectHistoryRepairWarnings(changed, skippedOps) {
|
|
196
|
+
function collectHistoryRepairWarnings(changed, skippedOps, reconciliation) {
|
|
193
197
|
const warnings = [];
|
|
194
198
|
if (!changed) {
|
|
195
199
|
warnings.push("history_repair_no_changes");
|
|
@@ -197,6 +201,9 @@ function collectHistoryRepairWarnings(changed, skippedOps) {
|
|
|
197
201
|
if (skippedOps > 0) {
|
|
198
202
|
warnings.push(`history_repair_skipped_unresolvable_ops:${skippedOps}`);
|
|
199
203
|
}
|
|
204
|
+
if (reconciliation && reconciliation.discarded_events.length > 0) {
|
|
205
|
+
warnings.push(`history_repair_reconcile_discards_events:${reconciliation.discarded_events.length}`, `history_repair_discarded_authors:${reconciliation.discarded_authors.join(",")}`);
|
|
206
|
+
}
|
|
200
207
|
return warnings;
|
|
201
208
|
}
|
|
202
209
|
async function applyHistoryRepairRewrite(params) {
|
|
@@ -241,11 +248,28 @@ export async function runHistoryRepair(id, options, global) {
|
|
|
241
248
|
throw new PmCliError(`No history entries exist for ${subject.id}; nothing to repair.`, EXIT_CODE.USAGE);
|
|
242
249
|
}
|
|
243
250
|
const chainBefore = verifyHistoryChain(historyEntries);
|
|
244
|
-
const
|
|
245
|
-
const
|
|
251
|
+
const chainVersionBefore = verifyHistoryChainWithVersion(historyEntries);
|
|
252
|
+
const provenanceNormalization = options.normalizeProvenance
|
|
253
|
+
? normalizeInvalidHistoryProvenance(historyEntries)
|
|
254
|
+
: {
|
|
255
|
+
entries: historyEntries,
|
|
256
|
+
receipt: {
|
|
257
|
+
changed: false,
|
|
258
|
+
events_changed: 0,
|
|
259
|
+
observations_removed: 0,
|
|
260
|
+
invalid_values: [],
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
const itemHashVersion = resolveHistoryRepairItemHashVersion(provenanceNormalization.entries);
|
|
264
|
+
const explicitVersionsBefore = new Set(provenanceNormalization.entries
|
|
265
|
+
.map((entry) => entry.item_hash_version)
|
|
266
|
+
.filter((version) => version !== undefined));
|
|
267
|
+
const reanchor = reanchorHistoryEntries(provenanceNormalization.entries, itemHashVersion);
|
|
268
|
+
const itemReplayContext = await loadHistoryRepairItemReplay(subject, settings, historyEntries, itemHashVersion);
|
|
246
269
|
const finalReplay = reanchor.finalDocument;
|
|
247
270
|
const reconcileNeeded = itemReplayContext.currentItemReplay !== null &&
|
|
248
|
-
replayHash(finalReplay) !==
|
|
271
|
+
replayHash(finalReplay, itemHashVersion) !==
|
|
272
|
+
replayHash(itemReplayContext.currentItemReplay, itemHashVersion);
|
|
249
273
|
// GH-603: reconciling toward the on-disk item can silently overwrite the
|
|
250
274
|
// replayed effect of other authors' events (classic after a lossy merge).
|
|
251
275
|
// Surface exactly what is being discarded before any write happens.
|
|
@@ -257,6 +281,7 @@ export async function runHistoryRepair(id, options, global) {
|
|
|
257
281
|
reanchor.entriesPatchRepaired > 0,
|
|
258
282
|
reconcileNeeded,
|
|
259
283
|
options.forceAuditEntry === true,
|
|
284
|
+
provenanceNormalization.receipt.changed,
|
|
260
285
|
].some(Boolean);
|
|
261
286
|
const author = resolveAuthor(options.author, settings.author_default);
|
|
262
287
|
const dryRun = Boolean(options.dryRun);
|
|
@@ -275,17 +300,20 @@ export async function runHistoryRepair(id, options, global) {
|
|
|
275
300
|
author,
|
|
276
301
|
message: repairMessage,
|
|
277
302
|
auditOperation: options.auditOperation ?? "history_repair",
|
|
278
|
-
auditContext:
|
|
303
|
+
auditContext: provenanceNormalization.receipt.changed
|
|
304
|
+
? {
|
|
305
|
+
...options.auditContext,
|
|
306
|
+
provenance_normalization: provenanceNormalization.receipt,
|
|
307
|
+
}
|
|
308
|
+
: options.auditContext,
|
|
309
|
+
itemHashVersion,
|
|
310
|
+
explicitItemHashVersion: reanchor.explicitItemHashVersion,
|
|
279
311
|
});
|
|
280
312
|
const historyVerify = verifyHistoryChain(rewrittenEntries);
|
|
281
313
|
if (!historyVerify.ok) {
|
|
282
314
|
throw new PmCliError(`history-repair produced an invalid rewritten chain (${historyVerify.errors.join(", ")}).`, EXIT_CODE.GENERIC_FAILURE);
|
|
283
315
|
}
|
|
284
|
-
const warnings = collectHistoryRepairWarnings(changed, reanchor.skippedOps);
|
|
285
|
-
if (reconciliation && reconciliation.discarded_events.length > 0) {
|
|
286
|
-
warnings.push(`history_repair_reconcile_discards_events:${reconciliation.discarded_events.length}`);
|
|
287
|
-
warnings.push(`history_repair_discarded_authors:${reconciliation.discarded_authors.join(",")}`);
|
|
288
|
-
}
|
|
316
|
+
const warnings = collectHistoryRepairWarnings(changed, reanchor.skippedOps, reconciliation);
|
|
289
317
|
if (changed && !dryRun) {
|
|
290
318
|
warnings.push(...(await applyHistoryRepairRewrite({
|
|
291
319
|
pmRoot,
|
|
@@ -317,12 +345,21 @@ export async function runHistoryRepair(id, options, global) {
|
|
|
317
345
|
audit_entry_added: auditEntryAdded,
|
|
318
346
|
verify_ok: historyVerify.ok,
|
|
319
347
|
verify_errors: historyVerify.errors,
|
|
348
|
+
item_hash_version_before: chainVersionBefore.item_hash_version ?? null,
|
|
349
|
+
item_hash_version_after: itemHashVersion,
|
|
350
|
+
version_disposition: explicitVersionsBefore.size > 1
|
|
351
|
+
? "selected_for_ambiguous_stream"
|
|
352
|
+
: "preserved",
|
|
320
353
|
},
|
|
321
354
|
item: {
|
|
322
355
|
exists: itemReplayContext.currentItemPath !== null,
|
|
323
356
|
path: itemReplayContext.currentItemPath,
|
|
324
357
|
matched_chain_before: itemReplayContext.matchedChainBefore,
|
|
325
358
|
},
|
|
359
|
+
provenance_normalization: {
|
|
360
|
+
requested: options.normalizeProvenance === true,
|
|
361
|
+
...provenanceNormalization.receipt,
|
|
362
|
+
},
|
|
326
363
|
...(reconciliation ? { reconciliation } : {}),
|
|
327
364
|
warnings: [...new Set(warnings)].sort((left, right) => left.localeCompare(right)),
|
|
328
365
|
generated_at: nowIso(),
|
|
@@ -348,10 +385,16 @@ export async function runHistoryRepairAll(options, global) {
|
|
|
348
385
|
const itemReadWarnings = [];
|
|
349
386
|
const items = await listAllItemMetadataWithBody(pmRoot, settings.item_format, typeRegistry.type_to_folder, itemReadWarnings, settings.schema, { forceSourceScan: true });
|
|
350
387
|
const drift = await scanHistoryDrift(pmRoot, items);
|
|
388
|
+
const invalidProvenanceIds = options.normalizeProvenance
|
|
389
|
+
? await listInvalidProvenanceHistoryStreamIds(pmRoot)
|
|
390
|
+
: [];
|
|
391
|
+
const targetedIds = [
|
|
392
|
+
...new Set([...drift.driftedItems, ...invalidProvenanceIds]),
|
|
393
|
+
].sort((left, right) => left.localeCompare(right));
|
|
351
394
|
const streams = [];
|
|
352
395
|
const repairWarnings = [];
|
|
353
396
|
const totals = { repaired: 0, skipped_clean: 0, failed: 0 };
|
|
354
|
-
for (const driftedId of
|
|
397
|
+
for (const driftedId of targetedIds) {
|
|
355
398
|
try {
|
|
356
399
|
const result = await runHistoryRepair(driftedId, {
|
|
357
400
|
...options,
|
|
@@ -392,6 +435,7 @@ export async function runHistoryRepairAll(options, global) {
|
|
|
392
435
|
dry_run: Boolean(options.dryRun),
|
|
393
436
|
scanned_streams: items.length,
|
|
394
437
|
drifted_streams: drift.driftedItems.length,
|
|
438
|
+
provenance_invalid_streams: invalidProvenanceIds.length,
|
|
395
439
|
streams,
|
|
396
440
|
totals,
|
|
397
441
|
warnings: [...new Set([...itemReadWarnings, ...repairWarnings])].sort((left, right) => left.localeCompare(right)),
|
|
@@ -399,4 +443,4 @@ export async function runHistoryRepairAll(options, global) {
|
|
|
399
443
|
};
|
|
400
444
|
}
|
|
401
445
|
//# sourceMappingURL=history-repair.js.map
|
|
402
|
-
//# debugId=
|
|
446
|
+
//# debugId=de9b7f82-0f51-599d-b1fa-2d54e3acbdbc
|
package/dist/sdk/index.d.ts
CHANGED
|
@@ -84,7 +84,7 @@ export * from "./history-compact.js";
|
|
|
84
84
|
export * from "./history-read.js";
|
|
85
85
|
export * from "./history-provenance.js";
|
|
86
86
|
export * from "./mutation-events.js";
|
|
87
|
-
export { appendWorkspaceAuditEvent, appendWorkspaceHistoryChange, getWorkspaceHistoryPath, mutateWorkspaceJsonWithHistory, WORKSPACE_HISTORY_ID, writeWorkspaceJsonWithHistory, type WorkspaceAuditEventOptions, type WorkspaceHistoryChange, type WorkspaceJsonMutation, type WorkspaceJsonMutationOptions, type WorkspaceJsonWriteOptions, } from "../core/history/workspace-history.js";
|
|
87
|
+
export { appendWorkspaceAuditEvent, appendWorkspaceHistoryChange, getWorkspaceHistoryPath, inspectWorkspaceHistoryState, mutateWorkspaceJsonWithHistory, reconcileWorkspaceJsonHistory, restoreWorkspaceJsonFromHistory, WORKSPACE_HISTORY_ID, writeWorkspaceJsonWithHistory, type WorkspaceAuditEventOptions, type WorkspaceHistoryChange, type WorkspaceHistoryStateAgreement, type WorkspaceJsonMutation, type WorkspaceJsonMutationOptions, type WorkspaceJsonReconciliationOptions, type WorkspaceJsonRestoreOptions, type WorkspaceJsonRestoreResult, type WorkspaceJsonWriteOptions, } from "../core/history/workspace-history.js";
|
|
88
88
|
export * from "./history-redact.js";
|
|
89
89
|
export { _testOnly } from "./history-redact.js";
|
|
90
90
|
export * from "./history-repair.js";
|