@ibgib/core-gib 0.1.28 → 0.1.30

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 (76) hide show
  1. package/.vscode/launch.json +17 -1
  2. package/dist/common/meta-stone/meta-stone-helper.d.mts.map +1 -1
  3. package/dist/common/meta-stone/meta-stone-helper.mjs +30 -12
  4. package/dist/common/meta-stone/meta-stone-helper.mjs.map +1 -1
  5. package/dist/common/meta-stone/meta-stone-types.d.mts +5 -2
  6. package/dist/common/meta-stone/meta-stone-types.d.mts.map +1 -1
  7. package/dist/sync/strategies/conflict-optimistic.d.mts +16 -0
  8. package/dist/sync/strategies/conflict-optimistic.d.mts.map +1 -1
  9. package/dist/sync/strategies/conflict-optimistic.mjs +28 -1
  10. package/dist/sync/strategies/conflict-optimistic.mjs.map +1 -1
  11. package/dist/sync/sync-conflict.respec.mjs +5 -5
  12. package/dist/sync/sync-conflict.respec.mjs.map +1 -1
  13. package/dist/sync/sync-helpers.d.mts +4 -4
  14. package/dist/sync/sync-helpers.d.mts.map +1 -1
  15. package/dist/sync/sync-helpers.mjs +12 -8
  16. package/dist/sync/sync-helpers.mjs.map +1 -1
  17. package/dist/sync/sync-innerspace-constants.respec.mjs +36 -36
  18. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  19. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +3 -1
  20. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  21. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +62 -9
  22. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  23. package/dist/sync/sync-innerspace.respec.mjs +45 -16
  24. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  25. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +0 -9
  26. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  27. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +25 -43
  28. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  29. package/dist/sync/sync-peer/sync-peer-v1.mjs +2 -2
  30. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  31. package/dist/sync/sync-saga-coordinator.d.mts +15 -10
  32. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  33. package/dist/sync/sync-saga-coordinator.mjs +304 -163
  34. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  35. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +3 -3
  36. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  37. package/dist/sync/sync-types.d.mts +12 -18
  38. package/dist/sync/sync-types.d.mts.map +1 -1
  39. package/dist/sync/sync-types.mjs +15 -21
  40. package/dist/sync/sync-types.mjs.map +1 -1
  41. package/dist/timeline/timeline-api.d.mts +12 -0
  42. package/dist/timeline/timeline-api.d.mts.map +1 -1
  43. package/dist/timeline/timeline-api.mjs +26 -0
  44. package/dist/timeline/timeline-api.mjs.map +1 -1
  45. package/dist/witness/space/inner-space/inner-space-v1.d.mts +19 -0
  46. package/dist/witness/space/inner-space/inner-space-v1.d.mts.map +1 -1
  47. package/dist/witness/space/inner-space/inner-space-v1.mjs +189 -30
  48. package/dist/witness/space/inner-space/inner-space-v1.mjs.map +1 -1
  49. package/dist/witness/space/inner-space/inner-space-v1.respec.mjs +9 -0
  50. package/dist/witness/space/inner-space/inner-space-v1.respec.mjs.map +1 -1
  51. package/dist/witness/space/space-helper.d.mts.map +1 -1
  52. package/dist/witness/space/space-helper.mjs +2 -1
  53. package/dist/witness/space/space-helper.mjs.map +1 -1
  54. package/package.json +2 -1
  55. package/src/common/meta-stone/meta-stone-helper.mts +25 -11
  56. package/src/common/meta-stone/meta-stone-types.mts +5 -2
  57. package/src/sync/README.md +4 -4
  58. package/src/sync/docs/architecture.md +6 -6
  59. package/src/sync/strategies/conflict-optimistic.mts +41 -4
  60. package/src/sync/sync-conflict.respec.mts +5 -5
  61. package/src/sync/sync-helpers.mts +13 -9
  62. package/src/sync/sync-innerspace-constants.respec.mts +39 -39
  63. package/src/sync/sync-innerspace-deep-updates.respec.mts +5 -5
  64. package/src/sync/sync-innerspace-dest-ahead.respec.mts +73 -9
  65. package/src/sync/sync-innerspace.respec.mts +17 -16
  66. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +23 -60
  67. package/src/sync/sync-peer/sync-peer-v1.mts +2 -2
  68. package/src/sync/sync-saga-coordinator.mts +231 -173
  69. package/src/sync/sync-saga-message/sync-saga-message-types.mts +3 -3
  70. package/src/sync/sync-types.mts +19 -26
  71. package/src/timeline/timeline-api.mts +51 -11
  72. package/src/witness/space/inner-space/inner-space-v1.mts +191 -29
  73. package/src/witness/space/inner-space/inner-space-v1.respec.mts +13 -0
  74. package/src/witness/space/space-helper.mts +3 -2
  75. package/test_output.log +0 -0
  76. package/tmp.md +170 -62
@@ -40,7 +40,7 @@ export interface SyncSagaMessageIbGib_V1 extends IbGib_V1<SyncSagaMessageData_V1
40
40
  /**
41
41
  * The "Hello" of the sync protocol.
42
42
  *
43
- * Exchanges knowledge vectors (what I have) and identity (who I am).
43
+ * Exchanges knowledge maps (what I have) and identity (who I am).
44
44
  */
45
45
  export interface SyncSagaMessageInitData_V1 extends SyncSagaMessageData_V1 {
46
46
  stage: typeof SyncStage.init;
@@ -51,7 +51,7 @@ export interface SyncSagaMessageInitData_V1 extends SyncSagaMessageData_V1 {
51
51
  *
52
52
  * IOW, this is a map of the starting and end points of an ibGib's timeline.
53
53
  */
54
- knowledgeVector: { [tjp: string]: IbGibAddr };
54
+ knowledgeMap: { [tjp: string]: IbGibAddr };
55
55
 
56
56
  /**
57
57
  * The Keystone Identity of the sender.
@@ -149,7 +149,7 @@ export interface SyncSagaMessageAckData_V1 extends SyncSagaMessageData_V1 {
149
149
  /**
150
150
  * Infos regarding ibgibs that the receiver (generator of this ack)
151
151
  * knows/believes that the sender does NOT have (after looking at knowledge
152
- * vector of sender).
152
+ * map of sender).
153
153
  *
154
154
  * This includes addrs that will correspond to the context.payloadAddrsDomain
155
155
  *
@@ -54,40 +54,34 @@ export function isValidSyncConflictStrategy(strategy: string): strategy is SyncC
54
54
  }
55
55
  // #endregion SyncConflictStrategy
56
56
 
57
- // #region SyncExecutionContext
58
- export const SYNC_EXECUTION_CONTEXT_SENDER = 'sender';
59
- export const SYNC_EXECUTION_CONTEXT_RECEIVER = 'receiver';
60
- export type SyncExecutionContext =
61
- | typeof SYNC_EXECUTION_CONTEXT_SENDER
62
- | typeof SYNC_EXECUTION_CONTEXT_RECEIVER
57
+ // #region SyncSagaFrameOrigin
58
+ export const SYNC_SAGA_FRAME_ORIGIN_SENDER = 'sender';
59
+ export const SYNC_SAGA_FRAME_ORIGIN_RECEIVER = 'receiver';
60
+ export type SyncSagaFrameOrigin =
61
+ | typeof SYNC_SAGA_FRAME_ORIGIN_SENDER
62
+ | typeof SYNC_SAGA_FRAME_ORIGIN_RECEIVER
63
63
  ;
64
64
  /**
65
- * if the current code execution is executing on the original sender (the
66
- * initiator of the sync saga operation) or the other party, the "receiver" (the
67
- * one responding).
65
+ * if the frame was created by the original sender (the initiator of the sync
66
+ * saga operation) or the other party, the "receiver" (the one responding).
68
67
  *
69
68
  * This is driven by looking at the latest value of `sagaFrame.data.n` value.
70
- *
71
- * NOTE: This is not to be confused with the sync saga context ibgib, which is
72
- * something else entirely. That is the transport wrapper ibgib around the saga.
73
- * this is strictly the enum for where the code is executing.
74
69
  */
75
- export const SyncExecutionContext = {
70
+ export const SyncSagaFrameOrigin = {
76
71
  /**
77
- * The current code is executing on the initial location that started the
78
- * sync.
72
+ * The frame was created on the initial location that started the sync.
79
73
  */
80
- sender: SYNC_EXECUTION_CONTEXT_SENDER,
74
+ sender: SYNC_SAGA_FRAME_ORIGIN_SENDER,
81
75
  /**
82
- * The current code is executing on the receiving end, which is either a
83
- * physically different location or is the logical "receiver" of an
84
- * in-memory sync execution.
76
+ * The frame was created on the receiving end, which is either a physically
77
+ * different location or is the logical "receiver" of an in-memory sync
78
+ * execution.
85
79
  */
86
- receiver: SYNC_EXECUTION_CONTEXT_RECEIVER,
87
- } satisfies { [key in SyncExecutionContext]: SyncExecutionContext };
88
- export const SYNC_EXECUTION_CONTEXT_VALID_VALUES = Object.values(SyncExecutionContext);
89
- export function isValidSyncExecutionContext(executionContext: string): executionContext is SyncExecutionContext {
90
- return SYNC_EXECUTION_CONTEXT_VALID_VALUES.includes(executionContext as SyncExecutionContext);
80
+ receiver: SYNC_SAGA_FRAME_ORIGIN_RECEIVER,
81
+ } satisfies { [key in SyncSagaFrameOrigin]: SyncSagaFrameOrigin };
82
+ export const SYNC_SAGA_FRAME_ORIGIN_VALID_VALUES = Object.values(SyncSagaFrameOrigin);
83
+ export function isValidSyncSagaFrameOrigin(sagaFrameOrigin: string): sagaFrameOrigin is SyncSagaFrameOrigin {
84
+ return SYNC_SAGA_FRAME_ORIGIN_VALID_VALUES.includes(sagaFrameOrigin as SyncSagaFrameOrigin);
91
85
  }
92
86
  // #endregion SyncConflictStrategy
93
87
 
@@ -113,7 +107,6 @@ export interface NextSagaFrameInfo_SagaComplete {
113
107
  export type NextSagaFrameInfo =
114
108
  NextSagaFrameInfo_Frame | NextSagaFrameInfo_SagaComplete;
115
109
 
116
-
117
110
  export interface HandleSagaResponseContextResult_Base {
118
111
  /**
119
112
  * if truthy, handling saga context failed, else it succeeded.
@@ -43,16 +43,16 @@ export interface Rel8nRemovalInfo {
43
43
 
44
44
  export interface CommonTimelineOptsSansSkipLock {
45
45
  /**
46
- * If true, dna will not be created when executing transforms.
47
- *
46
+ * If true, dna will not be created when executing transforms.
47
+ *
48
48
  * ## intent / driving use case
49
- *
50
- * We want to use the timeline api in working with the new sync saga code.
49
+ *
50
+ * We want to use the timeline api in working with the new sync saga code.
51
51
  * However, we do not want dna, because the sync saga should not be merged
52
52
  * and there should be no dynamic composition required from dna.
53
- *
54
- * But the default for this api should be for dna to be created, so we add
55
- * this negative flag.
53
+ *
54
+ * But the default for this api should be for dna to be created, so we add
55
+ * this negative flag.
56
56
  */
57
57
  noDna?: boolean,
58
58
  /**
@@ -173,16 +173,16 @@ export async function appendToTimeline({
173
173
  rel8nInfos: Rel8nInfo[],
174
174
  /**
175
175
  * if provided, will remove this rel8ns before appending {@link rel8nInfos}
176
- *
176
+ *
177
177
  * ## intent/driving use case
178
- *
178
+ *
179
179
  * we need to be able to clear out the existing rel8ns when evolving
180
180
  * `SyncSagaIbGib_V1`. This is not quite linkedRel8ns, rather, we just need
181
181
  * to clear out the message stones rel8n. The underlying {@link rel8}
182
182
  * transform already supports this via this:
183
- *
183
+ *
184
184
  * {@link TransformOpts_Rel8.rel8nsToRemoveByAddr}
185
- *
185
+ *
186
186
  * So these removal infos will translate to those `rel8nsToRemoveByAddr`.
187
187
  */
188
188
  rel8nRemovalInfos?: Rel8nRemovalInfo[],
@@ -1000,3 +1000,43 @@ export async function getHistory({
1000
1000
  if (logalot) { console.log(`${lc} complete.`); }
1001
1001
  }
1002
1002
  }
1003
+
1004
+ export async function getHistoryAddrs({
1005
+ timeline,
1006
+ getLatest,
1007
+ metaspace,
1008
+ space,
1009
+ }: {
1010
+ /**
1011
+ * The ibGib at the head of the timeline whose history you want to retrieve.
1012
+ */
1013
+ timeline: IbGib_V1,
1014
+ /**
1015
+ * if true, will first retrieve the latest ibgib in the {@link timeline} in
1016
+ * the given {@link space} if provided, else in the default local user space
1017
+ * according to the {@link metaspace}.
1018
+ */
1019
+ getLatest?: boolean,
1020
+ } & CommonTimelineOptsSansSkipLock): Promise<IbGibAddr[]> {
1021
+ const lc = `[${getHistoryAddrs.name}]`;
1022
+ try {
1023
+ if (logalot) { console.log(`${lc} starting... (I: c7a328b14018642138ebb47870c15626)`); }
1024
+
1025
+ const historyInfo = await getHistory({
1026
+ timeline,
1027
+ getLatest,
1028
+ includeDna: false,
1029
+ metaspace,
1030
+ space,
1031
+ });
1032
+
1033
+ const addrs = historyInfo.orderedPastIbGibs.map(x => getIbGibAddr({ ibGib: x }));
1034
+
1035
+ return addrs;
1036
+ } catch (error) {
1037
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1038
+ throw error;
1039
+ } finally {
1040
+ if (logalot) { console.log(`${lc} complete.`); }
1041
+ }
1042
+ }
@@ -1,6 +1,6 @@
1
1
  import { clone, extractErrorMsg, getUUID, groupBy, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
2
  import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
3
- import { getIbGibAddr, } from '@ibgib/ts-gib/dist/helper.mjs';
3
+ import { getIbAndGib, getIbGibAddr, } from '@ibgib/ts-gib/dist/helper.mjs';
4
4
  import { validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
5
5
 
6
6
  import { GLOBAL_LOG_A_LOT } from '../../../core-constants.mjs';
@@ -15,6 +15,10 @@ import { ReconciliationSpaceBase, ReconciliationSpaceData, ReconciliationSpaceRe
15
15
  import { DEFAULT_INNER_SPACE_DATA_V1, InnerSpaceData_V1, InnerSpaceRel8ns_V1 } from './inner-space-types.mjs';
16
16
  import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
17
17
  import { getGib } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
18
+ import { isMetaStone, newUpMetaStone, parseMetaStoneIb } from '../../../common/meta-stone/meta-stone-helper.mjs';
19
+ import { MetaStoneIbGib_V1, MetaStoneIbInfo } from '../../../common/meta-stone/meta-stone-types.mjs';
20
+ import { GIB } from '@ibgib/ts-gib/dist/V1/constants.mjs';
21
+ import { META_STONE_TARGET_REL8N_NAME } from '../../../common/meta-stone/meta-stone-constants.mjs';
18
22
 
19
23
  const logalot = GLOBAL_LOG_A_LOT;
20
24
 
@@ -53,6 +57,35 @@ export class InnerSpace_V1<
53
57
  */
54
58
  ibGibs: { [key: string]: TIbGib } = {};
55
59
 
60
+ /**
61
+ * Each tjp/timeline has its own map of metastones.
62
+ *
63
+ * NOTE: This is a map of maps.
64
+ */
65
+ ibGibMetastones: { [tjpOrStoneGib: string]: { [metastoneAddr: string]: MetaStoneIbGib_V1 } } = {};
66
+ /**
67
+ * all known metastone addrs for this innerspace
68
+ */
69
+ get metastoneAddrs(): IbGibAddr[] {
70
+ const resMetastones: IbGibAddr[] = [];
71
+ Object.values(this.ibGibMetastones).forEach(map => {
72
+ Object.keys(map)
73
+ .forEach(metastone => resMetastones.push(metastone));
74
+ });
75
+ return resMetastones;
76
+ }
77
+ /**
78
+ * all known metastone ibgibs for this innerspace
79
+ */
80
+ get metastoneIbGibs(): MetaStoneIbGib_V1[] {
81
+ const resMetastones: MetaStoneIbGib_V1[] = [];
82
+ Object.values(this.ibGibMetastones).forEach(map => {
83
+ Object.values(map)
84
+ .forEach(metastone => resMetastones.push(metastone));
85
+ });
86
+ return resMetastones;
87
+ }
88
+
56
89
  constructor(
57
90
  initialData: TData,
58
91
  initialRel8ns?: TRel8ns,
@@ -226,10 +259,30 @@ export class InnerSpace_V1<
226
259
  for (let i = 0; i < ibGibs?.length; i++) {
227
260
  const ibGib = ibGibs[i];
228
261
  const addr = getIbGibAddr({ ibGib });
229
- if (!Object.keys(this.ibGibs).includes(addr)) {
230
- this.ibGibs[addr] = ibGib;
262
+
263
+ if (isMetaStone({ ibGib })) {
264
+ const metastone = ibGib as unknown as MetaStoneIbGib_V1;
265
+ if (!metastone.data) { throw new Error(`(UNEXPECTED) ibGib is a metastone, but metastone.data falsy? (E: f3a05815c68821d564cb101821b91326)`); }
266
+ const { tjpGib } = metastone.data.targetData;
267
+ if (this.ibGibMetastones[tjpGib]) {
268
+ // has existing metastones for this timeline/stone
269
+ if (!Object.keys(this.ibGibMetastones[tjpGib]).includes(addr)) {
270
+ this.ibGibMetastones[tjpGib][addr] = metastone;
271
+ } else {
272
+ addrsAlreadyHave.push(addr);
273
+ }
274
+ } else {
275
+ // no existing metastones for this timeline/stone
276
+ this.ibGibMetastones[tjpGib] = {
277
+ [addr]: metastone,
278
+ };
279
+ }
231
280
  } else {
232
- addrsAlreadyHave.push(addr);
281
+ if (!Object.keys(this.ibGibs).includes(addr)) {
282
+ this.ibGibs[addr] = ibGib;
283
+ } else {
284
+ addrsAlreadyHave.push(addr);
285
+ }
233
286
  }
234
287
  }
235
288
  } catch (error) {
@@ -301,46 +354,155 @@ export class InnerSpace_V1<
301
354
  if (!arg.data) { throw new Error(`(UNEXPECTED) !arg.data? (E: 60869288f3deeff5d1dd93be5f4b8624)`); }
302
355
  if (!arg.data.ibGibAddrs) { throw new Error(`(UNEXPECTED) !arg.data.ibGibAddrs? (E: d62cfac462daacc5b2f50c7c3ae45d24)`); }
303
356
 
304
- // get all ibgibs in the space and group them by their tjp address
305
- const ibGibsInSpace = Object.values(this.ibGibs);
306
- const ibGibsInSpaceByTjp = groupBy({ items: ibGibsInSpace, keyFn: x => getTjpAddr({ ibGib: x })! });
307
-
308
- if (logalot) { console.log(`${lc} ibGibsInSpaceByTjp: ${pretty(ibGibsInSpaceByTjp)} (I: af9f88985b96822b68ad4928eb6f6a25)`); }
309
-
310
357
  const latestAddrsMap: { [addr: string]: IbGibAddr | null } = {};
311
358
 
312
- // iterate over each address we're looking for
359
+ // #region new impl with metastones
360
+
313
361
  for (const localAddr of arg.data.ibGibAddrs) {
362
+ if (isMetaStone({ addr: localAddr })) {
363
+ if (logalot) { console.log(`${lc} localAddr not found: ${localAddr} (I: 12c7668bbdb8e4a86ceb5f455eb00826)`); }
364
+ if (this.metastoneAddrs.includes(localAddr)) {
365
+ latestAddrsMap[localAddr] = localAddr;
366
+ } else {
367
+ if (logalot) { console.log(`${lc} metastone addr NOT found...what are we getting latest on metastone anyway? (I: 0e71b8a9234fcc93b8259578eb491626)`); }
368
+ latestAddrsMap[localAddr] = null;
369
+ }
370
+ continue;
371
+ }
314
372
  const localIbGib = this.ibGibs[localAddr];
315
373
  if (!localIbGib) {
374
+ if (logalot) { console.log(`${lc} localAddr not found: ${localAddr} (I: 12c7668bbdb8e4a86ceb5f455eb00826)`); }
316
375
  latestAddrsMap[localAddr] = null; // or handle as error/not found
317
376
  continue;
318
377
  }
319
378
 
320
- const tjpAddr = getTjpAddr({ ibGib: localIbGib });
321
- if (tjpAddr && ibGibsInSpaceByTjp[tjpAddr]) {
322
- // if we have a timeline for this tjp, find the latest
323
- const timeline = ibGibsInSpaceByTjp[tjpAddr];
379
+ // we have the ibgib, now see if we have any metastones for it.
380
+ const tjpAddr =
381
+ getTjpAddr({ ibGib: localIbGib, defaultIfNone: 'incomingAddr' }) ??
382
+ getIbGibAddr({ ibGib: localIbGib });
383
+ const { gib: tjpGib } = getIbAndGib({ ibGibAddr: tjpAddr });
384
+ // examine metastones
385
+ const metastoneMap = this.ibGibMetastones[tjpGib];
386
+ if (!metastoneMap) {
387
+ // no metastones for this, so there is no latest
388
+ latestAddrsMap[localAddr] = localAddr;
389
+ continue;
390
+ }
324
391
 
325
- if (timeline.some(ibGib => ibGib.data?.n === undefined)) {
326
- const filtered = timeline.filter(ibGib => ibGib.data?.n === undefined);
327
- console.warn(`${lc} timeline includes ibgibs with ibGib.data?.n === undefined.\nfiltered:\n${filtered.map(x => pretty(x)).join('\n')}}(W: 7360a8e81b05accf244fb4b86e796325)`);
328
- }
329
- // sort mutates array in place
330
- timeline.sort((a, b) => (a.data?.n ?? -1) > (b.data?.n ?? -1) ? 1 : -1); // sorts ascending, e.g., 0,1,2...[Highest]
392
+ // we DO have metastone(s) for this timeline/stone, so analyze
393
+ // these metastones and get the latest according to them
394
+
395
+ const metaStoneAddrs = Object.keys(metastoneMap);
396
+ if (metaStoneAddrs.length === 0) {
397
+ throw new Error(`(UNEXPECTED) we have a metastoneMap but no addrs? (E: 82a448407c08585f685a9b2543923826)`);
398
+ }
331
399
 
332
- // last one is the latest
333
- let latestInTimeline = timeline.at(-1);
334
- if (latestInTimeline) {
335
- latestAddrsMap[localAddr] = getIbGibAddr({ ibGib: latestInTimeline });
400
+ const metaStoneAddrsAndIbInfos: [IbGibAddr, MetaStoneIbInfo][] = metaStoneAddrs
401
+ .map(xAddr => [xAddr, getIbAndGib({ ibGibAddr: xAddr }).ib])
402
+ .map(([xAddr, metaStoneIb]) => [xAddr, parseMetaStoneIb({ ib: metaStoneIb })]);
403
+
404
+ /**
405
+ * sort mutates the actual array (shuffle sort I think), but
406
+ * we're storing it in a different variable name to be more
407
+ * explicit.
408
+ */
409
+ const metaStoneAddrsAndIbInfos_descending = metaStoneAddrsAndIbInfos.sort((a, b) => {
410
+ const [_aAddr, aInfo] = a;
411
+ const [_bAddr, bInfo] = b;
412
+ // we want the highest n, with tiebreaker going to
413
+ // timestampInTicks. if that's the same also, then what are we
414
+ // quibbling about?
415
+ if (aInfo.n > bInfo.n) {
416
+ return -1;
417
+ } else if (aInfo.n < bInfo.n) {
418
+ return 1;
419
+ } else if (aInfo.timestampInTicks > bInfo.timestampInTicks) {
420
+ return -1;
421
+ } else if (aInfo.timestampInTicks < bInfo.timestampInTicks) {
422
+ return 1;
336
423
  } else {
337
- latestAddrsMap[localAddr] = null;
424
+ // neither discriminator is different.
425
+ return 0;
338
426
  }
339
- } else {
340
- // if it has no tjp, it is its own latest if it exists
341
- latestAddrsMap[localAddr] = this.ibGibs[localAddr] ? localAddr : null;
427
+ });
428
+ if (logalot) {
429
+ console.log(`${lc} console.dir(metaStoneAddrsAndIbInfos_descending)... (I: 5ce425f199283e2185a2cc0801264826)`);
430
+ console.dir(metaStoneAddrsAndIbInfos_descending);
342
431
  }
432
+
433
+ // since we sorted into a descending order, the latest is the very
434
+ // first item. and we have already guaranteed that there is at
435
+ // least 1 in the array.
436
+ if (metaStoneAddrsAndIbInfos_descending.length === 0) { throw new Error(`(UNEXPECTED) metaStoneAddrsAndIbInfos_descending is empty? earlier in the function there should have been a check. did getMetaStoneAddrs return a populated list but no stones were found? (E: 63c035ebed77741f2330c7a625823f23)`); }
437
+
438
+ const [latestMetaStoneAddr, latestMetaStoneInfo] = metaStoneAddrsAndIbInfos_descending[0];
439
+ if (logalot) { console.log(`${lc} [latestMetaStoneAddr, latestMetaStoneInfo]: ${[latestMetaStoneAddr, latestMetaStoneInfo]} (I: 1307ca46b4abd62c7a30fe87c08fa923)`); }
440
+
441
+ let latestMetaStoneIbGib: MetaStoneIbGib_V1;
442
+ latestMetaStoneIbGib = metastoneMap[latestMetaStoneAddr];
443
+
444
+ // latestMetaStoneIbGib.rel8ns ensured via validation at this point
445
+ const latestMetaStoneRel8ns = latestMetaStoneIbGib.rel8ns!;
446
+ /**
447
+ * this is accurate as the punctiliar address that corresponds to
448
+ * the metastone.
449
+ *
450
+ * atow (11/2023) interface of rel8ns
451
+ * [META_STONE_TARGET_REL8N_NAME]: IbGibAddr[];
452
+ * [META_STONE_TARGET_TJP_REL8N_NAME]?: IbGibAddr[];
453
+ */
454
+ const latestAddr = latestMetaStoneRel8ns[META_STONE_TARGET_REL8N_NAME].at(0);
455
+ if (!latestAddr) { throw new Error(`metastone passed validation but latestMetaStoneRel8ns[META_STONE_TARGET_REL8N_NAME].at(0) is empty? (E: c188ec0089ad86efe4d925c118599d23)`); }
456
+
457
+ latestAddrsMap[localAddr] = latestAddr;
343
458
  }
459
+ // #region new impl with metastones
460
+
461
+
462
+ // #region old inefficient no metastones
463
+
464
+ // // wildly inefficient with a decent number of ibgibs
465
+ // // get all ibgibs in the space and group them by their tjp address
466
+ // const ibGibsInSpace = Object.values(this.ibGibs);
467
+ // const ibGibsInSpaceByTjp = groupBy({ items: ibGibsInSpace, keyFn: x => getTjpAddr({ ibGib: x })! });
468
+
469
+ // if (logalot) { console.log(`${lc} ibGibsInSpaceByTjp: ${pretty(ibGibsInSpaceByTjp)} (I: af9f88985b96822b68ad4928eb6f6a25)`); }
470
+
471
+
472
+ // // iterate over each address we're looking for
473
+ // for (const localAddr of arg.data.ibGibAddrs) {
474
+ // const localIbGib = this.ibGibs[localAddr];
475
+ // if (!localIbGib) {
476
+ // latestAddrsMap[localAddr] = null; // or handle as error/not found
477
+ // continue;
478
+ // }
479
+
480
+ // const tjpAddr = getTjpAddr({ ibGib: localIbGib });
481
+ // if (tjpAddr && ibGibsInSpaceByTjp[tjpAddr]) {
482
+ // // if we have a timeline for this tjp, find the latest
483
+ // const timeline = ibGibsInSpaceByTjp[tjpAddr];
484
+
485
+ // if (timeline.some(ibGib => ibGib.data?.n === undefined)) {
486
+ // const filtered = timeline.filter(ibGib => ibGib.data?.n === undefined);
487
+ // console.warn(`${lc} timeline includes ibgibs with ibGib.data?.n === undefined.\nfiltered:\n${filtered.map(x => pretty(x)).join('\n')}}(W: 7360a8e81b05accf244fb4b86e796325)`);
488
+ // }
489
+ // // sort mutates array in place
490
+ // timeline.sort((a, b) => (a.data?.n ?? -1) > (b.data?.n ?? -1) ? 1 : -1); // sorts ascending, e.g., 0,1,2...[Highest]
491
+
492
+ // // last one is the latest
493
+ // let latestInTimeline = timeline.at(-1);
494
+ // if (latestInTimeline) {
495
+ // latestAddrsMap[localAddr] = getIbGibAddr({ ibGib: latestInTimeline });
496
+ // } else {
497
+ // latestAddrsMap[localAddr] = null;
498
+ // }
499
+ // } else {
500
+ // // if it has no tjp, it is its own latest if it exists
501
+ // latestAddrsMap[localAddr] = this.ibGibs[localAddr] ? localAddr : null;
502
+ // }
503
+ // }
504
+
505
+ // #endregion old inefficient no metastones
344
506
 
345
507
  resultData.latestAddrsMap = latestAddrsMap;
346
508
  resultData.success = true;
@@ -201,4 +201,17 @@ await respecfully(sir, `[${InnerSpace_V1.name} specs]`, async () => {
201
201
 
202
202
  });
203
203
 
204
+ // await respecfully(sir, 'latest and metastone related', async () => {
205
+
206
+ // with the current innerspace implementation (01/26/2026), I am getting
207
+ // "latest already exist" warnings when calls to registerNewIbGib are
208
+ // called. this is because the initial implementation always gets the
209
+ // latest by brute forcing splitting ALL in-memory ibgibs by timelines,
210
+ // which is ridiculously inefficient. So I am adding metastone indexing
211
+ // to the innerspace.
212
+
213
+ //
214
+
215
+ // });
216
+
204
217
  });
@@ -979,7 +979,8 @@ export async function registerNewIbGib({
979
979
  } else {
980
980
  // not newer
981
981
  if (logalot) { console.log(`is not newer, so we don't need to do anything else. (I: 14c25dc3314748dc909d61b77eb64354)`) }
982
- console.warn(`${lc} incoming ibGib (${ibGibAddr}) has the same data.n value as another ibgib (${existingLatestAddr}), but different addresses. multiple branches for the same timeline? ignoring incoming ibGibAddr (W: 057baadca494473dabb26fb4fb879774)`)
982
+ debugger; // temp remove this...
983
+ console.warn(`${lc} incoming ibGib (${ibGibAddr}) is NOT NEWER than existing latest (${existingLatestAddr}). multiple branches for the same timeline? ignoring incoming ibGibAddr. n_ibGib: ${n_ibGib}. n_existingLatest: ${n_existingLatest}. space.ib: ${space.ib} (W: 057baadca494473dabb26fb4fb879774)`)
983
984
  return; /* <<<< returns early */
984
985
  }
985
986
  } else {
@@ -3434,7 +3435,7 @@ export function spaceNameIsValid(name: string): boolean {
3434
3435
 
3435
3436
  /**
3436
3437
  * wrapper for getting dependency graph from a space.
3437
- *
3438
+ *
3438
3439
  * NOTE: This calls the witness space with the command. This is NOT the
3439
3440
  * same as the logic helper in graph-helper.mts which performs the graph
3440
3441
  * traversal logic potentially in-memory or naively.
package/test_output.log CHANGED
Binary file