// #region Imports import { extractErrorMsg, getUUID, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs'; import { Factory_V1 as factory } from '@ibgib/ts-gib/dist/V1/factory.mjs'; import { ROOT } from '@ibgib/ts-gib/dist/V1/constants.mjs'; import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs'; import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs'; import { getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs"; import { mut8Timeline, appendToTimeline } from '@ibgib/core-gib/dist/timeline/timeline-api.mjs'; import { getTjpAddr } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs'; import { SyncSagaCoordinator } from '@ibgib/core-gib/dist/sync/sync-saga-coordinator.mjs'; import { GRAFT_BASE_REL8N_NAME, GRAFT_ORPHAN_REL8N_NAME, GRAFT_INFO_REL8N_NAME } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-constants.mjs'; import { SpaceGibApiBridge } from '../api/space-gib-api-bridge.mjs'; import { debugState, devLog, lc, setupDomainAndDelegateIdentities, runSyncPass, runSyncPassFromSpace, copyIdentitiesToSpace } from './common.mjs'; import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs'; // #endregion Imports // #region Module State interface Phase410State { domainI_initial?: KeystoneIbGib_V1; domainI_latest?: KeystoneIbGib_V1; remoteSpace?: any; alpha_tjpAddr?: string; beta_tjpAddr?: string; gamma_tjpAddr?: string; alpha_v0?: any; r2_alpha_v3_source_rel8beta?: any; r2_beta_v0_source?: any; } const state: Phase410State = {}; const TEST_REL8N_NAME = 'testrel8n'; // #endregion Module State // #region Phase 4.10B Setup export function init4_10bSetupButton(): void { const btn = document.getElementById('btn-4-10b-setup') as HTMLButtonElement | null; if (!btn) { return; } btn.addEventListener('click', async () => { try { btn.disabled = true; devLog('4.10B Setup: Setting up identities and preparing Round 1 & Round 2 divergence...'); const metaspace = await getGlobalMetaspace_waitIfNeeded(); const space = await metaspace.getLocalUserSpace({}) as any; if (!space) { throw new Error("No default space."); } const apiBridge = new SpaceGibApiBridge(); // 1. Create domain + delegate identities (DRY helper) await setupDomainAndDelegateIdentities({ masterSecret: 'test-sender-secret-phase4-10b', syncSalt: 'senderidentitysyncsaltphase4-10b', manageSalt: 'senderidentitymanagesaltphase4-10b', metaspace, space, apiBridge, phaseText: '4.10B' }); const domainI = debugState.domainI!; state.domainI_initial = domainI; state.domainI_latest = domainI; const domainAddr = getIbGibAddr({ ibGib: domainI }); // 2. Create the divergent "remote" space devLog('4.10B Setup: Creating temporary remote space...'); const remoteSpace = await metaspace.createNewLocalSpace({ opts: { allowCancel: false, spaceName: 'remote_space_4_10b', getFnPrompt: metaspace.getFnPrompt! } }) as any; await remoteSpace.initialized; state.remoteSpace = remoteSpace; // Copy user identity and delegate to remote space await copyIdentitiesToSpace({ domainI, metaspace, fromSpace: space, toSpace: remoteSpace }); // 3. Seed common history (Round 1) locally in default space devLog('4.10B Setup: Creating common history for alpha...'); const resRoot = await factory.firstGen({ parentIbGib: ROOT, ib: 'timeline_root_alpha_4_10b', data: { commonField: 'common field R1 val', label: 'AlphaRoot', random: Math.random() }, dna: true, nCounter: true, tjp: { uuid: true, timestamp: true } }); const alpha_v0 = resRoot.newIbGib; state.alpha_v0 = alpha_v0; await metaspace.persistTransformResult({ resTransform: resRoot, space }); await metaspace.registerNewIbGib({ ibGib: alpha_v0, space }); const alpha_tjpAddr = getTjpAddr({ ibGib: alpha_v0, defaultIfNone: 'incomingAddr' })!; state.alpha_tjpAddr = alpha_tjpAddr; // Copy alpha_v0 to remote space before it gets signed by the seeding sync await metaspace.persistTransformResult({ resTransform: resRoot, space: remoteSpace }); await metaspace.registerNewIbGib({ ibGib: alpha_v0, space: remoteSpace }); // Sync alpha_v0 to server immediately so server has it devLog('4.10B Setup: Seeding alpha_v0 to server...'); await runSyncPass({ domainIbGibs: [alpha_v0], passLabel: 'Seed alpha_v0', metaspace, space }); state.domainI_latest = debugState.domainI; devLog('4.10B Setup: ✓ alpha_v0 seeded on server.'); // Copy evolved delegate and domain tip to remoteSpace await copyIdentitiesToSpace({ domainI: debugState.domainI!, metaspace, fromSpace: space, toSpace: remoteSpace }); // 4. Create Round 2 Divergence: // Client (default space): Create beta, mutate alpha fieldA, relate alpha to beta const resBeta = await factory.firstGen({ parentIbGib: ROOT, ib: 'timeline_root_beta_4_10b', data: { fieldA: 'beta field A created on source', label: 'BetaRoot', random: Math.random() }, dna: true, nCounter: true, tjp: { uuid: true, timestamp: true } }); const beta_v0_source = resBeta.newIbGib; await metaspace.persistTransformResult({ resTransform: resBeta, space }); await metaspace.registerNewIbGib({ ibGib: beta_v0_source, space }); state.r2_beta_v0_source = beta_v0_source; const beta_tjpAddr = getTjpAddr({ ibGib: beta_v0_source, defaultIfNone: 'incomingAddr' })!; state.beta_tjpAddr = beta_tjpAddr; const r2_alpha_v1_source_sansBeta = await mut8Timeline({ timeline: alpha_v0, mut8Opts: { mut8Ib: alpha_v0.ib + '_r2client', dataToAddOrPatch: { fieldA: 'source_edit_r2' } }, metaspace, space, }); devLog(`r2_alpha_v1_source_sansBeta.gib: ${r2_alpha_v1_source_sansBeta.gib}`) betaAddr = getIbGibAddr({ ibGib: beta_v0_source }); const r2_alpha_v2_source_rel8dBeta = await appendToTimeline({ timeline: r2_alpha_v1_source_sansBeta, metaspace, space, rel8nInfos: [ { rel8nName: TEST_REL8N_NAME, ibGibs: [beta_v0_source] } ] }); state.r2_alpha_v3_source_rel8beta = r2_alpha_v2_source_rel8dBeta; devLog(`r2_alpha_v2_source_rel8dBeta.gib: ${r2_alpha_v2_source_rel8dBeta.gib}`) devLog('4.10B Setup: ✓ Created client Round 2 edits (alpha fieldA edit + relate beta).'); // Remote Space: Mutate alpha fieldB const r2_alpha_v1_remote = await mut8Timeline({ timeline: alpha_v0, mut8Opts: { mut8Ib: alpha_v0.ib + '_r2remote', dataToAddOrPatch: { fieldB: 'remote_edit_r2' } }, metaspace, space: remoteSpace, }); console.log(`alpha_v0: ${pretty(alpha_v0)}`) console.log(`r2_alpha_v1_remote: ${pretty(r2_alpha_v1_remote)}`) devLog(`r2_alpha_v1_remote.gib: ${r2_alpha_v1_remote.gib}`) // Sync remote Round 2 edit to server devLog('4.10B Setup: Pushing remote Round 2 edit to server...'); await runSyncPassFromSpace({ domainIbGibs: [r2_alpha_v1_remote], passLabel: 'Push remote Round 2 edit', metaspace, space: remoteSpace, primarySpace: space, domainI: debugState.domainI!, masterSecret: 'test-sender-secret-phase4-10b' }); state.domainI_latest = debugState.domainI; devLog('✓ 4.10B Setup Complete! Ready for 4.10B Sync (which runs Round 2, 3, and 4 in succession).'); btn.textContent = '✓ 4.10B Setup Complete'; const syncBtn = document.getElementById('btn-4-10b-sync') as HTMLButtonElement | null; if (syncBtn) { syncBtn.disabled = false; } } catch (error) { devLog(`✗ 4.10B Setup FAILED: ${extractErrorMsg(error)}`); console.error(error); btn.disabled = false; } }); } // #endregion Phase 4.10B Setup let gammaAddr: IbGibAddr | undefined = undefined; let betaAddr: IbGibAddr | undefined = undefined; // #region Phase 4.10B Sync Execution export function init4_10bSyncButton(): void { const btn = document.getElementById('btn-4-10b-sync') as HTMLButtonElement | null; if (!btn) { return; } btn.addEventListener('click', async () => { try { btn.disabled = true; devLog('4.10B Sync: Initiating WebSocket Sync for Round 2, 3, and 4 sequential evolution...'); let domainI = state.domainI_latest!; const remoteSpace = state.remoteSpace; const alpha_tjpAddr = state.alpha_tjpAddr!; const beta_tjpAddr = state.beta_tjpAddr!; const alpha_v0 = state.alpha_v0!; const metaspace = await getGlobalMetaspace_waitIfNeeded(); const space = await metaspace.getLocalUserSpace({}) as any; if (!space) { throw new Error("No default space."); } const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; const domainAddr = getIbGibAddr({ ibGib: state.domainI_initial! }); // ---------------------------------------------------- // #region Round 2 Sync // ---------------------------------------------------- devLog('4.10B Sync: Running Round 2 Sync (merging divergent alpha edits)...'); await runSyncPass({ domainIbGibs: [state.r2_alpha_v3_source_rel8beta], passLabel: 'Sync divergent alpha edits R2', metaspace, space }); state.domainI_latest = debugState.domainI; devLog('4.10B Sync: ✓ Round 2 Sync complete.'); // Copy evolved delegate and domain tip to remoteSpace await copyIdentitiesToSpace({ domainI: debugState.domainI!, metaspace, fromSpace: space, toSpace: remoteSpace }); // #endregion Round 2 Sync // ---------------------------------------------------- // #region Round 3 Divergence & Sync // ---------------------------------------------------- devLog('4.10B Sync: Preparing Round 3 divergence (multiple conflicting timelines)...'); // Client: Mutate alpha (fieldC), mutate beta (betaFieldA) const clientKV_R2 = await new SyncSagaCoordinator().getKnowledgeMap({ domainIbGibs: [state.r2_alpha_v3_source_rel8beta, state.r2_beta_v0_source], space, metaspace, }); const alpha_tipAddr_R2_client = clientKV_R2[alpha_tjpAddr]; const beta_tipAddr_R2_client = clientKV_R2[beta_tjpAddr]; const resGetAlphaClientR2 = await metaspace.get({ addr: alpha_tipAddr_R2_client!, space }); const resGetBetaClientR2 = await metaspace.get({ addr: beta_tipAddr_R2_client!, space }); const r3_alpha_v4_source = await mut8Timeline({ timeline: resGetAlphaClientR2.ibGibs![0], mut8Opts: { mut8Ib: alpha_v0.ib + '_r3client', dataToAddOrPatch: { fieldC: 'source_edit_r3' } }, metaspace, space, }); const r3_beta_v1_source = await mut8Timeline({ timeline: resGetBetaClientR2.ibGibs![0], mut8Opts: { mut8Ib: state.r2_beta_v0_source.ib + '_r3client', dataToAddOrPatch: { betaFieldA: 'source_beta_edit_r3' } }, metaspace, space, }); // Remote: Sync remote to latest merged tips, then mutate alpha (fieldD), mutate beta (betaFieldB) devLog('4.10B Sync: Updating remote space to latest merged tips...'); // Query remoteSpace for its latest tips to initiate sync const alphaLatestAddrRemoteR3 = await metaspace.getLatestAddr({ addr: alpha_tjpAddr, space: remoteSpace }); const resGetAlphaRemoteTipR3 = await metaspace.get({ addr: alphaLatestAddrRemoteR3!, space: remoteSpace }); const alphaRemoteTipR3 = resGetAlphaRemoteTipR3.ibGibs![0]; const domainIbGibsRemoteR3 = [alphaRemoteTipR3]; const betaLatestAddrRemoteR3 = await metaspace.getLatestAddr({ addr: beta_tjpAddr, space: remoteSpace }); if (betaLatestAddrRemoteR3) { const resGetBetaRemoteTipR3 = await metaspace.get({ addr: betaLatestAddrRemoteR3, space: remoteSpace }); domainIbGibsRemoteR3.push(resGetBetaRemoteTipR3.ibGibs![0]); } // Sync remote space to pull merged alpha and beta from server await runSyncPassFromSpace({ domainIbGibs: domainIbGibsRemoteR3, passLabel: 'Pull merged R2 tips to remoteSpace', metaspace, space: remoteSpace, primarySpace: space, domainI: debugState.domainI!, masterSecret: 'test-sender-secret-phase4-10b' }); state.domainI_latest = debugState.domainI; // Now mutate alpha (fieldD) and beta (betaFieldB) in remote space const remoteKV_R3 = await new SyncSagaCoordinator().getKnowledgeMap({ space: remoteSpace, metaspace, domainIbGibs: [alpha_v0, state.r2_beta_v0_source] }); const alpha_tipAddr_R2_remote = remoteKV_R3[alpha_tjpAddr]; const beta_tipAddr_R2_remote = remoteKV_R3[beta_tjpAddr]; const resGetAlphaRemoteR2 = await metaspace.get({ addr: alpha_tipAddr_R2_remote!, space: remoteSpace }); const resGetBetaRemoteR2 = await metaspace.get({ addr: beta_tipAddr_R2_remote!, space: remoteSpace }); const r3_alpha_v4_remote = await mut8Timeline({ timeline: resGetAlphaRemoteR2.ibGibs![0], mut8Opts: { mut8Ib: alpha_v0.ib + '_r3remote', dataToAddOrPatch: { fieldD: 'remote_edit_r3' } }, metaspace, space: remoteSpace, }); const r3_beta_v1_remote = await mut8Timeline({ timeline: resGetBetaRemoteR2.ibGibs![0], mut8Opts: { mut8Ib: state.r2_beta_v0_source.ib + '_r3remote', dataToAddOrPatch: { betaFieldB: 'remote_beta_edit_r3' } }, metaspace, space: remoteSpace, }); // Sync remote Round 3 edits to server devLog('4.10B Sync: Pushing remote Round 3 edits to server...'); await runSyncPassFromSpace({ domainIbGibs: [r3_alpha_v4_remote, r3_beta_v1_remote], passLabel: 'Push remote Round 3 edits', metaspace, space: remoteSpace, primarySpace: space, domainI: debugState.domainI!, masterSecret: 'test-sender-secret-phase4-10b' }); state.domainI_latest = debugState.domainI; // Sync Client Round 3 edits to server (merges client and server) devLog('4.10B Sync: Running Round 3 Client Sync (merging alpha & beta divergence)...'); await runSyncPass({ domainIbGibs: [r3_alpha_v4_source, r3_beta_v1_source], passLabel: 'Sync Client Round 3 edits', metaspace, space }); state.domainI_latest = debugState.domainI; devLog('4.10B Sync: ✓ Round 3 Sync complete.'); // Copy evolved delegate and domain tip to remoteSpace await copyIdentitiesToSpace({ domainI: debugState.domainI!, metaspace, fromSpace: space, toSpace: remoteSpace }); // #endregion Round 3 Divergence & Sync // ---------------------------------------------------- // #region Round 4 Divergence & Sync // ---------------------------------------------------- devLog('4.10B Sync: Preparing Round 4 divergence (post-graft chain edits & new timeline)...'); const clientKV_R3 = await new SyncSagaCoordinator().getKnowledgeMap({ space, metaspace, domainIbGibs: [alpha_v0, state.r2_beta_v0_source] }); const alpha_tipAddr_R3_client = clientKV_R3[alpha_tjpAddr]; const beta_tipAddr_R3_client = clientKV_R3[beta_tjpAddr]; const resGetAlphaClientR3 = await metaspace.get({ addr: alpha_tipAddr_R3_client!, space }); const resGetBetaClientR3 = await metaspace.get({ addr: beta_tipAddr_R3_client!, space }); // Client: Mutate alpha (fieldE), create gamma, relate alpha to gamma (v6), mutate alpha (fieldF). Mutate beta (betaFieldD). const r4_alpha_v5_source = await mut8Timeline({ timeline: resGetAlphaClientR3.ibGibs![0], mut8Opts: { mut8Ib: alpha_v0.ib + '_r4client_v5', dataToAddOrPatch: { fieldE: 'source_edit_r4_v5' } }, metaspace, space, }); // Create gamma const resGamma = await factory.firstGen({ parentIbGib: ROOT, ib: 'timeline_root_gamma_4_10b', data: { gammaField: 'gamma created on client', label: 'GammaRoot', random: Math.random() }, dna: true, nCounter: true, tjp: { uuid: true, timestamp: true } }); const gamma_v0_source = resGamma.newIbGib; await metaspace.persistTransformResult({ resTransform: resGamma, space }); await metaspace.registerNewIbGib({ ibGib: gamma_v0_source, space }); const gamma_tjpAddr = getTjpAddr({ ibGib: gamma_v0_source, defaultIfNone: 'incomingAddr' })!; state.gamma_tjpAddr = gamma_tjpAddr; // Relate alpha to gamma gammaAddr = getIbGibAddr({ ibGib: gamma_v0_source }); const r4_alpha_v6_source_rel8dGamma = await appendToTimeline({ timeline: r4_alpha_v5_source, metaspace, space, rel8nInfos: [ { rel8nName: TEST_REL8N_NAME, ibGibs: [gamma_v0_source] } ] }); // Mutate alpha again (fieldF) const r4_alpha_v7_source = await mut8Timeline({ timeline: r4_alpha_v6_source_rel8dGamma, mut8Opts: { mut8Ib: alpha_v0.ib + '_r4client_v7', dataToAddOrPatch: { fieldF: 'source_edit_r4_v7' } }, metaspace, space, }); // Mutate beta (betaFieldD) const r4_beta_v2_source = await mut8Timeline({ timeline: resGetBetaClientR3.ibGibs![0], mut8Opts: { mut8Ib: state.r2_beta_v0_source.ib + '_r4client_v2', dataToAddOrPatch: { betaFieldD: 'source_beta_edit_r4_v2' } }, metaspace, space, }); // Remote: Sync remote to latest merged tips, then mutate alpha (fieldG), mutate beta (betaFieldC) devLog('4.10B Sync: Updating remote space to Round 3 merged tips...'); // Query remoteSpace for its latest tips to initiate sync const alphaLatestAddrRemoteR4 = await metaspace.getLatestAddr({ addr: alpha_tjpAddr, space: remoteSpace }); const resGetAlphaRemoteTipR4 = await metaspace.get({ addr: alphaLatestAddrRemoteR4!, space: remoteSpace }); const alphaRemoteTipR4 = resGetAlphaRemoteTipR4.ibGibs![0]; const domainIbGibsRemoteR4 = [alphaRemoteTipR4]; const betaLatestAddrRemoteR4 = await metaspace.getLatestAddr({ addr: beta_tjpAddr, space: remoteSpace }); if (betaLatestAddrRemoteR4) { const resGetBetaRemoteTipR4 = await metaspace.get({ addr: betaLatestAddrRemoteR4, space: remoteSpace }); domainIbGibsRemoteR4.push(resGetBetaRemoteTipR4.ibGibs![0]); } await runSyncPassFromSpace({ domainIbGibs: domainIbGibsRemoteR4, passLabel: 'Pull merged R3 tips to remoteSpace', metaspace, space: remoteSpace, primarySpace: space, domainI: debugState.domainI!, masterSecret: 'test-sender-secret-phase4-10b' }); state.domainI_latest = debugState.domainI; // Mutate alpha (fieldG) and beta (betaFieldC) in remote space const remoteKV_R4 = await new SyncSagaCoordinator().getKnowledgeMap({ space: remoteSpace, metaspace, domainIbGibs: [alpha_v0, state.r2_beta_v0_source] }); const alpha_tipAddr_R3_remote = remoteKV_R4[alpha_tjpAddr]; const beta_tipAddr_R3_remote = remoteKV_R4[beta_tjpAddr]; const resGetAlphaRemoteR3 = await metaspace.get({ addr: alpha_tipAddr_R3_remote!, space: remoteSpace }); const resGetBetaRemoteR3 = await metaspace.get({ addr: beta_tipAddr_R3_remote!, space: remoteSpace }); const r4_alpha_v5_remote = await mut8Timeline({ timeline: resGetAlphaRemoteR3.ibGibs![0], mut8Opts: { mut8Ib: alpha_v0.ib + '_r4remote_v5', dataToAddOrPatch: { fieldG: 'remote_edit_r4_v5' } }, metaspace, space: remoteSpace, }); const r4_beta_v2_remote = await mut8Timeline({ timeline: resGetBetaRemoteR3.ibGibs![0], mut8Opts: { mut8Ib: state.r2_beta_v0_source.ib + '_r4remote_v2', dataToAddOrPatch: { betaFieldC: 'remote_beta_edit_r4_v2' } }, metaspace, space: remoteSpace, }); // Sync remote edits to server devLog('4.10B Sync: Pushing remote Round 4 edits to server...'); await runSyncPassFromSpace({ domainIbGibs: [r4_alpha_v5_remote, r4_beta_v2_remote], passLabel: 'Push remote Round 4 edits', metaspace, space: remoteSpace, primarySpace: space, domainI: debugState.domainI!, masterSecret: 'test-sender-secret-phase4-10b' }); state.domainI_latest = debugState.domainI; // Sync Client Round 4 edits to server (merges client and server final states) devLog('4.10B Sync: Running final Round 4 Client Sync (merging alpha, beta, and propagating gamma)...'); await runSyncPass({ domainIbGibs: [r4_alpha_v7_source, r4_beta_v2_source, gamma_v0_source], passLabel: 'Sync final Round 4 edits', metaspace, space }); state.domainI_latest = debugState.domainI; devLog('✓ 4.10B Sync: All rounds of divergent edits and merges complete!'); btn.textContent = '✓ 4.10B Sync Complete'; const checkBtn = document.getElementById('btn-4-10b-check') as HTMLButtonElement | null; if (checkBtn) { checkBtn.disabled = false; } // #endregion Round 4 Divergence & Sync } catch (error) { devLog(`✗ 4.10B Sync FAILED: ${extractErrorMsg(error)}`); console.error(error); btn.disabled = false; } }); } // #endregion Phase 4.10B Sync Execution // #region Phase 4.10B Check/Verification export function init4_10bCheckButton(): void { const btn = document.getElementById('btn-4-10b-check') as HTMLButtonElement | null; if (!btn) { return; } btn.addEventListener('click', async () => { try { btn.disabled = true; devLog('4.10B Check: Verifying multi-round merged timelines on client and server...'); const domainI = state.domainI_latest!; const alpha_tjpAddr = state.alpha_tjpAddr!; const beta_tjpAddr = state.beta_tjpAddr!; const gamma_tjpAddr = state.gamma_tjpAddr!; const metaspace = await getGlobalMetaspace_waitIfNeeded(); const space = await metaspace.getLocalUserSpace({}) as any; if (!space) { throw new Error("No default space."); } const domainAddr = getIbGibAddr({ ibGib: state.domainI_initial! }); // 1. Get Client tips const clientKV = await new SyncSagaCoordinator().getKnowledgeMap({ space, metaspace, domainIbGibs: [state.domainI_initial!] // Just a dummy domain to satisfy API or look up by root address }); // Get absolute tips from space const clientAlphaTipAddr = await metaspace.getLatestAddr({ addr: alpha_tjpAddr, space }); const clientBetaTipAddr = await metaspace.getLatestAddr({ addr: beta_tjpAddr, space }); const clientGammaTipAddr = await metaspace.getLatestAddr({ addr: gamma_tjpAddr, space }); if (!clientAlphaTipAddr || !clientBetaTipAddr || !clientGammaTipAddr) { throw new Error("Client space is missing timeline tips for Alpha, Beta, or Gamma."); } const resGetAlpha = await metaspace.get({ addr: clientAlphaTipAddr, space }); const resGetBeta = await metaspace.get({ addr: clientBetaTipAddr, space }); const alphaTip = resGetAlpha.ibGibs![0]; const betaTip = resGetBeta.ibGibs![0]; // Assertions for Alpha data values if (alphaTip.data?.fieldA !== 'source_edit_r2') { throw new Error(`Alpha fieldA mismatch! Expected 'source_edit_r2', got '${alphaTip.data?.fieldA}'`); } if (alphaTip.data?.fieldB !== 'remote_edit_r2') { throw new Error(`Alpha fieldB mismatch! Expected 'remote_edit_r2', got '${alphaTip.data?.fieldB}'`); } if (alphaTip.data?.fieldC !== 'source_edit_r3') { throw new Error(`Alpha fieldC mismatch! Expected 'source_edit_r3', got '${alphaTip.data?.fieldC}'`); } if (alphaTip.data?.fieldD !== 'remote_edit_r3') { throw new Error(`Alpha fieldD mismatch! Expected 'remote_edit_r3', got '${alphaTip.data?.fieldD}'`); } if (alphaTip.data?.fieldE !== 'source_edit_r4_v5') { throw new Error(`Alpha fieldE mismatch! Expected 'source_edit_r4_v5', got '${alphaTip.data?.fieldE}'`); } if (alphaTip.data?.fieldF !== 'source_edit_r4_v7') { throw new Error(`Alpha fieldF mismatch! Expected 'source_edit_r4_v7', got '${alphaTip.data?.fieldF}'`); } if (alphaTip.data?.fieldG !== 'remote_edit_r4_v5') { throw new Error(`Alpha fieldG mismatch! Expected 'remote_edit_r4_v5', got '${alphaTip.data?.fieldG}'`); } devLog('4.10B Check: ✓ Client Alpha merged tip contains all Round 2, 3, and 4 edits.'); // Assertions for Beta data values if (betaTip.data?.betaFieldA !== 'source_beta_edit_r3') { throw new Error(`Beta betaFieldA mismatch! Expected 'source_beta_edit_r3', got '${betaTip.data?.betaFieldA}'`); } if (betaTip.data?.betaFieldB !== 'remote_beta_edit_r3') { throw new Error(`Beta betaFieldB mismatch! Expected 'remote_beta_edit_r3', got '${betaTip.data?.betaFieldB}'`); } if (betaTip.data?.betaFieldC !== 'remote_beta_edit_r4_v2') { throw new Error(`Beta betaFieldC mismatch! Expected 'remote_beta_edit_r4_v2', got '${betaTip.data?.betaFieldC}'`); } if (betaTip.data?.betaFieldD !== 'source_beta_edit_r4_v2') { throw new Error(`Beta betaFieldD mismatch! Expected 'source_beta_edit_r4_v2', got '${betaTip.data?.betaFieldD}'`); } devLog('4.10B Check: ✓ Client Beta merged tip contains all Round 3 and 4 edits.'); // Verify alpha's relation to gamma const rels = alphaTip.rel8ns?.[TEST_REL8N_NAME] || []; if (!betaAddr) { throw new Error(`(UNEXPECTED) betaAddr falsy? (E: 81c032ae7a93bddfd8eed6664d314826)`); } if (!rels.includes(betaAddr)) { throw new Error("Client Alpha tip is missing relation to Beta timeline."); } if (!gammaAddr) { throw new Error(`(UNEXPECTED) gammaAddr falsy? (E: 12220a81d3b86385d1683d5a6bae5826)`); } if (!rels.includes(gammaAddr)) { throw new Error("Client Alpha tip is missing relation to Gamma timeline."); } devLog('4.10B Check: ✓ Client Alpha tip retains relation to Gamma.'); // 2. Check server tips const apiBridge = new SpaceGibApiBridge(); devLog('4.10B Check: Fetching server timeline graphs...'); const resServerGraphAlpha = await apiBridge.getIbGibGraph(domainAddr, clientAlphaTipAddr, true); const resServerGraphBeta = await apiBridge.getIbGibGraph(domainAddr, clientBetaTipAddr, true); if (!resServerGraphAlpha.success || !resServerGraphAlpha.graph || !resServerGraphBeta.success || !resServerGraphBeta.graph) { throw new Error("Failed to fetch merged graphs from server."); } const serverAlphaTip = resServerGraphAlpha.graph[clientAlphaTipAddr]; const serverBetaTip = resServerGraphBeta.graph[clientBetaTipAddr]; if (!serverAlphaTip || !serverBetaTip) { throw new Error("Server is missing the final merged tips for Alpha or Beta."); } if (serverAlphaTip.data?.fieldF !== 'source_edit_r4_v7' || serverAlphaTip.data?.fieldG !== 'remote_edit_r4_v5') { throw new Error("Server Alpha tip does not match final client merged state."); } if (serverBetaTip.data?.betaFieldC !== 'remote_beta_edit_r4_v2' || serverBetaTip.data?.betaFieldD !== 'source_beta_edit_r4_v2') { throw new Error("Server Beta tip does not match final client merged state."); } devLog('4.10B Check: ✓ Server tips match client merged states perfectly.'); devLog('✓ 4.10B Check SUCCESS: Advanced multi-round/timeline conflict resolved and verified on both client and server!'); btn.textContent = '✓ 4.10B Check Success'; } catch (error) { devLog(`✗ 4.10B Check FAILED: ${extractErrorMsg(error)}`); console.error(error); btn.disabled = false; } }); } // #endregion Phase 4.10B Check/Verification