@ibgib/core-gib 0.1.42 → 0.1.44

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 (88) hide show
  1. package/dist/keystone/kdf/kdf-constants.d.mts +25 -0
  2. package/dist/keystone/kdf/kdf-constants.d.mts.map +1 -0
  3. package/dist/keystone/kdf/kdf-constants.mjs +28 -0
  4. package/dist/keystone/kdf/kdf-constants.mjs.map +1 -0
  5. package/dist/keystone/kdf/kdf-helpers.d.mts +45 -0
  6. package/dist/keystone/kdf/kdf-helpers.d.mts.map +1 -0
  7. package/dist/keystone/kdf/kdf-helpers.mjs +94 -0
  8. package/dist/keystone/kdf/kdf-helpers.mjs.map +1 -0
  9. package/dist/keystone/kdf/kdf-types.d.mts +49 -0
  10. package/dist/keystone/kdf/kdf-types.d.mts.map +1 -0
  11. package/dist/keystone/kdf/kdf-types.mjs +2 -0
  12. package/dist/keystone/kdf/kdf-types.mjs.map +1 -0
  13. package/dist/keystone/keystone-config-builder.d.mts +65 -12
  14. package/dist/keystone/keystone-config-builder.d.mts.map +1 -1
  15. package/dist/keystone/keystone-config-builder.mjs +138 -46
  16. package/dist/keystone/keystone-config-builder.mjs.map +1 -1
  17. package/dist/keystone/keystone-config-builder.respec.mjs +21 -13
  18. package/dist/keystone/keystone-config-builder.respec.mjs.map +1 -1
  19. package/dist/keystone/keystone-constants.d.mts +15 -0
  20. package/dist/keystone/keystone-constants.d.mts.map +1 -1
  21. package/dist/keystone/keystone-constants.mjs +16 -0
  22. package/dist/keystone/keystone-constants.mjs.map +1 -1
  23. package/dist/keystone/keystone-helpers.d.mts +4 -4
  24. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  25. package/dist/keystone/keystone-helpers.mjs +8 -5
  26. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  27. package/dist/keystone/keystone-service-v1.d.mts +1 -1
  28. package/dist/keystone/keystone-service-v1.d.mts.map +1 -1
  29. package/dist/keystone/keystone-service-v1.mjs +6 -5
  30. package/dist/keystone/keystone-service-v1.mjs.map +1 -1
  31. package/dist/keystone/keystone-service-v1.respec.mjs +72 -45
  32. package/dist/keystone/keystone-service-v1.respec.mjs.map +1 -1
  33. package/dist/keystone/keystone-types.d.mts +28 -18
  34. package/dist/keystone/keystone-types.d.mts.map +1 -1
  35. package/dist/keystone/keystone-types.mjs +26 -15
  36. package/dist/keystone/keystone-types.mjs.map +1 -1
  37. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.d.mts.map +1 -1
  38. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs +7 -10
  39. package/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs.map +1 -1
  40. package/dist/sync/sync-conflict-text-merge.respec.mjs +26 -26
  41. package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
  42. package/dist/sync/sync-constants.d.mts +9 -0
  43. package/dist/sync/sync-constants.d.mts.map +1 -1
  44. package/dist/sync/sync-constants.mjs +10 -0
  45. package/dist/sync/sync-constants.mjs.map +1 -1
  46. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts +7 -0
  47. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts.map +1 -0
  48. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +282 -0
  49. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +1 -0
  50. package/dist/sync/sync-saga-coordinator.d.mts +22 -11
  51. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  52. package/dist/sync/sync-saga-coordinator.mjs +120 -27
  53. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  54. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +1 -7
  55. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  56. package/dist/sync/sync-types.d.mts +11 -0
  57. package/dist/sync/sync-types.d.mts.map +1 -1
  58. package/dist/sync/sync-types.mjs.map +1 -1
  59. package/dist/test/mock-space.d.mts +1 -38
  60. package/dist/test/mock-space.d.mts.map +1 -1
  61. package/dist/test/mock-space.mjs +73 -78
  62. package/dist/test/mock-space.mjs.map +1 -1
  63. package/package.json +1 -1
  64. package/src/keystone/README.md +119 -0
  65. package/src/keystone/docs/architecture.md +32 -1
  66. package/src/keystone/kdf/kdf-constants.mts +34 -0
  67. package/src/keystone/kdf/kdf-helpers.mts +105 -0
  68. package/src/keystone/kdf/kdf-types.mts +58 -0
  69. package/src/keystone/keystone-config-builder.mts +170 -47
  70. package/src/keystone/keystone-config-builder.respec.mts +21 -14
  71. package/src/keystone/keystone-constants.mts +21 -2
  72. package/src/keystone/keystone-helpers.mts +19 -14
  73. package/src/keystone/keystone-service-v1.mts +23 -22
  74. package/src/keystone/keystone-service-v1.respec.mts +71 -44
  75. package/src/keystone/keystone-types.mts +37 -23
  76. package/src/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mts +9 -13
  77. package/src/sync/README.md +122 -5
  78. package/src/sync/docs/architecture.md +2 -2
  79. package/src/sync/{SYNC_TESTING.md → docs/testing.md} +113 -28
  80. package/src/sync/sync-conflict-text-merge.respec.mts +25 -25
  81. package/src/sync/sync-constants.mts +12 -0
  82. package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +349 -0
  83. package/src/sync/sync-saga-coordinator.mts +158 -33
  84. package/src/sync/sync-saga-message/sync-saga-message-types.mts +1 -7
  85. package/src/sync/sync-types.mts +12 -0
  86. package/src/test/mock-space.mts +72 -72
  87. package/tmp.md +0 -274
  88. package/src/sync/docs/verification.md +0 -43
@@ -39,15 +39,132 @@ Init -> Ack -> Delta(s) -> Conflict/Commit via "ping pong" exchange.
39
39
  * For local-only syncs, the `SyncPeer_V1` implementation is responsible for moving verified `ibGibs` from the temporary saga space to the durable/persistent domain space.
40
40
  * From each endpoint's POV, the cleanup should remove the temp spaces used, in addition to any other required transaction cleanup (like closing any connections).
41
41
 
42
- ### Ephemeral Identity (`useSessionIdentity`)
42
+ ### Session Identity (`useSessionIdentity`)
43
+
43
44
  The sync protocol can optionally generate an ephemeral Keystone Identity for the duration of the saga.
44
- * **Purpose**: Allows secure, signed exchanges even if the Node doesn't have a long-lived identity, or wishes to isolate the sync session.
45
- * **Mechanism**: If `useSessionIdentity: true` (default) is passed to `sync()`, a new Keystone frame is generated and linked to the Saga.
46
- * **Pending Work**: Full verification of these ephemeral signatures is currently pending implementation.
45
+
46
+ **Purpose**: To allow secure, signed exchanges even if the Node doesn't have a long-lived identity, or to isolate the sync session security from master identity.
47
+
48
+ **Current Status**:
49
+ * ✅ Session keystone creation implemented ([getSessionIdentity()](file:./sync-saga-coordinator.mts#L328-L362))
50
+ * ✅ Keystone passed via Init message ([initData.identity](file:./sync-saga-message/sync-saga-message-types.mts#L75))
51
+ * ⚠️ **Signature generation/verification: NOT yet implemented**
52
+ * ⚠️ **Per-frame proof creation: NOT yet implemented**
53
+
54
+ **Usage**:
55
+ ```typescript
56
+ const { done } = await coordinator.sync({
57
+ peer,
58
+ domainIbGibs: [timeline],
59
+ localSpace,
60
+ metaspace,
61
+ useSessionIdentity: true, // Default, but currently non-functional
62
+ });
63
+ ```
64
+
65
+ > [!CAUTION]
66
+ > **🚧 Session identity is NOT working yet.** Tests explicitly set `useSessionIdentity: false` to avoid failures. See [sync-innerspace-dest-ahead-withid.respec.mts](file:./sync-innerspace-dest-ahead-withid.respec.mts) for the failing test case.
67
+
68
+ **Authentication/Authorization Hooks**:
69
+
70
+ Validation occurs in [SyncPeer_V1.witness()](file:./sync-peer/sync-peer-v1.mts#L129-L219):
71
+ 1. `validateContextAndSagaFrame()` - Intrinsic validation
72
+ 2. `authenticateContext()` - Verify identity (stub)
73
+ 3. `authorizeContext()` - Check permissions (stub)
74
+
75
+ ### Conflict Resolution via Grafting
76
+
77
+ > [!IMPORTANT]
78
+ > **🔀 When timelines diverge**, the sync protocol uses **grafting** to merge branches.
79
+
80
+ **Mechanism**:
81
+ 1. **Detect divergence** in Ack stage (tips differ, neither recognizes other's tip)
82
+ 2. **Exchange full timeline history** via `SyncSagaConflictInfo.receiverKnowledgeTimelineAddrs`
83
+ 3. **Find Latest Common Ancestor (LCA)**
84
+ 4. **Replay DNA transforms** from both branches
85
+ 5. **Create graft timeline** with merged result
86
+ 6. **Track via** `GraftInfoIbGib_V1` ([graft-info-types.mts](file:./graft-info/graft-info-types.mts))
87
+
88
+ **Conflict Info Tracking**:
89
+ * `graftInfoAddr`: Points to graft metadata
90
+ * `createdDnaAddrs`: DNA ibgibs created during merge
91
+ * `replayedDnaAddrs`: Original DNAs replayed
92
+ * `createdDomainAddrs`: Final timeline frames (in order)
93
+
94
+ See [graft-info-helpers.mts](file:./graft-info/graft-info-helpers.mts) for implementation.
95
+
96
+ ### Transaction Model (Temp Spaces)
97
+
98
+ > [!NOTE]
99
+ > **💾 Sync uses a two-phase commit pattern** with temporary spaces for atomic operations.
100
+
101
+ **Phases**:
102
+ 1. **Accumulation**: Domain ibgibs received during sync go to `tempSpace`
103
+ 2. **Commit**: On successful saga completion, verified ibgibs move to durable `localSpace`
104
+
105
+ **Rollback**: If saga fails, temp space cleanup discards unverified data.
106
+
107
+ **Lifecycle**:
108
+ * **Created**: `tempSpace = await metaspace.createNewLocalSpace()` at saga start
109
+ * **Destroyed**: Cleanup function runs in `sync()` finally block
110
+
111
+ **Why**: Ensures atomic sync - either all data validates and commits, or none does.
112
+
113
+
114
+ ## 🔒 Security Considerations
115
+
116
+ > [!WARNING]
117
+ > Session identity is **currently non-functional**. The mitigations below describe the intended security model.
118
+
119
+ ### Attack Vectors & Mitigations
120
+
121
+ | Attack Vector | Description | Mitigation |
122
+ |---------------|-------------|------------|
123
+ | **MITM Replay** | Attacker replays captured saga frames | • Frame signatures include timestamp<br>• Freshness checks reject old frames<br>• Challenge depletion prevents reuse<br>• sagaId deduplication |
124
+ | **Session Fixation** | Attacker pre-generates session keystone | • Session secret derived via KDF (strategy in keystone metadata)<br>• `sessionSecret = KDF(masterSecret, sagaId, strategy)` |
125
+ | **Identity Spoofing** | Impersonation via fake session keystone | • Session keystone includes `derivedFrom` master address<br>• Receiver validates master keystone is known/trusted |
126
+ | **Challenge Grinding** | Brute-force challenge solutions for target binding | • Hash pre-imaging computationally infeasible<br>• Stochastic selection adds randomness |
127
+ | **DoS (Pool Exhaustion)** | Excessive syncs deplete challenge pools | • Top-up replenishment refills challenges<br>• Rate limiting per identity<br>• Pool separation for critical ops |
128
+ | **Saga Hijacking** | Mid-flight frame injection | • All frames signed with session keystone<br>• `past` rel8n creates tamper-evident chain |
129
+
130
+ ### Cryptographic Primitives
131
+
132
+ * **Hash Function**: SHA-256 (content addressing, challenge generation)
133
+ * **Proof System**: Hash-reveal protocol (`hash-reveal-v1`)
134
+ * **Binding**: Target address → hex bucket → challenge selection
135
+ * **Entropy**: Stochastic challenge selection (anti-grinding)
136
+
137
+ ### Trust Model
138
+
139
+ **Session Keystones**:
140
+ - Ephemeral identity per sync saga
141
+ - Derived from master keystone + `sagaId`
142
+ - Validates via proof-of-work (solving challenges)
143
+ - Post-hoc audit trail: master can prove session authorship
144
+
145
+ **Propagation**:
146
+ - Sync does NOT rely on global PKI or certificate authorities
147
+ - Trust propagates through sync sessions (Alice syncs with Bob → Bob witnesses Alice's keystone)
148
+ - Revocation propagates same way (Alice revokes → syncs revocation to Bob → Bob sees revoked timeline)
149
+
150
+ **Threat Boundaries**:
151
+ - ✅ Protects against: MITM replay, impersonation, frame tampering
152
+ - ⚠️ Does NOT protect against: Compromised endpoint (live memory access during active session)
153
+ - ⚠️ Master secrets: Raw secrets should NOT stored; keystones master secrets to keystones should be derived secrets via key stretching passwords. raw secret files of course can drive these passwords and must be protected
154
+ - ⚠️ Transport security: Use TLS for network layer encryption (ibgib protocol provides authentication/integrity, not confidentiality)
155
+
156
+ ### Best Practices
157
+
158
+ 1. **Master Secret Protection**: Store master secrets in secure enclaves/keychains
159
+ 2. **Session Lifetime**: Limit saga duration, revoke sessions post-completion
160
+ 3. **Rate Limiting**: Implement per-identity sync rate limits
161
+ 4. **Freshness**: Reject frames older than 60 seconds
162
+ 5. **Audit Logs**: Persist saga timelines for post-hoc validation (saga timelines are ibgibs, so integrity is built-in via content addressing)
163
+ 6. **TLS**: Always use TLS for network transport (defense-in-depth)
47
164
 
48
165
  ## 📚 Documentation
49
166
  * **[Architecture](./docs/architecture.md)**: Detailed design of the Saga Protocol, State Machine, and Smart Diff logic.
50
- * **[Verification](./docs/verification.md)**: Test matrix, scenarios, and verification results.
167
+ * **[Testing & Verification](./docs/testing.md)**: Test strategy, verification matrix, and comprehensive testing guidelines.
51
168
 
52
169
  ## Features
53
170
  * **Symmetric Design**: No distinct "Client" or "Server" logic.
@@ -42,7 +42,7 @@ The `SyncSagaCoordinator` drives a Finite State Machine (FSM) via the `handleSag
42
42
 
43
43
  4. **Convergence (`handleDeltaFrame`)**:
44
44
  * Bob receives `Delta`.
45
- * **Verifies**: Checks hashes (`ib` vs `gib`) and signatures.
45
+ * **Verifies**: Checks content-address hashes (`ib` vs `gib`). ⚠️ Keystone signature verification pending.
46
46
  * **Merges**: Puts data into his local space.
47
47
  * Bob sends `Commit` frame.
48
48
 
@@ -65,5 +65,5 @@ The protocol supports two types of data:
65
65
  * **Stones (Constants)**: Immutable data without a history (e.g., Code lists, Configs). Syncing involves simple existence checks.
66
66
 
67
67
  ## 4. Security & Identity
68
- * **Session Keystone**: Each Saga typically generates an ephemeral identity to sign frames, linked to a master identity.
68
+ * **Session Keystone**: Each Saga can optionally generate an ephemeral identity to sign frames, linked to a master identity. ⚠️ **Currently non-functional** - see [README Session Identity section](file:../README.md#session-identity-usesessionidentity) for status.
69
69
  * **Trust Chain**: Each frame points to the previous one (`past` rel8n), creating a hash-linked chain of custody.
@@ -1,38 +1,116 @@
1
- # Sync Testing Guidelines
1
+ # Sync Protocol Testing & Verification
2
2
 
3
- 💣💥 USE THESE GUIDELINES TO MITIGATE COMPLEXITY EXPLOSION 💣💥
3
+ This document outlines the testing strategy, verification results, and comprehensive guidelines for testing the Symmetric Sync Protocol.
4
4
 
5
- Sync needs thorough testing and complexity increases exponentially. Ridiculously
6
- exponentially. I mean you won't believe just how vastly, hugely, mind-bogglingly
7
- fast...
5
+ 💣💥 **USE THESE GUIDELINES TO MITIGATE COMPLEXITY EXPLOSION** 💣💥
8
6
 
9
- ## Core Concepts
7
+ Sync needs thorough testing and complexity increases exponentially. Ridiculously exponentially. I mean you won't believe just how vastly, hugely, mind-bogglingly fast...
10
8
 
11
- ### Rounds
9
+ ---
10
+
11
+ ## Testing Strategy
12
+
13
+ We use `respec-gib` (a BDD-style framework) with **In-Memory Simulation (`InnerSpace`)** to verify logic. This allows us to test complex graph scenarios without network or disk I/O overhead.
14
+
15
+ ### Key Test Files
16
+
17
+ To see the most up-to-date test files for sync, search inside `libs/core-gib/src/sync` for `*.respec.mts` files.
18
+
19
+ **Basic Scenarios**:
20
+ * `sync-innerspace.respec.mts`: Basic Push/Pull scenarios
21
+ * `sync-innerspace-dest-ahead.respec.mts`: Receiver has newer data scenarios
22
+ * `sync-innerspace-multiple-timelines.respec.mts`: Multiple independent timelines in one saga
23
+ * `sync-innerspace-partial-update.respec.mts`: Smart diff verification (delta-only transfers)
24
+ * `sync-innerspace-deep-updates.respec.mts`: Timelines with extensive history (past link traversal)
25
+ * `sync-innerspace-constants.respec.mts`: Synchronization of stones (constants/non-TJPs)
26
+
27
+ **Conflict Resolution**:
28
+ * `sync-conflict-basic-divergence.respec.mts`: Single timeline divergence and merge
29
+ * `sync-conflict-basic-multitimelines.respec.mts`: Multiple timelines with conflicts
30
+ * `sync-conflict-adv-multitimelines.respec.mts`: Advanced multi-timeline, multi-round sync
31
+ * `sync-conflict-text-merge.respec.mts`: LCS-based text merging for `data.text` fields
32
+
33
+ **Identity & Security**:
34
+ * `sync-innerspace-dest-ahead-withid.respec.mts`: Session identity test (🚧 **currently failing**)
35
+
36
+ ---
37
+
38
+ ## Verification Matrix
39
+
40
+ ### 1. Basic Scenarios
41
+ | Feature | Description | Status | Test File |
42
+ | :--- | :--- | :--- | :--- |
43
+ | **Push** | Source syncs a new timeline to an empty Dest. | ✅ Verified | `sync-innerspace.respec.mts` |
44
+ | **Pull** | Dest requests data from Source (Reverse Sync). | ⏳ Pending | `sync-innerspace.respec.mts` |
45
+ | **Dest Ahead** | Dest has newer data; Source receives update. | ✅ Verified | `sync-innerspace-dest-ahead.respec.mts` |
46
+
47
+ ### 2. Complex Graph Scenarios
48
+ | Feature | Description | Status | Test File |
49
+ | :--- | :--- | :--- | :--- |
50
+ | **Multi-Timeline** | Syncing multiple separate timelines. | ✅ Verified | `sync-innerspace-multiple-timelines.respec.mts` |
51
+ | **Deep Updates** | Syncing deep dependency chains (Ancestors). | ✅ Verified | `sync-innerspace-deep-updates.respec.mts` |
52
+ | **Smart Diff** | Sender skips data Receiver already has. | ✅ Verified | `sync-innerspace-partial-update.respec.mts` |
53
+ | **Constants** | Syncing immutable stones (no TJP). | ✅ Verified | `sync-innerspace-constants.respec.mts` |
54
+
55
+ ### 3. Conflict Resolution & Edge Cases
56
+ | Feature | Description | Status | Test File |
57
+ | :--- | :--- | :--- | :--- |
58
+ | **Hash Validation** | Verifying integrity checks (ib/gib). | ✅ Verified | Built-in to all tests |
59
+ | **Basic Conflicts** | Divergent branches (single timeline). | ✅ Verified | `sync-conflict-basic-divergence.respec.mts` |
60
+ | **Multi-Timeline Conflicts** | Multiple timelines diverging. | ✅ Verified | `sync-conflict-basic-multitimelines.respec.mts` |
61
+ | **Advanced Conflicts** | Complex multi-round scenarios. | ✅ Verified | `sync-conflict-adv-multitimelines.respec.mts` |
62
+ | **Text Merge Conflicts** | LCS-based text merging. | ✅ Verified | `sync-conflict-text-merge.respec.mts` |
63
+
64
+ ### 4. Security & Identity
65
+ | Feature | Description | Status | Test File |
66
+ | :--- | :--- | :--- | :--- |
67
+ | **Session Keystones** | Ephemeral identity for sync sessions. | 🚧 **Non-functional** | `sync-innerspace-dest-ahead-withid.respec.mts` |
68
+
69
+ ---
70
+
71
+ ## Recent Verifications
72
+
73
+ ### Sync Constants (2026-01-08)
74
+ * **Goal**: Ensure constants (ibGibs without `tjp` or `past`) are synced.
75
+ * **Result**: ✅ Passed.
76
+ * **Fixes**: Updated `handleInitFrame` to request missing stones; updated `handleAckFrame` to include "tip" stones in payload even without dependencies.
77
+
78
+ ### Text Merge Conflicts (2026-01-14)
79
+ * **Goal**: Verify LCS-based text merging for divergent `data.text` fields.
80
+ * **Result**: ✅ Passed.
81
+ * **Implementation**: Uses Longest Common Subsequence algorithm for three-way merge.
82
+
83
+ ---
84
+
85
+ ## Testing Guidelines
86
+
87
+ ### Core Concepts
88
+
89
+ #### Rounds
12
90
 
13
91
  Tests are organized into **rounds**. Each round represents a complete cycle of:
14
92
  1. **State Setup**: Establish expected initial conditions
15
93
  2. **Actions**: Perform mutations, relations, and sync operations
16
94
  3. **Verification**: Assert final state expectations
17
95
 
18
- The **first round** is establishes common history between source and dest, and
19
- subsequent rounds perform one or more op(s) and sync(s).
96
+ The **first round** establishes common history between source and dest, and subsequent rounds perform one or more op(s) and sync(s).
20
97
 
21
- ### Broad Test Scenarios
98
+ #### Broad Test Scenarios
22
99
 
23
100
  Here are the broad category of ops that can occur to timelines WRT syncing:
24
101
  * **Fast-Forward (Source Ahead)**: Source has newer versions that dest lacks
25
102
  * **Fast-Forward (Dest Ahead)**: Dest has newer versions that source lacks
26
103
  * **Conflict**: Both source and dest have divergent edits from a common ancestor
27
104
  * **No Change**: Timeline exists on both sides with no edits
28
- * **Stones**: Stones are treated slightly differently in the sync engine right
29
- now, so these must also be tested in various permutations.
105
+ * **Stones**: Stones are treated slightly differently in the sync engine right now, so these must also be tested in various permutations.
106
+
107
+ ---
30
108
 
31
109
  ## Variable Naming Convention
32
110
 
33
111
  Variable names are a COMBINATION of BOTH snake_case AND camelCase:
34
112
 
35
- Format: `round_timeline_version_location_commentsHereInCamelCase_possiblyOtherComments`
113
+ **Format**: `round_timeline_version_location_commentsHereInCamelCase_possiblyOtherComments`
36
114
 
37
115
  ### Components
38
116
 
@@ -54,6 +132,8 @@ r1_delta_v1_source_createdInR1_rel8edFromAlpha // Round 1, delta v1 with multip
54
132
  r2_alpha_v4_dest_postConflict // Round 2, alpha v4 on dest, after conflict resolution
55
133
  ```
56
134
 
135
+ ---
136
+
57
137
  ## Test Structure
58
138
 
59
139
  ### File Organization
@@ -144,8 +224,7 @@ Pattern examples:
144
224
 
145
225
  * **`respecfully`**: Outer verification block per round with text "r{N} verify pre/post"
146
226
  * **`ifWeMight`**: Per-timeline verification within a round
147
- * NOTE: Graphs should be used for verification of sync, not individual addrs/ibgibs
148
- in most (all?) cases
227
+ * NOTE: Graphs should be used for verification of sync, not individual addrs/ibgibs in most (all?) cases
149
228
  * **`iReckon`**: Individual assertions
150
229
 
151
230
  Example:
@@ -163,15 +242,15 @@ await respecfully(sir, `r1 verify results`, async () => {
163
242
  });
164
243
  ```
165
244
 
245
+ ---
246
+
166
247
  ## Multiple Syncs Per Round
167
248
 
168
249
  A single round can have **multiple sync calls**. This is useful when:
169
250
  * Creating multiple timeline pairs (some on source, some on dest)
170
251
  * Testing specific sync scenarios in isolation
171
252
 
172
- Key principle: Verify **final state** at end of round, not intermediate states
173
- between syncs. We don't want to get bogged down trying to test every detail
174
- after every sync. The broad coverage should handle this.
253
+ Key principle: Verify **final state** at end of round, not intermediate states between syncs. We don't want to get bogged down trying to test every detail after every sync. The broad coverage should handle this.
175
254
 
176
255
  ```typescript
177
256
  // Round 1: Establish common history
@@ -187,6 +266,8 @@ await respecfully(sir, `r1 verify all timelines synced`, async () => {
187
266
  });
188
267
  ```
189
268
 
269
+ ---
270
+
190
271
  ## Domain-Level Focus
191
272
 
192
273
  Advanced tests focus on **domain-level correctness**, not protocol mechanics:
@@ -195,6 +276,8 @@ Advanced tests focus on **domain-level correctness**, not protocol mechanics:
195
276
  ❌ **Don't use**: `delay()` calls to control base/orphan selection
196
277
  ✅ **Do focus on**: Data field correctness, relation preservation, dependency completeness
197
278
 
279
+ ---
280
+
198
281
  ## Complexity Management
199
282
 
200
283
  ### Principles
@@ -207,14 +290,9 @@ Advanced tests focus on **domain-level correctness**, not protocol mechanics:
207
290
 
208
291
  ### Test Transformer
209
292
 
210
- Tests are making relatively arbitrary fork/mut8/rel8 calls. To help reduce
211
- implementation detail noise, the `TestTransformer` helper class was created.
212
-
213
- These methods return a `TestStepInfo` which itself has references to the `ibGib`
214
- and `addr`, as well as other metadata. So the variable
215
- `r2_alpha_v2_source_arbitraryMut8` does NOT reference an ibgib, rather, it
216
- references one of these test step info objects.
293
+ Tests are making relatively arbitrary fork/mut8/rel8 calls. To help reduce implementation detail noise, the `TestTransformer` helper class was created.
217
294
 
295
+ These methods return a `TestStepInfo` which itself has references to the `ibGib` and `addr`, as well as other metadata. So the variable `r2_alpha_v2_source_arbitraryMut8` does NOT reference an ibgib, rather, it references one of these test step info objects.
218
296
 
219
297
  ```typescript
220
298
  const r2_beta_v0_source = await testTransformer.create({
@@ -233,6 +311,8 @@ const r2_alpha_v2_source_arbitraryMut8 = await testTransformer.mut8({
233
311
 
234
312
  See `test-helpers.mts` and `test-types.mts` for implementations.
235
313
 
314
+ ---
315
+
236
316
  ## Scenarios to Test
237
317
 
238
318
  ### Basic Scenarios
@@ -248,9 +328,14 @@ See `test-helpers.mts` and `test-types.mts` for implementations.
248
328
  * **Reverse dependencies**: Timeline created on dest, source adds rel8n to it
249
329
  * **Removal conflicts**: Source removes rel8n while dest mut8s the rel8'd ibgib
250
330
  * **Chain edits**: Mutation → rel8 → mutation again on same timeline in one round
251
- * **Text edits**: Edit ibGib.data.text. If this is found to be different in
252
- divergent cases, then a special handler will try to merge the texts using
253
- basic text merging algorithm.
331
+ * **Text edits**: Edit `ibGib.data.text`. If divergent, uses LCS-based merge. See `sync-conflict-text-merge.respec.mts`.
332
+
333
+ ### Security Scenarios
334
+ * **Session identity creation**: Verify ephemeral keystone generation (🚧 pending implementation)
335
+ * **Signature verification**: (🚧 pending implementation)
336
+ * **Authorization checks**: Verify identity-based permissions (🚧 pending implementation)
337
+
338
+ ---
254
339
 
255
340
  ## Summary
256
341
 
@@ -148,7 +148,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
148
148
  });
149
149
  const r1_alpha_source_tipAddr = r1_alpha_sourceKV[alpha_tjpAddr];
150
150
  if (!r1_alpha_source_tipAddr) {
151
- ifWeMight(sir, 'r1_alpha_source_tipAddr is falsy?', async () => {
151
+ ifWe(sir, 'r1_alpha_source_tipAddr is falsy?', async () => {
152
152
  iReckon(sir, true).asTo('fail').isGonnaBeFalse();
153
153
  });
154
154
  return; /* <<<< returns early */
@@ -161,17 +161,17 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
161
161
  });
162
162
  const r1_alpha_dest_tipAddr = r1_alpha_destKV[alpha_tjpAddr];
163
163
  if (!r1_alpha_dest_tipAddr) {
164
- ifWeMight(sir, 'r1_alpha_dest_tipAddr is falsy?', async () => {
164
+ ifWe(sir, 'r1_alpha_dest_tipAddr is falsy?', async () => {
165
165
  iReckon(sir, true).asTo('fail').isGonnaBeFalse();
166
166
  });
167
167
  return; /* <<<< returns early */
168
168
  }
169
169
 
170
- await ifWeMight(sir, 'r1 tip addrs match', async () => {
170
+ await ifWe(sir, 'r1 tip addrs match', async () => {
171
171
  iReckon(sir, r1_alpha_source_tipAddr).asTo('R1 source/dest have same tip').isGonnaBe(r1_alpha_dest_tipAddr);
172
172
  });
173
173
 
174
- await ifWeMight(sir, 'r1 text synced correctly', async () => {
174
+ await ifWe(sir, 'r1 text synced correctly', async () => {
175
175
  if (!r1_alpha_dest_tipAddr) {
176
176
  throw new Error(`r1_dest_tipAddr is null/undefined (E: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d)`);
177
177
  }
@@ -181,7 +181,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
181
181
  iReckon(sir, destTipIbGib.data!.text).asTo('Dest has initial text').isGonnaBe(INITIAL_TEXT);
182
182
  });
183
183
 
184
- await ifWeMight(sir, 'r1 dep graphs synced', async () => {
184
+ await ifWe(sir, 'r1 dep graphs synced', async () => {
185
185
  const [r1_alpha_source_tip] = await getIbGibsFromCache_fallbackToSpaces({
186
186
  addrs: [r1_alpha_source_tipAddr],
187
187
  space: sourceSpace,
@@ -260,7 +260,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
260
260
  // #endregion r2 dest edits
261
261
 
262
262
  await respecfully(sir, `r2 verify pre`, async () => {
263
- await ifWeMight(sir, 'texts as expected', async () => {
263
+ await ifWe(sir, 'texts as expected', async () => {
264
264
  // before the sync, each side only has their edit. after the sync,
265
265
  // both sides should have both prepended and appended text
266
266
  iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha source has initial text').isGonnaBeTrue();
@@ -296,14 +296,14 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
296
296
  const kv_dest = await senderCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r1_alpha_v0_source.ibGib] });
297
297
  const r2_alpha_source_tipAddr = kv_source[alpha_tjpAddr];
298
298
  if (!r2_alpha_source_tipAddr) {
299
- await ifWeMight(sir, 'r2_alpha_source_tipAddr falsy?', async () => {
299
+ await ifWe(sir, 'r2_alpha_source_tipAddr falsy?', async () => {
300
300
  iReckon(sir, true).asTo('fails').isGonnaBe(false);
301
301
  });
302
302
  return; /* <<<< returns early */
303
303
  }
304
304
  const r2_alpha_dest_tipAddr = kv_dest[alpha_tjpAddr];
305
305
  if (!r2_alpha_dest_tipAddr) {
306
- await ifWeMight(sir, 'r2_alpha_dest_tipAddr falsy?', async () => {
306
+ await ifWe(sir, 'r2_alpha_dest_tipAddr falsy?', async () => {
307
307
  iReckon(sir, true).asTo('fails').isGonnaBe(false);
308
308
  });
309
309
  return; /* <<<< returns early */
@@ -317,11 +317,11 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
317
317
  space: sourceSpace,
318
318
  });
319
319
 
320
- await ifWeMight(sir, 'r2 tip addrs match', async () => {
320
+ await ifWe(sir, 'r2 tip addrs match', async () => {
321
321
  iReckon(sir, r2_alpha_source_tipAddr).asTo('alpha').isGonnaBe(r2_alpha_dest_tipAddr);
322
322
  });
323
323
 
324
- await ifWeMight(sir, 'r2 text merged correctly', async () => {
324
+ await ifWe(sir, 'r2 text merged correctly', async () => {
325
325
  // before the sync, each side only has their edit. after the sync,
326
326
  // both sides should have both prepended and appended text
327
327
  iReckon(sir, r2_alpha_v1_source_appendedText.ibGib.data?.text.includes(INITIAL_TEXT)).asTo('alpha source has initial text').isGonnaBeTrue();
@@ -340,7 +340,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
340
340
  iReckon(sir, text).asTo('R2 has both prepend and append').isGonnaBe(DEST_PREPEND + INITIAL_TEXT + SOURCE_APPEND);
341
341
  });
342
342
 
343
- await ifWeMight(sir, 'r2 dep graphs synced', async () => {
343
+ await ifWe(sir, 'r2 dep graphs synced', async () => {
344
344
  // alpha's full dep graph should exist on dest
345
345
  const depGraph_alpha_source = await getDependencyGraph({
346
346
  ibGib: r2_alpha_source_tip,
@@ -414,7 +414,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
414
414
  // // #endregion r3 dest edits
415
415
 
416
416
  // await respecfully(sir, `r3 verify pre`, async () => {
417
- // await ifWeMight(sir, 'dest has alpha after R2 graft', async () => {
417
+ // await ifWe(sir, 'dest has alpha after R2 graft', async () => {
418
418
  // const kv = await receiverCoordinator.getKnowledgeMap({ space: destSpace, metaspace, domainIbGibs: [r3_v0_graft_fromDest] });
419
419
  // iReckon(sir, !!kv[alpha_tjpAddr]).asTo('dest has tip').isGonnaBeTrue();
420
420
  // });
@@ -445,11 +445,11 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
445
445
  // const r3_tip_s = kv_s[alpha_tjpAddr];
446
446
  // const r3_tip_d = kv_d[alpha_tjpAddr];
447
447
 
448
- // await ifWeMight(sir, 'r3 tip addrs match', async () => {
448
+ // await ifWe(sir, 'r3 tip addrs match', async () => {
449
449
  // iReckon(sir, r3_tip_s).asTo('R3 tips match').isGonnaBe(r3_tip_d);
450
450
  // });
451
451
 
452
- // await ifWeMight(sir, 'r3 both paragraph edits merged', async () => {
452
+ // await ifWe(sir, 'r3 both paragraph edits merged', async () => {
453
453
  // const res = await getFromSpace({ space: sourceSpace, addr: r3_tip_s! });
454
454
  // const tip = res.ibGibs![0] as IbGib_V1<TestData>;
455
455
  // const mergedText = tip.data!.text!;
@@ -468,7 +468,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
468
468
  // .isGonnaBeTrue();
469
469
  // });
470
470
 
471
- // await ifWeMight(sir, 'r3 dep graphs synced', async () => {
471
+ // await ifWe(sir, 'r3 dep graphs synced', async () => {
472
472
  // const [d] = await getIbGibsFromCache_fallbackToSpaces({ addrs: [r3_tip_s!], space: destSpace });
473
473
  // iReckon(sir, d).asTo('exists dest').isGonnaBeTruthy();
474
474
  // });
@@ -502,7 +502,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
502
502
  // // #endregion r4 dest edits
503
503
 
504
504
  // await respecfully(sir, `r4 verify pre`, async () => {
505
- // await ifWeMight(sir, 'dest has alpha after R3 graft', async () => {
505
+ // await ifWe(sir, 'dest has alpha after R3 graft', async () => {
506
506
  // // TODO: Verify pre-sync state
507
507
  // });
508
508
  // });
@@ -512,16 +512,16 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
512
512
  // // TODO: Add sync operation
513
513
 
514
514
  // await respecfully(sir, `r4 verify post`, async () => {
515
- // await ifWeMight(sir, 'r4 tip addrs match', async () => {
515
+ // await ifWe(sir, 'r4 tip addrs match', async () => {
516
516
  // // TODO: Verify tips match
517
517
  // });
518
518
 
519
- // await ifWeMight(sir, 'r4 LCS merged both word changes', async () => {
519
+ // await ifWe(sir, 'r4 LCS merged both word changes', async () => {
520
520
  // // TODO: Verify text has both source and dest word changes
521
521
  // // TODO: Verify LCS algorithm preserved both edits correctly
522
522
  // });
523
523
 
524
- // await ifWeMight(sir, 'r4 dep graphs synced', async () => {
524
+ // await ifWe(sir, 'r4 dep graphs synced', async () => {
525
525
  // // TODO: Verify dep graphs
526
526
  // });
527
527
  // });
@@ -556,7 +556,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
556
556
  // // #endregion r5 dest edits
557
557
 
558
558
  // await respecfully(sir, `r5 verify pre`, async () => {
559
- // await ifWeMight(sir, 'dest has alpha after R4 graft', async () => {
559
+ // await ifWe(sir, 'dest has alpha after R4 graft', async () => {
560
560
  // // TODO: Verify pre-sync state
561
561
  // });
562
562
  // });
@@ -566,24 +566,24 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
566
566
  // // TODO: Add sync operation
567
567
 
568
568
  // await respecfully(sir, `r5 verify post`, async () => {
569
- // await ifWeMight(sir, 'r5 tip addrs match', async () => {
569
+ // await ifWe(sir, 'r5 tip addrs match', async () => {
570
570
  // // TODO: Verify tips match
571
571
  // });
572
572
 
573
- // await ifWeMight(sir, 'r5 text field merged', async () => {
573
+ // await ifWe(sir, 'r5 text field merged', async () => {
574
574
  // // TODO: Verify text field has both source and dest changes
575
575
  // });
576
576
 
577
- // await ifWeMight(sir, 'r5 description field merged', async () => {
577
+ // await ifWe(sir, 'r5 description field merged', async () => {
578
578
  // // TODO: Verify description field has both source and dest changes
579
579
  // });
580
580
 
581
- // await ifWeMight(sir, 'r5 both fields independently LCS-merged', async () => {
581
+ // await ifWe(sir, 'r5 both fields independently LCS-merged', async () => {
582
582
  // // TODO: Verify each field was merged independently
583
583
  // // TODO: Ensure one field's merge didn't affect the other
584
584
  // });
585
585
 
586
- // await ifWeMight(sir, 'r5 dep graphs synced', async () => {
586
+ // await ifWe(sir, 'r5 dep graphs synced', async () => {
587
587
  // // TODO: Verify dep graphs
588
588
  // });
589
589
  // });
@@ -1,3 +1,5 @@
1
+ import { ROOT_ADDR } from "@ibgib/ts-gib/dist/V1/constants.mjs";
2
+
1
3
  export const SYNC_ATOM = "sync";
2
4
 
3
5
  export const SYNC_MSG_REL8N_NAME = "syncmsg";
@@ -75,3 +77,13 @@ export function isValidSyncConflictStrategy(strategy: string): strategy is SyncC
75
77
  return SYNC_CONFLICT_STRATEGY_VALID_VALUES.includes(strategy as SyncConflictStrategy);
76
78
  }
77
79
  // #endregion SyncConflictStrategy
80
+
81
+ /**
82
+ * When synchronizing, the plan for identity integration is to create a session
83
+ * keystone. This keystone will have a primary pool, driven by the sender's
84
+ * secret, and a secondary delegated pool for use by the receiver. Initially,
85
+ * this will have a known, weak "secret" and it is the job of the receiver to
86
+ * use this to then change the keystone to use a secret chosen by the
87
+ * receiver's end.
88
+ */
89
+ export const DEFAULT_SESSION_IDENTITY_INITIAL_DELEGATE_SECRET = ROOT_ADDR;