@cello-protocol/daemon 0.0.53 → 0.0.55

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 (177) hide show
  1. package/dist/agent-handlers.d.ts +57 -0
  2. package/dist/agent-handlers.d.ts.map +1 -0
  3. package/dist/agent-handlers.js +360 -0
  4. package/dist/agent-handlers.js.map +1 -0
  5. package/dist/agent-id-migration.d.ts.map +1 -1
  6. package/dist/agent-id-migration.js +1 -0
  7. package/dist/agent-id-migration.js.map +1 -1
  8. package/dist/agent-loader.d.ts +3 -4
  9. package/dist/agent-loader.d.ts.map +1 -1
  10. package/dist/agent-loader.js +3 -4
  11. package/dist/agent-loader.js.map +1 -1
  12. package/dist/cbor-blob-migration.d.ts +8 -0
  13. package/dist/cbor-blob-migration.d.ts.map +1 -0
  14. package/dist/cbor-blob-migration.js +115 -0
  15. package/dist/cbor-blob-migration.js.map +1 -0
  16. package/dist/close-session-handler.d.ts +41 -0
  17. package/dist/close-session-handler.d.ts.map +1 -0
  18. package/dist/close-session-handler.js +399 -0
  19. package/dist/close-session-handler.js.map +1 -0
  20. package/dist/consortium-bootstrap.d.ts +83 -0
  21. package/dist/consortium-bootstrap.d.ts.map +1 -0
  22. package/dist/consortium-bootstrap.js +120 -0
  23. package/dist/consortium-bootstrap.js.map +1 -0
  24. package/dist/contact-handlers.d.ts +56 -0
  25. package/dist/contact-handlers.d.ts.map +1 -0
  26. package/dist/contact-handlers.js +303 -0
  27. package/dist/contact-handlers.js.map +1 -0
  28. package/dist/content-park-client.d.ts.map +1 -1
  29. package/dist/content-park-client.js +7 -7
  30. package/dist/content-park-client.js.map +1 -1
  31. package/dist/content-park.d.ts +15 -0
  32. package/dist/content-park.d.ts.map +1 -0
  33. package/dist/content-park.js +227 -0
  34. package/dist/content-park.js.map +1 -0
  35. package/dist/daemon.d.ts +4 -10
  36. package/dist/daemon.d.ts.map +1 -1
  37. package/dist/daemon.js +430 -4563
  38. package/dist/daemon.js.map +1 -1
  39. package/dist/db-identity-store.d.ts +31 -35
  40. package/dist/db-identity-store.d.ts.map +1 -1
  41. package/dist/db-identity-store.js +62 -66
  42. package/dist/db-identity-store.js.map +1 -1
  43. package/dist/directory-bootstrap.d.ts +27 -31
  44. package/dist/directory-bootstrap.d.ts.map +1 -1
  45. package/dist/directory-bootstrap.js +18 -21
  46. package/dist/directory-bootstrap.js.map +1 -1
  47. package/dist/frame-values.d.ts +3 -0
  48. package/dist/frame-values.d.ts.map +1 -0
  49. package/dist/frame-values.js +73 -0
  50. package/dist/frame-values.js.map +1 -0
  51. package/dist/identity-migration.d.ts +8 -8
  52. package/dist/identity-migration.d.ts.map +1 -1
  53. package/dist/identity-migration.js +30 -31
  54. package/dist/identity-migration.js.map +1 -1
  55. package/dist/inbound-seal-request.d.ts +17 -0
  56. package/dist/inbound-seal-request.d.ts.map +1 -0
  57. package/dist/inbound-seal-request.js +155 -0
  58. package/dist/inbound-seal-request.js.map +1 -0
  59. package/dist/inbound-sessions.d.ts +54 -0
  60. package/dist/inbound-sessions.d.ts.map +1 -0
  61. package/dist/inbound-sessions.js +603 -0
  62. package/dist/inbound-sessions.js.map +1 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +8 -10
  65. package/dist/index.js.map +1 -1
  66. package/dist/initiate-session-handler.d.ts +22 -0
  67. package/dist/initiate-session-handler.d.ts.map +1 -0
  68. package/dist/initiate-session-handler.js +150 -0
  69. package/dist/initiate-session-handler.js.map +1 -0
  70. package/dist/network-directory-node.d.ts +6 -6
  71. package/dist/network-directory-node.d.ts.map +1 -1
  72. package/dist/network-directory-node.js +29 -28
  73. package/dist/network-directory-node.js.map +1 -1
  74. package/dist/notification-handlers.d.ts +32 -0
  75. package/dist/notification-handlers.d.ts.map +1 -0
  76. package/dist/notification-handlers.js +73 -0
  77. package/dist/notification-handlers.js.map +1 -0
  78. package/dist/outbound-sessions.d.ts +54 -0
  79. package/dist/outbound-sessions.d.ts.map +1 -0
  80. package/dist/outbound-sessions.js +429 -0
  81. package/dist/outbound-sessions.js.map +1 -0
  82. package/dist/park-envelope.d.ts.map +1 -1
  83. package/dist/park-envelope.js +3 -2
  84. package/dist/park-envelope.js.map +1 -1
  85. package/dist/register-handler.d.ts +35 -0
  86. package/dist/register-handler.d.ts.map +1 -0
  87. package/dist/register-handler.js +179 -0
  88. package/dist/register-handler.js.map +1 -0
  89. package/dist/registration-manager.d.ts.map +1 -1
  90. package/dist/registration-manager.js +3 -6
  91. package/dist/registration-manager.js.map +1 -1
  92. package/dist/relay-receipt-store.d.ts.map +1 -1
  93. package/dist/relay-receipt-store.js +1 -2
  94. package/dist/relay-receipt-store.js.map +1 -1
  95. package/dist/retry-queue.d.ts +18 -60
  96. package/dist/retry-queue.d.ts.map +1 -1
  97. package/dist/retry-queue.js +46 -97
  98. package/dist/retry-queue.js.map +1 -1
  99. package/dist/seal-coordinator.d.ts +47 -0
  100. package/dist/seal-coordinator.d.ts.map +1 -0
  101. package/dist/seal-coordinator.js +551 -0
  102. package/dist/seal-coordinator.js.map +1 -0
  103. package/dist/seal-flows.d.ts +50 -0
  104. package/dist/seal-flows.d.ts.map +1 -0
  105. package/dist/seal-flows.js +454 -0
  106. package/dist/seal-flows.js.map +1 -0
  107. package/dist/seal-frontier-verify.d.ts +9 -9
  108. package/dist/seal-frontier-verify.d.ts.map +1 -1
  109. package/dist/seal-frontier-verify.js +11 -12
  110. package/dist/seal-frontier-verify.js.map +1 -1
  111. package/dist/seal-leaf.d.ts +58 -0
  112. package/dist/seal-leaf.d.ts.map +1 -0
  113. package/dist/seal-leaf.js +111 -0
  114. package/dist/seal-leaf.js.map +1 -0
  115. package/dist/seal-receipt-upgrade.d.ts +1 -1
  116. package/dist/seal-receipt-upgrade.js +1 -1
  117. package/dist/seal-upgrade.d.ts +10 -10
  118. package/dist/seal-upgrade.d.ts.map +1 -1
  119. package/dist/seal-upgrade.js +23 -24
  120. package/dist/seal-upgrade.js.map +1 -1
  121. package/dist/session-assignment-parser.d.ts +16 -19
  122. package/dist/session-assignment-parser.d.ts.map +1 -1
  123. package/dist/session-assignment-parser.js +30 -29
  124. package/dist/session-assignment-parser.js.map +1 -1
  125. package/dist/session-ceremony.d.ts +3 -6
  126. package/dist/session-ceremony.d.ts.map +1 -1
  127. package/dist/session-ceremony.js +7 -9
  128. package/dist/session-ceremony.js.map +1 -1
  129. package/dist/session-connection-gater.d.ts +4 -2
  130. package/dist/session-connection-gater.d.ts.map +1 -1
  131. package/dist/session-connection-gater.js +16 -10
  132. package/dist/session-connection-gater.js.map +1 -1
  133. package/dist/session-content-handlers.d.ts +25 -0
  134. package/dist/session-content-handlers.d.ts.map +1 -0
  135. package/dist/session-content-handlers.js +436 -0
  136. package/dist/session-content-handlers.js.map +1 -0
  137. package/dist/session-name.d.ts +35 -0
  138. package/dist/session-name.d.ts.map +1 -0
  139. package/dist/session-name.js +60 -0
  140. package/dist/session-name.js.map +1 -0
  141. package/dist/session-node-manager.d.ts +47 -62
  142. package/dist/session-node-manager.d.ts.map +1 -1
  143. package/dist/session-node-manager.js +297 -97
  144. package/dist/session-node-manager.js.map +1 -1
  145. package/dist/session-read-handlers.d.ts +38 -0
  146. package/dist/session-read-handlers.d.ts.map +1 -0
  147. package/dist/session-read-handlers.js +233 -0
  148. package/dist/session-read-handlers.js.map +1 -0
  149. package/dist/session-relay-client.d.ts +8 -8
  150. package/dist/session-relay-client.d.ts.map +1 -1
  151. package/dist/session-relay-client.js +44 -46
  152. package/dist/session-relay-client.js.map +1 -1
  153. package/dist/session-tree.d.ts +11 -23
  154. package/dist/session-tree.d.ts.map +1 -1
  155. package/dist/session-tree.js +14 -26
  156. package/dist/session-tree.js.map +1 -1
  157. package/dist/signaling-connect.d.ts +13 -5
  158. package/dist/signaling-connect.d.ts.map +1 -1
  159. package/dist/signaling-connect.js +55 -13
  160. package/dist/signaling-connect.js.map +1 -1
  161. package/dist/sqlcipher-db.d.ts +18 -19
  162. package/dist/sqlcipher-db.d.ts.map +1 -1
  163. package/dist/sqlcipher-db.js +30 -30
  164. package/dist/sqlcipher-db.js.map +1 -1
  165. package/dist/telegram-doorbell.d.ts +38 -0
  166. package/dist/telegram-doorbell.d.ts.map +1 -0
  167. package/dist/telegram-doorbell.js +139 -0
  168. package/dist/telegram-doorbell.js.map +1 -0
  169. package/dist/types.d.ts +86 -79
  170. package/dist/types.d.ts.map +1 -1
  171. package/dist/types.js +0 -1
  172. package/dist/types.js.map +1 -1
  173. package/dist/vocabulary.d.ts +30 -30
  174. package/dist/vocabulary.d.ts.map +1 -1
  175. package/dist/vocabulary.js +41 -49
  176. package/dist/vocabulary.js.map +1 -1
  177. package/package.json +5 -5
@@ -0,0 +1,551 @@
1
+ /**
2
+ * The seal cluster: bilateral seal, unilateral escalation, and the returning-absent-party upgrade.
3
+ *
4
+ * Five pieces of mutable state and the four signaling listeners that drive them. They were already
5
+ * seal-private inside startDaemon — nothing else touched them — but "private" was a convention you
6
+ * had to verify by reading 6,000 lines. Here it is the module boundary.
7
+ *
8
+ * What the cluster actually needs from the daemon is five things: the session store, a logger, the
9
+ * per-agent FROST persistence, the per-agent key provider, and a way to recover parked content
10
+ * before ratifying a seal. Notably NOT the signaling hub — a SignalingManager is passed in per
11
+ * listener registration, so the coordinator never reaches for the daemon's nervous system.
12
+ *
13
+ * The state objects (the waiter maps, the in-progress sets) are returned as-is rather than hidden
14
+ * behind accessors: cello_close_session drives them directly from ~30 sites and stays in daemon.ts
15
+ * (it inlines the cursor gate, governance, transcript append and retry enqueue — see the refactor
16
+ * plan's DO-NOT-CUT list). Preserving behavior beats tightening encapsulation in the same move;
17
+ * the encapsulation is a later, separate change with its own tests.
18
+ */
19
+ import { Buffer } from "node:buffer";
20
+ import { attemptSealUpgrade as attemptSealUpgradeImpl, verifyUpgradeConfirmedCert } from "./seal-upgrade.js";
21
+ import { upgradeAbsentToRecovered, hasAbsentParticipant } from "./seal-receipt-upgrade.js";
22
+ import { verifyUnilateralCertificate, verifyBilateralSealCertificate } from "./session-ceremony.js";
23
+ import { reDeriveFrontiers, findInflatedFrontier, checkUnilateralFrontier } from "./seal-frontier-verify.js";
24
+ import { frameValueToHex, normalizeLegibility } from "./frame-values.js";
25
+ export function createSealCoordinator(deps) {
26
+ const { logger, sessionNodeManager, getPersistence, getKeyProvider, recoverContent } = deps;
27
+ // DOD-LOOP-1: daemon-level seal bookkeeping is keyed by (agentName, sessionId), NOT sessionId
28
+ // alone — two of the operator's agents can hold both ends of the same session_id on one daemon
29
+ // (loopback), and each end seals independently. Keying by session_id alone would let A's close
30
+ // block B's (false seal_interrupted_in_progress) and make their seal waiters collide.
31
+ const sealKey = (agentName, sessionId) => `${agentName}\x1f${sessionId}`;
32
+ // M7-SESSION-001: tracks seal-interrupted flows currently in progress.
33
+ // Prevents duplicate concurrent seal-interrupted attempts for the same (agent, session) (AC-011).
34
+ const sealInterruptedInProgress = new Set();
35
+ // M7 DOD-SPINE-7: relay-mediated bilateral seal. cello_close_session registers a waiter
36
+ // per session_id (hex); the directory's session_sealed frame — delivered over the agent's
37
+ // signaling stream after FROST notarization, once BOTH parties have submitted their SEAL
38
+ // ctrl leaf — resolves it with the sealed_root.
39
+ // M7-SESSION-004: the bilateral seal resolves with the sealed_root AND the legibility
40
+ // certificate (receipt-not-assent, per-party frontiers, attestation modes, final_message).
41
+ const pendingSealWaiters = new Map();
42
+ // M7 DOD-SPINE-7: register the session_sealed completion handler on a signaling manager — per-agent
43
+ // in production (the directory routes session_sealed to the session-owning agent's authenticated
44
+ // stream), or the shared manager on the test path. Function declaration so getAgentSignaling
45
+ // (defined earlier, called at runtime) can wire it per-agent.
46
+ function registerSessionSealedListener(signaling, agentName, agentPubkeyHex) {
47
+ return signaling.registerInboundHandler((frame) => {
48
+ if (frame["type"] !== "session_sealed")
49
+ return;
50
+ const sidHex = frameValueToHex(frame["session_id"]);
51
+ const rootHex = frameValueToHex(frame["sealed_root"]);
52
+ if (!sidHex || !rootHex)
53
+ return;
54
+ void (async () => {
55
+ const toU8 = (v) => v instanceof Uint8Array ? v : Buffer.isBuffer(v) ? new Uint8Array(v) : null;
56
+ // M7 legibility-TBS-binding: when THIS party is the seal's signer (the initiator, whose
57
+ // group key produced the FROST signature), verify the signature over the legibility-bound
58
+ // TBS. A tampered legibility (answered / content_frontier_seq / attestation_mode, carried
59
+ // unsigned on the frame) changes the hash → the signature fails → the seal is REJECTED. The
60
+ // non-initiator does not hold the signer's key, so it accepts (verified:false): the frame
61
+ // arrived over the authenticated Noise channel, and the binding lets any out-of-band holder
62
+ // of the initiator's primary verify an exported cert.
63
+ if (frame["signature_type"] === "frost") {
64
+ const sessionIdBytes = toU8(frame["session_id"]);
65
+ const sealedRootBytes = toU8(frame["sealed_root"]);
66
+ const frostSig = toU8(frame["frost_signature"]);
67
+ const signerPubkey = toU8(frame["signer_pubkey"]);
68
+ const leafCount = typeof frame["leaf_count"] === "number" ? frame["leaf_count"] : null;
69
+ const ctRaw = frame["close_timestamp"];
70
+ const closeTs = typeof ctRaw === "number" ? ctRaw : typeof ctRaw === "bigint" ? Number(ctRaw) : null;
71
+ if (!sessionIdBytes || !sealedRootBytes || !frostSig || !signerPubkey || leafCount === null || closeTs === null) {
72
+ logger.error("session.sealed.signature.invalid", { sessionId: sidHex, reason: "missing_certificate_fields" });
73
+ return;
74
+ }
75
+ const record = sessionNodeManager.getSessionRecord(agentName, sidHex);
76
+ const verdict = await verifyBilateralSealCertificate({ persistence: getPersistence(agentName), agentPubkeyHex, logger, counterpartyPrimaryHex: record?.counterparty_primary_pubkey ?? null }, {
77
+ sessionId: sessionIdBytes,
78
+ sealedRoot: sealedRootBytes,
79
+ leafCount,
80
+ closeTimestamp: closeTs,
81
+ frostSignature: frostSig,
82
+ signerPubkey,
83
+ signatureType: "frost",
84
+ legibility: frame["legibility"] && typeof frame["legibility"] === "object"
85
+ ? frame["legibility"]
86
+ : null,
87
+ });
88
+ if (!verdict.ok) {
89
+ // tamper-evidence: do NOT mark sealed, do NOT resolve the waiter as success.
90
+ logger.error("session.sealed.signature.invalid", { sessionId: sidHex, reason: verdict.reason });
91
+ return;
92
+ }
93
+ // F2-a: on verified:false, surface WHY (signer_key_not_held / no_frost_share / …) so this
94
+ // event can never be mistaken for a tolerated failed check. A real failure took the early
95
+ // return above (session.sealed.signature.invalid) and never reaches here.
96
+ logger.info("session.sealed.signature.checked", {
97
+ sessionId: sidHex,
98
+ verified: verdict.verified,
99
+ ...(verdict.verified ? {} : { reason: verdict.reason }),
100
+ });
101
+ }
102
+ // M7-SESSION-004 (AC-005): normalise the wire legibility (Uint8Array pubkeys → hex) into a
103
+ // JSON-safe certificate and persist it with the sealed record so it survives a restart and
104
+ // is readable via cello_get_sealed_receipt — receipt-not-assent, per-party frontiers,
105
+ // attestation modes, and final_message.answered.
106
+ const legibility = normalizeLegibility(frame["legibility"]);
107
+ logger.info("session.sealed.received", {
108
+ sessionId: sidHex,
109
+ sealedRoot: rootHex,
110
+ hasLegibility: legibility !== undefined,
111
+ finalMessageAnswered: legibility && typeof legibility === "object" && "final_message" in legibility
112
+ ? legibility.final_message?.answered
113
+ : undefined,
114
+ });
115
+ // DOD-LEG-2 (SI-002): independently re-derive each party's content_frontier_seq from the
116
+ // signed leaves the directory shipped, and REJECT the certificate if any published frontier
117
+ // is inflated beyond what the signed leaves support. The client does NOT trust the directory
118
+ // for the frontier VALUE — only for transporting signed bytes it re-checks itself. When no
119
+ // frontier_leaves are present (a pre-LEG-2 directory), the guard is skipped (backward-compat).
120
+ const frontierLeavesRaw = frame["frontier_leaves"];
121
+ if (legibility !== undefined) {
122
+ const rawParticipants = legibility.participants ?? [];
123
+ // Any party claiming to have received content (frontier > 0) MUST be backed by signed leaves.
124
+ const anyClaimedFrontier = rawParticipants.some((p) => typeof p.content_frontier_seq === "number" && p.content_frontier_seq > 0);
125
+ const haveLeaves = Array.isArray(frontierLeavesRaw) && frontierLeavesRaw.length > 0;
126
+ // HIGH (fail-closed): a malicious directory must not bypass the guard by OMITTING the leaves
127
+ // while still publishing a frontier. No leaves + a claimed frontier → reject.
128
+ if (anyClaimedFrontier && !haveLeaves) {
129
+ logger.error("seal.certificate.frontier.unverifiable", { sessionId: sidHex, reason: "frontier_leaves_missing" });
130
+ return;
131
+ }
132
+ // LOW (robustness): a malformed/malicious legibility (null pubkey or non-numeric frontier)
133
+ // must be rejected, never crash the guard.
134
+ for (const p of rawParticipants) {
135
+ if (typeof p.pubkey !== "string" || typeof p.content_frontier_seq !== "number") {
136
+ logger.error("seal.certificate.frontier.unverifiable", { sessionId: sidHex, reason: "participant_malformed" });
137
+ return;
138
+ }
139
+ }
140
+ const participants = rawParticipants;
141
+ if (haveLeaves) {
142
+ const toU8 = (v) => (v instanceof Uint8Array ? v : new Uint8Array(v));
143
+ const leaves = frontierLeavesRaw.map((l) => {
144
+ const o = l;
145
+ return {
146
+ structure1_cbor: toU8(o["structure1_cbor"]),
147
+ sender_pubkey: toU8(o["sender_pubkey"]),
148
+ sender_signature: toU8(o["sender_signature"]),
149
+ };
150
+ });
151
+ // Session-bound re-derivation (BLOCKING fix): leaves must be from THIS session, so a
152
+ // malicious directory cannot replay a party's leaves from another session to inflate.
153
+ const rederived = reDeriveFrontiers(leaves, toU8(frame["session_id"]));
154
+ if (!rederived.ok) {
155
+ logger.error("seal.certificate.frontier.unverifiable", { sessionId: sidHex, reason: rederived.reason });
156
+ return;
157
+ }
158
+ const inflated = findInflatedFrontier(participants, rederived.frontiers);
159
+ if (inflated) {
160
+ // The directory published a frontier higher than the signed leaves support — refuse the
161
+ // seal (do NOT persist, do NOT resolve the close as success), exactly like a bad signature.
162
+ logger.error("seal.certificate.frontier.unverifiable", {
163
+ sessionId: sidHex,
164
+ party: inflated.party,
165
+ publishedFrontier: inflated.publishedFrontier,
166
+ derivedFrontier: inflated.derivedFrontier,
167
+ });
168
+ return;
169
+ }
170
+ logger.info("seal.certificate.frontier.verified", {
171
+ sessionId: sidHex,
172
+ parties: participants.length,
173
+ });
174
+ }
175
+ }
176
+ if (legibility !== undefined) {
177
+ try {
178
+ sessionNodeManager.recordSealCertificate(agentName, sidHex, rootHex, JSON.stringify(legibility));
179
+ }
180
+ catch (error) {
181
+ logger.warn("seal.certificate.persist.failed", {
182
+ sessionId: sidHex,
183
+ reason: error instanceof Error ? error.message : String(error),
184
+ });
185
+ }
186
+ }
187
+ const waiter = pendingSealWaiters.get(sealKey(agentName, sidHex));
188
+ if (waiter) {
189
+ pendingSealWaiters.delete(sealKey(agentName, sidHex));
190
+ waiter({ rootHex, legibility });
191
+ }
192
+ // Mark the session sealed + tear the node down (idempotent — safe if already gone).
193
+ void sessionNodeManager.destroySessionNode(agentName, sidHex, "sealed");
194
+ })();
195
+ });
196
+ }
197
+ // SESSION-002 (DOD-SEAL): cello_close_session escalates to a UNILATERAL seal when the
198
+ // counterparty never co-closes. The waiter is resolved by the seal_unilateral_confirmed
199
+ // listener AFTER it verifies the certificate signature (channel-independent), or by
200
+ // seal_unilateral_too_early (grace not elapsed). Keyed by session_id hex.
201
+ // F20: `remainingSeconds` carries the directory's seal_unilateral_too_early countdown so the
202
+ // close result can tell the operator WHEN a unilateral seal becomes available.
203
+ // M8B FINDING-3 (cascade-2): a successful unilateral seal now carries the legibility certificate
204
+ // (normalized, JSON-safe) so cello_close_session returns it inline — the same RESPONSE SHAPE as the
205
+ // bilateral close (not cryptographic parity: this cert is directory-attested, see FINDING-5). undefined
206
+ // when the directory shipped none (a pre-cascade-2 directory): the seal still completes, but no
207
+ // retrievable receipt is produced (the pre-fix behavior).
208
+ const pendingUnilateralWaiters = new Map();
209
+ // SESSION-002: per-agent listener for the unilateral certificate. Verifies the FROST
210
+ // signature over the rebuilt TBS against the agent's own primary_pubkey BEFORE resolving
211
+ // the close as sealed (SI-003: a channel-swapped sealed_root fails the signature check).
212
+ function registerUnilateralConfirmedListener(signaling, agentName, agentPubkeyHex) {
213
+ return signaling.registerInboundHandler((frame) => {
214
+ const ftype = frame["type"];
215
+ if (ftype !== "seal_unilateral_confirmed" && ftype !== "seal_unilateral_too_early")
216
+ return;
217
+ const sidHex = frameValueToHex(frame["session_id"]);
218
+ if (!sidHex)
219
+ return;
220
+ const waiter = pendingUnilateralWaiters.get(sidHex);
221
+ if (!waiter)
222
+ return;
223
+ if (ftype === "seal_unilateral_too_early") {
224
+ pendingUnilateralWaiters.delete(sidHex);
225
+ // F20: thread the directory's remaining_seconds through so the close guidance can
226
+ // say when the unilateral seal becomes available.
227
+ const rs = frame["remaining_seconds"];
228
+ waiter({
229
+ ok: false,
230
+ reason: "seal_unilateral_too_early",
231
+ ...(typeof rs === "number" ? { remainingSeconds: rs } : {}),
232
+ });
233
+ return;
234
+ }
235
+ void (async () => {
236
+ const toU8 = (v) => v instanceof Uint8Array ? v : Buffer.isBuffer(v) ? new Uint8Array(v) : null;
237
+ const sessionId = toU8(frame["session_id"]);
238
+ const sealedRoot = toU8(frame["sealed_root"]);
239
+ const frostSig = toU8(frame["frost_signature"]);
240
+ const leafCount = typeof frame["leaf_count"] === "number" ? frame["leaf_count"] : null;
241
+ const tsRaw = frame["close_timestamp"];
242
+ const closeTs = typeof tsRaw === "number" ? tsRaw : typeof tsRaw === "bigint" ? Number(tsRaw) : null;
243
+ const sigType = frame["signature_type"];
244
+ if (!sessionId || !sealedRoot || !frostSig || leafCount === null || closeTs === null ||
245
+ (sigType !== "frost" && sigType !== "single")) {
246
+ logger.warn("session.unilateral.certificate.invalid", { sessionId: sidHex, reason: "malformed_certificate" });
247
+ pendingUnilateralWaiters.delete(sidHex);
248
+ waiter({ ok: false, reason: "malformed_certificate" });
249
+ return;
250
+ }
251
+ const result = await verifyUnilateralCertificate({ persistence: getPersistence(agentName), agentPubkeyHex, logger }, { sessionId, sealedRoot, leafCount, closeTimestamp: closeTs, frostSignature: frostSig, signatureType: sigType });
252
+ pendingUnilateralWaiters.delete(sidHex);
253
+ if (!result.ok) {
254
+ // SI-003: do NOT mark sealed when the certificate signature does not verify.
255
+ logger.warn("session.unilateral.certificate.invalid", { sessionId: sidHex, reason: result.reason, signatureType: sigType });
256
+ waiter({ ok: false, reason: `certificate_invalid:${result.reason}` });
257
+ return;
258
+ }
259
+ logger.info("session.unilateral.certificate.verified", { sessionId: sidHex, signatureType: sigType, party: "present" });
260
+ // M8B FINDING-3 (cascade-2): normalise + PERSIST the legibility certificate the directory
261
+ // now ships on this frame — the SAME store the bilateral session_sealed handler writes
262
+ // (recordSealCertificate → read back by cello_get_sealed_receipt). Without this a unilateral
263
+ // close returned ok+root but sealed_receipt_not_found forever: the whole point of sealing
264
+ // when your counterparty vanished is walking away with a DURABLE, RETRIEVABLE receipt.
265
+ // Persist BEFORE destroying the node (bilateral ordering) so the sessions row still exists
266
+ // for the UPDATE. undefined legibility (a pre-cascade-2 directory) → nothing persisted; the
267
+ // seal still completes — surfaced loudly so this can never masquerade as a produced receipt.
268
+ const rootHex = Buffer.from(sealedRoot).toString("hex");
269
+ const legibility = normalizeLegibility(frame["legibility"]);
270
+ // M8B FINDING-5 (SI-002): before persisting, INDEPENDENTLY re-derive each CLIENT-VERIFIABLE
271
+ // ('live', the present party) frontier from the signed frontier_leaves and OVERRIDE an inflated
272
+ // directory-published value DOWN to the provable one (the directory cannot forge signed leaves,
273
+ // so the re-derived value is truth). We OVERRIDE, never reject — the unilateral seal has a
274
+ // directory-side dedup guard that makes a client rejection unrecoverable (a retry close is
275
+ // silently ignored → no receipt ever, worse than FINDING-3; cascade-2 reviewer Critical 2). The
276
+ // absent party's frontier stays directory-attested (its remainder is not re-derivable here). No
277
+ // frontier_leaves (pre-FINDING-5 directory) → the cert stays directory-attested (FINDING-3).
278
+ // A receipt is ALWAYS persisted; the close never dead-ends here.
279
+ if (legibility !== undefined) {
280
+ const rawParticipants = legibility.participants ?? [];
281
+ const guardParticipants = rawParticipants
282
+ .filter((p) => typeof p.pubkey === "string" && typeof p.attestation_mode === "string")
283
+ .map((p) => ({
284
+ pubkey: p.pubkey,
285
+ content_frontier_seq: typeof p.content_frontier_seq === "number" ? p.content_frontier_seq : 0,
286
+ attestation_mode: p.attestation_mode,
287
+ }));
288
+ const frontierLeavesRaw = frame["frontier_leaves"];
289
+ const toU8f = (v) => (v instanceof Uint8Array ? v : new Uint8Array(v));
290
+ const parsedFrontierLeaves = Array.isArray(frontierLeavesRaw) && frontierLeavesRaw.length > 0
291
+ ? frontierLeavesRaw.map((l) => {
292
+ const o = l;
293
+ return {
294
+ structure1_cbor: toU8f(o["structure1_cbor"]),
295
+ sender_pubkey: toU8f(o["sender_pubkey"]),
296
+ sender_signature: toU8f(o["sender_signature"]),
297
+ };
298
+ })
299
+ : undefined;
300
+ const check = checkUnilateralFrontier(guardParticipants, parsedFrontierLeaves, sessionId);
301
+ // Apply any frontier corrections to the object we persist — override inflated 'live'
302
+ // frontier(s) DOWN to the provable value, so the stored receipt never claims more than the
303
+ // signed leaves support. Runs for both 'corrected' (valid leaves) and 'leaves_invalid'
304
+ // (forged leaves → corrected to 0). Never rejects → the close never dead-ends.
305
+ if (check.corrections.size > 0) {
306
+ for (const p of rawParticipants) {
307
+ if (typeof p.pubkey === "string" && check.corrections.has(p.pubkey.toLowerCase())) {
308
+ p.content_frontier_seq = check.corrections.get(p.pubkey.toLowerCase());
309
+ }
310
+ }
311
+ }
312
+ if (check.status === "corrected") {
313
+ logger.error("seal.certificate.frontier.overridden", {
314
+ sessionId: sidHex,
315
+ corrections: [...check.corrections.entries()].map(([party, seq]) => ({ party, correctedTo: seq })),
316
+ path: "unilateral",
317
+ });
318
+ }
319
+ else if (check.status === "verified") {
320
+ logger.info("seal.certificate.frontier.verified", {
321
+ sessionId: sidHex,
322
+ parties: guardParticipants.filter((p) => p.attestation_mode === "live").length,
323
+ path: "unilateral",
324
+ });
325
+ }
326
+ else if (check.status === "leaves_invalid") {
327
+ // Forged / cross-session leaves — a tamper signal. The 'live' frontier(s) have been
328
+ // corrected to 0 above (zero trustworthy evidence); persist that (never reject → never
329
+ // dead-end). Surfaced loudly for audit.
330
+ logger.error("seal.certificate.frontier.leaves_invalid", {
331
+ sessionId: sidHex,
332
+ reason: check.reason,
333
+ corrections: [...check.corrections.entries()].map(([party, seq]) => ({ party, correctedTo: seq })),
334
+ path: "unilateral",
335
+ });
336
+ }
337
+ else {
338
+ // directory_attested: no frontier_leaves shipped (pre-FINDING-5 directory). Frontiers stay
339
+ // DIRECTORY-attested (already marked per-participant) — visible/auditable, never silently
340
+ // presented as client-verified.
341
+ logger.warn("seal.certificate.frontier.directory_attested", {
342
+ sessionId: sidHex,
343
+ reason: "no_frontier_leaves",
344
+ path: "unilateral",
345
+ });
346
+ }
347
+ }
348
+ if (legibility !== undefined) {
349
+ try {
350
+ sessionNodeManager.recordSealCertificate(agentName, sidHex, rootHex, JSON.stringify(legibility));
351
+ logger.info("session.unilateral.receipt.persisted", {
352
+ sessionId: sidHex,
353
+ sealedRoot: rootHex,
354
+ finalMessageAnswered: legibility && typeof legibility === "object" && "final_message" in legibility
355
+ ? legibility.final_message?.answered
356
+ : undefined,
357
+ });
358
+ }
359
+ catch (error) {
360
+ logger.warn("seal.certificate.persist.failed", {
361
+ sessionId: sidHex,
362
+ reason: error instanceof Error ? error.message : String(error),
363
+ });
364
+ }
365
+ }
366
+ else {
367
+ // The seal is valid, but no receipt is retrievable — a directory that predates cascade-2.
368
+ logger.warn("session.unilateral.receipt.absent", { sessionId: sidHex, reason: "no_legibility_on_frame" });
369
+ }
370
+ void sessionNodeManager.destroySessionNode(agentName, sidHex, "sealed");
371
+ waiter({ ok: true, sealedRootHex: rootHex, legibility });
372
+ })();
373
+ });
374
+ }
375
+ // ─── DOD-UP-1: returning-absent-party seal upgrade (unilateral → bilateral) ───
376
+ // Per-session idempotency guard so a notification burst (reconnect re-delivery) cannot launch
377
+ // concurrent upgrade attempts. Keyed `${agentName}:${sessionIdHex}`; cleared after each attempt.
378
+ const sealUpgradeInFlight = new Set();
379
+ /**
380
+ * DOD-UP-1: B (the absent party) ratifies a unilateral seal it learns about on reconnect.
381
+ *
382
+ * THE KERNEL: B signs the ratification ONLY after it has recovered + integrity-verified the
383
+ * content behind the sealed root. We (0) verify the unilateral cert so R1 is provably authentic
384
+ * (SI-003 — a channel-swapped root fails); (1) recover any parked content from the relay; (2) gate
385
+ * on getSealUpgradeReadiness — refuse content_unrecoverable (session unknown) or content_tamper
386
+ * (cross-check mismatch, AC-003); only then (3) sign the ack over R1 with B's OWN K_local and send
387
+ * seal_upgrade_request. B never co-signs content it could not verify.
388
+ */
389
+ // Thin wrapper over the extracted, unit-tested seal-upgrade.ts module (the KERNEL + AC-008 + H1/M1
390
+ // hardening live there so the refusal/reject bodies run under adversarial tests). This wrapper owns
391
+ // only the per-session in-flight guard and the real-dep injection.
392
+ async function attemptSealUpgrade(signaling, agentName, agentPubkeyHex, sidHex, frame) {
393
+ const key = `${agentName}:${sidHex}`;
394
+ if (sealUpgradeInFlight.has(key))
395
+ return;
396
+ sealUpgradeInFlight.add(key);
397
+ try {
398
+ const result = await attemptSealUpgradeImpl({
399
+ logger, agentName, agentPubkeyHex,
400
+ getReadiness: (a, s) => sessionNodeManager.getSealUpgradeReadiness(a, s),
401
+ getContentLeafCount: (a, s) => sessionNodeManager.getSessionTree(a, s).size(),
402
+ recoverContent: (a) => recoverContent(a),
403
+ getKeyProvider: (a) => getKeyProvider(a),
404
+ sendRaw: (f) => signaling.sendRaw(f),
405
+ }, sidHex, frame);
406
+ // M8B FINDING-6 (3b): the ABSENT party (B) persists its UNILATERAL receipt from the
407
+ // notification's legibility — but ONLY after the KERNEL content-recovery/verify gate passed.
408
+ // `result.sent` is true iff attemptSealUpgradeImpl recovered + integrity-verified the content
409
+ // behind R1 and sent the ratification request; a tampered/unrecoverable/incomplete case returns
410
+ // sent:false → NO receipt (never a receipt for content B could not verify). B may hold no local
411
+ // `sessions` row (recordSealCertificateEnsuringRow inserts a stub, counterparty = A's pubkey).
412
+ // The notification carries no frontier_leaves (FINDING-5 ships those only on the present party's
413
+ // confirm frame), so B's legibility is directory-attested — consistent with FINDING-5's
414
+ // directory_attested path; B trusts its own KERNEL-verified content, not a re-derivation.
415
+ if (result.sent) {
416
+ try {
417
+ // ONE-WAY RATCHET (cascade-2 FINDING-6 review): a re-delivered seal_unilateral_notification
418
+ // (reconnect burst) re-runs this path and would re-persist the notification's ORIGINAL
419
+ // legibility (counterparty 'absent'). If a prior upgrade already flipped the stored receipt
420
+ // to 'recovered' (no 'absent' participant), re-persisting would REGRESS it — and no later
421
+ // event restores 'recovered' (the directory dedups the duplicate as already_bilateral →
422
+ // seal_upgrade_rejected, which only logs). So skip the re-persist once the cert is upgraded.
423
+ const existing = sessionNodeManager.getSealCertificate(agentName, sidHex);
424
+ if (existing && !hasAbsentParticipant(existing.legibility)) {
425
+ logger.debug("session.unilateral.receipt.persist.skipped", { sessionId: sidHex, reason: "already_upgraded" });
426
+ }
427
+ else {
428
+ const legibility = normalizeLegibility(frame["legibility"]);
429
+ const rootHex = frameValueToHex(frame["sealed_root"]);
430
+ const counterpartyHex = frameValueToHex(frame["present_pubkey"]); // A — the present party
431
+ if (legibility !== undefined && rootHex && counterpartyHex) {
432
+ sessionNodeManager.recordSealCertificateEnsuringRow(agentName, sidHex, counterpartyHex, rootHex, JSON.stringify(legibility));
433
+ logger.info("session.unilateral.receipt.persisted", { sessionId: sidHex, sealedRoot: rootHex, party: "absent" });
434
+ }
435
+ else if (legibility === undefined) {
436
+ logger.warn("session.unilateral.receipt.absent", { sessionId: sidHex, reason: "no_legibility_on_notification" });
437
+ }
438
+ }
439
+ }
440
+ catch (error) {
441
+ logger.warn("seal.certificate.persist.failed", { sessionId: sidHex, reason: error instanceof Error ? error.message : String(error) });
442
+ }
443
+ }
444
+ }
445
+ finally {
446
+ // Clear the guard so a later reconnect can retry if the request never reached the directory;
447
+ // the directory dedups a repeat with already_bilateral.
448
+ sealUpgradeInFlight.delete(key);
449
+ }
450
+ }
451
+ // Thin wrapper: verify the dual-attestation cert (module, AC-008 + H1), then APPLY — mark bilateral
452
+ // ONLY on ok. Never trust the directory's "bilateral" claim.
453
+ async function verifyAndApplyUpgradeConfirmed(agentName, agentPubkeyHex, sidHex, frame) {
454
+ const result = await verifyUpgradeConfirmedCert({
455
+ logger, agentName, agentPubkeyHex, persistence: getPersistence(agentName),
456
+ getCounterpartyHex: (a, s) => sessionNodeManager.getSessionRecord(a, s)?.counterparty_pubkey ?? null,
457
+ }, sidHex, frame);
458
+ if (!result.ok)
459
+ return; // cert.invalid already logged inside; do NOT accept as bilateral.
460
+ logger.info("session.seal.upgraded", { sessionId: sidHex, agentName, party: result.party });
461
+ // M8B FINDING-6 (3a): the seal is now BILATERAL (verified) — upgrade THIS party's own stored
462
+ // receipt so the counterparty recorded 'absent' becomes 'recovered'. Client-side: the directory
463
+ // ships no bilateral legibility at upgrade time (the seal leaves aren't persisted there), so each
464
+ // party rebuilds from the cert it already holds — the present party's from its unilateral close
465
+ // (FINDING-3), the returning party's from the notification it persisted after the KERNEL gate
466
+ // (3b). The seal signatures do not bind the (unsigned) legibility, so mutating it is sound; only
467
+ // the attestation flips (frontiers unchanged — never overstated). No-op if no cert is stored yet.
468
+ const stored = sessionNodeManager.getSealCertificate(agentName, sidHex);
469
+ if (stored) {
470
+ try {
471
+ const upgraded = upgradeAbsentToRecovered(stored.legibility);
472
+ sessionNodeManager.recordSealCertificate(agentName, sidHex, stored.sealed_root, JSON.stringify(upgraded));
473
+ logger.info("session.seal.receipt.upgraded", { sessionId: sidHex, agentName, party: result.party });
474
+ }
475
+ catch (error) {
476
+ logger.warn("seal.certificate.persist.failed", { sessionId: sidHex, reason: error instanceof Error ? error.message : String(error) });
477
+ }
478
+ }
479
+ void sessionNodeManager.destroySessionNode(agentName, sidHex, "sealed");
480
+ }
481
+ /**
482
+ * DOD-UP-1: per-agent listener for the absent-party seal upgrade. On reconnect the directory
483
+ * delivers a queued seal_unilateral_notification to B (the absent party) — that triggers the
484
+ * ratification attempt. The directory's seal_upgrade_confirmed / seal_upgrade_rejected responses
485
+ * are observed here too (B marks the session bilaterally sealed / logs the refusal).
486
+ */
487
+ function registerUnilateralUpgradeListener(signaling, agentName, agentPubkeyHex) {
488
+ return signaling.registerInboundHandler((frame) => {
489
+ const ftype = frame["type"];
490
+ if (ftype === "seal_upgrade_confirmed") {
491
+ const sidHex = frameValueToHex(frame["session_id"]);
492
+ if (!sidHex)
493
+ return;
494
+ // AC-008: do NOT accept "bilateral" on the directory's word — verify the dual attestation.
495
+ void verifyAndApplyUpgradeConfirmed(agentName, agentPubkeyHex, sidHex, frame);
496
+ return;
497
+ }
498
+ if (ftype === "seal_upgrade_rejected") {
499
+ const sidHex = frameValueToHex(frame["session_id"]);
500
+ if (!sidHex)
501
+ return;
502
+ logger.warn("session.seal.upgrade.rejected", { sessionId: sidHex, agentName, reason: frame["reason"] });
503
+ return;
504
+ }
505
+ if (ftype !== "seal_unilateral_notification")
506
+ return;
507
+ const sidHex = frameValueToHex(frame["session_id"]);
508
+ if (!sidHex)
509
+ return;
510
+ // Only the ABSENT party receives this frame — B reacts by attempting the ratification.
511
+ void attemptSealUpgrade(signaling, agentName, agentPubkeyHex, sidHex, frame);
512
+ });
513
+ }
514
+ /**
515
+ * Wire the WHOLE seal listener set onto an authenticated signaling stream.
516
+ *
517
+ * A BUNDLE, deliberately — the three listeners are NOT exported individually, because being able
518
+ * to register two of the three is what caused the bug this replaced. The daemon's VISITING stream
519
+ * registered `session_sealed` + `seal_unilateral_confirmed` but not the upgrade listener, and that
520
+ * looked intentional. It was not: the directory drains its DURABLE notification queue on any
521
+ * stream that authenticates — visiting included — and DELETES each row once sent. So a
522
+ * `seal_unilateral_notification` pushed down a visiting stream hit no handler, was dropped, and
523
+ * its durable row was gone. The absent party never ratified, and the seal stayed unilateral
524
+ * forever: silent, permanent loss of a notarized receipt.
525
+ *
526
+ * Every stream that can carry a seal frame gets every seal listener. Making the partial case
527
+ * impossible to express is the fix; a comment asking future callers to remember all three is not.
528
+ *
529
+ * Safe to call on any stream, including transient ones: `attemptSealUpgrade` holds a per-session
530
+ * in-flight guard, the receipt persist is behind the one-way ratchet, and the directory dedups a
531
+ * repeated ratification with `already_bilateral`.
532
+ */
533
+ function registerSealListeners(signaling, agentName, agentPubkeyHex) {
534
+ const unregisterSealed = registerSessionSealedListener(signaling, agentName, agentPubkeyHex);
535
+ const unregisterUnilateral = registerUnilateralConfirmedListener(signaling, agentName, agentPubkeyHex);
536
+ const unregisterUpgrade = registerUnilateralUpgradeListener(signaling, agentName, agentPubkeyHex);
537
+ return () => {
538
+ unregisterSealed();
539
+ unregisterUnilateral();
540
+ unregisterUpgrade();
541
+ };
542
+ }
543
+ return {
544
+ sealKey,
545
+ sealInterruptedInProgress,
546
+ pendingSealWaiters,
547
+ pendingUnilateralWaiters,
548
+ registerSealListeners,
549
+ };
550
+ }
551
+ //# sourceMappingURL=seal-coordinator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal-coordinator.js","sourceRoot":"","sources":["../src/seal-coordinator.ts"],"names":[],"mappings":"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"}