@ibgib/core-gib 0.1.41 → 0.1.43

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 (28) hide show
  1. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +2 -2
  2. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
  3. package/dist/sync/sync-conflict-text-merge.respec.d.mts +4 -1
  4. package/dist/sync/sync-conflict-text-merge.respec.d.mts.map +1 -1
  5. package/dist/sync/sync-conflict-text-merge.respec.mjs +314 -181
  6. package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
  7. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts +7 -0
  8. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts.map +1 -0
  9. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +252 -0
  10. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +1 -0
  11. package/dist/sync/sync-saga-coordinator.mjs +3 -3
  12. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  13. package/dist/test/mock-space.d.mts +1 -38
  14. package/dist/test/mock-space.d.mts.map +1 -1
  15. package/dist/test/mock-space.mjs +73 -78
  16. package/dist/test/mock-space.mjs.map +1 -1
  17. package/package.json +1 -1
  18. package/src/keystone/README.md +118 -0
  19. package/src/keystone/docs/architecture.md +30 -1
  20. package/src/sync/README.md +122 -5
  21. package/src/sync/docs/architecture.md +2 -2
  22. package/src/sync/{SYNC_TESTING.md → docs/testing.md} +113 -28
  23. package/src/sync/sync-conflict-adv-multitimelines.respec.mts +3 -3
  24. package/src/sync/sync-conflict-text-merge.respec.mts +326 -164
  25. package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +316 -0
  26. package/src/sync/sync-saga-coordinator.mts +4 -4
  27. package/src/test/mock-space.mts +72 -72
  28. package/src/sync/docs/verification.md +0 -43
@@ -16,5 +16,123 @@ Validation in this system is **Auditability**: to verify an identity (e.g., "Is
16
16
  3. **Hash-based**: Uses hash pre-imaging for quantum resistance (`hash-reveal-v1`).
17
17
  4. **Merkle Graphs**: Efficient communication by only transmitting missing graph nodes.
18
18
 
19
+ ## Challenge Pools
20
+
21
+ Keystones organize challenges into **pools** with specific purposes:
22
+
23
+ * **Default Pool**: General-purpose signing operations
24
+ * **Revoke Pool**: Permanent identity termination (one-time use, `verb: revoke`)
25
+ * **Manage Pool**: Structural changes like adding pools (`verb: manage`)
26
+ * **Foreign Pools**: Delegation to external identities (SSO-like workflows)
27
+
28
+ Each pool configuration specifies:
29
+ * **`poolId`**: Unique identifier within the keystone
30
+ * **`verb`**: Auto-routes operations (e.g., `revoke`, `manage`, `login`)
31
+ * **`replenishStrategy`**: `'top-up'` (reusable) or `'scorched-earth'` (burn after use)
32
+ * **`challengeCount`**: Number of hash challenges in the pool
33
+
34
+ ## Basic Usage
35
+
36
+ ### Genesis (Create Identity)
37
+
38
+ ```typescript
39
+ const keystone = await keystoneService.genesis({
40
+ masterSecret: "user-password",
41
+ configs: [
42
+ { poolId: 'default', challengeCount: 100, replenishStrategy: 'top-up' },
43
+ { poolId: 'revoke', verb: 'revoke', challengeCount: 10, replenishStrategy: 'scorched-earth' }
44
+ ],
45
+ metaspace,
46
+ space
47
+ });
48
+ ```
49
+
50
+ ### Sign a Claim
51
+
52
+ ```typescript
53
+ const signedKeystone = await keystoneService.sign({
54
+ latestKeystone: keystone,
55
+ claim: { action: 'login', timestamp: Date.now() },
56
+ masterSecret: "user-password",
57
+ poolId: 'default', // or use verb-based auto-routing
58
+ metaspace,
59
+ space
60
+ });
61
+ ```
62
+
63
+ ### Revoke Identity
64
+
65
+ ```typescript
66
+ await keystoneService.revoke({
67
+ latestKeystone: keystone,
68
+ reason: "Device compromised",
69
+ masterSecret: "user-password",
70
+ metaspace,
71
+ space
72
+ });
73
+ ```
74
+
75
+ ## Delegation via Foreign Pools
76
+
77
+ > [!IMPORTANT]
78
+ > **🔑 Foreign pools enable delegation** - Alice can grant Bob signing authority for specific operations.
79
+
80
+ Alice can delegate signing authority to Bob by adding his challenge pool:
81
+
82
+ ```typescript
83
+ const aliceWithBobPool = await keystoneService.addPools({
84
+ latestKeystone: aliceKeystone,
85
+ newPoolConfigs: [
86
+ {
87
+ poolId: 'bob-sso',
88
+ verb: 'login',
89
+ foreignServerUrl: 'https://bob-server.com',
90
+ challengeCount: 50
91
+ }
92
+ ],
93
+ masterSecret: aliceSecret,
94
+ metaspace,
95
+ space
96
+ });
97
+ ```
98
+
99
+ Now Bob can sign login claims on Alice's behalf, but only for operations using the `login` verb.
100
+
101
+ **Trust Model**:
102
+ - Alice validates Bob's pool **shape** when adding (via `validateChallengePool`)
103
+ - Bob never transmits his secrets
104
+ - Communication secured via TLS
105
+ - Bob can validate his pool section when Alice evolves keystone
106
+
107
+ ## Validation
108
+
109
+ To verify a keystone timeline:
110
+
111
+ 1. **Replay** from genesis to current frame
112
+ 2. **Verify** each proof's hash pre-images match challenges
113
+ 3. **Validate** challenge selection matches policy engine rules
114
+ 4. **Check** revocation status (if revoked, identity cannot evolve)
115
+
116
+ Validation helpers:
117
+ * `validateEvolution()`: Verifies transition from previous to current frame
118
+ * `validateKeystoneTimeline()`: Replays entire timeline from genesis
119
+
120
+ ## Integration with Sync
121
+
122
+ Keystones integrate with the sync protocol to provide **session identity**:
123
+
124
+ * **Session Keystones**: Ephemeral identities created per sync saga
125
+ * **Saga Binding**: Session keystone salted with `sagaId`
126
+ * **Signature Frames**: Each saga frame can be signed with session identity
127
+
128
+ > [!CAUTION]
129
+ > **🚧 Session identity integration is NOT yet functional.** See [sync README](file:../sync/README.md#session-identity-usesessionidentity) for current status.
130
+
19
131
  ## Implementation
132
+
20
133
  The v1 implementation creates a pure TypeScript, isomorphic, hash-based identity system. It is designed to be "Non-Evil" and "Graph-Native".
134
+
135
+ **Key Files**:
136
+ * [keystone-service-v1.mts](file:./keystone-service-v1.mts): Core service implementation
137
+ * [keystone-types.mts](file:./keystone-types.mts): TypeScript type definitions
138
+ * [keystone-helpers.mts](file:./keystone-helpers.mts): Utility functions
@@ -14,6 +14,33 @@
14
14
  * **Challenge Pool**: A collection of puzzles stored in each Keystone Frame.
15
15
  * **Constraint/Policy Engine**: Logic that determines *which* challenges must be solved to authorize a specific action (Binding, FIFO, Stochastic).
16
16
 
17
+ ### Foreign Pools (Delegation)
18
+
19
+ > [!IMPORTANT]
20
+ > **🔀 Keystones support delegation** by embedding challenges from external identities.
21
+
22
+ **Mechanism**:
23
+ * **Use Case**: Alice adds Bob's challenge pool to her keystone
24
+ * **Validation**: Alice validates Bob's pool **shape** when adding (via `validateChallengePool`)
25
+ * **Signing**: Bob can sign claims on Alice's behalf (limited by `verb` field)
26
+ * **Trust Model**:
27
+ - Bob never transmits secrets across network
28
+ - Communication secured via TLS
29
+ - Bob can validate his pool section when Alice evolves keystone
30
+ * **SSO Pattern**: Enables Single Sign-On workflows without shared secrets
31
+
32
+ **Configuration**:
33
+ ```typescript
34
+ {
35
+ poolId: 'bob-sso',
36
+ verb: 'login',
37
+ foreignServerUrl: 'https://bob-server.com',
38
+ challengeCount: 50
39
+ }
40
+ ```
41
+
42
+ See [KeystoneService_V1.addPools()](file:../keystone-service-v1.mts) for implementation.
43
+
17
44
  ## 3. Policy Engine (Selection & Mitigation)
18
45
 
19
46
  To prevent replay attacks by Man-in-the-Middle (MITM) actors, the challenges required to sign a frame are selected via a multi-layered pipeline:
@@ -45,7 +72,9 @@ Inputs: `LatestKeystone`, `Claim`, `MasterSecret`.
45
72
  1. **Auto-Routing**: Selects pool based on Verb (e.g., 'revoke').
46
73
  2. **Selection**: Runs Policy Engine.
47
74
  3. **Solving**: Generates solutions.
48
- 4. **Replenishment**: Adds new challenges (Top-Up) or burns them.
75
+ 4. **Replenishment**: Adds new challenges based on pool's `replenishStrategy`:
76
+ * **`'top-up'`**: Refills consumed challenges (default, reusable identity)
77
+ * **`'scorched-earth'`**: Burns challenges permanently (revocation, one-time operations)
49
78
 
50
79
  ### 5.3 Validate
51
80
  Inputs: `PreviousFrame`, `CurrentFrame`.
@@ -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
 
@@ -114,6 +114,8 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
114
114
  in: 'source',
115
115
  name: 'r1_alpha_v0_source', // should be auto-calculated?
116
116
  });
117
+ const alpha_tjpAddr =
118
+ getTjpAddr({ ibGib: r1_alpha_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
117
119
 
118
120
  // Create v1 (common) - will be synced to dest
119
121
  const r1_alpha_v1_source_common = await testTransformer.mut8({
@@ -121,8 +123,6 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
121
123
  strField: 'commonField',
122
124
  name: 'r1_alpha_v1_source_common'
123
125
  });
124
- const alpha_tjpAddr =
125
- getTjpAddr({ ibGib: r1_alpha_v0_source.ibGib, defaultIfNone: 'incomingAddr' })!;
126
126
 
127
127
  // #endregion r1 setup
128
128
 
@@ -170,7 +170,7 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
170
170
  });
171
171
 
172
172
  // Get alpha_v1_common from destSpace for Round 2
173
- const resGetDest = await getFromSpace({ space: destSpace, addr: alpha_tjpAddr });
173
+ const resGetDest = await getFromSpace({ space: destSpace, addr: r1_alpha_v1_source_common.addr });
174
174
  if (!resGetDest.success || !resGetDest.ibGibs || resGetDest.ibGibs.length === 0) {
175
175
  throw new Error(`Failed to retrieve alpha from destSpace after sync. (E: 40c67811eba14f729880a46dcbb65126)`);
176
176
  }