@unbrained/pm-cli 2026.9.3 → 2026.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +27 -0
  3. package/dist/cli-bundle/bundle-manifest.json +146 -146
  4. package/dist/cli-bundle/chunks/{chunk-E5RBBCXO.js → chunk-6XSKPNCF.js} +75 -75
  5. package/dist/cli-bundle/chunks/chunk-A24WAVE6.js +8 -0
  6. package/dist/cli-bundle/chunks/{chunk-DKGP3QLE.js → chunk-HI6BHPCU.js} +2 -2
  7. package/dist/cli-bundle/chunks/{chunk-Y4PJ6HPK.js → chunk-I2AS367G.js} +2 -2
  8. package/dist/cli-bundle/chunks/{chunk-IEHHE6GA.js → chunk-OGBVU67G.js} +2 -2
  9. package/dist/cli-bundle/chunks/{chunk-EDPIS7EB.js → chunk-RI4XNOYS.js} +2 -2
  10. package/dist/cli-bundle/chunks/chunk-TXW6VL33.js +38 -0
  11. package/dist/cli-bundle/chunks/{chunk-LENC656S.js → chunk-V72UV7QS.js} +76 -79
  12. package/dist/cli-bundle/chunks/chunk-VGLHECAP.js +9 -0
  13. package/dist/cli-bundle/chunks/{chunk-34HASX3S.js → chunk-X6CMGV6L.js} +2 -2
  14. package/dist/cli-bundle/chunks/{chunk-UPPM2FOZ.js → chunk-YW4QK2G7.js} +2 -2
  15. package/dist/cli-bundle/chunks/{register-list-query-W2ZTOMKP.js → register-list-query-Z5YYSJJG.js} +2 -2
  16. package/dist/cli-bundle/chunks/{register-mutation-RVND5NCG.js → register-mutation-ELSP6I4I.js} +2 -2
  17. package/dist/cli-bundle/chunks/{register-operations-TTROIVC4.js → register-operations-OH7R3ZT4.js} +2 -2
  18. package/dist/cli-bundle/chunks/{register-setup-D3ZFHY3L.js → register-setup-E2AE72QG.js} +2 -2
  19. package/dist/cli-bundle/focused-chunks/{chunk-Q45NHPF2.js → chunk-25UJBH4M.js} +2 -2
  20. package/dist/cli-bundle/focused-chunks/{chunk-4HJFY4MB.js → chunk-3646BZ4W.js} +2 -2
  21. package/dist/cli-bundle/focused-chunks/{chunk-TXE4TSHM.js → chunk-4YRAVI43.js} +2 -2
  22. package/dist/cli-bundle/focused-chunks/{chunk-M5M6SVHS.js → chunk-53IHPICX.js} +2 -2
  23. package/dist/cli-bundle/focused-chunks/chunk-5P4HVOWG.js +176 -0
  24. package/dist/cli-bundle/focused-chunks/chunk-636VVQ7F.js +54 -0
  25. package/dist/cli-bundle/focused-chunks/{chunk-D7KXFBXV.js → chunk-6PWPQKDN.js} +2 -2
  26. package/dist/cli-bundle/focused-chunks/{chunk-S27XMBIN.js → chunk-7N2TV7WZ.js} +2 -2
  27. package/dist/cli-bundle/focused-chunks/{chunk-5RFXUPN5.js → chunk-AJR3OP2E.js} +2 -2
  28. package/dist/cli-bundle/focused-chunks/{chunk-KZ2NB3ET.js → chunk-B3A6MJYE.js} +2 -2
  29. package/dist/cli-bundle/focused-chunks/{chunk-BWKHEIVF.js → chunk-BFDDJ2T2.js} +2 -2
  30. package/dist/cli-bundle/focused-chunks/{chunk-4WR46RMG.js → chunk-BHUIRZWQ.js} +8 -8
  31. package/dist/cli-bundle/focused-chunks/{chunk-4RRHC3S4.js → chunk-JADHHPY6.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/{chunk-GT7MXDLW.js → chunk-MHKUIPJW.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/chunk-NBMJD6MK.js +2 -0
  34. package/dist/cli-bundle/focused-chunks/chunk-NSKBLHVI.js +20 -0
  35. package/dist/cli-bundle/focused-chunks/{chunk-OL5EH6I3.js → chunk-P2GOAOQN.js} +2 -2
  36. package/dist/cli-bundle/focused-chunks/{chunk-UCLO3XDU.js → chunk-YARWJM2B.js} +2 -2
  37. package/dist/cli-bundle/main.js +2 -2
  38. package/dist/cli-bundle/sdk-authoring.js +1 -1
  39. package/dist/cli-bundle/sdk-contracts.js +1 -1
  40. package/dist/cli-bundle/sdk-core.js +28 -31
  41. package/dist/cli-bundle/sdk-governance.js +1 -1
  42. package/dist/cli-bundle/sdk-graph.js +1 -1
  43. package/dist/cli-bundle/sdk-merge.js +42 -37
  44. package/dist/cli-bundle/sdk-query.js +1 -1
  45. package/dist/cli-bundle/sdk-runtime.js +1 -1
  46. package/dist/cli-bundle/sdk-testing.js +1 -1
  47. package/dist/cli-bundle/sdk.js +10 -10
  48. package/dist/core/diagnostics/remediation.js +4 -4
  49. package/dist/core/history/history.d.ts +37 -1
  50. package/dist/core/history/history.js +278 -58
  51. package/dist/core/history/replay.js +68 -34
  52. package/dist/core/lock/lock.d.ts +10 -0
  53. package/dist/core/lock/lock.js +42 -3
  54. package/dist/core/shared/author.d.ts +3 -1
  55. package/dist/core/shared/author.js +111 -23
  56. package/dist/sdk/environment/agent-environment.d.ts +296 -0
  57. package/dist/sdk/environment/agent-environment.js +467 -0
  58. package/dist/sdk/environment/project-runtime-compatibility.d.ts +19 -1
  59. package/dist/sdk/environment/project-runtime-compatibility.js +118 -21
  60. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -2
  61. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -14
  62. package/dist/sdk/governance/health.js +13 -44
  63. package/dist/sdk/governance/merge-receipt-history.d.ts +62 -0
  64. package/dist/sdk/governance/merge-receipt-history.js +207 -0
  65. package/dist/sdk/governance/provenance-health.js +9 -3
  66. package/dist/sdk/history-compact.js +14 -5
  67. package/dist/sdk/history-redact.js +58 -23
  68. package/dist/sdk/history-repair.js +16 -6
  69. package/dist/sdk/index.d.ts +2 -0
  70. package/dist/sdk/index.js +4 -2
  71. package/dist/sdk/merge/driver.d.ts +3 -1
  72. package/dist/sdk/merge/driver.js +9 -9
  73. package/dist/sdk/merge/index.d.ts +1 -1
  74. package/dist/sdk/merge/index.js +3 -3
  75. package/dist/sdk/merge/receipts.d.ts +17 -6
  76. package/dist/sdk/merge/receipts.js +246 -75
  77. package/dist/sdk/merge/reconcile.d.ts +9 -7
  78. package/dist/sdk/merge/reconcile.js +175 -12
  79. package/dist/sdk/merge/three-way.d.ts +22 -2
  80. package/dist/sdk/merge/three-way.js +92 -25
  81. package/dist/sdk/runtime-primitives.d.ts +2 -2
  82. package/dist/sdk/runtime-primitives.js +4 -4
  83. package/dist/types.d.ts +25 -0
  84. package/dist/types.js +2 -2
  85. package/docs/AGENT_ENVIRONMENTS.md +47 -0
  86. package/docs/AGENT_PROVENANCE_ADR.md +17 -2
  87. package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +38 -1
  88. package/docs/MERGE_SAFETY.md +119 -23
  89. package/docs/README.md +1 -0
  90. package/docs/SDK_CONTEXT_EVIDENCE_CONTRACTS.md +24 -2
  91. package/docs/SDK_RUNTIME_BOUNDARIES.md +17 -1
  92. package/docs/examples/sdk-agent-environment/README.md +14 -0
  93. package/docs/examples/sdk-agent-environment/package.json +8 -0
  94. package/docs/examples/sdk-agent-environment/run-agent-environment.mjs +154 -0
  95. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +4 -3
  96. package/marketplace.json +2 -2
  97. package/package.json +2 -2
  98. package/packages/pm-beads/package.json +1 -1
  99. package/packages/pm-calendar/package.json +1 -1
  100. package/packages/pm-command-kit/package.json +1 -1
  101. package/packages/pm-digital-twin/package.json +1 -1
  102. package/packages/pm-governance-audit/package.json +1 -1
  103. package/packages/pm-guide-shell/package.json +1 -1
  104. package/packages/pm-kanban/package.json +1 -1
  105. package/packages/pm-lifecycle-hooks/package.json +1 -1
  106. package/packages/pm-linked-test-adapters/package.json +1 -1
  107. package/packages/pm-search-advanced/package.json +1 -1
  108. package/packages/pm-templates/package.json +1 -1
  109. package/packages/pm-todos/package.json +1 -1
  110. package/packages/pm-vcs/package.json +1 -1
  111. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  112. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  113. package/sdk/public-surface.json +534 -24
  114. package/dist/cli-bundle/chunks/chunk-AY324UJ5.js +0 -9
  115. package/dist/cli-bundle/chunks/chunk-L7B7343B.js +0 -8
  116. package/dist/cli-bundle/chunks/chunk-LISESA7W.js +0 -35
  117. package/dist/cli-bundle/focused-chunks/chunk-3ZBI35HU.js +0 -176
  118. package/dist/cli-bundle/focused-chunks/chunk-GHCZ3YFR.js +0 -20
  119. package/dist/cli-bundle/focused-chunks/chunk-KBLZRU62.js +0 -2
  120. package/dist/cli-bundle/focused-chunks/chunk-QKHCSUGJ.js +0 -51
@@ -0,0 +1,207 @@
1
+ /**
2
+ * @module sdk/governance/merge-receipt-history
3
+ *
4
+ * Classifies privacy-safe merge receipt references embedded in history.
5
+ */
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]="1e73338f-221a-580f-85a8-6f2a488fb89d")}catch(e){}}();
8
+ import { createHash } from "node:crypto";
9
+ import path from "node:path";
10
+ import { compareTimestampStrings, isRfc3339DateTime, } from "../../core/shared/time.js";
11
+ import { isSafeReceiptId } from "../merge/receipts.js";
12
+ /** First commit timestamp at which merge receipts gained a tracked durable copy. */
13
+ export const DURABLE_MERGE_RECEIPT_INTRODUCED_AT = "2026-08-09T16:15:18.000Z";
14
+ const PRE_DURABLE_DISPOSITION_ELIGIBLE = Symbol("pre-durable-disposition-eligible");
15
+ /** Return whether an unknown value is a non-array record. */
16
+ function isRecord(value) {
17
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18
+ }
19
+ /** Return a bounded dense list of unique, non-empty field names. */
20
+ function isFieldArray(value) {
21
+ if (!Array.isArray(value) || value.length > 256)
22
+ return false;
23
+ const fields = new Set();
24
+ for (let index = 0; index < value.length; index += 1) {
25
+ const field = value[index];
26
+ if (!(index in value) ||
27
+ typeof field !== "string" ||
28
+ field.length === 0 ||
29
+ field.length > 256 ||
30
+ field.includes("\0") ||
31
+ fields.has(field)) {
32
+ return false;
33
+ }
34
+ fields.add(field);
35
+ }
36
+ return true;
37
+ }
38
+ /** Return whether an unknown value is one complete legacy field decision. */
39
+ function isLegacyDecision(value) {
40
+ if (!isRecord(value))
41
+ return false;
42
+ return (typeof value.field === "string" &&
43
+ value.field.length > 0 &&
44
+ value.field.length <= 256 &&
45
+ !value.field.includes("\0") &&
46
+ typeof value.retained_hash === "string" &&
47
+ /^[a-f0-9]{64}$/u.test(value.retained_hash) &&
48
+ typeof value.discarded_hash === "string" &&
49
+ /^[a-f0-9]{64}$/u.test(value.discarded_hash));
50
+ }
51
+ /** Return whether a legacy item path is normalized, bounded, and item-scoped. */
52
+ function isLegacyItemPath(value, historyItemId) {
53
+ if (typeof value !== "string")
54
+ return false;
55
+ const normalized = path.posix.normalize(value);
56
+ return (value.length <= 4_096 &&
57
+ !value.includes("\\") &&
58
+ !value.includes("\0") &&
59
+ !path.posix.isAbsolute(value) &&
60
+ normalized === value &&
61
+ !normalized.startsWith("../") &&
62
+ (path.posix.basename(normalized) === `${historyItemId}.toon` ||
63
+ path.posix.basename(normalized) === `${historyItemId}.md`));
64
+ }
65
+ /** Return whether a preferred-era summary has one safe canonical identity. */
66
+ function hasLegacyReceiptIdentity(value, historyItemId) {
67
+ return (typeof value.receipt_id === "string" &&
68
+ isSafeReceiptId(value.receipt_id) &&
69
+ (value.preferred === "ours" || value.preferred === "theirs") &&
70
+ value.requested_preference === undefined &&
71
+ value.conflict_resolution === undefined &&
72
+ value.item_id === historyItemId &&
73
+ isLegacyItemPath(value.item_path, historyItemId));
74
+ }
75
+ /** Return whether preferred-era summary collections are dense and self-consistent. */
76
+ function hasLegacyReceiptCollections(value) {
77
+ const conflictFields = value.conflict_fields;
78
+ const fieldsFromTheirs = value.fields_from_theirs;
79
+ const unionFields = value.union_fields;
80
+ const decisions = value.decisions;
81
+ const decisionFields = Array.isArray(decisions)
82
+ ? new Set(decisions.flatMap((decision) => isLegacyDecision(decision) ? [decision.field] : []))
83
+ : new Set();
84
+ return (isFieldArray(conflictFields) &&
85
+ isFieldArray(fieldsFromTheirs) &&
86
+ isFieldArray(unionFields) &&
87
+ Array.isArray(decisions) &&
88
+ decisions.length > 0 &&
89
+ decisions.length <= 256 &&
90
+ Object.keys(decisions).length === decisions.length &&
91
+ decisions.every(isLegacyDecision) &&
92
+ decisionFields.size === decisions.length &&
93
+ conflictFields.length === decisionFields.size &&
94
+ conflictFields.every((field) => decisionFields.has(field)));
95
+ }
96
+ /** Return whether one summary is a complete, self-contained preferred-era receipt. */
97
+ export function isLegacyMergeReceiptSummary(value, historyItemId) {
98
+ return (hasLegacyReceiptIdentity(value, historyItemId) &&
99
+ hasLegacyReceiptCollections(value));
100
+ }
101
+ /** Return whether a summary matches the final clone-local-only schema before durable receipts. */
102
+ export function isPreDurableCloneLocalReceiptSummary(value, historyItemId) {
103
+ return (typeof value.receipt_id === "string" &&
104
+ isSafeReceiptId(value.receipt_id) &&
105
+ (value.preferred === "ours" || value.preferred === "theirs") &&
106
+ value.requested_preference === undefined &&
107
+ (value.conflict_resolution === "preferred_side" ||
108
+ value.conflict_resolution === "stable_value_order") &&
109
+ value.item_id === historyItemId &&
110
+ isLegacyItemPath(value.item_path, historyItemId) &&
111
+ hasLegacyReceiptCollections(value));
112
+ }
113
+ /** Return whether an extracted reference carried a validated pre-durable summary. */
114
+ export function isPreDurableDispositionEligibleReference(reference) {
115
+ return (reference[PRE_DURABLE_DISPOSITION_ELIGIBLE] === true);
116
+ }
117
+ /** Extract receipt ids and legacy compatibility disposition from one history entry. */
118
+ export function extractHistoryMergeReceiptReferences(value, historyItemId) {
119
+ if (!isRecord(value) || !isRecord(value.context))
120
+ return [];
121
+ const merge = value.context.merge;
122
+ if (!isRecord(merge) || !Array.isArray(merge.receipts))
123
+ return [];
124
+ return merge.receipts.flatMap((receipt) => {
125
+ if (!isRecord(receipt) ||
126
+ typeof receipt.receipt_id !== "string" ||
127
+ receipt.receipt_id.trim().length === 0) {
128
+ return [];
129
+ }
130
+ const reference = {
131
+ receiptId: receipt.receipt_id,
132
+ legacySummaryAccepted: isLegacyMergeReceiptSummary(receipt, historyItemId),
133
+ [PRE_DURABLE_DISPOSITION_ELIGIBLE]: isPreDurableCloneLocalReceiptSummary(receipt, historyItemId),
134
+ ...(typeof value.ts === "string" && isRfc3339DateTime(value.ts)
135
+ ? { eventTimestamp: value.ts }
136
+ : {}),
137
+ };
138
+ return [reference];
139
+ });
140
+ }
141
+ /** Extract validated explicit missing-receipt dispositions from one merge audit event. */
142
+ export function extractHistoryMergeReceiptDispositions(value, historyItemId, historyLine) {
143
+ if (!isRecord(value) || value.op !== "merge_reconcile")
144
+ return [];
145
+ if (!isRecord(value.context) || !isRecord(value.context.merge))
146
+ return [];
147
+ const dispositions = value.context.merge.missing_receipt_dispositions;
148
+ if (!Array.isArray(dispositions) || dispositions.length > 256)
149
+ return [];
150
+ return dispositions.flatMap((disposition) => {
151
+ if (!isRecord(disposition) ||
152
+ typeof disposition.receipt_id !== "string" ||
153
+ !isSafeReceiptId(disposition.receipt_id) ||
154
+ typeof disposition.original_history_line !== "number" ||
155
+ !Number.isSafeInteger(disposition.original_history_line) ||
156
+ disposition.original_history_line < 1 ||
157
+ typeof disposition.original_event_ts !== "string" ||
158
+ !isRfc3339DateTime(disposition.original_event_ts) ||
159
+ disposition.reason !== "legacy_clone_local_only") {
160
+ return [];
161
+ }
162
+ return [
163
+ {
164
+ itemId: historyItemId,
165
+ receiptId: disposition.receipt_id,
166
+ originalHistoryLine: disposition.original_history_line,
167
+ originalEventTimestamp: disposition.original_event_ts,
168
+ auditHistoryLine: historyLine,
169
+ reason: disposition.reason,
170
+ },
171
+ ];
172
+ });
173
+ }
174
+ /** Classify scanned references without treating complete legacy summaries as absent. */
175
+ export function classifyHistoryMergeReceiptReferences(references, availableReceiptIds, dispositions = []) {
176
+ const dispositionAuditLineByCoordinate = new Map();
177
+ for (const disposition of dispositions) {
178
+ const coordinate = `${disposition.itemId}\0${disposition.originalHistoryLine}\0${disposition.receiptId}\0${disposition.originalEventTimestamp}`;
179
+ dispositionAuditLineByCoordinate.set(coordinate, Math.max(dispositionAuditLineByCoordinate.get(coordinate) ?? 0, disposition.auditHistoryLine));
180
+ }
181
+ const dispositionAccepts = (reference) => isPreDurableDispositionEligibleReference(reference) &&
182
+ reference.eventTimestamp !== undefined &&
183
+ compareTimestampStrings(reference.eventTimestamp, DURABLE_MERGE_RECEIPT_INTRODUCED_AT) < 0 &&
184
+ (dispositionAuditLineByCoordinate.get(`${reference.itemId}\0${reference.line}\0${reference.receiptId}\0${reference.eventTimestamp}`) ?? 0) > reference.line;
185
+ const missing = references
186
+ .filter((reference) => !reference.legacySummaryAccepted &&
187
+ !availableReceiptIds.has(reference.receiptId) &&
188
+ !dispositionAccepts(reference))
189
+ .map((reference) => ({
190
+ item_id: reference.itemId,
191
+ history_line: reference.line,
192
+ ...(isSafeReceiptId(reference.receiptId)
193
+ ? { receipt_id: reference.receiptId }
194
+ : {
195
+ receipt_reference_hash: createHash("sha256")
196
+ .update(reference.receiptId)
197
+ .digest("hex"),
198
+ }),
199
+ }));
200
+ return {
201
+ missing,
202
+ acceptedLegacyCount: references.filter((reference) => reference.legacySummaryAccepted).length,
203
+ acceptedDispositionCount: references.filter(dispositionAccepts).length,
204
+ };
205
+ }
206
+ //# sourceMappingURL=merge-receipt-history.js.map
207
+ //# debugId=1e73338f-221a-580f-85a8-6f2a488fb89d
@@ -4,9 +4,10 @@
4
4
  * Reads bounded, privacy-safe provenance resolver outcomes for health checks.
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]="6efed404-acd2-5c3a-a008-856df67c8b77")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="cb3bf7ee-808f-5ff6-af84-edb034760c54")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
+ import { resealHistoryRewrite, verifyHistoryRecordHash, } from "../../core/history/history.js";
10
11
  const DEFAULT_PROVENANCE_HISTORY_BYTE_LIMIT = 8_388_608;
11
12
  const ATTEMPTED_PROVENANCE_OUTCOME_STATUSES = new Set(["resolved", "failed"]);
12
13
  const INVALID_PROVENANCE_VALUE_CLASSIFIERS = [
@@ -45,6 +46,8 @@ export function normalizeInvalidHistoryProvenance(entries) {
45
46
  : undefined;
46
47
  if (provenance === undefined)
47
48
  return entry;
49
+ if (!verifyHistoryRecordHash(entry).ok)
50
+ return entry;
48
51
  const retained = {};
49
52
  let eventChanged = false;
50
53
  for (const [dimension, observation] of Object.entries(provenance)) {
@@ -78,7 +81,10 @@ export function normalizeInvalidHistoryProvenance(entries) {
78
81
  else {
79
82
  next.agent_provenance = retained;
80
83
  }
81
- return next;
84
+ return resealHistoryRewrite(entry, next, {
85
+ retainPriorRecord: true,
86
+ retainPriorRecordHash: false,
87
+ });
82
88
  });
83
89
  return {
84
90
  entries: normalized,
@@ -274,4 +280,4 @@ export async function scanProvenanceResolverHealth(pmRoot, eventLimit = 10_000)
274
280
  };
275
281
  }
276
282
  //# sourceMappingURL=provenance-health.js.map
277
- //# debugId=6efed404-acd2-5c3a-a008-856df67c8b77
283
+ //# debugId=cb3bf7ee-808f-5ff6-af84-edb034760c54
@@ -4,11 +4,11 @@
4
4
  * Implements the pm history compact 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]="31152621-df59-54a5-a28d-63119e734e6e")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7570ecac-7f15-5a1b-9b2d-2f1744a00720")}catch(e){}}();
8
8
  import { assertInitializedTracker } from "./environment/tracker-preflight.js";
9
9
  import fs from "node:fs/promises";
10
10
  import path from "node:path";
11
- import { createHistoryEntry } from "../core/history/history.js";
11
+ import { createHistoryEntry, hashHistoryStream, resealHistoryRewrite, } from "../core/history/history.js";
12
12
  import { selectHistoryCompactBulkTargets, } from "../core/history/history-compact-bulk.js";
13
13
  import { executeHistoryRewrite, writeHistoryRawWithRollback, } from "../core/history/history-rewrite.js";
14
14
  import { cloneEmptyReplayDocument, historyEntriesToRaw, replayHash, replayToItemDocument, toReplayDocument, verifyHistoryChain, } from "../core/history/replay.js";
@@ -106,11 +106,11 @@ function reanchorRetainedEntries(retainedEntries, seed, retainedEntryOffset) {
106
106
  for (const [index, entry] of retainedEntries.entries()) {
107
107
  const beforeHash = replayHash(replay);
108
108
  replay = applyHistoryPatch(replay, entry.patch, retainedEntryOffset + index + 1, entry.op);
109
- rewritten.push({
109
+ rewritten.push(resealHistoryRewrite(entry, {
110
110
  ...entry,
111
111
  before_hash: beforeHash,
112
112
  after_hash: replayHash(replay),
113
- });
113
+ }));
114
114
  }
115
115
  return {
116
116
  entries: rewritten,
@@ -169,6 +169,15 @@ function buildHistoryCompactEntries(params) {
169
169
  before: replayToItemDocument(cloneEmptyReplayDocument()),
170
170
  after: replayToItemDocument(checkpoint),
171
171
  message: buildHistoryCompactBaselineMessage(params.boundary),
172
+ context: {
173
+ history_compaction: {
174
+ contract_version: 1,
175
+ pruned_entry_count: params.boundary.compactCount,
176
+ pruned_stream_digest: hashHistoryStream(params.historyEntries.slice(0, params.boundary.compactCount)),
177
+ retained_proof: "stream_digest_and_checkpoint",
178
+ limitation: "individual_pruned_entries_require_pre_compaction_stream",
179
+ },
180
+ },
172
181
  });
173
182
  const rewrittenEntries = [baselineEntry, ...reanchored.entries];
174
183
  if (!params.dryRun) {
@@ -521,4 +530,4 @@ export async function runHistoryCompactBulk(options, global) {
521
530
  };
522
531
  }
523
532
  //# sourceMappingURL=history-compact.js.map
524
- //# debugId=31152621-df59-54a5-a28d-63119e734e6e
533
+ //# debugId=7570ecac-7f15-5a1b-9b2d-2f1744a00720
@@ -4,11 +4,11 @@
4
4
  * Implements the pm history redact 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]="05b945f2-4f96-5f88-98ff-84cc856d0d57")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bd1e86b0-6696-5fba-8dd4-b9636bf3ee60")}catch(e){}}();
8
8
  import { assertInitializedTracker } from "./environment/tracker-preflight.js";
9
9
  import fs from "node:fs/promises";
10
10
  import { pathExists, readFileIfExists, writeFileAtomic, } from "../core/fs/fs-utils.js";
11
- import { createHistoryEntry } from "../core/history/history.js";
11
+ import { createHistoryEntry, resealHistoryRewrite, verifyHistoryRecordHash, } from "../core/history/history.js";
12
12
  import { invalidateHistoryDriftCacheForPath } from "../core/history/drift-cache.js";
13
13
  import { executeHistoryRewrite } from "../core/history/history-rewrite.js";
14
14
  import { EMPTY_REPLAY_DOCUMENT, historyEntriesToRaw, replayHash, replayToItemDocument, verifyHistoryChain, } from "../core/history/replay.js";
@@ -189,6 +189,22 @@ function redactUnknownValue(value, rules, replacement) {
189
189
  replacements: 0,
190
190
  };
191
191
  }
192
+ function redactHistoryPatch(patch, rules, replacement) {
193
+ let replacements = 0;
194
+ const redactedPatch = patch.map((operation) => {
195
+ /* c8 ignore start -- patch operations without `value` are covered in lower-level patch adapters. */
196
+ if (!Object.prototype.hasOwnProperty.call(operation, "value")) {
197
+ return operation;
198
+ }
199
+ /* c8 ignore stop */
200
+ const redactedValue = redactUnknownValue(operation.value, rules, replacement);
201
+ replacements += redactedValue.replacements;
202
+ return redactedValue.replacements > 0
203
+ ? { ...operation, value: redactedValue.value }
204
+ : operation;
205
+ });
206
+ return { patch: redactedPatch, replacements };
207
+ }
192
208
  function inspectHistoryIntegrity(entries) {
193
209
  let replay = structuredClone(EMPTY_REPLAY_DOCUMENT);
194
210
  let hashMismatchesBefore = 0;
@@ -214,6 +230,7 @@ function inspectHistoryIntegrity(entries) {
214
230
  function redactHistoryEntry(entry, rules, replacement) {
215
231
  let replacements = 0;
216
232
  let changed = false;
233
+ let reanchorEvidenceRedacted = false;
217
234
  let nextMessage = entry.message;
218
235
  if (typeof entry.message === "string") {
219
236
  const redactedMessage = redactStringValue(entry.message, rules, replacement);
@@ -223,31 +240,41 @@ function redactHistoryEntry(entry, rules, replacement) {
223
240
  changed = true;
224
241
  }
225
242
  }
226
- const nextPatch = entry.patch.map((operation) => {
227
- /* c8 ignore start -- patch operations without `value` are covered in lower-level patch adapters. */
228
- if (!Object.prototype.hasOwnProperty.call(operation, "value")) {
229
- return operation;
230
- }
231
- /* c8 ignore stop */
232
- const redactedValue = redactUnknownValue(operation.value, rules, replacement);
233
- replacements += redactedValue.replacements;
234
- if (redactedValue.replacements > 0) {
235
- changed = true;
236
- return {
237
- ...operation,
238
- value: redactedValue.value,
239
- };
240
- }
241
- return operation;
243
+ const redactedPatch = redactHistoryPatch(entry.patch, rules, replacement);
244
+ replacements += redactedPatch.replacements;
245
+ changed ||= redactedPatch.replacements > 0;
246
+ const nextReanchorEvidence = entry.reanchor_evidence?.map((evidence) => {
247
+ const redactedEvidencePatch = evidence.patch
248
+ ? redactHistoryPatch(evidence.patch, rules, replacement)
249
+ : { patch: undefined, replacements: 0 };
250
+ const redactedEvidenceRecord = evidence.record
251
+ ? redactUnknownValue(evidence.record, rules, replacement)
252
+ : { value: undefined, replacements: 0 };
253
+ replacements += redactedEvidencePatch.replacements;
254
+ replacements += redactedEvidenceRecord.replacements;
255
+ const evidenceChanged = redactedEvidencePatch.replacements > 0 ||
256
+ redactedEvidenceRecord.replacements > 0;
257
+ changed ||= evidenceChanged;
258
+ if (!evidenceChanged)
259
+ return evidence;
260
+ reanchorEvidenceRedacted = true;
261
+ const { patch: _sensitivePatch, record: _sensitiveRecord, record_hash: _priorRecordHash, record_hash_version: _priorRecordHashVersion, ...digestOnlyEvidence } = evidence;
262
+ return redactedEvidencePatch.replacements > 0
263
+ ? digestOnlyEvidence
264
+ : { ...digestOnlyEvidence, patch: evidence.patch };
242
265
  });
243
266
  return {
244
267
  entry: {
245
268
  ...entry,
246
269
  message: nextMessage,
247
- patch: nextPatch,
270
+ patch: redactedPatch.patch,
271
+ ...(nextReanchorEvidence
272
+ ? { reanchor_evidence: nextReanchorEvidence }
273
+ : {}),
248
274
  },
249
275
  replacements,
250
276
  changed,
277
+ reanchorEvidenceRedacted,
251
278
  };
252
279
  }
253
280
  function rewriteHistoryEntries(entries, rules, replacement) {
@@ -256,7 +283,12 @@ function rewriteHistoryEntries(entries, rules, replacement) {
256
283
  let replacements = 0;
257
284
  const rewrittenEntries = [];
258
285
  for (let index = 0; index < entries.length; index += 1) {
259
- const redacted = redactHistoryEntry(entries[index], rules, replacement);
286
+ const original = entries[index];
287
+ const recordVerification = verifyHistoryRecordHash(original);
288
+ if (!recordVerification.ok) {
289
+ throw new PmCliError(`history-redact refuses invalid immutable record ${index + 1} (${recordVerification.error}).`, EXIT_CODE.GENERIC_FAILURE);
290
+ }
291
+ const redacted = redactHistoryEntry(original, rules, replacement);
260
292
  replacements += redacted.replacements;
261
293
  if (redacted.changed) {
262
294
  entriesChanged += 1;
@@ -264,11 +296,14 @@ function rewriteHistoryEntries(entries, rules, replacement) {
264
296
  const beforeHash = replayHash(replay);
265
297
  replay = applyHistoryPatch(replay, redacted.entry.patch, index + 1, redacted.entry.op);
266
298
  const afterHash = replayHash(replay);
267
- rewrittenEntries.push({
299
+ rewrittenEntries.push(resealHistoryRewrite(original, {
268
300
  ...redacted.entry,
269
301
  before_hash: beforeHash,
270
302
  after_hash: afterHash,
271
- });
303
+ }, {
304
+ retainPriorRecord: redacted.changed,
305
+ retainPriorRecordHash: !redacted.changed,
306
+ }));
272
307
  }
273
308
  return {
274
309
  entries: rewrittenEntries,
@@ -606,4 +641,4 @@ export const _testOnly = {
606
641
  redactUnknownValue,
607
642
  };
608
643
  //# sourceMappingURL=history-redact.js.map
609
- //# debugId=05b945f2-4f96-5f88-98ff-84cc856d0d57
644
+ //# debugId=bd1e86b0-6696-5fba-8dd4-b9636bf3ee60
@@ -4,7 +4,7 @@
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]="151e5d26-d6f5-5fcf-84ab-ce89e2b7664e")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="cb0b0e36-3135-5fc4-a0ae-f4e5b974e57f")}catch(e){}}();
8
8
  import { assertInitializedTracker } from "./environment/tracker-preflight.js";
9
9
  import { realpath } from "node:fs/promises";
10
10
  import path from "node:path";
@@ -13,21 +13,24 @@ import { patchPathToChangedField } from "../core/history/history-diff.js";
13
13
  import { pathExists, readFileIfExists } from "../core/fs/fs-utils.js";
14
14
  import { executeHistoryRewrite, writeHistoryRawWithRollback, } from "../core/history/history-rewrite.js";
15
15
  import { historyEntriesToRaw, normalizeReplayPatchOps, reanchorHistoryEntries, replayHashVerificationCandidates, resolveHistoryRepairItemHashVersion, toReplayDocument, verifyHistoryChain, verifyHistoryChainWithVersion, } from "../core/history/replay.js";
16
+ import { sealHistoryRecord, } from "../core/history/history.js";
17
+ import { classifyHistoryEvent } from "../core/history/event-classification.js";
16
18
  import { scanHistoryDrift } from "../core/history/drift-scan.js";
17
19
  import { invalidateHistoryDriftCache } from "../core/history/drift-cache.js";
18
20
  import { readHistoryEntries } from "../core/history/read.js";
19
21
  import { resolveItemTypeRegistry } from "../core/item/type-registry.js";
20
22
  import { EXIT_CODE } from "../core/shared/constants.js";
21
23
  import { PmCliError } from "../core/shared/errors.js";
24
+ import { sha256Hex, stableStringify } from "../core/shared/serialization.js";
22
25
  import { resolveAuthor } from "../core/shared/author.js";
23
26
  import { nowIso } from "../core/shared/time.js";
24
- import { sha256Hex, stableStringify } from "../core/shared/serialization.js";
25
27
  import { getActiveExtensionRegistrations, runActiveOnWriteHooks, } from "../core/extensions/index.js";
26
28
  import { listAllItemMetadataWithBody, readLocatedItem, } from "../core/store/item-store.js";
27
29
  import { resolvePmRoot } from "../core/store/paths.js";
28
30
  import { readSettings } from "../core/store/settings.js";
29
31
  import { resolveHistorySubject } from "./history-redact.js";
30
32
  import { inspectMergeReceiptEvidence, summarizeMergeReceipt, } from "./merge/receipts.js";
33
+ import { encodeItemScalarDecisionValue, hashItemScalarDecisionValue, } from "./merge/three-way.js";
31
34
  import { listInvalidProvenanceHistoryStreamIds, normalizeInvalidHistoryProvenance, } from "./governance/provenance-health.js";
32
35
  function replayFieldValue(document, field) {
33
36
  return field === "body"
@@ -169,7 +172,10 @@ async function verifyReceiptAgainstSnapshot(params) {
169
172
  const currentMetadata = params.currentItemReplay.metadata;
170
173
  const valuesMatch = declaredFields.every((field) => {
171
174
  const value = field === "body" ? params.currentItemReplay.body : currentMetadata[field];
172
- return hashes[field] === sha256Hex(stableStringify(value));
175
+ return [
176
+ hashItemScalarDecisionValue(value),
177
+ sha256Hex(stableStringify(encodeItemScalarDecisionValue(value))),
178
+ ].includes(hashes[field]);
173
179
  });
174
180
  return valuesMatch ? { receipt: params.receipt, declaredFields } : null;
175
181
  }
@@ -316,7 +322,7 @@ function buildHistoryRepairEntries(params) {
316
322
  const previousAfterHash = params.reanchorEntries[params.reanchorEntries.length - 1].after_hash;
317
323
  const semanticIndex = beforeHashes.indexOf(previousAfterHash);
318
324
  const afterHashes = replayHashVerificationCandidates(afterReplay, params.itemHashVersion);
319
- rewrittenEntries.push({
325
+ const auditEntry = {
320
326
  ts: nowIso(),
321
327
  author: params.author,
322
328
  op: params.auditOperation,
@@ -332,7 +338,11 @@ function buildHistoryRepairEntries(params) {
332
338
  ...(params.auditContext === undefined
333
339
  ? {}
334
340
  : { context: params.auditContext }),
335
- });
341
+ };
342
+ rewrittenEntries.push(sealHistoryRecord({
343
+ ...auditEntry,
344
+ event_class: classifyHistoryEvent(auditEntry),
345
+ }));
336
346
  return { rewrittenEntries, auditEntryAdded: true };
337
347
  }
338
348
  function collectHistoryRepairWarnings(changed, skippedOps, reconciliation) {
@@ -598,4 +608,4 @@ export async function runHistoryRepairAll(options, global) {
598
608
  };
599
609
  }
600
610
  //# sourceMappingURL=history-repair.js.map
601
- //# debugId=151e5d26-d6f5-5fcf-84ab-ce89e2b7664e
611
+ //# debugId=cb0b0e36-3135-5fc4-a0ae-f4e5b974e57f
@@ -14,6 +14,7 @@ export * from "./mcp/apps.js";
14
14
  export * from "./mcp/skills.js";
15
15
  export * from "./cli-contracts/grammar-contracts.js";
16
16
  export * from "./agent-session-context.js";
17
+ export * from "./environment/agent-environment.js";
17
18
  export type { PmCommandCapabilityContract, PmCommandCapabilityFamily, PmCommandVisibilityContract, PmCommandVisibilityTier, PmMcpPromptArgumentContract, PmMcpPromptContract, PmMcpResourceContract, PmMcpToolProfile, } from "./agent-capability-contracts.js";
18
19
  export { isErrnoError, limitAnnotationEntries, parseAnnotationTextInput, readAnnotationEntries, normalizeAnnotationTransportOptions, resolveAnnotationInput, resolveAnnotationIndex, runAnnotationCommand, wrapOwnershipConflict, type AnnotationCommandConfig, type AnnotationCommandOptions, type AnnotationCommandResult, type AnnotationEntry, type AnnotationInput, type AnnotationHistoryRestoration, type AnnotationMutationReceipt, type AnnotationOmissionReceipt, type AnnotationSourceOptions, type OwnershipConflictGuidance, } from "./annotations.js";
19
20
  export { acknowledgeUnknownAuthorHistoryEvents, acknowledgeUnknownAuthorHistoryEventsFromTransport, inspectHistoryAuthorStream, parseUnknownAuthorHistoryEventCoordinates, planUnknownAuthorHistoryAcknowledgment, resolveUnknownAuthorAcknowledgmentSelector, scanHistoryAuthorAttribution, type AcknowledgeUnknownAuthorEventsOptions, type HistoryAuthorAttributionScan, type UnknownAuthorAcknowledgmentPlan, type UnknownAuthorAcknowledgmentPlanCoordinate, type UnknownAuthorAcknowledgmentResult, type UnknownAuthorHistoryEvent, } from "./author-attribution.js";
@@ -75,6 +76,7 @@ export * from "./governance/assurance-runtime.js";
75
76
  export * from "./governance/assurance-presets.js";
76
77
  export * from "./governance/boundary-fixtures.js";
77
78
  export * from "./governance/defect-recurrence.js";
79
+ export * from "./governance/merge-receipt-history.js";
78
80
  export * from "./compile-cache.js";
79
81
  export * from "./environment/project-runtime-compatibility.js";
80
82
  export * from "./environment/source-context.js";
package/dist/sdk/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Defines public SDK APIs and package-author helpers for Index.
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]="62e450f7-9ed9-5855-923a-7b2ffb8b49f4")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ea74fa78-184f-55e7-8c8e-fb912f4d26d8")}catch(e){}}();
8
8
  export { PM_COMMAND_CAPABILITY_CONTRACTS, PM_COMMAND_VISIBILITY_CONTRACTS, PM_MCP_PROMPT_CONTRACTS, PM_MCP_RESOURCE_CONTRACTS, PM_MCP_TOOL_COMMAND_CONTRACTS, listPmCommandsForFamily, listPmCommandsForTier, listPmMcpToolsForProfile, renderPmCommandVisibilityMarkdown, resolvePmCommandCapabilityFamily, resolvePmCommandVisibilityTier, } from "./agent-capability-contracts.js";
9
9
  export * from "./mcp/protocol.js";
10
10
  export * from "./mcp/interactions.js";
@@ -16,6 +16,7 @@ export * from "./mcp/apps.js";
16
16
  export * from "./mcp/skills.js";
17
17
  export * from "./cli-contracts/grammar-contracts.js";
18
18
  export * from "./agent-session-context.js";
19
+ export * from "./environment/agent-environment.js";
19
20
  export { isErrnoError, limitAnnotationEntries, parseAnnotationTextInput, readAnnotationEntries, normalizeAnnotationTransportOptions, resolveAnnotationInput, resolveAnnotationIndex, runAnnotationCommand, wrapOwnershipConflict, } from "./annotations.js";
20
21
  export { acknowledgeUnknownAuthorHistoryEvents, acknowledgeUnknownAuthorHistoryEventsFromTransport, inspectHistoryAuthorStream, parseUnknownAuthorHistoryEventCoordinates, planUnknownAuthorHistoryAcknowledgment, resolveUnknownAuthorAcknowledgmentSelector, scanHistoryAuthorAttribution, } from "./author-attribution.js";
21
22
  export { BUILTIN_CORPUS_SHAPES, PM_CORPUS_SHAPE_SCHEMA, buildCorpusShapeItemPlan, createCorpusShapeMeasurement, defineCorpusShape, listBuiltinCorpusShapes, measureCorpusShapePlan, resolveBuiltinCorpusShape, } from "./corpus-shape.js";
@@ -72,6 +73,7 @@ export * from "./governance/assurance-runtime.js";
72
73
  export * from "./governance/assurance-presets.js";
73
74
  export * from "./governance/boundary-fixtures.js";
74
75
  export * from "./governance/defect-recurrence.js";
76
+ export * from "./governance/merge-receipt-history.js";
75
77
  export * from "./compile-cache.js";
76
78
  export * from "./environment/project-runtime-compatibility.js";
77
79
  export * from "./environment/source-context.js";
@@ -179,4 +181,4 @@ export * from "./mcp/discovery.js";
179
181
  export * from "./query.js";
180
182
  export * from "./testing.js";
181
183
  //# sourceMappingURL=index.js.map
182
- //# debugId=62e450f7-9ed9-5855-923a-7b2ffb8b49f4
184
+ //# debugId=ea74fa78-184f-55e7-8c8e-fb912f4d26d8
@@ -56,7 +56,9 @@ export interface MergeDriverResult {
56
56
  item?: {
57
57
  fields_from_theirs: string[];
58
58
  union_fields: string[];
59
- conflict_resolution: "stable_value_order";
59
+ conflict_resolution: "latest_document_update";
60
+ /** Item scalars ignore branch-direction preference under the convergent recency policy. */
61
+ requested_preference_applied: false;
60
62
  };
61
63
  /** JSON-merge key accounting; present only for the json artifact. */
62
64
  json?: {
@@ -9,7 +9,7 @@
9
9
  * merge never corrupts tracker storage the way raw conflict markers do.
10
10
  */
11
11
 
12
- !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]="2c8046a5-06aa-58f8-b347-e757086082d1")}catch(e){}}();
12
+ !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]="5dc5f70c-0b04-51bb-983b-49b15be11587")}catch(e){}}();
13
13
  import { readFile, writeFile } from "node:fs/promises";
14
14
  import path from "node:path";
15
15
  import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
@@ -18,11 +18,10 @@ import { pathExists } from "../../core/fs/fs-utils.js";
18
18
  import { parseItemDocument } from "../../core/item/item-format.js";
19
19
  import { EXIT_CODE } from "../../core/shared/constants.js";
20
20
  import { PmCliError } from "../../core/shared/errors.js";
21
- import { sha256Hex, stableStringify } from "../../core/shared/serialization.js";
22
21
  import { nowIso } from "../../core/shared/time.js";
23
22
  import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
24
23
  import { readSettings } from "../../core/store/settings.js";
25
- import { mergeHistoryStreams, mergeItemDocuments, mergeJsonDocuments, mergeRelationshipEventStreams, } from "./three-way.js";
24
+ import { hashItemScalarDecisionValue, mergeHistoryStreams, mergeItemDocuments, mergeJsonDocuments, mergeRelationshipEventStreams, } from "./three-way.js";
26
25
  import { summarizeMergeReceipt, writeMergeReceipt, } from "./receipts.js";
27
26
  /** Supported values accepted by the merge driver artifact contract across CLI, SDK, and MCP surfaces. */
28
27
  export const MERGE_DRIVER_ARTIFACT_VALUES = [
@@ -131,14 +130,15 @@ export async function runMergeDriver(options, global) {
131
130
  schema: settings?.schema,
132
131
  extensionFieldNames,
133
132
  preferred,
134
- conflictResolution: "stable_value_order",
133
+ conflictResolution: "latest_document_update",
135
134
  });
136
135
  merged = itemMerge.merged;
137
136
  conflicts.push(...itemMerge.conflict_fields);
138
137
  result.item = {
139
138
  fields_from_theirs: itemMerge.fields_from_theirs,
140
139
  union_fields: itemMerge.union_fields,
141
- conflict_resolution: "stable_value_order",
140
+ conflict_resolution: "latest_document_update",
141
+ requested_preference_applied: false,
142
142
  };
143
143
  if (options.itemPath !== undefined) {
144
144
  const mergedDocument = parseItemDocument(merged, {
@@ -158,12 +158,12 @@ export async function runMergeDriver(options, global) {
158
158
  cwd: process.cwd(),
159
159
  itemPath: options.itemPath,
160
160
  preferred,
161
- conflictResolution: "stable_value_order",
161
+ conflictResolution: "latest_document_update",
162
162
  fieldsFromTheirs: itemMerge.fields_from_theirs,
163
163
  unionFields: itemMerge.union_fields,
164
164
  mergedFieldHashes: Object.fromEntries(receiptFields.map((field) => [
165
165
  field,
166
- sha256Hex(stableStringify(field === "body" ? mergedDocument.body : mergedMetadata[field])),
166
+ hashItemScalarDecisionValue(field === "body" ? mergedDocument.body : mergedMetadata[field]),
167
167
  ])),
168
168
  decisions: itemMerge.conflict_decisions,
169
169
  };
@@ -191,7 +191,7 @@ export async function runMergeDriver(options, global) {
191
191
  const receiptGuidance = result.receipt === undefined
192
192
  ? 'Run "pm merge report" to inspect clone-local merge evidence.'
193
193
  : `Run "pm merge report" and correlate receipt ${result.receipt.receipt_id} with item ${result.receipt.item_id}; clone-local discarded values are never copied into this result.`;
194
- guidance.push(`Both branches changed ${conflicts.join(", ")}; the item driver kept the direction-independent stable value. ${receiptGuidance} Review the merged file, re-apply the discarded change if needed, then "git add" it.`);
194
+ guidance.push(`Both branches changed ${conflicts.join(", ")}; the item driver kept the value from the later document update, with stable value order only as an equal-timestamp tie-break. --prefer does not apply to convergent item scalar conflicts. ${receiptGuidance} Review the merged file, re-apply the discarded change if needed, then "git add" it.`);
195
195
  }
196
196
  if (artifact === "history" && result.history?.reanchored) {
197
197
  guidance.push('The merged history chain was re-anchored. Run "pm merge reconcile --dry-run" to inspect the complete post-merge repair, then "pm merge reconcile" to apply it; use --force only after explicitly accepting reported discards.');
@@ -208,4 +208,4 @@ export async function runMergeDriver(options, global) {
208
208
  };
209
209
  }
210
210
  //# sourceMappingURL=driver.js.map
211
- //# debugId=2c8046a5-06aa-58f8-b347-e757086082d1
211
+ //# debugId=5dc5f70c-0b04-51bb-983b-49b15be11587