@ibgib/vcs-gib 0.0.21 → 0.0.26

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 (93) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/VCS_CLI_USER_GUIDE.md +94 -89
  3. package/dist/AUTO-GENERATED-version.d.mts +1 -1
  4. package/dist/AUTO-GENERATED-version.mjs +1 -1
  5. package/dist/bootstrap/node-bootstrap.mjs +1 -1
  6. package/dist/cli/cli-arg-parser.d.mts +1 -0
  7. package/dist/cli/cli-arg-parser.d.mts.map +1 -1
  8. package/dist/cli/cli-arg-parser.mjs +5 -1
  9. package/dist/cli/cli-arg-parser.mjs.map +1 -1
  10. package/dist/cli/cli-constants.d.mts +6 -0
  11. package/dist/cli/cli-constants.d.mts.map +1 -1
  12. package/dist/cli/cli-constants.mjs +12 -0
  13. package/dist/cli/cli-constants.mjs.map +1 -1
  14. package/dist/cli/commands/add-cmd.d.mts.map +1 -1
  15. package/dist/cli/commands/add-cmd.mjs +5 -2
  16. package/dist/cli/commands/add-cmd.mjs.map +1 -1
  17. package/dist/cli/commands/commit-cmd.d.mts +5 -4
  18. package/dist/cli/commands/commit-cmd.d.mts.map +1 -1
  19. package/dist/cli/commands/commit-cmd.mjs +149 -33
  20. package/dist/cli/commands/commit-cmd.mjs.map +1 -1
  21. package/dist/cli/commands/generate-comment-cmd.d.mts +19 -0
  22. package/dist/cli/commands/generate-comment-cmd.d.mts.map +1 -0
  23. package/dist/cli/commands/generate-comment-cmd.mjs +140 -0
  24. package/dist/cli/commands/generate-comment-cmd.mjs.map +1 -0
  25. package/dist/cli/commands/log-cmd.d.mts +12 -3
  26. package/dist/cli/commands/log-cmd.d.mts.map +1 -1
  27. package/dist/cli/commands/log-cmd.mjs +236 -38
  28. package/dist/cli/commands/log-cmd.mjs.map +1 -1
  29. package/dist/cli/commands/merge-cmd.d.mts +21 -8
  30. package/dist/cli/commands/merge-cmd.d.mts.map +1 -1
  31. package/dist/cli/commands/merge-cmd.mjs +138 -70
  32. package/dist/cli/commands/merge-cmd.mjs.map +1 -1
  33. package/dist/cli/commands/status-cmd.d.mts +5 -6
  34. package/dist/cli/commands/status-cmd.d.mts.map +1 -1
  35. package/dist/cli/commands/status-cmd.mjs +50 -205
  36. package/dist/cli/commands/status-cmd.mjs.map +1 -1
  37. package/dist/cli/vcs-cli-main.d.mts.map +1 -1
  38. package/dist/cli/vcs-cli-main.mjs +27 -6
  39. package/dist/cli/vcs-cli-main.mjs.map +1 -1
  40. package/dist/engine/index/index-helper.d.mts.map +1 -1
  41. package/dist/engine/index/index-helper.mjs +3 -0
  42. package/dist/engine/index/index-helper.mjs.map +1 -1
  43. package/dist/engine/item/item-helper.d.mts +31 -1
  44. package/dist/engine/item/item-helper.d.mts.map +1 -1
  45. package/dist/engine/item/item-helper.mjs +44 -2
  46. package/dist/engine/item/item-helper.mjs.map +1 -1
  47. package/dist/engine/merge/b2tfs-3way-graft-strategy.d.mts +74 -0
  48. package/dist/engine/merge/b2tfs-3way-graft-strategy.d.mts.map +1 -0
  49. package/dist/engine/merge/{b2tfs-3way-merge-strategy.mjs → b2tfs-3way-graft-strategy.mjs} +133 -304
  50. package/dist/engine/merge/b2tfs-3way-graft-strategy.mjs.map +1 -0
  51. package/dist/engine/merge/{b2tfs-3way-merge-types.d.mts → b2tfs-3way-graft-types.d.mts} +2 -9
  52. package/dist/engine/merge/b2tfs-3way-graft-types.d.mts.map +1 -0
  53. package/dist/engine/merge/b2tfs-3way-graft-types.mjs +2 -0
  54. package/dist/engine/merge/b2tfs-3way-graft-types.mjs.map +1 -0
  55. package/dist/engine/status/status-helper.d.mts +89 -0
  56. package/dist/engine/status/status-helper.d.mts.map +1 -0
  57. package/dist/engine/status/status-helper.mjs +285 -0
  58. package/dist/engine/status/status-helper.mjs.map +1 -0
  59. package/dist/test/test-helpers.d.mts +51 -0
  60. package/dist/test/test-helpers.d.mts.map +1 -0
  61. package/dist/test/test-helpers.mjs +135 -0
  62. package/dist/test/test-helpers.mjs.map +1 -0
  63. package/package.json +4 -4
  64. package/src/AUTO-GENERATED-version.mts +1 -1
  65. package/src/bootstrap/node-bootstrap.mts +1 -1
  66. package/src/cli/cli-arg-parser.mts +5 -0
  67. package/src/cli/cli-constants.mts +13 -0
  68. package/src/cli/commands/add-cmd.mts +5 -2
  69. package/src/cli/commands/branch-checkout-cmd.respec.log +8 -101
  70. package/src/cli/commands/branch-checkout-cmd.respec.mts +11 -10
  71. package/src/cli/commands/commit-cmd.mts +165 -42
  72. package/src/cli/commands/commit-log-cmd.respec.mts +216 -3
  73. package/src/cli/commands/generate-comment-cmd.mts +171 -0
  74. package/src/cli/commands/log-cmd.mts +288 -41
  75. package/src/cli/commands/merge-cmd.mts +154 -76
  76. package/src/cli/commands/status-cmd.mts +57 -256
  77. package/src/cli/vcs-cli-main.mts +28 -7
  78. package/src/engine/index/index-helper.mts +3 -0
  79. package/src/engine/item/item-helper.mts +76 -3
  80. package/src/engine/merge/{b2tfs-3way-merge-strategy.mts → b2tfs-3way-graft-strategy.mts} +152 -374
  81. package/src/engine/merge/{b2tfs-3way-merge-strategy.respec.mts → b2tfs-3way-graft-strategy.respec.mts} +27 -122
  82. package/src/engine/merge/{b2tfs-3way-merge-types.mts → b2tfs-3way-graft-types.mts} +34 -42
  83. package/src/engine/merge/b2tfs-sync-comments.respec.mts +399 -0
  84. package/src/engine/status/status-helper.mts +380 -0
  85. package/src/test/test-helpers.mts +168 -0
  86. package/tsconfig.test.tsbuildinfo +1 -1
  87. package/tsconfig.tsbuildinfo +1 -1
  88. package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts +0 -48
  89. package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts.map +0 -1
  90. package/dist/engine/merge/b2tfs-3way-merge-strategy.mjs.map +0 -1
  91. package/dist/engine/merge/b2tfs-3way-merge-types.d.mts.map +0 -1
  92. package/dist/engine/merge/b2tfs-3way-merge-types.mjs +0 -2
  93. package/dist/engine/merge/b2tfs-3way-merge-types.mjs.map +0 -1
@@ -1,42 +1,53 @@
1
1
  /**
2
- * @module b2tfs-3way-merge-strategy
2
+ * @module b2tfs-3way-graft-strategy
3
3
  *
4
- * Extensible Graft Merge Strategy for 3-way B2tFS filesystem snapshot trees and text files.
4
+ * ============================================================================
5
+ * ⚠️ CRITICAL GRAFT STRATEGY GUIDANCE WARNING ⚠️
6
+ * BEFORE MAKING ANY CHANGES TO THIS FILE, YOU MUST CONSULT AND CAREFULLY READ:
7
+ * libs/core-gib/src/sync/GRAFT_STRATEGY_GUIDANCE.md
8
+ *
9
+ * Graft strategies must strictly fulfill the `GraftTimelinesResult` contract,
10
+ * ensure timeline `n` monotonicity (using Math.max over base/orphan branch frames),
11
+ * and include ALL newly referenced ancillary dependency nodes (comments, binary
12
+ * stones, DNAs) in `ancillaryIbGibsCreated` so that the destination branch
13
+ * space is completely self-contained.
14
+ * ============================================================================
15
+ *
16
+ * 3-way text line diff graft strategy for B2tFS file item timelines.
17
+ * Reconciles diverging file content via 3-way line diff (LCA, Base, Orphan)
18
+ * and inserts Git conflict markers when line edits collide.
19
+ *
20
+ * Non-text binaries and non-file items return early / false in `canGraft` and
21
+ * fall through to `DefaultDnaReplayGraftStrategy`.
22
+ * Folder hierarchies are re-synchronized post-merge via `reifyB2tFSHierarchy`.
5
23
  */
6
24
 
7
- import crypto from 'node:crypto';
8
-
9
- import { extractErrorMsg, hash, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
25
+ import { extractErrorMsg, hash } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
10
26
  import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
11
27
  import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
12
- import { getGib } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
28
+ import { getGib, isDna } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
13
29
  import { rel8 } from '@ibgib/ts-gib/dist/V1/transforms/rel8.mjs';
14
- import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
15
30
 
16
31
  import { GraftMergeStrategyBase_V1 } from '@ibgib/core-gib/dist/sync/graft-info/graft-merge-strategy-base-v1.mjs';
17
- import { GraftContext, GraftPreference, GraftStrategy, GraftTimelinesResult, GraftMergeContext, GraftMergeResult } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-types.mjs';
32
+ import { GraftContext, GraftStrategy, GraftTimelinesResult } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-types.mjs';
18
33
  import { FlatIbGibGraph } from '@ibgib/core-gib/dist/common/other/graph-types.mjs';
19
-
20
-
21
34
  import { getFromSpace, persistTransformResult, registerNewIbGib, putInSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
22
- import { getBinIb, getIbGibsFromCache_fallbackToSpaces, getTimelinesGroupedByTjp, getTimestampInfo, splitPerTjpAndOrDna } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs';
23
-
24
- import { applyTransforms, getUniqueDnas } from '@ibgib/core-gib/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs';
35
+ import { getBinIb, getIbGibsFromCache_fallbackToSpaces, splitPerTjpAndOrDna, getTimelinesGroupedByTjp } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs';
36
+ import { getDependencyGraph } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs';
25
37
  import { createGraftInfo } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-helpers.mjs';
26
38
  import { GRAFT_INFO_REL8N_NAME } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-constants.mjs';
27
39
  import { BinIbGib_V1 } from '@ibgib/core-gib/dist/common/bin/bin-types.mjs';
28
40
  import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.mjs';
41
+ import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
29
42
 
30
43
  import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
31
44
  import { isBinaryBuffer, decodeToLines, computeLineLcsDiff } from '../diff/line-diff-helper.mjs';
32
- import { B2tFSItemIbGib_V1, B2TFS_CHILD_ITEM_REL8N_NAME, BINARY_REL8N_NAME, B2tFSType } from '../item/item-types.mjs';
45
+ import { B2tFSItemIbGib_V1, BINARY_REL8N_NAME, B2tFSType } from '../item/item-types.mjs';
33
46
  import { evolveB2tFSItemIbGib, isB2tFSItemIbGib } from '../item/item-helper.mjs';
34
- import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
35
- import { B2TFS_ITEM_ATOM } from '../item/item-atom-helper.mjs';
36
- import { B2tFS3WayAddlGraftDetails } from './b2tfs-3way-merge-types.mjs';
47
+ import { B2tFS3WayAddlGraftDetails } from './b2tfs-3way-graft-types.mjs';
37
48
 
38
- const lcFile = `[b2tfs-3way-merge-strategy]`;
39
- const logalot = GLOBAL_LOG_A_LOT || true;
49
+ const lcFile = `[b2tfs-3way-graft-strategy]`;
50
+ const logalot = GLOBAL_LOG_A_LOT;
40
51
  const mergeDiag = `[MERGE DIAGNOSTIC]`;
41
52
 
42
53
  /**
@@ -61,9 +72,6 @@ export function perform3WayTextLineMerge({
61
72
  textBase: string;
62
73
  textOrphan: string;
63
74
  }): Text3WayMergeResult {
64
- console.log(`[DEBUG 3WAY] textLCA: ${JSON.stringify(textLCA)}`);
65
- console.log(`[DEBUG 3WAY] textBase: ${JSON.stringify(textBase)}`);
66
- console.log(`[DEBUG 3WAY] textOrphan: ${JSON.stringify(textOrphan)}`);
67
75
  if (textBase === textOrphan) {
68
76
  return { mergedText: textBase, hasConflict: false };
69
77
  }
@@ -74,7 +82,6 @@ export function perform3WayTextLineMerge({
74
82
  return { mergedText: textBase, hasConflict: false };
75
83
  }
76
84
 
77
-
78
85
  const linesLCA = textLCA.split(/\r?\n/);
79
86
  const linesBase = textBase.split(/\r?\n/);
80
87
  const linesOrphan = textOrphan.split(/\r?\n/);
@@ -157,6 +164,12 @@ export function perform3WayTextLineMerge({
157
164
  };
158
165
  }
159
166
 
167
+ /**
168
+ * 3-way text line diff graft strategy for B2tFS file item timelines.
169
+ *
170
+ * ⚠️ **IMPORTANT**: Before making ANY changes to this class or its methods, consult:
171
+ * `libs/core-gib/src/sync/GRAFT_STRATEGY_GUIDANCE.md`.
172
+ */
160
173
  export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements GraftStrategy {
161
174
  readonly strategyId: string = 'B2tFS3WayGraftStrategy';
162
175
  private lc = '[B2tFS3WayGraftStrategy]';
@@ -164,12 +177,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
164
177
  /**
165
178
  * Returns true only if the graft context has two tips that are text-based file b2tfs item ibgibs.
166
179
  *
167
- * ## notes
168
- *
169
- * atow (08/12/2026) implementation is guantlet style: if cannot graft, return early
170
- *
171
180
  * @param context info about the divergent timelines {@link GraftContext}
172
- *
173
181
  * @returns true if it's a text file item ibgib, else false
174
182
  */
175
183
  async canGraft(context: GraftContext): Promise<boolean> {
@@ -177,19 +185,16 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
177
185
  try {
178
186
  const { conflictStrategy, timelineAddrsA, timelineAddrsB, ibGibReadCache, space } = context;
179
187
 
180
- // todo: refactor conflict strategy to be more generic: 'graft' | 'abort' | maybe something else.
181
188
  const hasRelevantStrategy = conflictStrategy === SyncConflictStrategy.optimisticWithLCS || (conflictStrategy as string) === 'b2tfs3WayMerge';
182
189
  if (!hasRelevantStrategy) {
183
- // immediately return false because we are not the chosen strategy.
184
- // todo: after refactor, really this should be out of the hands of the implementation and we should have a discriminator as part of the strategy interface. So the graft strategy pipeline executor can just check that first, and then if multiple found, it will delegate to this `canGraft` method.
185
- return false; /* <<<< returns early */
190
+ return false;
186
191
  }
187
192
 
188
193
  const tipAddrA = timelineAddrsA.at(-1);
189
194
  const tipAddrB = timelineAddrsB.at(-1);
190
195
  if (!tipAddrA || !tipAddrB) {
191
- if (logalot) { console.log(`${lc} we don't have two tip addrs? how was a graft decided upon? (I: b20b6de462c35e0e74360cc8d317f126)`); }
192
- return false; /* <<<< returns early */
196
+ if (logalot) { console.log(`${lc} we don't have two tip addrs? (I: b20b6de462c35e0e74360cc8d317f126)`); }
197
+ return false;
193
198
  }
194
199
 
195
200
  const [tipA, tipB] = await getIbGibsFromCache_fallbackToSpaces({
@@ -198,26 +203,26 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
198
203
  space,
199
204
  });
200
205
 
201
- if (!tipA) { throw new Error(`(UNEXPECTED) tipA falsy? couldn't get tipA? should have been available to us in the temp space or cache.(E: 752101026888140f074614e893531826)`); }
202
- if (!tipB) { throw new Error(`(UNEXPECTED) tipB falsy? couldn't get tipB? should have been available to us in the temp space or cache. (E: d4d4a876cad8c7869830d33832bfde26)`); }
206
+ if (!tipA) { throw new Error(`(UNEXPECTED) tipA falsy? (E: 752101026888140f074614e893531826)`); }
207
+ if (!tipB) { throw new Error(`(UNEXPECTED) tipB falsy? (E: d4d4a876cad8c7869830d33832bfde26)`); }
203
208
 
204
209
  const bothTipsAreB2tFSNodes = isB2tFSItemIbGib(tipA) && isB2tFSItemIbGib(tipB);
205
210
 
206
211
  if (!bothTipsAreB2tFSNodes) {
207
- // at this point, we're returning false. But I'm being extra defensive since this algorithm is so difficult to implement. So throw if somehow only one is a b2tfs item
208
212
  if (isB2tFSItemIbGib(tipA) || isB2tFSItemIbGib(tipB)) {
209
- console.error(`${lc}${mergeDiag} (UNEXPECTED)(NOT THROWN) only tipA or tipB but not both are b2tfs items? (E: cacb38796da881268898e9d1af245826)`)
213
+ console.error(`${lc}${mergeDiag} (UNEXPECTED)(NOT THROWN) only tipA or tipB but not both are b2tfs items? (E: cacb38796da881268898e9d1af245826)`);
210
214
  }
211
- return false; /* <<<< returns early */
215
+ return false;
212
216
  }
213
217
 
214
- if (tipA.data.fsType !== tipB.data.fsType) { throw new Error(`(UNEXPECTED) tipA.data.fsType (${tipA.data.fsType}) !== tipB.data.fsType (${tipB.data.fsType})? both tips are expected to be the same B2tFSType. (E: c01c1885ac738f679813117852c48426)`); }
218
+ if (tipA.data.fsType !== tipB.data.fsType) {
219
+ throw new Error(`(UNEXPECTED) tipA.data.fsType (${tipA.data.fsType}) !== tipB.data.fsType (${tipB.data.fsType})? (E: c01c1885ac738f679813117852c48426)`);
220
+ }
215
221
 
216
- // only do files. folders can use the replay dna strategy.
222
+ // only do files. folders and other containers fall back to DefaultDnaReplayGraftStrategy.
217
223
  const isFile = tipA.data.fsType === B2tFSType.file;
218
- if (!isFile) { return false; /* <<<< returns early */ }
224
+ if (!isFile) { return false; }
219
225
 
220
- // passed gauntlet, we have a b2tfs file item that we can merge
221
226
  return true;
222
227
  } catch (error) {
223
228
  console.error(`${lc} ${extractErrorMsg(error)} (E: 8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e)`);
@@ -225,6 +230,16 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
225
230
  }
226
231
  }
227
232
 
233
+ /**
234
+ * Executes 3-way line diff text graft across LCA, Base, and Orphan file items.
235
+ *
236
+ * ⚠️ **CRITICAL CONTRACT**: Before modifying this method, review:
237
+ * `libs/core-gib/src/sync/GRAFT_STRATEGY_GUIDANCE.md`
238
+ * Ensure:
239
+ * 1. Monotonic `n` counter (`highestDataN = Math.max(...)`)
240
+ * 2. Full dependency graph inclusion in `ancillaryIbGibsCreated` (comments, bin stones, DNAs)
241
+ * 3. Self-contained destination branch space
242
+ */
228
243
  async graft(context: GraftContext): Promise<GraftTimelinesResult | undefined> {
229
244
  const lc = `${lcFile}[${this.strategyId}][${this.graft.name}]`;
230
245
  try {
@@ -242,7 +257,6 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
242
257
  graftPreference,
243
258
  } = context;
244
259
 
245
-
246
260
  // 1. Fetch branch slices since LCA (timeline A = Sender, timeline B = Receiver)
247
261
  const indexLCA_A = timelineAddrsA.lastIndexOf(latestCommonFrameAddr);
248
262
  const addrsA_sinceLCA = timelineAddrsA.slice(indexLCA_A + 1);
@@ -262,7 +276,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
262
276
  });
263
277
  const tipB_receiver = branchB_receiver_sinceLCA.at(-1)!;
264
278
 
265
- // 2. Base & Orphan tip determination (directional preference) via DRY base helper
279
+ // 2. Base & Orphan resolution via DRY helper
266
280
  const {
267
281
  baseTip,
268
282
  baseBranch,
@@ -280,109 +294,13 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
280
294
  const baseBranchAddrs = baseBranch.map(x => getIbGibAddr({ ibGib: x }));
281
295
  const orphanTipAddr = getIbGibAddr({ ibGib: orphanTip });
282
296
  const orphanBranchAddrs = orphanBranch.map(x => getIbGibAddr({ ibGib: x }));
283
- if (logalot) { console.log(`${lc} baseBranchAddrs:\n${baseBranchAddrs.join('\n')}\n(I: 2cad420d7bc822f798b8a8785f1f8c26)`); }
284
- if (logalot) { console.log(`${lc} orphanBranchAddrs:\n${orphanBranchAddrs.join('\n')}\n(I: cc86489d6737e2aced42b585cba13526)`); }
285
297
 
286
- // 3. Replay orphan branch transforms onto base tip
287
- const [latestCommonFrameIbGib] = await getIbGibsFromCache_fallbackToSpaces({
288
- addrs: [latestCommonFrameAddr],
289
- space,
290
- });
298
+ if (logalot) {
299
+ console.log(`${lc} baseBranchAddrs:\n${baseBranchAddrs.join('\n')} (I: 2cad420d7bc822f798b8a8785f1f8c26)`);
300
+ console.log(`${lc} orphanBranchAddrs:\n${orphanBranchAddrs.join('\n')} (I: cc86489d6737e2aced42b585cba13526)`);
301
+ }
291
302
 
292
- // It is non-trivial and not at all obvious, but the following approach is WRONG!!
293
- //
294
- // This is not a generic timeline, rather, this is a timeline that
295
- // is restricted to a b2tfs node, which itself has two
296
- // possibilities: file or folder. So we can't replay dna blindly
297
- // between the two branches and then try to do some kind of text
298
- // merge later. We must analyze each branch and decide how to handle
299
- // each change.
300
- //
301
- // NOTE: I have tweaked canGraft to only return true on
302
- // B2tFSType.file and not folders, to see if the dna replay is good
303
- // enough for folders, so we can concentrate on just files. Keep
304
- // that in mind when I discuss the following notes.
305
- //
306
- // what we know at this point:
307
- // * graft was invoked, so the sync engine detected divergence in
308
- // the two spaces, i.e., our two branches (branch-per-space)
309
- // * IOW, this is NOT a FF merge. That would have already been
310
- // applied and not triggered this graft.
311
- // * This is either a file or a folder b2tfs item.
312
- // * If it is a folder...
313
- // * How does git handle two folders merging, or does it?
314
- // * git is file-based, and handles folders only secondarily.
315
- // * How does our current vcs-gib diffing engine even detect if a
316
- // folder has moved? does it?
317
- // * If it is a file...
318
- // * Is there anything that can happen besides the related binary file changing?
319
- // * If there are multiple changes to the binary file, should we
320
- // do each of those file changes in the graft?
321
- // * we need to game out multiple scenarios to answer this.
322
- // * What about multiple changes to each branch? Do we squash
323
- // the orphan to a single change and then merge the final?
324
- // * It is possible we can even parameterize this in this
325
- // strategy object, but the caller would need to configure
326
- // this strategy ahead of each sync call if that is the case I
327
- // think.
328
- // * One thing to parameterize would be how to handle graft
329
- // points, as I just realized in the context of version
330
- // control systems, it is possible that we may want to
331
- // configure the sync/merge to drop/do something with large
332
- // binaries (or just files in general) in a specific way.
333
-
334
- // const dnaAddrsAlreadyAccountedFor: IbGibAddr[] = (latestCommonFrameIbGib?.rel8ns?.dna ?? []).concat();
335
- // const dnaAddrsToApply: IbGibAddr[] = [];
336
- // for (const orphanFrame of orphanBranch) {
337
- // if (!orphanFrame.rel8ns) { throw new Error(`(UNEXPECTED) orphanFrame.rel8ns falsy? (E: bc9a78ef8dbcd9748305d898bf1b2826)`); }
338
- // // I don't know if this is expected or not, but seems like if
339
- // // we're doing a merge, we are expecting the ibgib frames to
340
- // // have dna
341
- // if (!orphanFrame.rel8ns.dna || orphanFrame.rel8ns.dna.length === 0) {
342
- // throw new Error(`(UNEXPECTED) !orphanFrame.rel8ns.dna || orphanFrame.rel8ns.dna.length === 0? How can we be grafting when the orphan slice has no dna? (E: 7e58797aa2f98dfa811e8fa88c693826)`);
343
- // }
344
- // const orphanDnaAddrsToApply = getUniqueDnas({
345
- // base: dnaAddrsAlreadyAccountedFor,
346
- // extended: orphanFrame.rel8ns.dna,
347
- // throwIfExtendedDoesntContainBase: true,
348
- // });
349
- // orphanDnaAddrsToApply.forEach(x => dnaAddrsAlreadyAccountedFor.push(x));
350
- // orphanDnaAddrsToApply.forEach(x => dnaAddrsToApply.push(x));
351
- // }
352
-
353
- // const dnaIbGibsToApply = await getIbGibsFromCache_fallbackToSpaces({
354
- // addrs: dnaAddrsToApply,
355
- // readCache_graph: ibGibReadCache,
356
- // space,
357
- // });
358
-
359
- // if (logalot) { console.log(`${lc}${mergeDiag} dnaAddrsToApply addrs (${dnaAddrsToApply.length}): ${dnaAddrsToApply} (I: 78a8a82f540d520682664aa806f1b826)`); }
360
-
361
- // const createdIbGibs_Running: IbGib_V1[] = [];
362
- // const newGraftedIntermediateIbGibs_ordered: IbGib_V1[] = [];
363
- // const newGraftDnaIbGibs: IbGib_V1[] = [];
364
-
365
- // let currentGraftTip = await applyTransforms({
366
- // src: baseTip,
367
- // dnaAddrsToApplyToStoreVersion_MUTATES_IN_PLACE: dnaAddrsToApply.concat(),
368
- // allLocalIbGibs: dnaIbGibsToApply,
369
- // createdIbGibs_Running,
370
- // });
371
-
372
- // if (createdIbGibs_Running.length > 0) {
373
- // await putInSpace({ space, ibGibs: createdIbGibs_Running });
374
- // const { mapWithTjp_YesDna: newGraftedIbGibsMap } = splitPerTjpAndOrDna({ ibGibs: createdIbGibs_Running });
375
- // const newGraftedIbGibs_orderNotGuaranteed = Object.values(newGraftedIbGibsMap);
376
- // const newGraftedIbGibsByTjp = getTimelinesGroupedByTjp({ ibGibs: newGraftedIbGibs_orderNotGuaranteed });
377
- // if (Object.keys(newGraftedIbGibsByTjp).length > 0) {
378
- // Object.values(newGraftedIbGibsByTjp)[0].forEach(x => newGraftedIntermediateIbGibs_ordered.push(x));
379
- // for (const item of newGraftedIntermediateIbGibs_ordered) {
380
- // await registerNewIbGib({ ibGib: item, space });
381
- // }
382
- // }
383
- // }
384
-
385
- // 4. Perform 3-way filesystem tree merge across lcaItem, baseItem, orphanItem
303
+ // 3. Perform 3-way filesystem tree merge across lcaItem, baseItem, orphanItem
386
304
  const lcaNode = await this.fetchIbGib({ addr: latestCommonFrameAddr, space, readCache_graph: ibGibReadCache });
387
305
  if (!lcaNode) { throw new Error(`(UNEXPECTED) lcaNode falsy? (E: a8b2d80dc4f8ba1448fa280d89dfb626)`); }
388
306
  const lcaItem = await this.resolveRootItemNode({ nodeOrAddr: lcaNode, space, readCache_graph: ibGibReadCache });
@@ -394,68 +312,49 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
394
312
 
395
313
  if (lcaItem.data.fsType !== baseItem.data.fsType) { throw new Error(`(UNEXPECTED) lcaItem.data.fsType !== baseItem.data.fsType? (E: 794608f3e678a399ed670388629a6826)`); }
396
314
  if (lcaItem.data.fsType !== orphanItem.data.fsType) { throw new Error(`(UNEXPECTED) lcaItem.data.fsType !== orphanItem.data.fsType? (E: 2813981c8c422b41f85a02fd8aa88226)`); }
397
- // all three fsTypes are equal
398
315
 
399
316
  const fsType = lcaItem.data.fsType;
400
317
  if (fsType === B2tFSType.folder) {
401
- throw new Error(`(UNEXPECTED) fsType === B2tFSType.folder? I have tweaked the canGraft so we should only be handling files atow (08/11/2026) (E: b282b8f77b18575378edb902bd80a826)`);
318
+ throw new Error(`(UNEXPECTED) fsType === B2tFSType.folder? Folders fall back to DefaultDnaReplayGraftStrategy and reification. (E: b282b8f77b18575378edb902bd80a826)`);
402
319
  }
403
-
404
- if (fsType !== B2tFSType.file) { throw new Error(`(UNEXPECTED) fsType (${fsType}) is not a file? (E: 272418fe2067ea3e16dac028e86d1a26)`); }
405
-
406
-
407
- const lcaPayload = await this.getFilePayloadBuffer({
408
- fileItem: lcaItem, space, readCache_graph: ibGibReadCache
409
- });
410
- if (lcaPayload === undefined) {
411
- if (logalot) { console.log(`${lc}${mergeDiag} lcaPayload undefined? (I: 59b25835cce856cea883cf989ceb3826)`); }
412
- }
413
- const basePayload = await this.getFilePayloadBuffer({
414
- fileItem: baseItem, space, readCache_graph: ibGibReadCache
415
- });
416
- if (basePayload === undefined) {
417
- if (logalot) { console.log(`${lc}${mergeDiag} basePayload undefined? (I: 54f05406dca85eb98821b79f7325c826)`); }
418
- }
419
- const orphanPayload = await this.getFilePayloadBuffer({
420
- fileItem: orphanItem, space, readCache_graph: ibGibReadCache
421
- });
422
- if (orphanPayload === undefined) {
423
- if (logalot) { console.log(`${lc}${mergeDiag} orphanPayload undefined? (I: cd8b785875b43fc6684c65d818edd826)`); }
320
+ if (fsType !== B2tFSType.file) {
321
+ throw new Error(`(UNEXPECTED) fsType (${fsType}) is not a file? (E: 272418fe2067ea3e16dac028e86d1a26)`);
424
322
  }
425
323
 
324
+ const lcaPayload = await this.getFilePayloadBuffer({ fileItem: lcaItem, space, readCache_graph: ibGibReadCache });
325
+ const basePayload = await this.getFilePayloadBuffer({ fileItem: baseItem, space, readCache_graph: ibGibReadCache });
326
+ const orphanPayload = await this.getFilePayloadBuffer({ fileItem: orphanItem, space, readCache_graph: ibGibReadCache });
327
+
426
328
  const isBaseBin = basePayload ? isBinaryBuffer(basePayload.buffer) : false;
427
329
  const isOrphanBin = orphanPayload ? isBinaryBuffer(orphanPayload.buffer) : false;
428
330
  const isLcaBin = lcaPayload ? isBinaryBuffer(lcaPayload.buffer) : false;
429
331
 
430
332
  if (isBaseBin || isOrphanBin || isLcaBin) {
431
333
  if (logalot) {
432
- console.log(`${lc} Non-text binary file detected (${baseItem.data?.name}). Skipping 3-way line diff. (I: 4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b)`);
334
+ console.log(`${lc} Non-text binary file detected (${baseItem.data?.name}). Skipping 3-way line diff and falling through. (I: 4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b)`);
433
335
  }
434
-
435
- // even though we've gotten this far into this `graft` method,
436
- // we can still return `undefined` early if we decide we can't
437
- // handle it and we haven't persisted/registered any ibgibs. In
438
- // this particular case of 3-way text merges, we don't graft
439
- // non-text binary divergences, e.g., pics, sound files, etc.
440
-
441
- return undefined; /* <<<< returns early */
336
+ return undefined;
442
337
  }
443
338
 
444
- if (!lcaPayload) { throw new Error(`(UNEXPECTED) lcaPayload falsy? By this point in code, we have guaranteed that we are dealing with a text payload. (E: 0b82892204482f5538a430b8915b7826)`); }
445
- if (!basePayload) { throw new Error(`(UNEXPECTED) basePayload falsy? By this point in code, we have guaranteed that we are dealing with a text payload. (E: af1f68a020280b3a5d6ed4a812acd426)`); }
446
- if (!orphanPayload) { throw new Error(`(UNEXPECTED) orphanPayload falsy? By this point in code, we have guaranteed that we are dealing with a text payload. (E: 6a521b684763862c3a2e0ca315d62826)`); }
339
+ if (!lcaPayload) { throw new Error(`(UNEXPECTED) lcaPayload falsy? (E: 0b82892204482f5538a430b8915b7826)`); }
340
+ if (!basePayload) { throw new Error(`(UNEXPECTED) basePayload falsy? (E: af1f68a020280b3a5d6ed4a812acd426)`); }
341
+ if (!orphanPayload) { throw new Error(`(UNEXPECTED) orphanPayload falsy? (E: 6a521b684763862c3a2e0ca315d62826)`); }
447
342
 
448
343
  const textLCA = decodeToLines(lcaPayload.buffer).join('\n');
449
344
  const textBase = decodeToLines(basePayload.buffer).join('\n');
450
345
  const textOrphan = decodeToLines(orphanPayload.buffer).join('\n');
451
346
 
452
- console.log(`${lc}${mergeDiag} file: ${baseItem.data.name}`);
453
- console.log(`${lc}${mergeDiag} textLCA:\n${textLCA}`);
454
- console.log(`${lc}${mergeDiag} textBase:\n${textBase}`);
455
- console.log(`${lc}${mergeDiag} textOrphan:\n${textOrphan}`);
347
+ if (logalot) {
348
+ console.log(`${lc}${mergeDiag} file: ${baseItem.data.name}`);
349
+ console.log(`${lc}${mergeDiag} textLCA:\n${textLCA}`);
350
+ console.log(`${lc}${mergeDiag} textBase:\n${textBase}`);
351
+ console.log(`${lc}${mergeDiag} textOrphan:\n${textOrphan}`);
352
+ }
456
353
 
457
354
  const { mergedText } = perform3WayTextLineMerge({ textLCA, textBase, textOrphan });
458
- console.log(`${lc}${mergeDiag} mergedText:\n${mergedText}`);
355
+ if (logalot) {
356
+ console.log(`${lc}${mergeDiag} mergedText:\n${mergedText}`);
357
+ }
459
358
 
460
359
  const dataBuffer = Buffer.from(mergedText, 'utf8');
461
360
  const fileHash = await hash({ s: mergedText });
@@ -478,38 +377,84 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
478
377
 
479
378
  const binAddr = getIbGibAddr({ ibGib: binIbGib });
480
379
 
481
- // at this point, we are committed to performing the 3-way merge.
482
380
  await putInSpace({ ibGib: binIbGib, space });
483
381
  await registerNewIbGib({ ibGib: binIbGib, space });
484
382
 
485
-
486
- const fnGetN: (item: B2tFSItemIbGib_V1) => number = (item: B2tFSItemIbGib_V1) => {
383
+ const fnGetN = (item: B2tFSItemIbGib_V1): number => {
487
384
  if (item.data.n || item.data.n === 0) {
488
385
  return item.data.n!;
489
386
  } else {
490
387
  throw new Error(`(UNEXPECTED) item.data.n not a number? (E: 896ceae089c83ca67817fff826be5826)`);
491
388
  }
492
- }
389
+ };
493
390
  const baseItemDataN = fnGetN(baseItem);
494
391
  const orphanItemDataN = fnGetN(orphanItem);
495
- const lowestDataN = baseItemDataN <= orphanItemDataN ?
496
- baseItemDataN :
497
- orphanItemDataN;
392
+ const highestDataN = Math.max(baseItemDataN, orphanItemDataN);
393
+
394
+ const lcaCommentAddrs = lcaItem.rel8ns?.comment || [];
395
+ const lcaCommentAddrsSet = new Set(lcaCommentAddrs);
396
+ const mergedCommentAddrsSinceLCA_base = (baseItem.rel8ns?.comment || []).filter(addr => !lcaCommentAddrsSet.has(addr));
397
+ const mergedCommentAddrsSinceLCA_orphan = (orphanItem.rel8ns?.comment || []).filter(addr => !lcaCommentAddrsSet.has(addr));
398
+ const newCommentAddrs = Array.from(new Set([...mergedCommentAddrsSinceLCA_base, ...mergedCommentAddrsSinceLCA_orphan]));
399
+ const allMergedCommentAddrs = Array.from(new Set([...lcaCommentAddrs, ...newCommentAddrs]));
400
+
401
+ const commentDepIbGibs: IbGib_V1[] = [];
402
+ if (newCommentAddrs.length > 0) {
403
+ for (const cAddr of newCommentAddrs) {
404
+ const cIb = await this.fetchIbGib({ addr: cAddr, space, readCache_graph: ibGibReadCache });
405
+ if (!cIb) {
406
+ throw new Error(`(UNEXPECTED) Comment ibgib for address '${cAddr}' not found in cache or space (E: a1b2c3d4e5f67a8b9c0d1e2f3a4b5c6d)`);
407
+ }
408
+ commentDepIbGibs.push(cIb);
409
+ const cDepGraph = await getDependencyGraph({
410
+ ibGib: cIb,
411
+ space,
412
+ ibGibs: ibGibReadCache ? Object.values(ibGibReadCache) : undefined,
413
+ });
414
+ for (const depNode of Object.values(cDepGraph)) {
415
+ const depAddr = getIbGibAddr({ ibGib: depNode });
416
+ if (!commentDepIbGibs.some(x => getIbGibAddr({ ibGib: x }) === depAddr)) {
417
+ commentDepIbGibs.push(depNode);
418
+ }
419
+ }
420
+ }
421
+
422
+ const { mapWithTjp_YesDna, mapWithoutTjps } = splitPerTjpAndOrDna({ ibGibs: commentDepIbGibs });
423
+
424
+ // Put DNA and non-timeline stones into space with isDna flag
425
+ for (const dnaOrStone of Object.values(mapWithoutTjps)) {
426
+ if (space) {
427
+ await putInSpace({ ibGib: dnaOrStone, space, isDna: isDna({ ibGib: dnaOrStone }) });
428
+ }
429
+ }
430
+
431
+ // Register timeline frames in order
432
+ const timelinesByTjp = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_YesDna) });
433
+ for (const tjpAddr of Object.keys(timelinesByTjp)) {
434
+ const timeline = timelinesByTjp[tjpAddr];
435
+ for (const frame of timeline) {
436
+ if (space) {
437
+ await putInSpace({ ibGib: frame, space });
438
+ await registerNewIbGib({ ibGib: frame, space });
439
+ }
440
+ }
441
+ }
442
+ }
498
443
 
499
444
  const evolveRes = await evolveB2tFSItemIbGib({
500
445
  existingItem: baseItem,
501
446
  dataToUpdate: {
502
447
  fileHash,
503
- n: lowestDataN + 1,
448
+ n: highestDataN + 1,
504
449
  },
505
450
  rel8nsToUpdate: {
506
451
  [BINARY_REL8N_NAME]: [binAddr],
452
+ ...(allMergedCommentAddrs.length > 0 ? { comment: allMergedCommentAddrs } : {}),
507
453
  },
508
454
  });
509
455
 
510
- // sanity checks
511
- if (!evolveRes.dnas) { throw new Error(`(UNEXPECTED) evolveRes.dnas falsy? We should be using dna when working with B2tFS items. (E: e640e892cc76c77f98f3881301035826)`); }
512
- if (!evolveRes.newIbGib) { throw new Error(`(UNEXPECTED) evolveRes.newIbGib falsy? we just did the merge, so this should be truthy. (E: 9e488d07772827b66a2aff4801905426)`); }
456
+ if (!evolveRes.dnas) { throw new Error(`(UNEXPECTED) evolveRes.dnas falsy? (E: e640e892cc76c77f98f3881301035826)`); }
457
+ if (!evolveRes.newIbGib) { throw new Error(`(UNEXPECTED) evolveRes.newIbGib falsy? (E: 9e488d07772827b66a2aff4801905426)`); }
513
458
  const newItemWithNewBinPayload = evolveRes.newIbGib as B2tFSItemIbGib_V1;
514
459
  const newItemAddr = getIbGibAddr({ ibGib: newItemWithNewBinPayload });
515
460
  if (logalot) { console.log(`${lc} newItemAddr: ${newItemAddr} (I: d23eef651b88be1248ee29ca179eff26)`); }
@@ -519,31 +464,20 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
519
464
 
520
465
  newGraftDnaIbGibs.push(...evolveRes.dnas);
521
466
  if (evolveRes.intermediateIbGibs) {
522
- // todo: when we have this completed, we should know whether or not there are intermediate ibgibs in all cases, some cases, or no cases (never). we should change this from an `if` block with no else to throw an unexpected error (assertion) if it is indeed unexpected
523
467
  evolveRes.intermediateIbGibs.forEach(x => newGraftedIntermediateIbGibs_ordered.push(x));
524
468
  }
525
469
 
526
470
  await persistTransformResult({ resTransform: evolveRes, space });
527
471
  await registerNewIbGib({ ibGib: evolveRes.newIbGib, space });
528
472
 
529
- const baseItemAddr = getIbGibAddr({ ibGib: baseItem });
530
- const mergedRootAddr = getIbGibAddr({ ibGib: newItemWithNewBinPayload });
531
- const currentRootAddr = baseItem ? getIbGibAddr({ ibGib: baseItem }) : undefined;
532
-
533
- /**
534
- * stupid word "details" is plural and I have this set to be an
535
- * array. don't have the ability to refactor right now, so this will
536
- * be mildly confusing unfortunately. Agents should not try to just
537
- * refactor this on the fly.
538
- */
539
473
  const b2tfsAddlGraftDetails: B2tFS3WayAddlGraftDetails = {
540
474
  baseTextB2tFSItemAddr: baseTipAddr,
541
475
  baseTextBinAddr: basePayload.binIbGib ? getIbGibAddr({ ibGib: basePayload.binIbGib }) : undefined,
542
476
  orphanTextB2tFSItemAddr: orphanTipAddr,
543
477
  orphanTextBinAddr: orphanPayload.binIbGib ? getIbGibAddr({ ibGib: orphanPayload.binIbGib }) : undefined,
544
- }
478
+ };
545
479
 
546
- // 6. Attach GraftInfo frame
480
+ // 4. Attach GraftInfo frame
547
481
  const graftInfo = await createGraftInfo({
548
482
  conflictStrategy,
549
483
  details: `Merged orphan tip text with the baseTip as a starting point.`,
@@ -584,7 +518,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
584
518
  dnasReplayed: [],
585
519
  dnasCreatedInGraft: newGraftDnaIbGibs,
586
520
  intermediateIbGibsCreatedInGraft: newGraftedIntermediateIbGibs_ordered,
587
- ancillaryIbGibsCreated: [binIbGib],
521
+ ancillaryIbGibsCreated: [binIbGib, ...commentDepIbGibs],
588
522
  newGraftTip: finalGraftTip,
589
523
  graftInfoCreated: graftInfo,
590
524
  };
@@ -608,28 +542,24 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
608
542
  readCache_graph?: FlatIbGibGraph;
609
543
  }): Promise<IbGib_V1 | undefined> {
610
544
  if (!addr) { return undefined; }
611
- const cleanAddr = addr.includes('^') ? addr.split('^')[0] : addr;
612
545
  if (readCache_graph) {
613
- if (readCache_graph[cleanAddr]) { return readCache_graph[cleanAddr]; }
614
546
  if (readCache_graph[addr]) { return readCache_graph[addr]; }
615
- const matchingKey = Object.keys(readCache_graph).find(k => k === cleanAddr || k.startsWith(cleanAddr + '^') || (k.includes('^') && k.split('^')[0] === cleanAddr));
547
+ const gib = addr.includes('^') ? addr.substring(addr.lastIndexOf('^') + 1) : addr;
548
+ const matchingKey = Object.keys(readCache_graph).find(k => k === addr || (gib && k.endsWith('^' + gib)));
616
549
  if (matchingKey) { return readCache_graph[matchingKey]; }
617
550
  }
618
551
  try {
619
- const res = await getFromSpace({ space, addrs: [addr, cleanAddr] });
620
- if (res && res.success && res.ibGibs && res.ibGibs.length > 0) {
621
- const found = res.ibGibs.find((x: any) => !!x);
552
+ const res = await getFromSpace({ space, addrs: [addr] });
553
+ if (res) {
554
+ const found = res.ibGibs?.find((x: any) => !!x) || (res.rawResultIbGib as any)?.ibGibs?.find((x: any) => !!x);
622
555
  if (found) { return found; }
623
556
  }
624
557
  } catch {
625
558
  // Suppress fetch error if address not found
626
- // why suppress? any ibgibs available to us here should be in space
627
- // (the temp space of the sync receiver)
628
559
  }
629
560
  return undefined;
630
561
  }
631
562
 
632
-
633
563
  private async resolveRootItemNode({
634
564
  nodeOrAddr,
635
565
  space,
@@ -650,11 +580,9 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
650
580
  if (!node) { throw new Error(`(UNEXPECTED) node falsy? couldn't get node? (E: bd7d1c3b4a3881ff882746281869d826)`); }
651
581
 
652
582
  if (isB2tFSItemIbGib(node)) {
653
- // it's an item ibgib
654
583
  return node;
655
584
  } else {
656
- // not an item ibgib
657
- throw new Error(`(UNEXPECTED) node is not a B2tFSItemIbGib_V1? canGraft should have returned false then and we should never have gotten here. (E: ddabb281ccb2fb1a181109a82046b826)`);
585
+ throw new Error(`(UNEXPECTED) node is not a B2tFSItemIbGib_V1? (E: ddabb281ccb2fb1a181109a82046b826)`);
658
586
  }
659
587
  }
660
588
 
@@ -674,7 +602,7 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
674
602
 
675
603
  const binIbGib = await this.fetchIbGib({ addr: latestBinAddr, space, readCache_graph });
676
604
  if (!binIbGib) { throw new Error(`(UNEXPECTED) couldn't fetch binIbGib? latestBinAddr: ${latestBinAddr}. space.ib: ${space.ib} (E: 3d1238b3a348924038a79f88264d8226)`); }
677
- if (binIbGib.data === undefined) { return undefined; } // what if it's an empty file. will data be undefined? do we handle this at the b2tfs item level for fsType === 'file'?
605
+ if (binIbGib.data === undefined) { return undefined; }
678
606
 
679
607
  let fileData: Uint8Array;
680
608
  const dataObj = binIbGib.data as any;
@@ -697,156 +625,6 @@ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 implements
697
625
  fileData = new Uint8Array(0);
698
626
  }
699
627
 
700
-
701
628
  return { buffer: fileData, binIbGib };
702
629
  }
703
-
704
- private async getChildItemsMap({
705
- folderItem,
706
- space,
707
- readCache_graph,
708
- }: {
709
- folderItem?: B2tFSItemIbGib_V1;
710
- space: IbGibSpaceAny;
711
- readCache_graph?: FlatIbGibGraph;
712
- }): Promise<Map<string, B2tFSItemIbGib_V1>> {
713
- const map = new Map<string, B2tFSItemIbGib_V1>();
714
- if (!folderItem || !folderItem.rel8ns) { return map; }
715
- const childAddrs = folderItem.rel8ns[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
716
- for (const addr of childAddrs) {
717
- const childNode = await this.fetchIbGib({ addr, space, readCache_graph }) as B2tFSItemIbGib_V1;
718
- if (childNode && childNode.data?.name) {
719
- map.set(childNode.data.name, childNode);
720
- }
721
- }
722
- return map;
723
- }
724
-
725
- private async mergeTreeNodes({
726
- lcaItem,
727
- baseItem,
728
- orphanItem,
729
- space,
730
- readCache_graph,
731
- newGraftDnaIbGibs,
732
- newGraftedIntermediateIbGibs_ordered,
733
- }: {
734
- lcaItem?: B2tFSItemIbGib_V1;
735
- baseItem?: B2tFSItemIbGib_V1;
736
- orphanItem?: B2tFSItemIbGib_V1;
737
- space: IbGibSpaceAny;
738
- readCache_graph?: FlatIbGibGraph;
739
- newGraftDnaIbGibs: IbGib_V1[];
740
- newGraftedIntermediateIbGibs_ordered: IbGib_V1[];
741
- }): Promise<B2tFSItemIbGib_V1 | undefined> {
742
- const lc = `${lcFile}[${this.mergeTreeNodes.name}]`;
743
-
744
- const baseAddr = baseItem ? getIbGibAddr({ ibGib: baseItem }) : undefined;
745
- const orphanAddr = orphanItem ? getIbGibAddr({ ibGib: orphanItem }) : undefined;
746
-
747
- const lcaAddr = lcaItem ? getIbGibAddr({ ibGib: lcaItem }) : undefined;
748
-
749
- if (baseAddr && orphanAddr && baseAddr === orphanAddr) {
750
- return baseItem;
751
- }
752
-
753
- if (lcaAddr && baseAddr && baseAddr === lcaAddr && orphanItem) {
754
- return orphanItem;
755
- }
756
-
757
- if (lcaAddr && orphanAddr && orphanAddr === lcaAddr && baseItem) {
758
- return baseItem;
759
- }
760
-
761
- if (!baseItem && !orphanItem) {
762
- return undefined;
763
- }
764
-
765
- if (baseItem && !orphanItem) {
766
- if (lcaAddr && baseAddr === lcaAddr) {
767
- return undefined;
768
- }
769
- return baseItem;
770
- }
771
-
772
- if (orphanItem && !baseItem) {
773
- if (lcaAddr && orphanAddr === lcaAddr) {
774
- return undefined;
775
- }
776
- return orphanItem;
777
- }
778
-
779
- if (!baseItem || !orphanItem) {
780
- throw new Error(`(UNEXPECTED) baseItem or orphanItem missing in 3-way merge branch (E: 5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a)`);
781
- }
782
-
783
- const fsType = baseItem.data?.fsType || orphanItem.data?.fsType;
784
-
785
- if (fsType === 'file') {
786
- } else if (fsType === 'folder') {
787
- // const lcaChildrenMap = await this.getChildItemsMap({ folderItem: lcaItem, space, readCache_graph });
788
- // const baseChildrenMap = await this.getChildItemsMap({ folderItem: baseItem, space, readCache_graph });
789
- // const orphanChildrenMap = await this.getChildItemsMap({ folderItem: orphanItem, space, readCache_graph });
790
-
791
- // const allChildAddrs = new Set([
792
- // ...lcaChildrenMap.keys(),
793
- // ...baseChildrenMap.keys(),
794
- // ...orphanChildrenMap.keys(),
795
- // ]);
796
-
797
- // const mergedChildAddrs: string[] = [];
798
-
799
- // for (const childItemAddr of allChildAddrs) {
800
- // const childLCA = lcaChildrenMap.get(childItemAddr);
801
- // const childBase = baseChildrenMap.get(childItemAddr);
802
- // const childOrphan = orphanChildrenMap.get(childItemAddr);
803
-
804
- // const mergedChild = await this.mergeTreeNodes({
805
- // lcaItem: childLCA,
806
- // baseItem: childBase,
807
- // orphanItem: childOrphan,
808
- // space,
809
- // readCache_graph,
810
- // newGraftDnaIbGibs,
811
- // newGraftedIntermediateIbGibs_ordered,
812
- // });
813
-
814
-
815
- // if (mergedChild) {
816
- // mergedChildAddrs.push(getIbGibAddr({ ibGib: mergedChild }));
817
- // }
818
- // }
819
-
820
- // const currentChildAddrs = baseItem.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
821
- // const addrsChanged = mergedChildAddrs.length !== currentChildAddrs.length ||
822
- // mergedChildAddrs.some((addr, idx) => addr !== currentChildAddrs[idx]);
823
-
824
- // if (!addrsChanged) {
825
- // return baseItem;
826
- // }
827
-
828
- // const evolveRes = await evolveB2tFSItemIbGib({
829
- // existingItem: baseItem,
830
- // rel8nsToUpdate: {
831
- // [B2TFS_CHILD_ITEM_REL8N_NAME]: mergedChildAddrs,
832
- // },
833
- // rel8nsToRemove: {
834
- // [B2TFS_CHILD_ITEM_REL8N_NAME]: baseItem.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [],
835
- // },
836
- // });
837
-
838
- // if (evolveRes.dnas) { newGraftDnaIbGibs.push(...evolveRes.dnas); }
839
- // if (evolveRes.newIbGib) { newGraftedIntermediateIbGibs_ordered.push(evolveRes.newIbGib); }
840
- // if (space) {
841
- // await persistTransformResult({ resTransform: evolveRes, space });
842
- // await registerNewIbGib({ ibGib: evolveRes.newIbGib, space });
843
- // }
844
-
845
- // return evolveRes.newIbGib as B2tFSItemIbGib_V1;
846
- }
847
-
848
- return baseItem;
849
- }
850
630
  }
851
-
852
- export const B2tFSItem3WayMergeStrategy = B2tFS3WayGraftStrategy;