@ibgib/core-gib 0.1.55 → 0.1.58

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 (134) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/dist/keystone/keystone-config-builder.d.mts +12 -1
  3. package/dist/keystone/keystone-config-builder.d.mts.map +1 -1
  4. package/dist/keystone/keystone-config-builder.mjs +58 -4
  5. package/dist/keystone/keystone-config-builder.mjs.map +1 -1
  6. package/dist/keystone/keystone-constants.d.mts +40 -5
  7. package/dist/keystone/keystone-constants.d.mts.map +1 -1
  8. package/dist/keystone/keystone-constants.mjs +39 -5
  9. package/dist/keystone/keystone-constants.mjs.map +1 -1
  10. package/dist/keystone/keystone-helpers.d.mts +11 -1
  11. package/dist/keystone/keystone-helpers.d.mts.map +1 -1
  12. package/dist/keystone/keystone-helpers.mjs +37 -1
  13. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  14. package/dist/keystone/keystone-policy-types.d.mts +23 -0
  15. package/dist/keystone/keystone-policy-types.d.mts.map +1 -0
  16. package/dist/keystone/keystone-policy-types.mjs +2 -0
  17. package/dist/keystone/keystone-policy-types.mjs.map +1 -0
  18. package/dist/sync/graft-info/graft-info-helpers.respec.mjs +8 -8
  19. package/dist/sync/graft-info/graft-info-helpers.respec.mjs.map +1 -1
  20. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +22 -22
  21. package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
  22. package/dist/sync/sync-conflict-basic-divergence.respec.mjs +3 -3
  23. package/dist/sync/sync-conflict-basic-divergence.respec.mjs.map +1 -1
  24. package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs +6 -6
  25. package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs.map +1 -1
  26. package/dist/sync/sync-conflict-text-merge.respec.mjs +26 -26
  27. package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
  28. package/dist/sync/sync-helpers.d.mts +19 -0
  29. package/dist/sync/sync-helpers.d.mts.map +1 -1
  30. package/dist/sync/sync-helpers.mjs +51 -1
  31. package/dist/sync/sync-helpers.mjs.map +1 -1
  32. package/dist/sync/sync-innerspace-constants.respec.mjs +2 -2
  33. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  34. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +2 -2
  35. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  36. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +4 -4
  37. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  38. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +2 -2
  39. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  40. package/dist/sync/sync-innerspace-partial-update.respec.mjs +3 -3
  41. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  42. package/dist/sync/sync-innerspace.respec.mjs +4 -4
  43. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  44. package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.d.mts +5 -0
  45. package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.d.mts.map +1 -1
  46. package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mjs +18 -0
  47. package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mjs.map +1 -1
  48. package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.d.mts +5 -0
  49. package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.d.mts.map +1 -1
  50. package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mjs +21 -3
  51. package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mjs.map +1 -1
  52. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +12 -0
  53. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  54. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +34 -0
  55. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  56. package/dist/sync/sync-peer/sync-peer-types.d.mts +69 -1
  57. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  58. package/dist/sync/sync-peer/sync-peer-v1.d.mts +30 -0
  59. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  60. package/dist/sync/sync-peer/sync-peer-v1.mjs +88 -1
  61. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  62. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.d.mts +30 -0
  63. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.d.mts.map +1 -0
  64. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mjs +2 -0
  65. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mjs.map +1 -0
  66. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts +66 -0
  67. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts.map +1 -0
  68. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs +280 -0
  69. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs.map +1 -0
  70. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts +85 -0
  71. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts.map +1 -0
  72. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs +332 -0
  73. package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -0
  74. package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.d.mts +29 -0
  75. package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.d.mts.map +1 -0
  76. package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.mjs +2 -0
  77. package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.mjs.map +1 -0
  78. package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts +42 -0
  79. package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts.map +1 -0
  80. package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs +282 -0
  81. package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs.map +1 -0
  82. package/dist/sync/sync-saga-coordinator.d.mts +35 -1
  83. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  84. package/dist/sync/sync-saga-coordinator.mjs +62 -1
  85. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  86. package/dist/sync/sync-withid.connect.respec.d.mts +12 -0
  87. package/dist/sync/sync-withid.connect.respec.d.mts.map +1 -0
  88. package/dist/sync/sync-withid.connect.respec.mjs +205 -0
  89. package/dist/sync/sync-withid.connect.respec.mjs.map +1 -0
  90. package/dist/sync/sync-withid.establish.respec.d.mts +19 -0
  91. package/dist/sync/sync-withid.establish.respec.d.mts.map +1 -0
  92. package/dist/sync/sync-withid.establish.respec.mjs +322 -0
  93. package/dist/sync/sync-withid.establish.respec.mjs.map +1 -0
  94. package/package.json +1 -1
  95. package/src/keystone/keystone-config-builder.mts +73 -4
  96. package/src/keystone/keystone-constants.mts +42 -6
  97. package/src/keystone/keystone-helpers.mts +44 -2
  98. package/src/keystone/keystone-policy-types.mts +25 -0
  99. package/src/keystone/keystone-policy.schema.json +51 -0
  100. package/src/keystone/keystone-service-v1.mts +3 -3
  101. package/src/sync/README.md +1 -104
  102. package/src/sync/docs/architecture.md +28 -8
  103. package/src/sync/docs/security.md +380 -0
  104. package/src/sync/graft-info/graft-info-helpers.respec.mts +7 -7
  105. package/src/sync/sync-conflict-adv-multitimelines.respec.mts +21 -21
  106. package/src/sync/sync-conflict-basic-divergence.respec.mts +2 -2
  107. package/src/sync/sync-conflict-basic-multitimelines.respec.mts +5 -5
  108. package/src/sync/sync-conflict-text-merge.respec.mts +25 -25
  109. package/src/sync/sync-helpers.mts +51 -1
  110. package/src/sync/sync-innerspace-constants.respec.mts +1 -1
  111. package/src/sync/sync-innerspace-deep-updates.respec.mts +1 -1
  112. package/src/sync/sync-innerspace-dest-ahead.respec.mts +3 -3
  113. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +1 -1
  114. package/src/sync/sync-innerspace-partial-update.respec.mts +2 -2
  115. package/src/sync/sync-innerspace.respec.mts +3 -3
  116. package/src/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mts +20 -0
  117. package/src/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mts +23 -3
  118. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +38 -1
  119. package/src/sync/sync-peer/sync-peer-types.mts +70 -1
  120. package/src/sync/sync-peer/sync-peer-v1.mts +94 -1
  121. package/src/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mts +36 -0
  122. package/src/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mts +337 -0
  123. package/src/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +388 -0
  124. package/src/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.mts +35 -0
  125. package/src/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mts +321 -0
  126. package/src/sync/sync-saga-coordinator.mts +84 -0
  127. package/src/sync/sync-withid.connect.respec.mts +243 -0
  128. package/src/sync/sync-withid.establish.respec.mts +361 -0
  129. package/src/sync/unused-identity-backup.mts.md +1 -1
  130. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts +0 -2
  131. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts.map +0 -1
  132. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +0 -310
  133. package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +0 -1
  134. package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +0 -364
@@ -0,0 +1,51 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "KeystonePolicyConfigTemplate",
4
+ "type": "object",
5
+ "properties": {
6
+ "behaviorProfiles": {
7
+ "type": "object",
8
+ "additionalProperties": {
9
+ "type": "object",
10
+ "properties": {
11
+ "size": { "type": "integer", "minimum": 1 },
12
+ "replenish": { "type": "string", "enum": ["top-up", "replace-all", "consume", "delete-all"] },
13
+ "selectSequentially": { "type": "integer", "minimum": 0 },
14
+ "selectRandomly": { "type": "integer", "minimum": 0 },
15
+ "targetBindingChars": { "type": "integer", "minimum": 0 }
16
+ },
17
+ "required": ["size", "replenish", "selectSequentially", "selectRandomly", "targetBindingChars"]
18
+ }
19
+ },
20
+ "pools": {
21
+ "type": "object",
22
+ "additionalProperties": {
23
+ "type": "object",
24
+ "properties": {
25
+ "id": { "type": "string" },
26
+ "allowedVerbs": {
27
+ "type": "array",
28
+ "items": { "type": "string" }
29
+ },
30
+ "behaviorProfile": { "type": "string" },
31
+ "behaviorInline": {
32
+ "type": "object",
33
+ "properties": {
34
+ "size": { "type": "integer", "minimum": 1 },
35
+ "replenish": { "type": "string", "enum": ["top-up", "replace-all", "consume", "delete-all"] },
36
+ "selectSequentially": { "type": "integer", "minimum": 0 },
37
+ "selectRandomly": { "type": "integer", "minimum": 0 },
38
+ "targetBindingChars": { "type": "integer", "minimum": 0 }
39
+ },
40
+ "required": ["size", "replenish", "selectSequentially", "selectRandomly", "targetBindingChars"]
41
+ },
42
+ "algo": { "type": "string", "enum": ["SHA-256", "SHA-512"] },
43
+ "rounds": { "type": "integer", "minimum": 1 },
44
+ "type": { "type": "string", "enum": ["hash-reveal-v1"] }
45
+ },
46
+ "required": ["id", "allowedVerbs", "algo", "rounds"]
47
+ }
48
+ }
49
+ },
50
+ "required": ["pools"]
51
+ }
@@ -256,10 +256,10 @@ export class KeystoneService_V1 {
256
256
 
257
257
  /**
258
258
  * Retrieves the latest keystone frame for the given address.
259
- *
259
+ *
260
260
  * Uses `metaspace.getLatestAddr` to find the actual tip instead of trusting
261
261
  * an incoming payload's `past` rel8n.
262
- *
262
+ *
263
263
  * @see `ibgib-get-pattern` SKILL.md
264
264
  */
265
265
  async getLatestKeystone({
@@ -274,7 +274,7 @@ export class KeystoneService_V1 {
274
274
  const lc = `${this.lc}[${this.getLatestKeystone.name}]`;
275
275
  try {
276
276
  if (logalot) { console.log(`${lc} starting...`); }
277
-
277
+
278
278
  const latestAddr = await metaspace.getLatestAddr({ tjpAddr: addr, space });
279
279
  if (!latestAddr) {
280
280
  throw new Error(`could not find latest addr for ${addr}`);
@@ -20,7 +20,6 @@ Init -> Ack -> Delta(s) -> Conflict/Commit via "ping pong" exchange.
20
20
 
21
21
  1. **Init**: Sender initiates sync.
22
22
  * Creates the `SyncSagaIbGib_V1` with an `Init` msg frame containing knowledge about domain ibgibs to sync.
23
- * Optionally creates session keystone based off of Sender's primary keystone.
24
23
  * Wraps the saga ibgib in a `SyncSagaContextIbGib_V1` and passes to the `SyncPeer_V1`.
25
24
  2. **Ack**: Receiver gets incoming `SyncSagaContextIbGib_V1` and passes to its `SyncSagaCoordinator`.
26
25
  * Handles the `Init` frame, comparing knowledge with Receiver's own status of each timeline/stone in domain ibgibs.
@@ -34,44 +33,11 @@ Init -> Ack -> Delta(s) -> Conflict/Commit via "ping pong" exchange.
34
33
  * `SyncPeer_V1.payloadIbGibsDomainReceived$` is an observable for the actual domain payload ibgibs transmitted.
35
34
  * So the a node sends domain payloads out in bulk to the `SyncPeer_V1`, receives the return saga ibgib with a manifest, but may have to wait for the observable to complete to actually process the ibgibs.
36
35
  * `Delta` frame can include `requests` (e.g., asking for missing conflict history).
37
- * Once no deltas required, `Delta` frame sets `proposeCommit` flag. If the other has nothing to add, the session transitions to `Commit`.
36
+ * Once no deltas required, `Delta` frame sets `proposeCommit` flag. If the other has nothing to add, the saga transitions to `Commit`.
38
37
  4. **Commit**: When receive `Delta` frame with `proposeCommit`, should trigger the receiver of this to start its commit. If that is successful, it should return a `Commit` frame, which signals the commit was successful on their end. When this `Commit` frame is received, this end should not perform its own commit.
39
38
  * 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
39
  * 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
40
 
42
- ### Session Identity (`useSessionIdentity`)
43
-
44
- The sync protocol can optionally generate an ephemeral Keystone Identity for the duration of the saga.
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
41
  ### Conflict Resolution via Grafting
76
42
 
77
43
  > [!IMPORTANT]
@@ -110,58 +76,6 @@ See [graft-info-helpers.mts](file:./graft-info/graft-info-helpers.mts) for imple
110
76
 
111
77
  **Why**: Ensures atomic sync - either all data validates and commits, or none does.
112
78
 
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)
164
-
165
79
  ## 📚 Documentation
166
80
  * **[Architecture](./docs/architecture.md)**: Detailed design of the Saga Protocol, State Machine, and Smart Diff logic.
167
81
  * **[Testing & Verification](./docs/testing.md)**: Test strategy, verification matrix, and comprehensive testing guidelines.
@@ -175,20 +89,3 @@ See [graft-info-helpers.mts](file:./graft-info/graft-info-helpers.mts) for imple
175
89
  ## Verification
176
90
  We rely on rigorous In-Memory Simulation (`InnerSpace`) to verify complex graph scenarios. See **[Verification](./docs/verification.md)** for the full status.
177
91
 
178
- ---
179
-
180
- ## ❓ Open Questions
181
-
182
- ### Payload Scope Validation: Can the Protocol Police What ibGibs Are Transmitted?
183
-
184
- **Question**: During a sync session authorized by session substone S (itself authorized by domain keystone I with `claim.target = S^Stjp` and sync subject `X^X10.Xtjp`), should the server validate that all Delta payload ibgibs are genuinely related to X's timeline? Or is it sufficient that they arrive under a valid substone?
185
-
186
- **Context**: The substone's `frameDetails` records both the parent identity `I^Itjp` and the sync subject `X^X10.Xtjp`. In theory the server could walk the dependency graph of each incoming Delta payload and confirm every ibgib is either:
187
- - A control ibgib (sync saga, context, substone frames), or
188
- - Part of the dependency graph rooted at some frame of X's timeline (`X^Xtjp`)
189
-
190
- **Problem**: This check may not be enforceable at the protocol layer. A client who controls the keystone (has the master secret) could always evolve X's timeline to hard-link any arbitrary ibgib, and that ibgib would then pass the "is in X's dependency graph" check. So the constraint can be trivially bypassed by the legitimate key-holder, making it only useful against *illegitimate* actors — who are already blocked by the keystone proof requirement.
191
-
192
- **Current position**: This is likely a **higher-layer business rule** rather than a sync protocol concern. The sync protocol's job is to ensure the session is cryptographically authorized (via keystone proofs). What is stored under an authorized session is the domain owner's responsibility. Enforcement of content policies (e.g., "only ibgibs of type X are allowed") belongs in the server's `authorizeContext` hook, not in the core sync coordinator.
193
-
194
- **Tracked in**: `space-gib.sync-walkthrough.md`
@@ -21,7 +21,7 @@ The `SyncSagaCoordinator` drives a Finite State Machine (FSM) via the `handleSag
21
21
  ### 2.1 The Ping-Pong Flow
22
22
 
23
23
  1. **Start (Initiator)**:
24
- * Initiator (Alice) calls `startSaga`.
24
+ * Initiator (Alice) calls `sync`.
25
25
  * Generates `Init` frame containing her `KnowledgeMap` and `Mode` (Push/Pull/Sync).
26
26
  * Sends `Init` to Bob.
27
27
 
@@ -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 content-address hashes (`ib` vs `gib`). ⚠️ Keystone signature verification pending.
45
+ * **Verifies**: Checks content-address hashes.
46
46
  * **Merges**: Puts data into his local space.
47
47
  * Bob sends `Commit` frame.
48
48
 
@@ -55,7 +55,7 @@ The `SyncSagaCoordinator` drives a Finite State Machine (FSM) via the `handleSag
55
55
  ### 3.1 SyncSagaMessage
56
56
  All frames are `SyncIbGib`s carrying specific data payloads.
57
57
 
58
- * `sagaId`: Unique UUID for the session.
58
+ * `sagaId`: Unique UUID for the duration of this exchange.
59
59
  * `stage`: `init` | `ack` | `delta` | `commit` | `conflict`.
60
60
  * `knowledgeMap`: `{ [tjpAddr]: [tipAddr, ...ancestors] }`.
61
61
 
@@ -65,8 +65,19 @@ 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 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
- * **Trust Chain**: Each frame points to the previous one (`past` rel8n), creating a hash-linked chain of custody.
68
+
69
+ See [Security](./security.md) documentation.
70
+
71
+ ### 4.1 Ephemeral Session Domain-Binding
72
+ To prevent an ephemeral session keystone `S` from acting as a "blank check" that could authorize operations on arbitrary timelines, the protocol implements strict domain-binding:
73
+ * **Genesis Binding**: The first frame of the session keystone ($S^{Stjp}$) must explicitly contain a `targetAddrs` array inside its `frameDetails` mapping to the exact addresses of the ibgibs being synchronized.
74
+ * **Verification Boundary**: During the initial turn-based synchronization (e.g., `handleInitFrame`), the validating peer (Receiver) must extract this `targetAddrs` array from $S^{Stjp}$'s genesis `frameDetails` and verify it contains the synchronizing domain's target address, rejecting the handshake on any mismatch.
75
+
76
+ ## 5. Sync Peer Lifetime
77
+
78
+ A `SyncPeer` is **single-saga scoped**. One peer instance services exactly one `sync(...)` call from creation through saga completion. The coordinator's `newTestPeer()` factory pattern (or equivalent in production) must create a fresh peer per saga.
79
+
80
+ **Rationale**: The session keystone `S` is derived from `KDF(senderSecret, sagaId)`. Since `sagaId` is unique per saga, `S` is inherently saga-bound. A peer that outlived its saga would hold stale identity state, violating the security model.
70
81
 
71
82
  > [!WARNING]
72
83
  > ## 5. Sync Storage & Persistence Rules (Critical Security)
@@ -74,17 +85,26 @@ The protocol supports two types of data:
74
85
  > Knowing **when** to put **what** ibgib frames into **which** space is a high-priority security concern. The sync algorithm must balance maintaining a robust audit trail with protecting durable spaces from unauthorized pollution. Always follow these rules:
75
86
  >
76
87
  > ### Rule 1: Saga/Control Audit Trail (Immediate Persistence)
77
- > We need an audit trail of the sync saga itself (including context and identity info).
88
+ > We need an audit trail of the sync saga itself (including context and authentication info).
78
89
  > * The initial session keystone (or any valid evolution performed locally) and saga control ibgibs are trusted because *we* just generated them.
79
90
  > * Persist these immediately in the **local durable space** (and possibly the local temporary space if needed for transit) so they are available for validation and auditing.
80
91
  >
81
92
  > ### Rule 2: Domain IbGibs (Deferred Persistence)
82
93
  > We do NOT persist *any* domain ibgibs (e.g., user payloads) into the durable space before the `commit` phase of the sync process.
83
- > * Domain ibgibs must be routed to the **tempSpace** during the `delta` or `ack` phases.
94
+ > * Domain ibgibs must be routed to the **tempSpace** during the `delta` or `ack` phases.
84
95
  > * The `commit` phase acts as the transaction boundary. By waiting for the commit, we avoid polluting durable spaces on error, preventing the need for complex rollbacks.
85
96
  >
86
97
  > ### Rule 3: Validate First, Store Second
87
98
  > We never chance storing intrinsically invalid ibgibs.
88
99
  > * **First step:** Intrinsically validate ibgibs (hashes, basic structure).
89
- > * **Second step:** Perform AuthN/AuthZ checks (using the ephemeral session keystone).
100
+ > * **Second step:** Perform AuthN/AuthZ checks (using the session keystone).
90
101
  > * **Final step:** Once verified, saga "control" ibgibs (which only contain "soft" links to domain ibgibs) can be safely persisted to durable spaces.
102
+
103
+ ## 6. Transport & Framing (Naive WebSocket Implementation)
104
+
105
+ > [!NOTE]
106
+ > ### TODO: Robust WebSocket Framing & TCP Reassembly
107
+ > The current custom WebSocket integration on the node server (`ws-helper.mts`) relies on a naive framing implementation. It assumes each socket `data` event emitted by Node's TCP stream contains exactly one complete WebSocket frame.
108
+ >
109
+ > * **TCP Fragmentation Risk**: When payload sizes grow (e.g. sending larger cryptographic proofs or domain datasets), TCP will split the frame across multiple packets or buffers. The naive decoder will decode a partial frame, causing parse errors (e.g., `Unterminated string in JSON`).
110
+ > * **Future Action**: Replace the custom, naive WebSocket framing code with a robust stateful accumulator that aggregates incoming TCP chunks until the entire frame length (indicated in the frame header) is present in memory, or transition to a fully tested, production-grade library (such as the NPM `ws` package).