@cello-protocol/daemon 0.0.225 → 0.0.227

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 (891) hide show
  1. package/package.json +5 -5
  2. package/dist/agent-admin-handlers.d.ts +0 -56
  3. package/dist/agent-admin-handlers.d.ts.map +0 -1
  4. package/dist/agent-admin-handlers.js +0 -73
  5. package/dist/agent-admin-handlers.js.map +0 -1
  6. package/dist/agent-handlers.d.ts +0 -72
  7. package/dist/agent-handlers.d.ts.map +0 -1
  8. package/dist/agent-handlers.js +0 -604
  9. package/dist/agent-handlers.js.map +0 -1
  10. package/dist/agent-id-migration.d.ts +0 -70
  11. package/dist/agent-id-migration.d.ts.map +0 -1
  12. package/dist/agent-id-migration.js +0 -468
  13. package/dist/agent-id-migration.js.map +0 -1
  14. package/dist/agent-loader.d.ts +0 -37
  15. package/dist/agent-loader.d.ts.map +0 -1
  16. package/dist/agent-loader.js +0 -37
  17. package/dist/agent-loader.js.map +0 -1
  18. package/dist/agent-selection-root.d.ts +0 -29
  19. package/dist/agent-selection-root.d.ts.map +0 -1
  20. package/dist/agent-selection-root.js +0 -126
  21. package/dist/agent-selection-root.js.map +0 -1
  22. package/dist/agent-selection.d.ts +0 -73
  23. package/dist/agent-selection.d.ts.map +0 -1
  24. package/dist/agent-selection.js +0 -80
  25. package/dist/agent-selection.js.map +0 -1
  26. package/dist/agent-settings-keys.d.ts +0 -52
  27. package/dist/agent-settings-keys.d.ts.map +0 -1
  28. package/dist/agent-settings-keys.js +0 -114
  29. package/dist/agent-settings-keys.js.map +0 -1
  30. package/dist/agent-state.d.ts +0 -67
  31. package/dist/agent-state.d.ts.map +0 -1
  32. package/dist/agent-state.js +0 -66
  33. package/dist/agent-state.js.map +0 -1
  34. package/dist/assignment-verify.d.ts +0 -90
  35. package/dist/assignment-verify.d.ts.map +0 -1
  36. package/dist/assignment-verify.js +0 -301
  37. package/dist/assignment-verify.js.map +0 -1
  38. package/dist/attendance-wiring.d.ts +0 -23
  39. package/dist/attendance-wiring.d.ts.map +0 -1
  40. package/dist/attendance-wiring.js +0 -248
  41. package/dist/attendance-wiring.js.map +0 -1
  42. package/dist/attestation-body.d.ts +0 -47
  43. package/dist/attestation-body.d.ts.map +0 -1
  44. package/dist/attestation-body.js +0 -71
  45. package/dist/attestation-body.js.map +0 -1
  46. package/dist/authorship-verification.d.ts +0 -91
  47. package/dist/authorship-verification.d.ts.map +0 -1
  48. package/dist/authorship-verification.js +0 -532
  49. package/dist/authorship-verification.js.map +0 -1
  50. package/dist/away-detection.d.ts +0 -139
  51. package/dist/away-detection.d.ts.map +0 -1
  52. package/dist/away-detection.js +0 -186
  53. package/dist/away-detection.js.map +0 -1
  54. package/dist/away-inbox-oneshot.d.ts +0 -40
  55. package/dist/away-inbox-oneshot.d.ts.map +0 -1
  56. package/dist/away-inbox-oneshot.js +0 -311
  57. package/dist/away-inbox-oneshot.js.map +0 -1
  58. package/dist/backup-restore-handlers.d.ts +0 -10
  59. package/dist/backup-restore-handlers.d.ts.map +0 -1
  60. package/dist/backup-restore-handlers.js +0 -82
  61. package/dist/backup-restore-handlers.js.map +0 -1
  62. package/dist/backup-restore.d.ts +0 -102
  63. package/dist/backup-restore.d.ts.map +0 -1
  64. package/dist/backup-restore.js +0 -341
  65. package/dist/backup-restore.js.map +0 -1
  66. package/dist/bin/cello-daemon.d.ts +0 -13
  67. package/dist/bin/cello-daemon.d.ts.map +0 -1
  68. package/dist/bin/cello-daemon.js.map +0 -1
  69. package/dist/boot-agents.d.ts +0 -64
  70. package/dist/boot-agents.d.ts.map +0 -1
  71. package/dist/boot-agents.js +0 -241
  72. package/dist/boot-agents.js.map +0 -1
  73. package/dist/boot-connection-state.d.ts +0 -38
  74. package/dist/boot-connection-state.d.ts.map +0 -1
  75. package/dist/boot-connection-state.js +0 -95
  76. package/dist/boot-connection-state.js.map +0 -1
  77. package/dist/boot-core.d.ts +0 -36
  78. package/dist/boot-core.d.ts.map +0 -1
  79. package/dist/boot-core.js +0 -293
  80. package/dist/boot-core.js.map +0 -1
  81. package/dist/boot-parked-content.d.ts +0 -34
  82. package/dist/boot-parked-content.d.ts.map +0 -1
  83. package/dist/boot-parked-content.js +0 -528
  84. package/dist/boot-parked-content.js.map +0 -1
  85. package/dist/boot-sweeps.d.ts +0 -22
  86. package/dist/boot-sweeps.d.ts.map +0 -1
  87. package/dist/boot-sweeps.js +0 -51
  88. package/dist/boot-sweeps.js.map +0 -1
  89. package/dist/bundled-consortium-manifest.d.ts +0 -47
  90. package/dist/bundled-consortium-manifest.d.ts.map +0 -1
  91. package/dist/bundled-consortium-manifest.js +0 -116
  92. package/dist/bundled-consortium-manifest.js.map +0 -1
  93. package/dist/cbor-blob-migration.d.ts +0 -8
  94. package/dist/cbor-blob-migration.d.ts.map +0 -1
  95. package/dist/cbor-blob-migration.js +0 -116
  96. package/dist/cbor-blob-migration.js.map +0 -1
  97. package/dist/challenge-verifier.d.ts +0 -12
  98. package/dist/challenge-verifier.d.ts.map +0 -1
  99. package/dist/challenge-verifier.js +0 -11
  100. package/dist/challenge-verifier.js.map +0 -1
  101. package/dist/close-commitment.d.ts +0 -67
  102. package/dist/close-commitment.d.ts.map +0 -1
  103. package/dist/close-commitment.js +0 -78
  104. package/dist/close-commitment.js.map +0 -1
  105. package/dist/close-session-handler.d.ts +0 -94
  106. package/dist/close-session-handler.d.ts.map +0 -1
  107. package/dist/close-session-handler.js +0 -1418
  108. package/dist/close-session-handler.js.map +0 -1
  109. package/dist/co-attendance.d.ts +0 -29
  110. package/dist/co-attendance.d.ts.map +0 -1
  111. package/dist/co-attendance.js +0 -32
  112. package/dist/co-attendance.js.map +0 -1
  113. package/dist/column-birth.d.ts +0 -40
  114. package/dist/column-birth.d.ts.map +0 -1
  115. package/dist/column-birth.js +0 -61
  116. package/dist/column-birth.js.map +0 -1
  117. package/dist/connect-or-start.d.ts +0 -25
  118. package/dist/connect-or-start.d.ts.map +0 -1
  119. package/dist/connect-or-start.js +0 -175
  120. package/dist/connect-or-start.js.map +0 -1
  121. package/dist/connection-agents.d.ts +0 -16
  122. package/dist/connection-agents.d.ts.map +0 -1
  123. package/dist/connection-agents.js +0 -68
  124. package/dist/connection-agents.js.map +0 -1
  125. package/dist/consent-migration.d.ts +0 -49
  126. package/dist/consent-migration.d.ts.map +0 -1
  127. package/dist/consent-migration.js +0 -128
  128. package/dist/consent-migration.js.map +0 -1
  129. package/dist/consortium-bootstrap.d.ts +0 -138
  130. package/dist/consortium-bootstrap.d.ts.map +0 -1
  131. package/dist/consortium-bootstrap.js +0 -339
  132. package/dist/consortium-bootstrap.js.map +0 -1
  133. package/dist/consortium-fingerprint.d.ts +0 -115
  134. package/dist/consortium-fingerprint.d.ts.map +0 -1
  135. package/dist/consortium-fingerprint.js +0 -175
  136. package/dist/consortium-fingerprint.js.map +0 -1
  137. package/dist/contact-handlers.d.ts +0 -59
  138. package/dist/contact-handlers.d.ts.map +0 -1
  139. package/dist/contact-handlers.js +0 -343
  140. package/dist/contact-handlers.js.map +0 -1
  141. package/dist/contact-pubkey-case.d.ts +0 -65
  142. package/dist/contact-pubkey-case.d.ts.map +0 -1
  143. package/dist/contact-pubkey-case.js +0 -136
  144. package/dist/contact-pubkey-case.js.map +0 -1
  145. package/dist/contacts-tier-migration.d.ts +0 -90
  146. package/dist/contacts-tier-migration.d.ts.map +0 -1
  147. package/dist/contacts-tier-migration.js +0 -150
  148. package/dist/contacts-tier-migration.js.map +0 -1
  149. package/dist/content-encryption-status.d.ts +0 -111
  150. package/dist/content-encryption-status.d.ts.map +0 -1
  151. package/dist/content-encryption-status.js +0 -158
  152. package/dist/content-encryption-status.js.map +0 -1
  153. package/dist/content-park-client.d.ts +0 -90
  154. package/dist/content-park-client.d.ts.map +0 -1
  155. package/dist/content-park-client.js +0 -362
  156. package/dist/content-park-client.js.map +0 -1
  157. package/dist/content-park.d.ts +0 -52
  158. package/dist/content-park.d.ts.map +0 -1
  159. package/dist/content-park.js +0 -1309
  160. package/dist/content-park.js.map +0 -1
  161. package/dist/cross-node-negotiation.d.ts +0 -44
  162. package/dist/cross-node-negotiation.d.ts.map +0 -1
  163. package/dist/cross-node-negotiation.js +0 -34
  164. package/dist/cross-node-negotiation.js.map +0 -1
  165. package/dist/daemon-handle.d.ts +0 -57
  166. package/dist/daemon-handle.d.ts.map +0 -1
  167. package/dist/daemon-handle.js +0 -2
  168. package/dist/daemon-handle.js.map +0 -1
  169. package/dist/daemon-status-report.d.ts +0 -50
  170. package/dist/daemon-status-report.d.ts.map +0 -1
  171. package/dist/daemon-status-report.js +0 -81
  172. package/dist/daemon-status-report.js.map +0 -1
  173. package/dist/daemon.d.ts +0 -45
  174. package/dist/daemon.d.ts.map +0 -1
  175. package/dist/daemon.js +0 -1177
  176. package/dist/daemon.js.map +0 -1
  177. package/dist/db-identity-store.d.ts +0 -159
  178. package/dist/db-identity-store.d.ts.map +0 -1
  179. package/dist/db-identity-store.js +0 -502
  180. package/dist/db-identity-store.js.map +0 -1
  181. package/dist/delivery-open-registry.d.ts +0 -92
  182. package/dist/delivery-open-registry.d.ts.map +0 -1
  183. package/dist/delivery-open-registry.js +0 -121
  184. package/dist/delivery-open-registry.js.map +0 -1
  185. package/dist/delivery-session-suspects.d.ts +0 -56
  186. package/dist/delivery-session-suspects.d.ts.map +0 -1
  187. package/dist/delivery-session-suspects.js +0 -94
  188. package/dist/delivery-session-suspects.js.map +0 -1
  189. package/dist/directory-auth-posture.d.ts +0 -87
  190. package/dist/directory-auth-posture.d.ts.map +0 -1
  191. package/dist/directory-auth-posture.js +0 -134
  192. package/dist/directory-auth-posture.js.map +0 -1
  193. package/dist/directory-bootstrap.d.ts +0 -310
  194. package/dist/directory-bootstrap.d.ts.map +0 -1
  195. package/dist/directory-bootstrap.js +0 -557
  196. package/dist/directory-bootstrap.js.map +0 -1
  197. package/dist/directory-connect.d.ts +0 -27
  198. package/dist/directory-connect.d.ts.map +0 -1
  199. package/dist/directory-connect.js +0 -106
  200. package/dist/directory-connect.js.map +0 -1
  201. package/dist/disconnect-cleanup.d.ts +0 -51
  202. package/dist/disconnect-cleanup.d.ts.map +0 -1
  203. package/dist/disconnect-cleanup.js +0 -72
  204. package/dist/disconnect-cleanup.js.map +0 -1
  205. package/dist/document-amendment-store.d.ts +0 -120
  206. package/dist/document-amendment-store.d.ts.map +0 -1
  207. package/dist/document-amendment-store.js +0 -266
  208. package/dist/document-amendment-store.js.map +0 -1
  209. package/dist/document-delivery-transport.d.ts +0 -168
  210. package/dist/document-delivery-transport.d.ts.map +0 -1
  211. package/dist/document-delivery-transport.js +0 -206
  212. package/dist/document-delivery-transport.js.map +0 -1
  213. package/dist/document-engine.d.ts +0 -134
  214. package/dist/document-engine.d.ts.map +0 -1
  215. package/dist/document-engine.js +0 -282
  216. package/dist/document-engine.js.map +0 -1
  217. package/dist/document-flag.d.ts +0 -58
  218. package/dist/document-flag.d.ts.map +0 -1
  219. package/dist/document-flag.js +0 -70
  220. package/dist/document-flag.js.map +0 -1
  221. package/dist/document-frame-router.d.ts +0 -245
  222. package/dist/document-frame-router.d.ts.map +0 -1
  223. package/dist/document-frame-router.js +0 -397
  224. package/dist/document-frame-router.js.map +0 -1
  225. package/dist/document-gate-wiring.d.ts +0 -61
  226. package/dist/document-gate-wiring.d.ts.map +0 -1
  227. package/dist/document-gate-wiring.js +0 -125
  228. package/dist/document-gate-wiring.js.map +0 -1
  229. package/dist/document-gate.d.ts +0 -149
  230. package/dist/document-gate.d.ts.map +0 -1
  231. package/dist/document-gate.js +0 -509
  232. package/dist/document-gate.js.map +0 -1
  233. package/dist/document-handlers.d.ts +0 -47
  234. package/dist/document-handlers.d.ts.map +0 -1
  235. package/dist/document-handlers.js +0 -2203
  236. package/dist/document-handlers.js.map +0 -1
  237. package/dist/document-handshake.d.ts +0 -176
  238. package/dist/document-handshake.d.ts.map +0 -1
  239. package/dist/document-handshake.js +0 -452
  240. package/dist/document-handshake.js.map +0 -1
  241. package/dist/document-inbound.d.ts +0 -162
  242. package/dist/document-inbound.d.ts.map +0 -1
  243. package/dist/document-inbound.js +0 -530
  244. package/dist/document-inbound.js.map +0 -1
  245. package/dist/document-json.d.ts +0 -120
  246. package/dist/document-json.d.ts.map +0 -1
  247. package/dist/document-json.js +0 -191
  248. package/dist/document-json.js.map +0 -1
  249. package/dist/document-layer.d.ts +0 -215
  250. package/dist/document-layer.d.ts.map +0 -1
  251. package/dist/document-layer.js +0 -1025
  252. package/dist/document-layer.js.map +0 -1
  253. package/dist/document-lifecycle.d.ts +0 -52
  254. package/dist/document-lifecycle.d.ts.map +0 -1
  255. package/dist/document-lifecycle.js +0 -134
  256. package/dist/document-lifecycle.js.map +0 -1
  257. package/dist/document-live-docs.d.ts +0 -58
  258. package/dist/document-live-docs.d.ts.map +0 -1
  259. package/dist/document-live-docs.js +0 -126
  260. package/dist/document-live-docs.js.map +0 -1
  261. package/dist/document-notify.d.ts +0 -228
  262. package/dist/document-notify.d.ts.map +0 -1
  263. package/dist/document-notify.js +0 -580
  264. package/dist/document-notify.js.map +0 -1
  265. package/dist/document-profile.d.ts +0 -61
  266. package/dist/document-profile.d.ts.map +0 -1
  267. package/dist/document-profile.js +0 -112
  268. package/dist/document-profile.js.map +0 -1
  269. package/dist/document-publish.d.ts +0 -87
  270. package/dist/document-publish.d.ts.map +0 -1
  271. package/dist/document-publish.js +0 -173
  272. package/dist/document-publish.js.map +0 -1
  273. package/dist/document-reachability.d.ts +0 -42
  274. package/dist/document-reachability.d.ts.map +0 -1
  275. package/dist/document-reachability.js +0 -80
  276. package/dist/document-reachability.js.map +0 -1
  277. package/dist/document-reconcile-engine.d.ts +0 -66
  278. package/dist/document-reconcile-engine.d.ts.map +0 -1
  279. package/dist/document-reconcile-engine.js +0 -225
  280. package/dist/document-reconcile-engine.js.map +0 -1
  281. package/dist/document-reconcile-scheduler.d.ts +0 -163
  282. package/dist/document-reconcile-scheduler.d.ts.map +0 -1
  283. package/dist/document-reconcile-scheduler.js +0 -303
  284. package/dist/document-reconcile-scheduler.js.map +0 -1
  285. package/dist/document-rejection.d.ts +0 -251
  286. package/dist/document-rejection.d.ts.map +0 -1
  287. package/dist/document-rejection.js +0 -435
  288. package/dist/document-rejection.js.map +0 -1
  289. package/dist/document-screen.d.ts +0 -114
  290. package/dist/document-screen.d.ts.map +0 -1
  291. package/dist/document-screen.js +0 -223
  292. package/dist/document-screen.js.map +0 -1
  293. package/dist/document-store.d.ts +0 -372
  294. package/dist/document-store.d.ts.map +0 -1
  295. package/dist/document-store.js +0 -931
  296. package/dist/document-store.js.map +0 -1
  297. package/dist/document-surface.d.ts +0 -32
  298. package/dist/document-surface.d.ts.map +0 -1
  299. package/dist/document-surface.js +0 -151
  300. package/dist/document-surface.js.map +0 -1
  301. package/dist/document-types.d.ts +0 -94
  302. package/dist/document-types.d.ts.map +0 -1
  303. package/dist/document-types.js +0 -90
  304. package/dist/document-types.js.map +0 -1
  305. package/dist/document-watch.d.ts +0 -69
  306. package/dist/document-watch.d.ts.map +0 -1
  307. package/dist/document-watch.js +0 -108
  308. package/dist/document-watch.js.map +0 -1
  309. package/dist/document-wiring.d.ts +0 -53
  310. package/dist/document-wiring.d.ts.map +0 -1
  311. package/dist/document-wiring.js +0 -323
  312. package/dist/document-wiring.js.map +0 -1
  313. package/dist/document-write-guard.d.ts +0 -66
  314. package/dist/document-write-guard.d.ts.map +0 -1
  315. package/dist/document-write-guard.js +0 -98
  316. package/dist/document-write-guard.js.map +0 -1
  317. package/dist/document-write-path.d.ts +0 -94
  318. package/dist/document-write-path.d.ts.map +0 -1
  319. package/dist/document-write-path.js +0 -530
  320. package/dist/document-write-path.js.map +0 -1
  321. package/dist/error-message.d.ts +0 -7
  322. package/dist/error-message.d.ts.map +0 -1
  323. package/dist/error-message.js +0 -19
  324. package/dist/error-message.js.map +0 -1
  325. package/dist/file-manifest-provider.d.ts +0 -37
  326. package/dist/file-manifest-provider.d.ts.map +0 -1
  327. package/dist/file-manifest-provider.js +0 -105
  328. package/dist/file-manifest-provider.js.map +0 -1
  329. package/dist/frame-values.d.ts +0 -3
  330. package/dist/frame-values.d.ts.map +0 -1
  331. package/dist/frame-values.js +0 -84
  332. package/dist/frame-values.js.map +0 -1
  333. package/dist/frontier-mismatch.d.ts +0 -73
  334. package/dist/frontier-mismatch.d.ts.map +0 -1
  335. package/dist/frontier-mismatch.js +0 -89
  336. package/dist/frontier-mismatch.js.map +0 -1
  337. package/dist/gateway-config-handlers.d.ts +0 -26
  338. package/dist/gateway-config-handlers.d.ts.map +0 -1
  339. package/dist/gateway-config-handlers.js +0 -429
  340. package/dist/gateway-config-handlers.js.map +0 -1
  341. package/dist/held-content.d.ts +0 -145
  342. package/dist/held-content.d.ts.map +0 -1
  343. package/dist/held-content.js +0 -389
  344. package/dist/held-content.js.map +0 -1
  345. package/dist/http-manifest-poll.d.ts +0 -67
  346. package/dist/http-manifest-poll.d.ts.map +0 -1
  347. package/dist/http-manifest-poll.js +0 -150
  348. package/dist/http-manifest-poll.js.map +0 -1
  349. package/dist/identity-migration.d.ts +0 -40
  350. package/dist/identity-migration.d.ts.map +0 -1
  351. package/dist/identity-migration.js +0 -461
  352. package/dist/identity-migration.js.map +0 -1
  353. package/dist/inbound-refusals.d.ts +0 -283
  354. package/dist/inbound-refusals.d.ts.map +0 -1
  355. package/dist/inbound-refusals.js +0 -919
  356. package/dist/inbound-refusals.js.map +0 -1
  357. package/dist/inbound-seal-request.d.ts +0 -32
  358. package/dist/inbound-seal-request.d.ts.map +0 -1
  359. package/dist/inbound-seal-request.js +0 -228
  360. package/dist/inbound-seal-request.js.map +0 -1
  361. package/dist/inbound-sessions.d.ts +0 -291
  362. package/dist/inbound-sessions.d.ts.map +0 -1
  363. package/dist/inbound-sessions.js +0 -1609
  364. package/dist/inbound-sessions.js.map +0 -1
  365. package/dist/inclusion-proof-handlers.d.ts +0 -43
  366. package/dist/inclusion-proof-handlers.d.ts.map +0 -1
  367. package/dist/inclusion-proof-handlers.js +0 -565
  368. package/dist/inclusion-proof-handlers.js.map +0 -1
  369. package/dist/inclusion-proof.d.ts +0 -151
  370. package/dist/inclusion-proof.d.ts.map +0 -1
  371. package/dist/inclusion-proof.js +0 -228
  372. package/dist/inclusion-proof.js.map +0 -1
  373. package/dist/index.d.ts +0 -32
  374. package/dist/index.d.ts.map +0 -1
  375. package/dist/index.js.map +0 -1
  376. package/dist/initiate-session-handler.d.ts +0 -55
  377. package/dist/initiate-session-handler.d.ts.map +0 -1
  378. package/dist/initiate-session-handler.js +0 -310
  379. package/dist/initiate-session-handler.js.map +0 -1
  380. package/dist/ipc-client.d.ts +0 -31
  381. package/dist/ipc-client.d.ts.map +0 -1
  382. package/dist/ipc-client.js +0 -113
  383. package/dist/ipc-client.js.map +0 -1
  384. package/dist/ipc-server.d.ts +0 -63
  385. package/dist/ipc-server.d.ts.map +0 -1
  386. package/dist/ipc-server.js +0 -429
  387. package/dist/ipc-server.js.map +0 -1
  388. package/dist/ipc-surface.d.ts +0 -44
  389. package/dist/ipc-surface.d.ts.map +0 -1
  390. package/dist/ipc-surface.js +0 -107
  391. package/dist/ipc-surface.js.map +0 -1
  392. package/dist/line-lcs.d.ts +0 -51
  393. package/dist/line-lcs.d.ts.map +0 -1
  394. package/dist/line-lcs.js +0 -71
  395. package/dist/line-lcs.js.map +0 -1
  396. package/dist/lock-file.d.ts +0 -39
  397. package/dist/lock-file.d.ts.map +0 -1
  398. package/dist/lock-file.js +0 -120
  399. package/dist/lock-file.js.map +0 -1
  400. package/dist/log-collapse.d.ts +0 -66
  401. package/dist/log-collapse.d.ts.map +0 -1
  402. package/dist/log-collapse.js +0 -244
  403. package/dist/log-collapse.js.map +0 -1
  404. package/dist/log-rotate.d.ts +0 -67
  405. package/dist/log-rotate.d.ts.map +0 -1
  406. package/dist/log-rotate.js +0 -134
  407. package/dist/log-rotate.js.map +0 -1
  408. package/dist/manifest-deps.d.ts +0 -25
  409. package/dist/manifest-deps.d.ts.map +0 -1
  410. package/dist/manifest-deps.js +0 -151
  411. package/dist/manifest-deps.js.map +0 -1
  412. package/dist/manifest-poll-scheduler.d.ts +0 -31
  413. package/dist/manifest-poll-scheduler.d.ts.map +0 -1
  414. package/dist/manifest-poll-scheduler.js +0 -59
  415. package/dist/manifest-poll-scheduler.js.map +0 -1
  416. package/dist/manifest-validity.d.ts +0 -153
  417. package/dist/manifest-validity.d.ts.map +0 -1
  418. package/dist/manifest-validity.js +0 -268
  419. package/dist/manifest-validity.js.map +0 -1
  420. package/dist/manifest-version-store-db.d.ts +0 -24
  421. package/dist/manifest-version-store-db.d.ts.map +0 -1
  422. package/dist/manifest-version-store-db.js +0 -58
  423. package/dist/manifest-version-store-db.js.map +0 -1
  424. package/dist/manifest-version-store.d.ts +0 -16
  425. package/dist/manifest-version-store.d.ts.map +0 -1
  426. package/dist/manifest-version-store.js +0 -15
  427. package/dist/manifest-version-store.js.map +0 -1
  428. package/dist/network-directory-node.d.ts +0 -136
  429. package/dist/network-directory-node.d.ts.map +0 -1
  430. package/dist/network-directory-node.js +0 -810
  431. package/dist/network-directory-node.js.map +0 -1
  432. package/dist/nonce-dedup.d.ts +0 -68
  433. package/dist/nonce-dedup.d.ts.map +0 -1
  434. package/dist/nonce-dedup.js +0 -205
  435. package/dist/nonce-dedup.js.map +0 -1
  436. package/dist/notification-dispatcher.d.ts +0 -92
  437. package/dist/notification-dispatcher.d.ts.map +0 -1
  438. package/dist/notification-dispatcher.js +0 -210
  439. package/dist/notification-dispatcher.js.map +0 -1
  440. package/dist/notification-handlers.d.ts +0 -53
  441. package/dist/notification-handlers.d.ts.map +0 -1
  442. package/dist/notification-handlers.js +0 -461
  443. package/dist/notification-handlers.js.map +0 -1
  444. package/dist/onboarding-guidance.d.ts +0 -79
  445. package/dist/onboarding-guidance.d.ts.map +0 -1
  446. package/dist/onboarding-guidance.js +0 -95
  447. package/dist/onboarding-guidance.js.map +0 -1
  448. package/dist/operator-guidance.d.ts +0 -25
  449. package/dist/operator-guidance.d.ts.map +0 -1
  450. package/dist/operator-guidance.js +0 -50
  451. package/dist/operator-guidance.js.map +0 -1
  452. package/dist/orphan-triage.d.ts +0 -130
  453. package/dist/orphan-triage.d.ts.map +0 -1
  454. package/dist/orphan-triage.js +0 -207
  455. package/dist/orphan-triage.js.map +0 -1
  456. package/dist/outbound-sessions.d.ts +0 -126
  457. package/dist/outbound-sessions.d.ts.map +0 -1
  458. package/dist/outbound-sessions.js +0 -1052
  459. package/dist/outbound-sessions.js.map +0 -1
  460. package/dist/park-envelope.d.ts +0 -329
  461. package/dist/park-envelope.d.ts.map +0 -1
  462. package/dist/park-envelope.js +0 -509
  463. package/dist/park-envelope.js.map +0 -1
  464. package/dist/park-recovery.d.ts +0 -273
  465. package/dist/park-recovery.d.ts.map +0 -1
  466. package/dist/park-recovery.js +0 -717
  467. package/dist/park-recovery.js.map +0 -1
  468. package/dist/park-refusals.d.ts +0 -147
  469. package/dist/park-refusals.d.ts.map +0 -1
  470. package/dist/park-refusals.js +0 -331
  471. package/dist/park-refusals.js.map +0 -1
  472. package/dist/quarantine-framing.d.ts +0 -92
  473. package/dist/quarantine-framing.d.ts.map +0 -1
  474. package/dist/quarantine-framing.js +0 -111
  475. package/dist/quarantine-framing.js.map +0 -1
  476. package/dist/reconnect-drain.d.ts +0 -22
  477. package/dist/reconnect-drain.d.ts.map +0 -1
  478. package/dist/reconnect-drain.js +0 -65
  479. package/dist/reconnect-drain.js.map +0 -1
  480. package/dist/recovered-position.d.ts +0 -14
  481. package/dist/recovered-position.d.ts.map +0 -1
  482. package/dist/recovered-position.js +0 -59
  483. package/dist/recovered-position.js.map +0 -1
  484. package/dist/refusal-notices.d.ts +0 -196
  485. package/dist/refusal-notices.d.ts.map +0 -1
  486. package/dist/refusal-notices.js +0 -516
  487. package/dist/refusal-notices.js.map +0 -1
  488. package/dist/refusal-reasons.d.ts +0 -245
  489. package/dist/refusal-reasons.d.ts.map +0 -1
  490. package/dist/refusal-reasons.js +0 -363
  491. package/dist/refusal-reasons.js.map +0 -1
  492. package/dist/register-handler.d.ts +0 -36
  493. package/dist/register-handler.d.ts.map +0 -1
  494. package/dist/register-handler.js +0 -285
  495. package/dist/register-handler.js.map +0 -1
  496. package/dist/registration-context.d.ts +0 -72
  497. package/dist/registration-context.d.ts.map +0 -1
  498. package/dist/registration-context.js +0 -126
  499. package/dist/registration-context.js.map +0 -1
  500. package/dist/registration-manager.d.ts +0 -94
  501. package/dist/registration-manager.d.ts.map +0 -1
  502. package/dist/registration-manager.js +0 -585
  503. package/dist/registration-manager.js.map +0 -1
  504. package/dist/registration-persistence.d.ts +0 -183
  505. package/dist/registration-persistence.d.ts.map +0 -1
  506. package/dist/registration-persistence.js +0 -263
  507. package/dist/registration-persistence.js.map +0 -1
  508. package/dist/registry-poll.d.ts +0 -52
  509. package/dist/registry-poll.d.ts.map +0 -1
  510. package/dist/registry-poll.js +0 -140
  511. package/dist/registry-poll.js.map +0 -1
  512. package/dist/registry-version-store-db.d.ts +0 -22
  513. package/dist/registry-version-store-db.d.ts.map +0 -1
  514. package/dist/registry-version-store-db.js +0 -50
  515. package/dist/registry-version-store-db.js.map +0 -1
  516. package/dist/relay-endpoints.d.ts +0 -18
  517. package/dist/relay-endpoints.d.ts.map +0 -1
  518. package/dist/relay-endpoints.js +0 -9
  519. package/dist/relay-endpoints.js.map +0 -1
  520. package/dist/relay-only.d.ts +0 -140
  521. package/dist/relay-only.d.ts.map +0 -1
  522. package/dist/relay-only.js +0 -193
  523. package/dist/relay-only.js.map +0 -1
  524. package/dist/relay-receipt-store.d.ts +0 -155
  525. package/dist/relay-receipt-store.d.ts.map +0 -1
  526. package/dist/relay-receipt-store.js +0 -284
  527. package/dist/relay-receipt-store.js.map +0 -1
  528. package/dist/relay-reconnect.d.ts +0 -32
  529. package/dist/relay-reconnect.d.ts.map +0 -1
  530. package/dist/relay-reconnect.js +0 -29
  531. package/dist/relay-reconnect.js.map +0 -1
  532. package/dist/reply-lag.d.ts +0 -11
  533. package/dist/reply-lag.d.ts.map +0 -1
  534. package/dist/reply-lag.js +0 -46
  535. package/dist/reply-lag.js.map +0 -1
  536. package/dist/resolve-named-agent.d.ts +0 -49
  537. package/dist/resolve-named-agent.d.ts.map +0 -1
  538. package/dist/resolve-named-agent.js +0 -77
  539. package/dist/resolve-named-agent.js.map +0 -1
  540. package/dist/restart-seal-resolver.d.ts +0 -110
  541. package/dist/restart-seal-resolver.d.ts.map +0 -1
  542. package/dist/restart-seal-resolver.js +0 -353
  543. package/dist/restart-seal-resolver.js.map +0 -1
  544. package/dist/resume-last-seen.d.ts +0 -15
  545. package/dist/resume-last-seen.d.ts.map +0 -1
  546. package/dist/resume-last-seen.js +0 -44
  547. package/dist/resume-last-seen.js.map +0 -1
  548. package/dist/retry-queue.d.ts +0 -203
  549. package/dist/retry-queue.d.ts.map +0 -1
  550. package/dist/retry-queue.js +0 -701
  551. package/dist/retry-queue.js.map +0 -1
  552. package/dist/roster-freshness.d.ts +0 -160
  553. package/dist/roster-freshness.d.ts.map +0 -1
  554. package/dist/roster-freshness.js +0 -250
  555. package/dist/roster-freshness.js.map +0 -1
  556. package/dist/screening-status.d.ts +0 -15
  557. package/dist/screening-status.d.ts.map +0 -1
  558. package/dist/screening-status.js +0 -65
  559. package/dist/screening-status.js.map +0 -1
  560. package/dist/seal-carried-close.d.ts +0 -37
  561. package/dist/seal-carried-close.d.ts.map +0 -1
  562. package/dist/seal-carried-close.js +0 -179
  563. package/dist/seal-carried-close.js.map +0 -1
  564. package/dist/seal-certificate-pull.d.ts +0 -79
  565. package/dist/seal-certificate-pull.d.ts.map +0 -1
  566. package/dist/seal-certificate-pull.js +0 -186
  567. package/dist/seal-certificate-pull.js.map +0 -1
  568. package/dist/seal-certified-root-check.d.ts +0 -37
  569. package/dist/seal-certified-root-check.d.ts.map +0 -1
  570. package/dist/seal-certified-root-check.js +0 -127
  571. package/dist/seal-certified-root-check.js.map +0 -1
  572. package/dist/seal-coordinator.d.ts +0 -118
  573. package/dist/seal-coordinator.d.ts.map +0 -1
  574. package/dist/seal-coordinator.js +0 -927
  575. package/dist/seal-coordinator.js.map +0 -1
  576. package/dist/seal-escalation.d.ts +0 -80
  577. package/dist/seal-escalation.d.ts.map +0 -1
  578. package/dist/seal-escalation.js +0 -283
  579. package/dist/seal-escalation.js.map +0 -1
  580. package/dist/seal-evidence-root-check.d.ts +0 -70
  581. package/dist/seal-evidence-root-check.d.ts.map +0 -1
  582. package/dist/seal-evidence-root-check.js +0 -199
  583. package/dist/seal-evidence-root-check.js.map +0 -1
  584. package/dist/seal-failure-store.d.ts +0 -129
  585. package/dist/seal-failure-store.d.ts.map +0 -1
  586. package/dist/seal-failure-store.js +0 -173
  587. package/dist/seal-failure-store.js.map +0 -1
  588. package/dist/seal-flows.d.ts +0 -107
  589. package/dist/seal-flows.d.ts.map +0 -1
  590. package/dist/seal-flows.js +0 -638
  591. package/dist/seal-flows.js.map +0 -1
  592. package/dist/seal-frontier-verify.d.ts +0 -103
  593. package/dist/seal-frontier-verify.d.ts.map +0 -1
  594. package/dist/seal-frontier-verify.js +0 -143
  595. package/dist/seal-frontier-verify.js.map +0 -1
  596. package/dist/seal-leaf.d.ts +0 -58
  597. package/dist/seal-leaf.d.ts.map +0 -1
  598. package/dist/seal-leaf.js +0 -112
  599. package/dist/seal-leaf.js.map +0 -1
  600. package/dist/seal-legibility-tbs.d.ts +0 -25
  601. package/dist/seal-legibility-tbs.d.ts.map +0 -1
  602. package/dist/seal-legibility-tbs.js +0 -77
  603. package/dist/seal-legibility-tbs.js.map +0 -1
  604. package/dist/seal-local-terminus.d.ts +0 -41
  605. package/dist/seal-local-terminus.d.ts.map +0 -1
  606. package/dist/seal-local-terminus.js +0 -170
  607. package/dist/seal-local-terminus.js.map +0 -1
  608. package/dist/seal-receipt-upgrade.d.ts +0 -30
  609. package/dist/seal-receipt-upgrade.d.ts.map +0 -1
  610. package/dist/seal-receipt-upgrade.js +0 -49
  611. package/dist/seal-receipt-upgrade.js.map +0 -1
  612. package/dist/seal-relay-silence.d.ts +0 -51
  613. package/dist/seal-relay-silence.d.ts.map +0 -1
  614. package/dist/seal-relay-silence.js +0 -76
  615. package/dist/seal-relay-silence.js.map +0 -1
  616. package/dist/seal-settle.d.ts +0 -38
  617. package/dist/seal-settle.d.ts.map +0 -1
  618. package/dist/seal-settle.js +0 -33
  619. package/dist/seal-settle.js.map +0 -1
  620. package/dist/seal-upgrade.d.ts +0 -107
  621. package/dist/seal-upgrade.d.ts.map +0 -1
  622. package/dist/seal-upgrade.js +0 -200
  623. package/dist/seal-upgrade.js.map +0 -1
  624. package/dist/sealed-conversation.d.ts +0 -36
  625. package/dist/sealed-conversation.d.ts.map +0 -1
  626. package/dist/sealed-conversation.js +0 -171
  627. package/dist/sealed-conversation.js.map +0 -1
  628. package/dist/sealed-leaf-set.d.ts +0 -92
  629. package/dist/sealed-leaf-set.d.ts.map +0 -1
  630. package/dist/sealed-leaf-set.js +0 -122
  631. package/dist/sealed-leaf-set.js.map +0 -1
  632. package/dist/send-claims.d.ts +0 -56
  633. package/dist/send-claims.d.ts.map +0 -1
  634. package/dist/send-claims.js +0 -50
  635. package/dist/send-claims.js.map +0 -1
  636. package/dist/session-assignment-parser.d.ts +0 -98
  637. package/dist/session-assignment-parser.d.ts.map +0 -1
  638. package/dist/session-assignment-parser.js +0 -325
  639. package/dist/session-assignment-parser.js.map +0 -1
  640. package/dist/session-category.d.ts +0 -19
  641. package/dist/session-category.d.ts.map +0 -1
  642. package/dist/session-category.js +0 -14
  643. package/dist/session-category.js.map +0 -1
  644. package/dist/session-ceremony.d.ts +0 -297
  645. package/dist/session-ceremony.d.ts.map +0 -1
  646. package/dist/session-ceremony.js +0 -964
  647. package/dist/session-ceremony.js.map +0 -1
  648. package/dist/session-closed.d.ts +0 -79
  649. package/dist/session-closed.d.ts.map +0 -1
  650. package/dist/session-closed.js +0 -189
  651. package/dist/session-closed.js.map +0 -1
  652. package/dist/session-connection-gater.d.ts +0 -148
  653. package/dist/session-connection-gater.d.ts.map +0 -1
  654. package/dist/session-connection-gater.js +0 -332
  655. package/dist/session-connection-gater.js.map +0 -1
  656. package/dist/session-content-context.d.ts +0 -162
  657. package/dist/session-content-context.d.ts.map +0 -1
  658. package/dist/session-content-context.js +0 -2
  659. package/dist/session-content-context.js.map +0 -1
  660. package/dist/session-content-handlers.d.ts +0 -82
  661. package/dist/session-content-handlers.d.ts.map +0 -1
  662. package/dist/session-content-handlers.js +0 -1382
  663. package/dist/session-content-handlers.js.map +0 -1
  664. package/dist/session-content-ingest.d.ts +0 -206
  665. package/dist/session-content-ingest.d.ts.map +0 -1
  666. package/dist/session-content-ingest.js +0 -2167
  667. package/dist/session-content-ingest.js.map +0 -1
  668. package/dist/session-content-send.d.ts +0 -191
  669. package/dist/session-content-send.d.ts.map +0 -1
  670. package/dist/session-content-send.js +0 -1360
  671. package/dist/session-content-send.js.map +0 -1
  672. package/dist/session-delivery-acks.d.ts +0 -169
  673. package/dist/session-delivery-acks.d.ts.map +0 -1
  674. package/dist/session-delivery-acks.js +0 -569
  675. package/dist/session-delivery-acks.js.map +0 -1
  676. package/dist/session-ephemerals.d.ts +0 -279
  677. package/dist/session-ephemerals.d.ts.map +0 -1
  678. package/dist/session-ephemerals.js +0 -591
  679. package/dist/session-ephemerals.js.map +0 -1
  680. package/dist/session-leaf-records.d.ts +0 -159
  681. package/dist/session-leaf-records.d.ts.map +0 -1
  682. package/dist/session-leaf-records.js +0 -408
  683. package/dist/session-leaf-records.js.map +0 -1
  684. package/dist/session-lifecycle.d.ts +0 -303
  685. package/dist/session-lifecycle.d.ts.map +0 -1
  686. package/dist/session-lifecycle.js +0 -1679
  687. package/dist/session-lifecycle.js.map +0 -1
  688. package/dist/session-liveness.d.ts +0 -135
  689. package/dist/session-liveness.d.ts.map +0 -1
  690. package/dist/session-liveness.js +0 -347
  691. package/dist/session-liveness.js.map +0 -1
  692. package/dist/session-name.d.ts +0 -35
  693. package/dist/session-name.d.ts.map +0 -1
  694. package/dist/session-name.js +0 -60
  695. package/dist/session-name.js.map +0 -1
  696. package/dist/session-node-factory.d.ts +0 -18
  697. package/dist/session-node-factory.d.ts.map +0 -1
  698. package/dist/session-node-factory.js +0 -182
  699. package/dist/session-node-factory.js.map +0 -1
  700. package/dist/session-node-manager.d.ts +0 -875
  701. package/dist/session-node-manager.d.ts.map +0 -1
  702. package/dist/session-node-manager.js +0 -2995
  703. package/dist/session-node-manager.js.map +0 -1
  704. package/dist/session-node-types.d.ts +0 -1057
  705. package/dist/session-node-types.d.ts.map +0 -1
  706. package/dist/session-node-types.js +0 -657
  707. package/dist/session-node-types.js.map +0 -1
  708. package/dist/session-notify.d.ts +0 -46
  709. package/dist/session-notify.d.ts.map +0 -1
  710. package/dist/session-notify.js +0 -116
  711. package/dist/session-notify.js.map +0 -1
  712. package/dist/session-own-chain-store.d.ts +0 -65
  713. package/dist/session-own-chain-store.d.ts.map +0 -1
  714. package/dist/session-own-chain-store.js +0 -75
  715. package/dist/session-own-chain-store.js.map +0 -1
  716. package/dist/session-queries.d.ts +0 -476
  717. package/dist/session-queries.d.ts.map +0 -1
  718. package/dist/session-queries.js +0 -1007
  719. package/dist/session-queries.js.map +0 -1
  720. package/dist/session-read-handlers.d.ts +0 -87
  721. package/dist/session-read-handlers.d.ts.map +0 -1
  722. package/dist/session-read-handlers.js +0 -682
  723. package/dist/session-read-handlers.js.map +0 -1
  724. package/dist/session-records.d.ts +0 -341
  725. package/dist/session-records.d.ts.map +0 -1
  726. package/dist/session-records.js +0 -858
  727. package/dist/session-records.js.map +0 -1
  728. package/dist/session-relay-client.d.ts +0 -659
  729. package/dist/session-relay-client.d.ts.map +0 -1
  730. package/dist/session-relay-client.js +0 -2876
  731. package/dist/session-relay-client.js.map +0 -1
  732. package/dist/session-relay.d.ts +0 -397
  733. package/dist/session-relay.d.ts.map +0 -1
  734. package/dist/session-relay.js +0 -1636
  735. package/dist/session-relay.js.map +0 -1
  736. package/dist/session-salt-agreement.d.ts +0 -331
  737. package/dist/session-salt-agreement.d.ts.map +0 -1
  738. package/dist/session-salt-agreement.js +0 -472
  739. package/dist/session-salt-agreement.js.map +0 -1
  740. package/dist/session-salts.d.ts +0 -432
  741. package/dist/session-salts.d.ts.map +0 -1
  742. package/dist/session-salts.js +0 -1540
  743. package/dist/session-salts.js.map +0 -1
  744. package/dist/session-schema.d.ts +0 -30
  745. package/dist/session-schema.d.ts.map +0 -1
  746. package/dist/session-schema.js +0 -877
  747. package/dist/session-schema.js.map +0 -1
  748. package/dist/session-seal-leaf-store.d.ts +0 -70
  749. package/dist/session-seal-leaf-store.d.ts.map +0 -1
  750. package/dist/session-seal-leaf-store.js +0 -105
  751. package/dist/session-seal-leaf-store.js.map +0 -1
  752. package/dist/session-seal.d.ts +0 -334
  753. package/dist/session-seal.d.ts.map +0 -1
  754. package/dist/session-seal.js +0 -1017
  755. package/dist/session-seal.js.map +0 -1
  756. package/dist/session-terminal-refusal.d.ts +0 -65
  757. package/dist/session-terminal-refusal.d.ts.map +0 -1
  758. package/dist/session-terminal-refusal.js +0 -87
  759. package/dist/session-terminal-refusal.js.map +0 -1
  760. package/dist/session-tree.d.ts +0 -110
  761. package/dist/session-tree.d.ts.map +0 -1
  762. package/dist/session-tree.js +0 -144
  763. package/dist/session-tree.js.map +0 -1
  764. package/dist/session-views.d.ts +0 -47
  765. package/dist/session-views.d.ts.map +0 -1
  766. package/dist/session-views.js +0 -278
  767. package/dist/session-views.js.map +0 -1
  768. package/dist/signal-handlers.d.ts +0 -63
  769. package/dist/signal-handlers.d.ts.map +0 -1
  770. package/dist/signal-handlers.js +0 -980
  771. package/dist/signal-handlers.js.map +0 -1
  772. package/dist/signal-requirement-policy.d.ts +0 -51
  773. package/dist/signal-requirement-policy.d.ts.map +0 -1
  774. package/dist/signal-requirement-policy.js +0 -89
  775. package/dist/signal-requirement-policy.js.map +0 -1
  776. package/dist/signal-revocability.d.ts +0 -49
  777. package/dist/signal-revocability.d.ts.map +0 -1
  778. package/dist/signal-revocability.js +0 -93
  779. package/dist/signal-revocability.js.map +0 -1
  780. package/dist/signal-submission.d.ts +0 -181
  781. package/dist/signal-submission.d.ts.map +0 -1
  782. package/dist/signal-submission.js +0 -368
  783. package/dist/signal-submission.js.map +0 -1
  784. package/dist/signaling-connect.d.ts +0 -118
  785. package/dist/signaling-connect.d.ts.map +0 -1
  786. package/dist/signaling-connect.js +0 -538
  787. package/dist/signaling-connect.js.map +0 -1
  788. package/dist/signaling-wiring.d.ts +0 -105
  789. package/dist/signaling-wiring.d.ts.map +0 -1
  790. package/dist/signaling-wiring.js +0 -393
  791. package/dist/signaling-wiring.js.map +0 -1
  792. package/dist/singleton-lock.d.ts +0 -85
  793. package/dist/singleton-lock.d.ts.map +0 -1
  794. package/dist/singleton-lock.js +0 -219
  795. package/dist/singleton-lock.js.map +0 -1
  796. package/dist/sqlcipher-db.d.ts +0 -139
  797. package/dist/sqlcipher-db.d.ts.map +0 -1
  798. package/dist/sqlcipher-db.js +0 -357
  799. package/dist/sqlcipher-db.js.map +0 -1
  800. package/dist/standing-receivers.d.ts +0 -319
  801. package/dist/standing-receivers.d.ts.map +0 -1
  802. package/dist/standing-receivers.js +0 -1295
  803. package/dist/standing-receivers.js.map +0 -1
  804. package/dist/start-agent.d.ts +0 -64
  805. package/dist/start-agent.d.ts.map +0 -1
  806. package/dist/start-agent.js +0 -136
  807. package/dist/start-agent.js.map +0 -1
  808. package/dist/status-handler.d.ts +0 -54
  809. package/dist/status-handler.d.ts.map +0 -1
  810. package/dist/status-handler.js +0 -61
  811. package/dist/status-handler.js.map +0 -1
  812. package/dist/submission-retry.d.ts +0 -208
  813. package/dist/submission-retry.d.ts.map +0 -1
  814. package/dist/submission-retry.js +0 -506
  815. package/dist/submission-retry.js.map +0 -1
  816. package/dist/telegram-bot-client.d.ts +0 -34
  817. package/dist/telegram-bot-client.d.ts.map +0 -1
  818. package/dist/telegram-bot-client.js +0 -36
  819. package/dist/telegram-bot-client.js.map +0 -1
  820. package/dist/telegram-doorbell.d.ts +0 -38
  821. package/dist/telegram-doorbell.d.ts.map +0 -1
  822. package/dist/telegram-doorbell.js +0 -140
  823. package/dist/telegram-doorbell.js.map +0 -1
  824. package/dist/test-handlers.d.ts +0 -62
  825. package/dist/test-handlers.d.ts.map +0 -1
  826. package/dist/test-handlers.js +0 -240
  827. package/dist/test-handlers.js.map +0 -1
  828. package/dist/testing.d.ts +0 -10
  829. package/dist/testing.d.ts.map +0 -1
  830. package/dist/testing.js +0 -10
  831. package/dist/testing.js.map +0 -1
  832. package/dist/transport-composition.d.ts +0 -31
  833. package/dist/transport-composition.d.ts.map +0 -1
  834. package/dist/transport-composition.js +0 -55
  835. package/dist/transport-composition.js.map +0 -1
  836. package/dist/transport-selector.d.ts +0 -202
  837. package/dist/transport-selector.d.ts.map +0 -1
  838. package/dist/transport-selector.js +0 -196
  839. package/dist/transport-selector.js.map +0 -1
  840. package/dist/trust-signal-pickup-listener.d.ts +0 -43
  841. package/dist/trust-signal-pickup-listener.d.ts.map +0 -1
  842. package/dist/trust-signal-pickup-listener.js +0 -48
  843. package/dist/trust-signal-pickup-listener.js.map +0 -1
  844. package/dist/trust-signal-store.d.ts +0 -406
  845. package/dist/trust-signal-store.d.ts.map +0 -1
  846. package/dist/trust-signal-store.js +0 -939
  847. package/dist/trust-signal-store.js.map +0 -1
  848. package/dist/trust-signal-sweep-tick.d.ts +0 -60
  849. package/dist/trust-signal-sweep-tick.d.ts.map +0 -1
  850. package/dist/trust-signal-sweep-tick.js +0 -101
  851. package/dist/trust-signal-sweep-tick.js.map +0 -1
  852. package/dist/trust-signal-sweep.d.ts +0 -94
  853. package/dist/trust-signal-sweep.d.ts.map +0 -1
  854. package/dist/trust-signal-sweep.js +0 -147
  855. package/dist/trust-signal-sweep.js.map +0 -1
  856. package/dist/type-registry.d.ts +0 -42
  857. package/dist/type-registry.d.ts.map +0 -1
  858. package/dist/type-registry.js +0 -37
  859. package/dist/type-registry.js.map +0 -1
  860. package/dist/types.d.ts +0 -746
  861. package/dist/types.d.ts.map +0 -1
  862. package/dist/types.js +0 -20
  863. package/dist/types.js.map +0 -1
  864. package/dist/unresolved-nodes-report.d.ts +0 -14
  865. package/dist/unresolved-nodes-report.d.ts.map +0 -1
  866. package/dist/unresolved-nodes-report.js +0 -96
  867. package/dist/unresolved-nodes-report.js.map +0 -1
  868. package/dist/vocabulary.d.ts +0 -150
  869. package/dist/vocabulary.d.ts.map +0 -1
  870. package/dist/vocabulary.js +0 -386
  871. package/dist/vocabulary.js.map +0 -1
  872. package/dist/who-label.d.ts +0 -28
  873. package/dist/who-label.d.ts.map +0 -1
  874. package/dist/who-label.js +0 -31
  875. package/dist/who-label.js.map +0 -1
  876. package/dist/who-resolver.d.ts +0 -15
  877. package/dist/who-resolver.d.ts.map +0 -1
  878. package/dist/who-resolver.js +0 -47
  879. package/dist/who-resolver.js.map +0 -1
  880. package/dist/wire-content-hash.d.ts +0 -93
  881. package/dist/wire-content-hash.d.ts.map +0 -1
  882. package/dist/wire-content-hash.js +0 -116
  883. package/dist/wire-content-hash.js.map +0 -1
  884. package/dist/withheld-content.d.ts +0 -13
  885. package/dist/withheld-content.d.ts.map +0 -1
  886. package/dist/withheld-content.js +0 -46
  887. package/dist/withheld-content.js.map +0 -1
  888. package/dist/witness-alerts.d.ts +0 -40
  889. package/dist/witness-alerts.d.ts.map +0 -1
  890. package/dist/witness-alerts.js +0 -102
  891. package/dist/witness-alerts.js.map +0 -1
@@ -1,1382 +0,0 @@
1
- /**
2
- * cello_send and cello_receive — the content path.
3
- *
4
- * The two biggest handlers in the daemon, and the two I had put on a DO-NOT-CUT list. That list was
5
- * written before anything had been measured, and it was wrong: these close over eleven things, not
6
- * the whole daemon. They are listed below, which is the point of the move.
7
- *
8
- * They stay TOGETHER because they are two halves of one state machine — the read cursor. cello_send
9
- * appends to the daemon-owned tree; cello_receive advances the per-connection cursor and the durable
10
- * watermark. Splitting them would put the cursor's writer and its reader in different modules.
11
- */
12
- // `wireContentHash` is no longer imported here: every outbound hash in this file now comes from
13
- // `SessionNodeManager.contentHashForSession`, which returns the hash and its ALGORITHM together
14
- // (`DOD-M15-SEALWIRE-1` part B2b). A direct call would be a hash computed without deciding — or
15
- // recording — how it was made, which is the state that made a version skew look like a tamper.
16
- import { randomUUID } from "node:crypto";
17
- import { LEAF_KIND_MSG } from "./session-relay-client.js";
18
- import { MAX_CONTENT_BYTES } from "@cello-protocol/protocol-types";
19
- import { TIER } from "./contacts-tier-migration.js";
20
- import { GATEWAY_UNAVAILABLE, GOVERNANCE_TIMEOUT } from "@cello-protocol/gateway";
21
- import { isAutoReplyMarked } from "./away-detection.js";
22
- import { REFUSAL_COUNT_GUIDANCE, REFUSAL_KIND_GUIDANCE } from "./refusal-reasons.js";
23
- import { extractErrorMessage } from "./error-message.js";
24
- import { SESSION_CLOSED_GUIDANCE, SESSION_CLOSED_REASON, SESSION_SEALING_IMPACT, closedSessionImpact, isClosedStatus } from "./session-closed.js";
25
- import { replyLag } from "./reply-lag.js";
26
- /** Whether the other side's latest replies were written before they saw this side's newest message. */
27
- function replyLagFor(snm, agentName, sessionId) {
28
- // Runs AFTER the read position moved, so a throw here would lose the messages being handed over.
29
- // The warning is optional; the messages are not.
30
- try {
31
- const db = snm.getDb();
32
- const row = db.prepare("SELECT k_local_pubkey FROM agents WHERE agent_id = ?").get(snm.resolveAgentId(agentName));
33
- return row ? replyLag(db, row.k_local_pubkey, sessionId) : undefined;
34
- }
35
- catch {
36
- return undefined;
37
- }
38
- }
39
- /**
40
- * DOD-M12B-AWAY-MARK-1 — what a reader needs to know the moment it sees a marked message.
41
- *
42
- * Written for the failure it prevents, not the mechanism: an agent reads an away reply, concludes a
43
- * person answered, and tells its operator a conversation is under way. Two agents did exactly that
44
- * to each other for a morning on 2026-08-17. So it leads with "nobody read your message", and it
45
- * says what the reader should do instead of replying into an empty room.
46
- */
47
- /**
48
- * DOD-M15-REFUSED-INBOUND-SILENT-1 — spread the operator's unshown refusals into a reply, or
49
- * nothing at all.
50
- *
51
- * A spread rather than a field so the key is ABSENT when there is nothing to say. An always-present
52
- * `refusals: []` is a field readers learn to skip, and this is precisely the field that explains
53
- * why a conversation went quiet — it has to be unusual to be read.
54
- *
55
- * Draining is the point: the operator is told once per reason per session. The count travels with
56
- * it, so "this happened 90 times" is visible without announcing it 90 times.
57
- */
58
- /**
59
- * ⚠️ RETURNS THE ADVICE WITH THE NOTICE, and that pairing is the fix — not a convenience.
60
- *
61
- * The drain is DESTRUCTIVE: whoever reads first consumes the notice. When only the quiet exit
62
- * carried the "waiting will not help" sentence, a catch-up read (`--since-seq -1`, the stateless
63
- * door the refusals elsewhere point people at) drained the refusal into a payload with no advice at
64
- * all — and the operator's NEXT blocking read then said "call again and keep waiting", because the
65
- * notice was already gone. The catch-up door destroyed the one sentence that made it actionable and
66
- * replaced it with the advice this whole line exists to stop.
67
- *
68
- * Returning them together means no call site can take one without the other. A future exit that
69
- * spreads this gets the advice for free; that is the property, and it is why the guidance does not
70
- * live at the call sites any more.
71
- */
72
- function refusalsField(mgr, agentName, sessionId,
73
- /**
74
- * WHO is being shown this. Without it the first window to read consumed the notice for every
75
- * other window attending the same agent — the defect the delivery loop below was rewritten to
76
- * remove, re-created on a different surface.
77
- */
78
- consumerId) {
79
- const refusals = mgr.takeContentRefusals(agentName, sessionId, consumerId);
80
- if (refusals.length === 0)
81
- return {};
82
- /**
83
- * COMPOSED FROM THE KINDS PRESENT — review F4, and the same rule the inbox door follows.
84
- *
85
- * One fixed sentence said "received and REFUSED — not verified, neither ingested nor shown". True
86
- * of the three hash-verification reasons it was written for; false of a screener block, which was
87
- * verified, IS in the chain, and WAS acknowledged; false of a transcript write failure; and
88
- * pointing at the wrong party entirely for `delivery_impaired`, which is this side's own send.
89
- */
90
- const kindsPresent = new Set(refusals.map((r) => r.kind));
91
- const refusal_guidance = Object.keys(REFUSAL_KIND_GUIDANCE)
92
- .filter((k) => kindsPresent.has(k))
93
- // Prefixed with the kind (review N7) so two paragraphs that read as contradicting each other —
94
- // "received and REFUSED" beside "NOTHING WAS REFUSED BY THIS AGENT" — can each be joined to the
95
- // rows they are about.
96
- .map((k) => `[kind: ${k}] ${REFUSAL_KIND_GUIDANCE[k]}`)
97
- .join("\n\n");
98
- return {
99
- refusals: refusals.map((r) => ({
100
- reason: r.reason, kind: r.kind, impact: r.impact, guidance: r.guidance,
101
- times_since_dismissed: r.timesSinceDismissed,
102
- ...(r.timesTotal === undefined ? {} : { times_total: r.timesTotal }),
103
- ...(r.timesTotalAtLeast === undefined ? {} : { times_total_at_least: r.timesTotalAtLeast }),
104
- // `041-PARKSTUCK`: the cadence beside the count, so a loop is not read as a crowd.
105
- ...(r.recurrence === undefined ? {} : { recurrence: r.recurrence }),
106
- ...(r.repeat === true ? { repeat: true } : {}),
107
- })),
108
- // DOD-M15-REFUSALTERMINAL-1 review F4: the counts need their sentence at BOTH doors. Without
109
- // it this one hands an agent the small number with nothing saying it is not the lifetime one —
110
- // which is the whole defect, moved rather than fixed.
111
- refusal_guidance: `${refusal_guidance}\n\n${REFUSAL_COUNT_GUIDANCE}`,
112
- };
113
- }
114
- const AUTO_REPLY_GUIDANCE = "At least one message here is an AUTOMATIC reply generated by the counterparty's daemon because " +
115
- "nobody was attending that agent — no person and no agent read what you sent. Do not treat it as " +
116
- "an answer, do not report a conversation is happening, and do not infer anything from its " +
117
- "content. Your message is queued and will be read when their operator returns.\n\n" +
118
- "THE MARK IS A ONE-WAY SIGNAL. `auto_reply: true` means machine-generated. Its ABSENCE means " +
119
- "nothing — the mark is produced by the SENDER's daemon, so an older build, a third-party client, " +
120
- "or anyone who simply omits it sends automatic replies with no mark at all. An unmarked message " +
121
- "is NOT evidence a person wrote it. Never tell the operator a human replied because a message " +
122
- "was unmarked.";
123
- /**
124
- * DOD-M15-SEALWIRE-1 bullet 5, SENT half — the proof for a message THIS agent sent.
125
- *
126
- * Present only when the relay WITNESSED the leaf: an unwitnessed send never put a Structure-1 on the
127
- * wire, so there is nothing signed to store, and the row must record `self_authored` with no proof
128
- * rather than imply one. `sendContent` returns it per-send rather than stashing it by session,
129
- * because a side map hands a caller the wrong send's signature the moment two are in flight.
130
- */
131
- /**
132
- * Did the RELAY witness this leaf — the single fact every `witnessed` in this file is read from.
133
- *
134
- * `016-RELAYLOSS` review HIGH-2. The first version of the fix put `witnessed` on two of `cello_send`'s
135
- * FIVE return paths, which defeats the reason it was added at all: a field that is present on some
136
- * outcomes and absent on others cannot be branched on, and its absence reads as an older daemon
137
- * rather than as an answer. Worse, the two it missed are the two that matter most — the diverged
138
- * path is reachable ONLY after an unwitnessed leaf, and the durably-queued path is the one
139
- * production takes when the relay is also the transport (behind NAT, content and witness die
140
- * together), where it was telling operators "No action needed."
141
- *
142
- * Read off the PLACEMENT, not re-derived from the sequence number, so this and the
143
- * `session.tree.own_leaf_unwitnessed` ERROR beside it can never disagree about the same send.
144
- *
145
- * ⚠️ A HELD leaf (`placed: false`) is WITNESSED, and that is not a special case being papered over.
146
- * A leaf is held precisely BECAUSE the relay assigned it a position beyond this side's tail — being
147
- * held is itself proof of an assignment. Reporting `witnessed: false` there would tell an operator
148
- * their record had lost a message when the opposite is true.
149
- */
150
- export function wasWitnessed(p) {
151
- return p.placed ? p.unwitnessed !== true : true;
152
- }
153
- /**
154
- * The durably-queued path's guidance: the relay's OWN words, plus what a missing witness costs.
155
- *
156
- * **Exported so the test can call THIS rather than re-implement it.** The first version of the
157
- * composition test rebuilt the string inline and asserted on its own copy — which stays green if
158
- * production stops composing entirely, and is therefore the hollow shape this milestone keeps
159
- * finding. A rule worth pinning has to be pinned on the code that runs.
160
- *
161
- * The rule, and why it is a composition rather than a choice: `upstream` is where the relay's own
162
- * retry window reaches the operator ("try again in about 45 seconds"), and a rate-limited park is
163
- * unwitnessed BY CONSTRUCTION — so choosing between the two messages silently drops the more
164
- * specific one exactly when it is most useful. Both are true at once and the operator needs both.
165
- *
166
- * The default splits on `witnessed` for one reason only: "No action needed" is false for a leaf the
167
- * relay never recorded.
168
- */
169
- export function queuedSendGuidance(upstream, witnessed) {
170
- const base = upstream
171
- ?? (witnessed
172
- ? "The message is queued and will be re-sent automatically when the relay link is back. No action needed."
173
- : "The message is queued and will be re-sent automatically when the relay link is back.");
174
- if (witnessed)
175
- return base;
176
- return base
177
- + " The relay did NOT witness this leaf, so your record is now one leaf ahead of it. "
178
- + "Ordering does not repair itself: the next message the relay does witness will report this "
179
- + "session as diverged, and a diverged session can never be sealed with the counterparty. The "
180
- + "re-send is automatic — do not send it again yourself. If the receipt matters, close rather "
181
- + "than continuing.";
182
- }
183
- export function sentAuthorship(r) {
184
- /**
185
- * ⚠️ NOT `r.ok ? …` — that made two of the five call sites DEAD BY CONSTRUCTION.
186
- *
187
- * Both live inside `if (!sendResult.ok)`, so an `ok`-gated read is unconditionally `undefined`
188
- * there: the durably-queued send — witnessed, signed, only the direct hand-off failed — wrote a
189
- * row with no proof while the proof sat in the result. The union now carries `authorship` on the
190
- * failure member too, so read it off whichever shape arrived.
191
- */
192
- return r.authorship;
193
- }
194
- export function registerSessionContentHandlers(deps) {
195
- const { handlers, logger, sessionNodeManager, securityGateway, retryQueue, getConnState, resolveCurrentAgent, NO_CURRENT_AGENT_RESPONSE, getConnectionCursor, advanceConnectionCursor, clearTelegramRung, attendanceCount, sendClaims, } = deps;
196
- /**
197
- * DOD-COATTEND-SENDWINDOW-1 (review F1) — sessions with a send ON THE WIRE right now.
198
- *
199
- * The frontier comparison alone was not enough, and the reasoning that produced it had a hole:
200
- * it is TRUE that a send cannot be refused after `sendContent` (the counterparty already holds
201
- * the message, and refusing would strand the session with disagreeing frontiers — the
202
- * DOD-FRONTIER-STRAND-1 shape). It does NOT follow that checking only before it is sufficient.
203
- * `sendContent` IS the last await, and the wider one: it awaits the relay hash submit, the
204
- * stream open and the stream close — a network round trip in production, against the gateway
205
- * round trip the frontier check covers. Reproduced by review on a real daemon with two real IPC
206
- * connections: two `ok: true`, two frames on the wire, two leaves.
207
- *
208
- * So the window is closed by a CLAIM rather than a later check. A sibling that finds the claim
209
- * held is refused BEFORE its own wire call — nothing is on the wire, nothing is stranded, and the
210
- * strand argument that ruled out a post-wire refusal never applies.
211
- *
212
- * Keyed (agent, session): the race is two connections replying into ONE conversation. Held in the
213
- * factory closure, which runs once per daemon, so it is exactly as long-lived as the handler set.
214
- */
215
- /**
216
- * DOD-COATTEND-VISIBLE-1 AC6 (review F2) — attendance as reported ON A RESPONSE.
217
- *
218
- * `attendanceCount` walks the connections that explicitly called `cello_use_agent`. A connection
219
- * can reach these handlers WITHOUT having done so, through `resolveCurrentAgent`'s sole-online
220
- * fallback — which is not exotic: it is every `cello` CLI invocation with no persisted selection,
221
- * and any MCP client that skipped the call. Such a reader was not counted, INCLUDING ITSELF, and
222
- * was handed `attendance: 0` — told that zero sessions attend the agent it is reading.
223
- *
224
- * That is worse than the missing field this AC set out to fix: not absent, but a definite
225
- * negative that is false. The caller is holding the response, so at least one session is on this
226
- * agent by construction. A response can never honestly say 0.
227
- */
228
- const attendingNow = (agentName) => Math.max(1, attendanceCount(agentName));
229
- // ─── CELLO-M7-DAEMON-004: cello_send (live send + daemon-owned tree append) ──
230
- handlers.set("cello_send", async (params, connectionId) => {
231
- const connState = getConnState(connectionId);
232
- // CC-3 / M8C-AUTOSTART-1 F18: explicit { agent } > current > sole online agent.
233
- const agentName = resolveCurrentAgent(connState, params?.agent);
234
- if (!agentName)
235
- return NO_CURRENT_AGENT_RESPONSE;
236
- // round-2 BLOCKING: read the snake_case public field cello-mcp.ts actually sends.
237
- const sessionId = params?.session_id;
238
- const contentStr = typeof params?.content === "string" ? params.content : undefined;
239
- if (!sessionId || contentStr === undefined) {
240
- return { ok: false, reason: "missing_params", guidance: "Provide 'session_id' (hex) and 'content' (string) parameters." };
241
- }
242
- // DOD-LOOP-1: the (agent, session_id) lookup is itself the ownership scope.
243
- const record = sessionNodeManager.getSessionRecord(agentName, sessionId);
244
- if (!record) {
245
- return { ok: false, reason: "session_not_found", guidance: "No session found with this ID. Check cello_sessions for active sessions." };
246
- }
247
- if (record.agent_name !== agentName) {
248
- return { ok: false, reason: "session_not_owned", guidance: "This session belongs to a different agent. Call cello_use_agent to switch to the agent that owns it, then retry." };
249
- }
250
- /**
251
- * ─── A CLOSED CONVERSATION CANNOT BE ADDED TO — `DOD-M15-CLOSEDSESSION-1` ───────────────────
252
- *
253
- * BEFORE THE WIRE, BEFORE THE REVIVAL, BEFORE THE SCREENING. Nothing is placed, nothing reaches
254
- * the relay, and nothing reports `delivered`.
255
- *
256
- * **Why it sits ahead of the revival rather than inside it.** `reviveIfNeededForSend` already
257
- * refuses a sealed row — as `session_terminal`, a name about resurrection — but it is reached
258
- * only through `record.status !== "active"`, and the case measured live had a row that still
259
- * read `active`. Session `9d253bce…`: this side's own seal leaf was submitted and
260
- * auto-acknowledged, the ceremony's status write had not happened yet, and the send sailed past
261
- * every status check in the daemon. The relay had retired the session at the seal, so the hash
262
- * submit failed `relay_session_gone`, the leaf was appended unwitnessed, and the operator was
263
- * handed a paragraph about relay witnessing and ordering divergence — all true, none of it the
264
- * point, and the counterparty refused the bytes as `ack_hash_unknown_content`.
265
- *
266
- * **Two facts, one refusal, and only local state is consulted.** The status row and this side's
267
- * own seal commitment are both unambiguous and both ours. `relay_session_gone` is deliberately
268
- * NOT one of them: `delivery-session-suspects.ts` refuses to make it terminal on evidence — the
269
- * relay defaults to an in-memory store, so a restart tells every client the same string for
270
- * sessions that are perfectly alive.
271
- */
272
- if (isClosedStatus(record.status)) {
273
- logger.info("session.send.refused_closed", {
274
- sessionId, agentName, status: record.status, trigger: "status",
275
- impact: closedSessionImpact(record.status),
276
- });
277
- return { ok: false, reason: SESSION_CLOSED_REASON, impact: closedSessionImpact(record.status), guidance: SESSION_CLOSED_GUIDANCE };
278
- }
279
- if (sessionNodeManager.hasCommittedSealLeaf(agentName, sessionId)) {
280
- logger.info("session.send.refused_closed", {
281
- sessionId, agentName, status: record.status, trigger: "seal_committed",
282
- impact: SESSION_SEALING_IMPACT,
283
- });
284
- return { ok: false, reason: SESSION_CLOSED_REASON, impact: SESSION_SEALING_IMPACT, guidance: SESSION_CLOSED_GUIDANCE };
285
- }
286
- if (record.status !== "active") {
287
- /**
288
- * DOD-M12B-SESSION-SEED-1 — THE DEMAND EDGE. Before this, an interrupted session refused here
289
- * forever: a transport event could take a session out of `active` and no code path anywhere
290
- * put one back, so a laptop close ended the conversation permanently even though both
291
- * processes were alive and both peer ids still valid.
292
- *
293
- * The operator sending IS the demand, and it is the only trigger — nothing revives on a timer
294
- * (the REDIAL-1 discipline, and Andre's tenet: a background rebuilder would hold a dialable
295
- * endpoint open for a session nobody is using).
296
- *
297
- * A session that cannot be revived still refuses, and says WHY — `session_terminal` for one
298
- * that has ended, `session_identity_lost` for one whose keypair died with a daemon restart.
299
- * The second is the one an operator most needs named: it means waiting for a reconnect is
300
- * pointless and the session should be closed for its receipt.
301
- */
302
- const revived = await sessionNodeManager.reviveIfNeededForSend(agentName, sessionId);
303
- if (!revived.ok) {
304
- return {
305
- ok: false,
306
- reason: revived.reason,
307
- guidance: revived.guidance
308
- ?? `Session is '${record.status}', not active. Content can only be sent on an active session.`,
309
- };
310
- }
311
- }
312
- // M8C-CURSOR-1: read-before-write gate. current_seq is the tree's highest leaf index
313
- // (message_count is kept in sync with leafCount on every append, both directions — DAEMON-004
314
- // finding #2), so it reflects EVERY message in the session regardless of which connection sent
315
- // or received it. If this connection hasn't read up to current_seq (e.g. a second attended
316
- // session on the same agent that hasn't polled since the other connection's last send), refuse
317
- // rather than let it send blind — the WhatsApp-group-chat model. Runs BEFORE the
318
- // governance-decisions parsing below: an access-control gate must short-circuit before any
319
- // unrelated prep work for a send that may not be allowed to proceed at all.
320
- //
321
- // The gate consults TWO authorities and passes if EITHER says the caller is caught up:
322
- //
323
- // 1. the connection cursor (in-memory, per-connection) — satisfied by a long-lived client
324
- // like the MCP shim, which holds one socket for the whole session.
325
- //
326
- // 2. the persisted per-(agent, session) read watermark. A STATELESS client CANNOT satisfy
327
- // authority 1: the `cello` CLI runs a fresh process, and therefore a fresh connection, per
328
- // command, so it always presents cursor -1. Without the watermark, every CLI send is
329
- // refused forever once the counterparty has spoken — as is every send from a RECONNECTING
330
- // MCP client, whose new connectionId also resets the cursor to -1. Do not remove it.
331
- //
332
- // What the gate protects, precisely: an agent must never reply to COUNTERPARTY content nobody
333
- // on its side has seen. That guarantee is durable — it survives the socket.
334
- //
335
- // What it deliberately does NOT protect: a message this agent SENT from a different local
336
- // connection does not block. Two attended windows on one agent do not gate each other, because
337
- // locally-authored content is not "unread counterparty content" — the AGENT wrote it. The
338
- // principal is the agent, not the socket, and the daemon cannot referee which of an operator's
339
- // own windows a human is looking at. This is deliberate; do not "fix" it.
340
- const currentSeq = record.message_count - 1;
341
- // DOD-COATTEND-SENDWINDOW-1: the frontier AS THIS SEND SAW IT. Re-read immediately before the
342
- // wire, below — anything that moved it in between is a leaf this send was never checked
343
- // against.
344
- const frontierAtGate = sessionNodeManager.getSessionTree(agentName, sessionId).size();
345
- const connectionCursor = getConnectionCursor(connectionId, sessionId);
346
- const unreadReceived = sessionNodeManager.getUnreadReceivedCount(agentName, sessionId);
347
- const caughtUp = connectionCursor >= currentSeq || unreadReceived === 0;
348
- if (!caughtUp) {
349
- // M8C-CURSOR-1 (reviewer MEDIUM fix): every sibling rejection in this handler logs; this
350
- // gate must too — a security-relevant control-flow path with no observability is a gap.
351
- // Both authorities are logged, so the next reader can tell WHICH one refused.
352
- logger.warn("session.send.blocked", {
353
- sessionId,
354
- currentSeq,
355
- lastReadSeq: connectionCursor,
356
- unreadReceived,
357
- connectionId,
358
- agentName,
359
- // AC2 asks the event to NAME the authority that refused (review F7). Reaching this branch
360
- // means BOTH authorities said no — the gate passes if EITHER is satisfied — so there is no
361
- // "binding one" to report and the ternary I first wrote here was dead: `connectionCursor <
362
- // currentSeq` is always true at this point, so it could only ever print `unread_watermark`,
363
- // and an operator filtering for `connection_cursor` would get zero hits forever and
364
- // conclude cursor refusals do not exist. That is the defect F7 was raised to fix, rebuilt
365
- // (review H2). The true statement is that both are false; `lastReadSeq` and
366
- // `unreadReceived` above already carry which is how far off.
367
- authority: "cursor_and_watermark",
368
- });
369
- return {
370
- ok: false,
371
- reason: "session_not_current",
372
- current_seq: currentSeq,
373
- last_read_seq: connectionCursor,
374
- unread_received: unreadReceived,
375
- // DOD-ONBOARD-HELP-1 §5: say what is wrong and what to do, in that order, in plain words.
376
- // The old text opened with the internal noun ("this agent hasn't read…"); a refused send is
377
- // the most common wall a new operator hits, so it leads with the COUNT and the FIX. The
378
- // session id is interpolated so the remedy is copy-pasteable, not a template to fill in.
379
- // Rendered per surface at the IPC boundary — a CLI caller sees `cello receive <id>`.
380
- guidance: `${unreadReceived} unread message(s) — run cello_receive ${sessionId} first to read them, then send again. (Or cello_transcript ${sessionId} for the whole conversation.) You are blocked from replying to something you haven't read.`,
381
- };
382
- }
383
- // M9-FEED-001 §6: the agent's governance re-send decisions, keyed by the flagId a prior `warn`
384
- // returned. Optional; validated shape only (the gateway re-scans + applies them, INV-4). A
385
- // malformed map is ignored rather than failing the send (the gateway will just re-warn).
386
- const rawDecisions = params?.governance_decisions;
387
- let governanceDecisions;
388
- if (rawDecisions && typeof rawDecisions === "object" && !Array.isArray(rawDecisions)) {
389
- const valid = {};
390
- for (const [k, v] of Object.entries(rawDecisions)) {
391
- if (v === "redact" || v === "allow_once" || v === "allow_always")
392
- valid[k] = v;
393
- }
394
- if (Object.keys(valid).length > 0)
395
- governanceDecisions = valid;
396
- }
397
- const correlationId = randomUUID();
398
- const contentBytes = new TextEncoder().encode(contentStr);
399
- // CELLO-M7-MSG-001 (AC-013/AC-018/AC-021): enforce the 1 MB application content cap
400
- // BEFORE any transmission or hash/leaf production. This replaces the silent oversize
401
- // decode-failure → desync: the send is rejected with a distinct, diagnosable reason
402
- // and actionable guidance; no content frame is transmitted, no leaf is appended, and
403
- // the session stays usable.
404
- if (contentBytes.length > MAX_CONTENT_BYTES) {
405
- logger.warn("content.rejected.too_large", {
406
- sessionId,
407
- contentSize: contentBytes.length,
408
- cap: MAX_CONTENT_BYTES,
409
- correlationId,
410
- });
411
- return {
412
- ok: false,
413
- reason: "content_too_large",
414
- guidance: `This message is ${contentBytes.length} bytes, over the ${MAX_CONTENT_BYTES}-byte (1 MB) per-message content cap. Split it into multiple messages each under the cap, or use the large-object/file transfer path for large payloads (not cello_send). Nothing was sent and the session is still active — retry with smaller content.`,
415
- };
416
- }
417
- const recipientPubkey = record.counterparty_pubkey;
418
- // M9 outbound screening seam (INV-5/SI-001). Screen BEFORE anything reaches the wire. The
419
- // gateway verdict drives the four cello_send outcomes (M9-FEED-001): block / warn → NOT sent;
420
- // allow → sent as-is; redact → sent in ALTERED form. A configured-but-unreachable gateway fails
421
- // closed (block, gateway_unavailable), so a screening outage can never let content out ungated.
422
- const outboundVerdict = await securityGateway.screenOutbound(contentBytes, {
423
- direction: "outbound",
424
- agentName: record.agent_name,
425
- sessionId,
426
- correlationId,
427
- ...(governanceDecisions !== undefined ? { governanceDecisions } : {}),
428
- });
429
- if (outboundVerdict.disposition === "block") {
430
- if (outboundVerdict.reason === GOVERNANCE_TIMEOUT) {
431
- logger.error("security.gateway.timeout", { sessionId, reason: outboundVerdict.reason, correlationId });
432
- }
433
- else if (outboundVerdict.reason === GATEWAY_UNAVAILABLE) {
434
- logger.error("security.gateway.unavailable", { direction: "outbound", reason: outboundVerdict.reason, correlationId });
435
- }
436
- else {
437
- logger.info("security.verdict.returned", { disposition: "block", sessionId, reason: outboundVerdict.reason, correlationId });
438
- }
439
- return {
440
- ok: false,
441
- reason: outboundVerdict.reason ?? "blocked_by_governance",
442
- guidance: outboundVerdict.guidance ??
443
- "This message was blocked by the security gateway and was NOT sent. The session is still active.",
444
- blocks: (outboundVerdict.events ?? []).filter((e) => e.disposition === "block"),
445
- };
446
- }
447
- if (outboundVerdict.disposition === "warn") {
448
- logger.info("security.verdict.returned", { disposition: "warn", sessionId, correlationId });
449
- return {
450
- ok: false,
451
- reason: "governance_warn",
452
- guidance: outboundVerdict.guidance ??
453
- "This message was held for a governance decision and was NOT sent. Re-send the same content with a " +
454
- "governance_decisions map ({flagId: redact | allow_once | allow_always}) to resolve each flagged item.",
455
- flags: (outboundVerdict.events ?? []).filter((e) => e.disposition === "warn"),
456
- };
457
- }
458
- // FAIL-CLOSED (code-review MED): a `redact` verdict MUST carry the redacted content. If it ever
459
- // arrives without it, sending the original `contentBytes` would leak the pre-redaction draft — the
460
- // one place M9 could fail OPEN. Treat it as a block, never an allow-original. (Unreachable today:
461
- // the gateway always includes content on redact; this is the defensive floor.)
462
- if (outboundVerdict.disposition === "redact" && outboundVerdict.content === undefined) {
463
- logger.error("security.verdict.redact_without_content", { sessionId, correlationId });
464
- return {
465
- ok: false,
466
- reason: "redact_without_content",
467
- guidance: "The security gateway returned a redact verdict without the redacted content. To avoid " +
468
- "leaking the original, nothing was sent. This is a gateway fault — check the gateway logs and retry.",
469
- };
470
- }
471
- // allow or redact → send. On redact the ALTERED bytes are what go on the wire AND what the leaf
472
- // hash binds — the transcript records what was actually sent, not the pre-redaction draft.
473
- const modified = outboundVerdict.disposition === "redact" && outboundVerdict.content !== undefined;
474
- const sendBytes = modified ? new Uint8Array(outboundVerdict.content) : contentBytes;
475
- /**
476
- * `DOD-M15-SEALWIRE-1` part B2b — the hash and its ALGORITHM come from one decision point.
477
- *
478
- * Four outbound sites compute a content hash. Each of them independently deciding whether to
479
- * salt is the defect `wire-content-hash.ts` was created to end (its header: the expression was
480
- * written out five times, the last two got it wrong, and it took two live daemons to find),
481
- * with a worse failure mode — a message hashed one way and LABELLED another is refused by every
482
- * peer, including a correct one.
483
- */
484
- const { hash: contentHash, alg: contentHashAlg } = await sessionNodeManager.contentHashForSession(record.agent_name, sessionId, sendBytes);
485
- const contentHashHex = Buffer.from(contentHash).toString("hex");
486
- // ─── DOD-COATTEND-SENDWINDOW-1 (§4): re-check the gate, in the same synchronous window as the
487
- // act that makes this message irreversible ───────────────────────────────────────────────
488
- //
489
- // NO AWAIT MAY BE INTRODUCED BETWEEN THIS CHECK AND `sendContent` BELOW. The check is only
490
- // worth anything because nothing can interleave between it and the wire; adding an await here
491
- // reopens exactly the window it closes, silently, while leaving code that still looks correct.
492
- //
493
- // WHY HERE AND NOT AT `appendSessionLeaf`, WHICH IS WHAT AC1 ASKS FOR. AC1 copies the inbound
494
- // pattern (`session-node-manager.ts:3682-3695`), where the append IS the commit point.
495
- // Outbound it is not: `sendContent` puts the message ON THE WIRE and runs BEFORE the append, so
496
- // by the append the counterparty already holds it. Refusing there would leave them holding
497
- // content this side never leafed — the two frontiers disagree, neither will co-sign, and the
498
- // session is unsealable except by forfeiting the receipt. That is DOD-FRONTIER-STRAND-1, the
499
- // defect that left `dbb93dfc…` stranded for a week, manufactured on purpose to satisfy the
500
- // letter of an AC. The purpose of AC1 is "re-check where it still matters"; outbound, that is
501
- // the wire.
502
- //
503
- // WHY A FRONTIER COMPARISON RATHER THAN RE-RUNNING `caughtUp`. AC3: the gate's second authority
504
- // is the PERSISTED read watermark, which is AGENT-scoped — so the moment ANY connection reads,
505
- // `unreadReceived === 0` for every one of them, and re-running the gate would pass a racing
506
- // sibling exactly as it passed the first time. That agent-scoping is DOD-CURSOR-DURABLE-1
507
- // behaving as its own §6 predicted: right for stateless clients, wrong for this. So the tighten
508
- // is stated AGAINST it rather than around it — this asks a question the watermark cannot
509
- // answer: "did the session move under me while I was gone?"
510
- const frontierNow = sessionNodeManager.getSessionTree(agentName, sessionId).size();
511
- const claimedAt = sendClaims.claimedAt(agentName, sessionId);
512
- if (claimedAt !== undefined) {
513
- // A sibling is between its own frontier check and its append RIGHT NOW. Its leaf does not
514
- // exist yet, so the comparison below cannot see it — this is the half of the window a
515
- // frontier check structurally cannot cover, whatever it is compared against.
516
- logger.warn("session.send.blocked", {
517
- sessionId, agentName, connectionId, correlationId,
518
- authority: "sibling_send_in_flight",
519
- claimHeldMs: Date.now() - claimedAt,
520
- });
521
- // B2b-2 review F3: this send produced NOTHING — no leaf, no wire, no peer copy — so the
522
- // unsalted hash computed above must not keep this session unsalted for its life.
523
- sessionNodeManager.abandonUnsaltedHash(agentName, sessionId);
524
- return {
525
- ok: false,
526
- reason: "session_moved_under_send",
527
- in_flight: true,
528
- // Says "may have sent" (review L4): the in-flight send can still fail and be queued for
529
- // retry, in which case nothing was said and there is nothing to read. Promising the operator
530
- // a reply that does not exist sends them to an unchanged transcript to look for it.
531
- guidance: `Another session on this agent is sending into this conversation right now, so nothing was sent. Wait a moment, then check cello_transcript ${sessionId} — they may have already answered — before deciding whether your reply still applies. Do not simply resend.`,
532
- };
533
- }
534
- if (frontierNow !== frontierAtGate) {
535
- logger.warn("session.send.blocked", {
536
- sessionId, agentName, connectionId, correlationId,
537
- authority: "frontier_moved_during_send",
538
- frontierAtGate, frontierNow,
539
- });
540
- // B2b-2 review F3: nothing was sent, so release the unsalted hash's permanent closure. This
541
- // path got MORE likely with B2b-2 — the salt wait widens the interval this check watches.
542
- sessionNodeManager.abandonUnsaltedHash(agentName, sessionId);
543
- return {
544
- ok: false,
545
- reason: "session_moved_under_send",
546
- frontier_at_gate: frontierAtGate,
547
- frontier_now: frontierNow,
548
- // Says LEAF, not "message" (review F6). The frontier counts leaves, and a leaf can exist
549
- // with no transcript row — a security-gateway terminal block commits one and never records
550
- // the text. Promising N messages in the transcript and delivering fewer sends the operator
551
- // hunting for content that was screened out and is not there.
552
- guidance: `The conversation moved while this message was being prepared — the session's record gained ${frontierNow - frontierAtGate} leaf/leaves from another session on this agent or from the counterparty, so nothing was sent. Read what arrived with cello_transcript ${sessionId} (a leaf that was screened out has no readable text and will not appear there), then decide whether your reply still applies. Do not simply resend: another session may have already answered.`,
553
- };
554
- }
555
- // THE CLAIM — taken in the same synchronous window as the check above (no await between them),
556
- // and released the instant the wire call settles.
557
- //
558
- // Releasing there is safe and is not an oversight: after `await sendContent` resolves, the
559
- // continuation runs the `finally`, the ok-check and `appendSessionLeaf` WITHOUT YIELDING, so no
560
- // other connection can observe the gap. By the time one runs again the frontier has either
561
- // moved (append happened → its own frontier comparison catches it) or the send failed and
562
- // nothing was committed (→ it is free to try). `finally` rather than a plain call so a throw
563
- // cannot wedge the session into permanent refusal.
564
- sendClaims.claim(agentName, sessionId);
565
- let sendResult;
566
- try {
567
- sendResult = await sessionNodeManager.sendContent(record.agent_name, sessionId, sendBytes, new Uint8Array(contentHash), correlationId, LEAF_KIND_MSG, contentHashAlg);
568
- }
569
- finally {
570
- sendClaims.release(agentName, sessionId);
571
- }
572
- if (!sendResult.ok) {
573
- // DB-001 / dead-channel contract: never silently drop, never desync. Preserve
574
- // the content in the durable retry_queue so it is retried on reconnect, and
575
- // surface a named, diagnosable failure.
576
- //
577
- // M12-P13 (review MEDIUM-4): NOT on the durable path. `drainSession` — this nonce queue's
578
- // only consumer — has no production caller, so every row it writes is permanent: unbounded
579
- // growth plus a second copy of the message plaintext at rest. On a durable failure the
580
- // awaiting-ACK queue already holds the content and actually drains, so writing here too
581
- // stored the same plaintext twice and drained neither copy from this table.
582
- if (!sendResult.durable) {
583
- // B2b-2 review F3: a non-durable failure means the message is GONE — it reached no leaf, no
584
- // peer, and the queue below has no production consumer. Nothing exists to split a
585
- // transcript, so this session must not stay unsalted for its life over it.
586
- sessionNodeManager.abandonUnsaltedHash(agentName, sessionId);
587
- const nonce = randomUUID();
588
- try {
589
- retryQueue.enqueue(sessionId, new TextEncoder().encode(nonce), sendBytes);
590
- }
591
- catch (err) {
592
- logger.error("session.content.queue.failed", {
593
- sessionId,
594
- error: extractErrorMessage(err),
595
- correlationId,
596
- });
597
- }
598
- }
599
- logger.warn("session.content.send.failed", {
600
- sessionId,
601
- recipientPubkey,
602
- reason: sendResult.reason,
603
- errorMessage: sendResult.error,
604
- durable: sendResult.durable,
605
- cause: sendResult.cause,
606
- correlationId,
607
- });
608
- // M12-P13: a DURABLY QUEUED message still owns the sequence the relay witnessed for it before
609
- // direct delivery was ever attempted — the same reasoning that makes a parked message occupy
610
- // its leaf position below. Leaving the hole here is what stalls the far side: `nextExpected`
611
- // is this tree's size, so the counterparty's next message arrives at a sequence this tree can
612
- // never reach and is held behind the gap forever (found live 2026-08-05, M12 Entry 89).
613
- // A LOST message gets no leaf — that would commit a sequence no content will ever fill, and
614
- // the two roots could then never seal.
615
- if (sendResult.durable) {
616
- // DOD-M12B-INDEX-1: at the position the relay assigned, not at whatever the tail is. When
617
- // this side has a gap the two differ, and committing at the tail puts our leaf at someone
618
- // else's index — which parts the two roots and makes the next seal terminal.
619
- const placed = sessionNodeManager.placeOwnLeaf(record.agent_name, sessionId, contentHashHex, sendBytes, sendResult.sequenceNumber, correlationId, "msg", sentAuthorship(sendResult));
620
- // `sequence_number` is a LEAF INDEX or nothing. Reporting the relay's number when no leaf
621
- // exists hands the caller a value that matches no leaf on this side, and anything that
622
- // feeds it to a cursor is then wrong.
623
- const queuedLeaf = placed.placed ? placed.leafIndex : -1;
624
- if (placed.placed) {
625
- sessionNodeManager.recordTranscriptMessage(record.agent_name, sessionId, queuedLeaf, "sent", sendBytes, correlationId, sentAuthorship(sendResult));
626
- advanceConnectionCursor(connectionId, sessionId, queuedLeaf);
627
- }
628
- logger.info(placed.placed ? "session.content.queued.committed" : "session.content.queued.held", {
629
- sessionId, sequenceNumber: queuedLeaf, heldAt: placed.placed ? undefined : placed.heldAt,
630
- contentHash: contentHashHex, correlationId,
631
- });
632
- return {
633
- ok: false,
634
- reason: sendResult.reason,
635
- /**
636
- * DOD-M15-RELAYABUSE-1 review MEDIUM-7 — **THE CODE MUST CROSS THE BOUNDARY, NOT JUST THE
637
- * PARAGRAPH.**
638
- *
639
- * `reason` here is `session_stream_unavailable` — an EXIT-POINT label. The actual cause
640
- * (throttled / this counterparty's mailbox is full / the relay's store is full / this
641
- * build cannot seal the algorithm) was computed, logged, and then left inside the English
642
- * `guidance`. So an MCP caller wanting to tell "wait 45 seconds" from "another relay will
643
- * not help" was back to substring-matching prose — which is exactly what `cause` was added
644
- * to stop. Three newly-distinguishable causes had just landed and none of them reached the
645
- * agent that would act on them.
646
- */
647
- ...(sendResult.cause !== undefined ? { cause: sendResult.cause } : {}),
648
- queued: true,
649
- // Carried on BOTH paths: without it a caller cannot tell "queued and in the record" from
650
- // "queued and not in the record yet".
651
- ...(placed.placed ? {} : { held: true }),
652
- sequence_number: queuedLeaf,
653
- /**
654
- * ⚠️ THE BRANCH PRODUCTION ACTUALLY TAKES — review HIGH-2, and the reason the loopback
655
- * journey could not find it. Behind NAT the direct path runs over the relay's circuit, so
656
- * a relay outage kills the transport and the witness TOGETHER and the send lands here
657
- * rather than on the delivered path. On the harness the two are independent, the direct
658
- * send succeeds, and this branch is never reached.
659
- *
660
- * It was answering "No action needed" for a leaf the relay never witnessed.
661
- */
662
- witnessed: wasWitnessed(placed),
663
- /**
664
- * ⚠️ COMPOSED, NEVER CHOSEN — the first version of this fix CHOSE, and that discarded a
665
- * shipped guarantee. Caught deterministically by the `013-ABSENCE` lane in
666
- * `dod-m15-park-envelope-coded-error.test.ts`.
667
- *
668
- * A RATE-LIMITED park is unwitnessed BY CONSTRUCTION, so making the whole string
669
- * conditional on witnessing threw away `sendResult.guidance` — which is where the relay's
670
- * own retry window lives ("about 45 seconds"). That is Invariant 3 aimed back at this
671
- * unit: a downstream handler replacing an upstream descriptive value with a generic one.
672
- * The upstream sentence is more specific than anything this layer can produce, and a
673
- * missing witness does not make it less true.
674
- *
675
- * Both facts hold at once and the operator needs both — what the relay said to do, and
676
- * what the missing witness will cost. So upstream is kept VERBATIM and the unwitnessed
677
- * note is APPENDED to it, by `queuedSendGuidance`, which the test calls directly rather
678
- * than re-implementing.
679
- */
680
- guidance: queuedSendGuidance(sendResult.guidance, wasWitnessed(placed)),
681
- };
682
- }
683
- return {
684
- ok: false,
685
- reason: sendResult.reason,
686
- // DOD-M15-RELAYABUSE-1 review MEDIUM-7: the machine-readable cause crosses here too — see
687
- // the note on the queued return above. `reason` is the exit point; `cause` is what happened.
688
- ...(sendResult.cause !== undefined ? { cause: sendResult.cause } : {}),
689
- // M12-P12 (review pass 2): sendContent knows whether the content is actually recoverable;
690
- // this boundary used to overwrite that with one sentence promising a retry for EVERY
691
- // failure — including a persist that threw, where the message is simply gone, and a session
692
- // with no relay, where the direct nonce queue it names has no production drain. Telling an
693
- // operator "it will be retried" about a lost message is the same lie that let the original
694
- // defect sit unnoticed; the caller's own guidance wins whenever it has one.
695
- guidance: sendResult.guidance ?? "The content could not be delivered over the session stream right now, and no relay is configured for this session — it is NOT queued for automatic retry. Send it again once the counterparty is reachable; check cello_status for their status.",
696
- };
697
- }
698
- // Delivered directly OR dispatched to relay (DOD-LEAVEMSG-1) — either way the content is now
699
- // part of the daemon-owned tree: the relay witness (R1) already assigned it a sequence before
700
- // direct delivery was even attempted, so a parked message occupies the SAME leaf position it
701
- // would have taken if delivered live. Append once, for both outcomes.
702
- // DOD-M12B-INDEX-1: the relay assigned this message a position before delivery was attempted,
703
- // and the leaf goes THERE. Appending at the tail is only right while this side has no gap; the
704
- // first gap puts our own leaf at a position that belongs to a message of theirs we have not
705
- // seen, which parts the two roots permanently. When the position is ahead of the tail the leaf
706
- // is held — the bytes are already on the wire, so only the record waits, exactly as it does for
707
- // a message we receive out of order.
708
- const placement = sessionNodeManager.placeOwnLeaf(record.agent_name, sessionId, contentHashHex, sendBytes, sendResult.sequenceNumber, correlationId, "msg", sentAuthorship(sendResult));
709
- if (!placement.placed) {
710
- // NOT IN THE RECORD YET, and the caller is told so rather than handed a plain success.
711
- // `sequence_number` stays -1 because no leaf exists: `held_at` carries the relay's position
712
- // separately, so nothing mistakes a relay number for a leaf index.
713
- return {
714
- ok: true,
715
- sequence_number: -1,
716
- held: true,
717
- held_at: placement.heldAt,
718
- /**
719
- * TRUE, and it is not a courtesy default — review HIGH-2. A leaf is HELD precisely because
720
- * the relay assigned it a position beyond this side's tail, so being held is itself proof
721
- * that the relay witnessed it. Omitting the field here would leave an agent branching on
722
- * `witnessed !== true` reading a perfectly healthy message as a lost one.
723
- */
724
- witnessed: wasWitnessed(placement),
725
- // The screening verdict must survive this return, or an agent whose message was ALTERED is
726
- // never told — the one thing a redact verdict exists to surface.
727
- ...(modified ? { modified: true, transformations: (outboundVerdict.events ?? []).filter((e) => e.disposition === "redact") } : {}),
728
- guidance: "The message was delivered — the counterparty has it. Its place in the record is waiting on an earlier message from them that has not arrived yet, so it is not in your transcript until that gap fills. Nothing to do, and do not resend: a resend takes a second position in the record.",
729
- };
730
- }
731
- if (placement.diverged) {
732
- // THE OPERATOR HEARS ABOUT IT. Their message is in their own transcript, but this side's tree
733
- // is permanently ahead of the relay's counter, so the two can no longer agree on a root and
734
- // this session will never produce a notarized receipt. Returning the ordinary success here —
735
- // which is what the first build did — reports a healthy send on a conversation that has
736
- // silently lost the one thing the protocol exists to produce.
737
- logger.error("session.content.sent.diverged", {
738
- sessionId, agentName: record.agent_name, sequenceNumber: placement.leafIndex, correlationId,
739
- impact: "delivered and recorded locally, but this session can no longer be sealed bilaterally",
740
- });
741
- return {
742
- ok: true,
743
- sequence_number: placement.leafIndex,
744
- diverged: true,
745
- /**
746
- * ⚠️ THIS IS `true`, AND THE FIRST VERSION OF THIS COMMENT SAID OTHERWISE — review HIGH-B.
747
- *
748
- * The divergence branch is reached only when the relay DID assign a sequence, one behind
749
- * this side's frontier (`assignedSeq < nextExpected`). So the relay witnessed this leaf; it
750
- * witnessed it at a position our tree has already passed. `witnessed: true` is the honest
751
- * answer and `diverged: true` is the field that carries the bad news here.
752
- *
753
- * I had written that this return was "reachable only after an unwitnessed leaf" and would
754
- * otherwise report `witnessed: undefined`, so the operator could never see the `false` the
755
- * guidance told them to watch for. The first half is true — divergence is caused by an
756
- * earlier unwitnessed append — and the conclusion drawn from it was not: THIS send was
757
- * witnessed. Recorded rather than silently corrected, because a comment asserting the wrong
758
- * value of the field beside it is how the next reader learns the wrong model.
759
- */
760
- witnessed: wasWitnessed(placement),
761
- ...(modified ? { modified: true, transformations: (outboundVerdict.events ?? []).filter((e) => e.disposition === "redact") } : {}),
762
- guidance: `The message was delivered and is in your transcript. But this session's record has drifted out of step with the relay's ordering, so it can no longer be sealed with the counterparty — there will be no notarized receipt for it. Keep talking if you want to; when you are finished, cello_close_session ${sessionId} { force: true } is the only way it can end. cello_transcript ${sessionId} is the record you keep.`,
763
- };
764
- }
765
- const leafIndex = placement.leafIndex;
766
- // DOD-LOG-1: persist the readable SENT plaintext to the durable transcript, keyed by the
767
- // canonical leaf sequence so it joins the committed hash chain (survives restart).
768
- // M9 merge fix: use sendBytes (the ALTERED bytes on a redact verdict), never the pre-redaction
769
- // contentBytes — the leaf hash above already binds sendBytes; the transcript must match what
770
- // actually went on the wire, not the pre-redaction draft (M9's own stated seam invariant).
771
- /**
772
- * ⚠️ THE RESULT IS READ, and a `false` is a HOLE in the record of what this side said.
773
- *
774
- * The leaf exists; the row does not. The operator's own message is then invisible to every
775
- * reader of the transcript — including `away-inbox-oneshot.ts`, which asks exactly one question
776
- * of it: "has a human spoken in this session?" A silent `false` answers no about a message that
777
- * went out, and that answer ends the session. The inbound path has handled this case since
778
- * `content_undeliverable`; the outbound path ignored it.
779
- */
780
- const rowWritten = sessionNodeManager.recordTranscriptMessage(record.agent_name, sessionId, leafIndex, "sent", sendBytes, correlationId, sentAuthorship(sendResult));
781
- if (!rowWritten) {
782
- sendClaims.noteRowMissing(record.agent_name, sessionId);
783
- logger.error("session.send.transcript_row_failed", {
784
- sessionId, agentName: record.agent_name, sequenceNumber: leafIndex, correlationId,
785
- impact: "the message was sent and its leaf committed, but this side holds no readable copy of it. " +
786
- "The transcript under-reports what this agent said, and nothing that reads the transcript " +
787
- "to decide whether a human spoke here may treat this session as unspoken-in.",
788
- });
789
- }
790
- // M8C-CURSOR-1: the sender authored this leaf — advance ITS OWN cursor so it doesn't get
791
- // blocked by session_not_current on its own just-sent message.
792
- advanceConnectionCursor(connectionId, sessionId, leafIndex);
793
- // CC-1 (2026-07-07): operator engagement promotes the counterparty to a known contact. A
794
- // committed reply — past the read-before-write gate, content now on the wire AND in the tree —
795
- // IS the operator choosing to trust this sender; the inbound-accept path deliberately no longer
796
- // auto-adds (that defeated screening + anti-spam). For an OUTBOUND session the counterparty is
797
- // already a contact (cello_initiate_session added it), so this is an idempotent no-op there; it
798
- // matters for inbound-originated sessions, where the reply is the trust signal. addContact is
799
- // INSERT OR IGNORE — it never refreshes added_at. DOD-TIER-4 AC3: engaging (a committed reply into
800
- // an inbound session I accepted) makes the counterparty KNOWN, provenance 'accepted'. For an
801
- // OUTBOUND session the row already exists ('initiated', KNOWN) and INSERT OR IGNORE leaves it
802
- // untouched — 'initiated' correctly wins there.
803
- sessionNodeManager.addContact(record.agent_name, recipientPubkey, undefined, "accepted", TIER.KNOWN);
804
- if (modified) {
805
- logger.info("security.verdict.returned", { disposition: "redact", sessionId, sequenceNumber: leafIndex, correlationId });
806
- }
807
- if (!sendResult.delivered) {
808
- // DOD-LEAVEMSG-1 (sender half): direct delivery failed but the sealed, hashed content was
809
- // successfully deposited at the relay (pickup_queue) — this is a SUCCESS outcome, not a
810
- // failure. The recipient's daemon pulls it via RELAYWAKE on next reconnect. Reporting this
811
- // as ok:false (the pre-LEAVEMSG-1 behavior) misrepresented an in-flight message as lost.
812
- logger.info("session.content.dispatched_to_relay", {
813
- sessionId,
814
- recipientPubkey,
815
- contentHashHex,
816
- sequenceNumber: leafIndex,
817
- correlationId,
818
- });
819
- return {
820
- ok: true,
821
- sequence_number: leafIndex,
822
- delivered: false,
823
- reason: "dispatched_to_relay",
824
- modified,
825
- // Same fact, same shape, both branches — see the note on the delivered path below.
826
- witnessed: wasWitnessed(placement),
827
- /**
828
- * WHAT IS ACTUALLY TRUE, and the previous wording was neither.
829
- *
830
- * OBSERVED LIVE 2026-08-18. This exact response came back on a send that was delivered in
831
- * **8 seconds**, and the counterparty's agent read it and correctly reported "no change" —
832
- * because it is byte-identical to the response returned when the same send took THREE
833
- * MINUTES. The sender had no way to tell a good outcome from a bad one, and the rational
834
- * next move for anyone reading it is to send again, which produces a duplicate of a message
835
- * that was never lost.
836
- *
837
- * The old text also asserted a cause it does not know: *"delivered the next time the
838
- * counterparty's daemon reconnects."* The counterparty's daemon is frequently up the whole
839
- * time — this path is taken because the two SESSION NODES hold no direct connection to each
840
- * other, which is a different thing and points at a different party.
841
- *
842
- * So: say what happened, say what to expect, and claim nothing about their daemon.
843
- */
844
- /**
845
- * `016-RELAYLOSS`: **"witnessed" IS NOT SOMETHING THIS STRING GETS TO ASSERT.**
846
- *
847
- * It said so unconditionally, and it is false on exactly the path this order measured: a
848
- * relay that stops answering fails the hash submit and the leaf is appended unwitnessed,
849
- * while the content can still reach the counterparty. The reassurance was then strictly
850
- * worse than silence — it named the property that had just been lost as the reason not to
851
- * worry. Claimed only when true; the rest of the sentence is unchanged and still right.
852
- */
853
- /**
854
- * ⚠️ "NO ACTION IS NEEDED" IS CONDITIONAL TOO — review HIGH-C, and the same mistake the
855
- * queued path had already fixed one branch away.
856
- *
857
- * The first version left that reassurance unconditional and then contradicted it three
858
- * words later: no action is needed… BUT this session is on its way to being unsealable.
859
- * Telling the operator to relax and then telling them the conversation is dying is worse
860
- * than either sentence alone, because the one they act on is the first.
861
- *
862
- * This branch also named no remedy at all, while its two siblings both say to close. Same
863
- * situation, same advice.
864
- */
865
- guidance: "Sent. This message went via the relay rather than a direct connection, so it is sealed"
866
- + (wasWitnessed(placement) ? ", witnessed" : "") + " and on its way — the counterparty "
867
- + "normally has it within seconds. "
868
- + "`delivered: false` means it did not go over a direct link, NOT that it failed. "
869
- + (wasWitnessed(placement)
870
- ? "No action is needed, and re-sending would duplicate it."
871
- : "Do not re-send — that would duplicate it. BUT the relay did NOT witness this leaf, so "
872
- + "the ordering authority has no copy of it and your record is a leaf ahead of the "
873
- + "relay's. Ordering does not repair itself: the next message the relay does witness "
874
- + "will report this session as diverged, and a diverged session can never be sealed "
875
- + "with the counterparty. If the receipt matters, close rather than continuing."),
876
- ...(modified ? { transformations: (outboundVerdict.events ?? []).filter((e) => e.disposition === "redact") } : {}),
877
- };
878
- }
879
- logger.info("session.content.sent", {
880
- sessionId,
881
- recipientPubkey,
882
- contentHashHex,
883
- sequenceNumber: leafIndex,
884
- correlationId,
885
- });
886
- return {
887
- ok: true,
888
- sequence_number: leafIndex,
889
- delivered: true,
890
- modified,
891
- /**
892
- * ─── `016-RELAYLOSS`: THE ONE FACT THIS RESPONSE WAS MISSING ─────────────────────────────
893
- *
894
- * Measured, not supposed: with the relay black-holed mid-conversation, this send stalled ten
895
- * seconds and returned exactly the object above — the same `ok`, the same `delivered`, and a
896
- * `sequence_number` that is a LOCAL leaf index and therefore looks just as healthy. The
897
- * daemon logged `session.tree.own_leaf_unwitnessed` at ERROR, correctly and in detail, into a
898
- * file the agent cannot read. The operator's message arrived, they were told it succeeded,
899
- * and the ordering authority has no copy of it.
900
- *
901
- * `witnessed` is stated on BOTH outcomes rather than only the bad one. A field that appears
902
- * only when something is wrong cannot be relied on by a reader who has never seen it — its
903
- * absence is indistinguishable from an older daemon, and "absence is not a pass" is the rule
904
- * this milestone keeps re-learning. Present always, it is a fact the caller can branch on.
905
- */
906
- witnessed: wasWitnessed(placement),
907
- /**
908
- * ⚠️ THIS ONCE SAID *"send the next message normally — ordering re-establishes itself."* It
909
- * was false, and it was the most damaging sentence in the unit that added it — review HIGH-1.
910
- *
911
- * `placeOwnLeaf` states the opposite sixty lines away: an unwitnessed append leaves this
912
- * side's tree one leaf AHEAD of the relay's counter, so "from then on every ack comes back
913
- * behind our frontier and the two can never agree again — the seal was already lost at the
914
- * unwitnessed append, not here." The next WITNESSED send therefore takes the divergence
915
- * branch and marks the session permanently unsealable. Telling the operator to keep talking
916
- * was telling them to perform the act that makes the loss permanent.
917
- *
918
- * Which is this unit's own subject — a reassuring sentence asserting a property already lost
919
- * — reproduced one clause later in its replacement. Kept as a comment, not quietly deleted,
920
- * because the reasoning is the part that stops it coming back.
921
- *
922
- * `cello status` came out of the advice for the same reason: measured in this unit's own
923
- * runs, its relay fields read identically during the outage and before it.
924
- */
925
- ...(wasWitnessed(placement)
926
- ? {}
927
- : {
928
- guidance:
929
- /**
930
- * ⚠️ NOT "the counterparty's record cannot gain it" — review MED-D. On THIS branch the
931
- * direct send succeeded, and the receiving side appends unwitnessed content in arrival
932
- * order rather than refusing it (refusing would make the relay a precondition for
933
- * reading your mail). So they do get the message. What nobody gets is an independent
934
- * record that you sent it — which is the thing actually lost, and the thing the remedy
935
- * below is for. The old sentence would have had an operator conclude the conversation
936
- * was already broken bilaterally when the two trees may still agree.
937
- */
938
- "Delivered and in your transcript — but the relay did not witness it, so the ordering "
939
- + "authority has no copy of it: the counterparty has your message, and neither of you "
940
- + "has independent proof you sent it. Do NOT resend: "
941
- + "that adds a second copy to your record and does not witness the first. "
942
- + "ORDERING DOES NOT REPAIR ITSELF — your record is now one leaf ahead of the relay's, "
943
- + "so the next message the relay DOES witness will report this session as diverged, "
944
- + "and a diverged session can never be sealed with the counterparty. If the receipt "
945
- + "matters, stop sending and close now; if you keep talking, do it knowing this "
946
- + "conversation is unlikely to produce one.",
947
- }),
948
- // On a redact, tell the agent exactly what was transformed (the §6 sender-side surface).
949
- ...(modified ? { transformations: (outboundVerdict.events ?? []).filter((e) => e.disposition === "redact") } : {}),
950
- };
951
- });
952
- // ─── CELLO-M7-DAEMON-004 / F1-a: cello_receive (BLOCKING, session-scoped) ────────
953
- // F1-a fix: the daemon port had dropped the blocking receive (the handler was a
954
- // non-blocking buf.shift). It now BLOCKS up to timeout_ms, polling the received-content
955
- // buffer — resolved by the next arrival, a terminal seal answer (F1-b), or timeout. This is
956
- // the "blocking receive variant" the guidance names.
957
- //
958
- // ONE name (DOD-ONBOARD-HELP-1, Andre 2026-07-11). This was briefly registered under
959
- // `cello_receive_session` as well — one implementation behind two names. That alias is DELETED:
960
- // it accepted or joined nothing (inbound sessions are auto-accepted by the standing receiver),
961
- // so it was a second name for a step that does not exist, and its help said otherwise.
962
- const RECEIVE_DEFAULT_TIMEOUT_MS = 30000; // matches the cello-mcp shim's documented default
963
- const handleReceive = async (params, connectionId) => {
964
- const connState = getConnState(connectionId);
965
- // CC-3 / M8C-AUTOSTART-1 F18: explicit { agent } > current > sole online agent.
966
- const agentName = resolveCurrentAgent(connState, params?.agent);
967
- if (!agentName)
968
- return NO_CURRENT_AGENT_RESPONSE;
969
- // Read the snake_case public field cello-mcp.ts actually sends.
970
- const sessionId = params?.session_id;
971
- if (!sessionId) {
972
- return { ok: false, reason: "missing_params", guidance: "Provide 'session_id' (hex) to receive content for a specific session." };
973
- }
974
- const record = sessionNodeManager.getSessionRecord(agentName, sessionId);
975
- // DOD-UNREAD-1 D4b: a TRANSCRIPT-ONLY session — received rows exist but no sessions row (the
976
- // pre-D3/D4a phantom residue: the counterparty's reply landed while this side refused the
977
- // session). Those rows are counted unread by getUnreadSummary, so cello_receive MUST be able
978
- // to read them or the badge can never clear. Reading is a transcript operation: the read below
979
- // works from the durable transcript alone. Only a session with NEITHER a row
980
- // NOR transcript rows is truly not found.
981
- let transcriptOnly = false;
982
- if (!record) {
983
- /**
984
- * ⚠️ **QUARANTINED ROWS DO NOT MAKE A SESSION — review F4, and this is the clause
985
- * `DOD-M15-REFUSEDEVIDENCE-1` names by surface.**
986
- *
987
- * Every other reader of this table pins `direction = 'received'`, which is what makes a
988
- * refused message excluded by construction. This one counted rows. So after a
989
- * `session_orphaned` retention — no `sessions` row, one quarantined row — `cello_receive`
990
- * stopped answering `session_not_found` and began answering `session_not_live`, with guidance
991
- * saying *"This session exists only as a durable transcript"*. Nothing deliverable is there
992
- * and nobody opened it: the row is a probe someone aimed at an id. That is a milder shape of
993
- * the phantom-session residue this whole design exists to avoid — a session id materialising
994
- * in an operator surface because a stranger sent bytes at it.
995
- */
996
- const deliverable = sessionNodeManager
997
- .readTranscript(agentName, sessionId)
998
- .messages.filter((m) => m.direction !== "quarantined");
999
- if (deliverable.length === 0) {
1000
- return { ok: false, reason: "session_not_found", guidance: "No session found with this ID. Check cello_sessions." };
1001
- }
1002
- transcriptOnly = true;
1003
- }
1004
- // (D4 review F3: the old `record.agent_name !== agentName` → session_not_owned branch was dead
1005
- // code — getSessionRecord is keyed by (agent_name, session_id), so a record can never belong to
1006
- // a different agent. A cross-agent session id simply has no record under this agent.)
1007
- /**
1008
- * DOD-M12B-SESSION-SEED-1 (case B) — return an interrupted session to `active` on a local read.
1009
- *
1010
- * WHAT THIS ACTUALLY BUYS, stated correctly after review MEDIUM-5. The first version of this
1011
- * comment claimed an operator who only reads "was stuck forever" and that parked content never
1012
- * drained. **Neither is true.** The park drain runs off the AGENT's standing receiver, not the
1013
- * session node; `ingestReceivedContent` deliberately accepts `interrupted`; and the backstop
1014
- * tick fires for every agent every 5 minutes. So case-B content already reached the transcript.
1015
- *
1016
- * What the read-triggered revival adds is real but narrower: the status returns to `active`, so
1017
- * the operator's own next send is not refused, and the drain happens NOW rather than up to five
1018
- * minutes from now.
1019
- *
1020
- * WHY A READ MAY TRIGGER THIS AND AN INBOUND DIAL MAY NOT. Andre's tenet is about what a REMOTE
1021
- * party can cause — *"an open connection that a malicious agent can farm for."* Reviving because
1022
- * a peer dialled us would hand that lever to the peer. A read is the OPERATOR asking, on their
1023
- * own machine, for their own session.
1024
- *
1025
- * Narrowed to `interrupted` (review LOW-7). `reviveSessionNode` refuses the other non-active
1026
- * statuses by DENYLIST, so an allowlist here is what stops a sixth status added later from being
1027
- * force-flipped to `active` by a read.
1028
- *
1029
- * AWAITED — a loopback bind, sub-millisecond, and the receive deadline is computed after this so
1030
- * revival latency does not eat the read window — but its RESULT NEVER BLOCKS THE READ. Reading a
1031
- * stored transcript is always allowed, including for a sealed session, where this refuses.
1032
- */
1033
- /**
1034
- * DOD-M12B-SESSION-SEED-1 (case B) — return an interrupted session to `active` on a local read.
1035
- *
1036
- * **NOT AWAITED, and that is a correction made under live fire on 2026-08-18.** The first
1037
- * version awaited it. At the time the rebuild only opened a loopback port, so a stall was not
1038
- * credible — review asked that exact question and got that exact answer. The rebuild was then
1039
- * changed to take a circuit-relay reservation, so that a counterparty could dial us again, and
1040
- * nobody re-asked it. A relay that does not answer has no deadline. `cello_receive` hung for
1041
- * over two minutes on a session whose message was already verified and sitting in the
1042
- * transcript, and no `since_seq` catch-up could get past it either, because this ran first.
1043
- *
1044
- * **Reading your own stored messages must never depend on the network.** The revival is an
1045
- * optimisation on top of a local read — it makes the session sendable again and pulls anything
1046
- * parked — and both are worth nothing if the read cannot complete. So it runs alongside.
1047
- *
1048
- * WHY A READ MAY TRIGGER THIS AND AN INBOUND DIAL MAY NOT. Andre's tenet is about what a REMOTE
1049
- * party can cause — *"an open connection that a malicious agent can farm for."* Reviving because
1050
- * a peer dialled us would hand that lever to the peer. A read is the OPERATOR asking, on their
1051
- * own machine, for their own session.
1052
- *
1053
- * A refusal is no longer reported inline on this call; `session.revive.declined` names it in the
1054
- * log instead. That is the lesser evil against a read that never returns.
1055
- */
1056
- if (record && record.status === "interrupted") {
1057
- void sessionNodeManager.reviveIfNeededForRead(agentName, sessionId).catch(() => { });
1058
- }
1059
- // Catch-up mode is GONE (Andre, live test 2026-09-13): the ordinary read already returns
1060
- // everything unread. Refused by name so an old caller learns that, rather than being ignored.
1061
- if (params?.since_seq !== undefined) {
1062
- return {
1063
- ok: false,
1064
- reason: "since_seq_removed",
1065
- guidance: "since_seq no longer exists. Call cello_receive without it — it returns every unread message at once. For the whole conversation, use cello_transcript.",
1066
- };
1067
- }
1068
- /**
1069
- * ─── ONE READ, EVERY UNREAD MESSAGE, ONE BOOKMARK ───────────────────────────────────────────
1070
- *
1071
- * The bookmark is the agent's persisted watermark for this session. Everything received after it
1072
- * is handed over together and the bookmark moves to the last of them.
1073
- *
1074
- * It replaced three bookmarks, and the live test on 2026-09-13 shows why: catch-up moved two of
1075
- * them, the plain read consulted a third that belonged to the CONNECTION and started empty on
1076
- * every new one — so after catching up the next read re-served the old message, and every `/mcp`
1077
- * reconnect or `cello` CLI command started over at the oldest message in the conversation.
1078
- *
1079
- * The bookmark moves to the LAST message handed over, not through a gap-stopping walk. A hole —
1080
- * a blocked message, a document frame, a row that could not be decrypted — would otherwise strand
1081
- * every later message, re-served on every call. A row that could not be written is reported on
1082
- * the empty answer (`content_undeliverable`) rather than by holding the bookmark behind it.
1083
- */
1084
- const from = record ? record.counterparty_pubkey : null;
1085
- const takeUnread = () => {
1086
- const watermark = sessionNodeManager.getLastDeliveredSeq(agentName, sessionId);
1087
- // Asked ~47x/second while blocked, so the cheap SQL probe runs first and the transcript is
1088
- // decoded only when something is actually there.
1089
- if (!sessionNodeManager.findNextReceivedAfter(agentName, sessionId, watermark))
1090
- return null;
1091
- const unread = sessionNodeManager.readTranscript(agentName, sessionId).messages
1092
- .filter((m) => m.direction === "received" && m.sequence > watermark);
1093
- if (unread.length === 0)
1094
- return null;
1095
- sessionNodeManager.advanceLastDeliveredSeq(agentName, sessionId, unread[unread.length - 1].sequence);
1096
- clearTelegramRung(agentName, sessionId); // M8C-TGDOOR-1: read clears the ring
1097
- return Object.assign(unread, { previousWatermark: watermark });
1098
- };
1099
- const deliver = (unread, correlationId) => {
1100
- logger.info("session.receive.delivered", {
1101
- sessionId, agentName, connectionId, count: unread.length,
1102
- firstSequence: unread[0].sequence, lastSequence: unread[unread.length - 1].sequence,
1103
- attendance: attendanceCount(agentName), correlationId,
1104
- });
1105
- const lastText = unread[unread.length - 1].text.trimEnd();
1106
- // The turn signal belongs to the LAST message: it is what says whose move it is now.
1107
- const signalGuidance = lastText.endsWith("[[WRAP]]")
1108
- ? "Counterparty wrapped. Call cello_close_session now — do not reply."
1109
- : lastText.endsWith("[[OVER]]")
1110
- ? "Counterparty's turn is done. Counterparty has indicated they are expecting a reply — use cello_send to reply."
1111
- : /\[\[STANDBY EST:\d+m\]\]$/.test(lastText)
1112
- ? "Counterparty is working and will follow up when done — no response expected. To block: call cello_receive with a longer timeout_ms. To check back later: schedule a cron and call cello_receive then."
1113
- : undefined;
1114
- // DOD-M12B-AWAY-MARK-1: an away auto-reply is an ordinary message leaf, so without the mark a
1115
- // read is positive evidence a person answered. The content is passed through WHOLE.
1116
- const autoReplyCount = unread.filter((m) => isAutoReplyMarked(m.text)).length;
1117
- // A message that arrived but could not be written to the transcript has no row, so the
1118
- // bookmark just moved past it. Say so HERE, on the answer that crossed it — otherwise the
1119
- // operator sees only a gap in the sequence numbers (review of 86ec7524).
1120
- const lastSeq = unread[unread.length - 1].sequence;
1121
- // Only the lost messages THIS read moved past — the in-memory set is never pruned, so without
1122
- // the lower bound every later read would repeat the warning until a restart.
1123
- const readFrom = unread.previousWatermark ?? -1;
1124
- const crossed = sessionNodeManager.getUndeliverableSeqs(agentName, sessionId).filter((s) => s > readFrom && s <= lastSeq);
1125
- const lag = replyLagFor(sessionNodeManager, agentName, sessionId);
1126
- return {
1127
- ...(lag ? {
1128
- reply_lag: lag,
1129
- reply_lag_guidance: `Their last ${lag.replies} replies were written before they saw your message at position ${lag.your_unseen_seq}, so they may be answering something older. Check whether it reached them before assuming they disagree.`,
1130
- } : {}),
1131
- ok: true,
1132
- session_id: sessionId,
1133
- count: unread.length,
1134
- ...(crossed.length > 0 ? {
1135
- undeliverable_sequences: [...crossed],
1136
- undeliverable_guidance: `${crossed.length} message(s) arrived but could not be written to the local transcript, so they cannot be shown. This is a fault on THIS machine (check disk space and ~/.cello permissions), not the counterparty. Ask them to resend once it is fixed.`,
1137
- } : {}),
1138
- messages: unread.map((m) => ({
1139
- sequence: m.sequence,
1140
- content: m.text,
1141
- from,
1142
- ...(isAutoReplyMarked(m.text) ? { auto_reply: true } : {}),
1143
- })),
1144
- ...(autoReplyCount > 0 ? { auto_reply_guidance: AUTO_REPLY_GUIDANCE } : {}),
1145
- ...refusalsField(sessionNodeManager, agentName, sessionId, connectionId),
1146
- attendance: attendingNow(agentName),
1147
- ...(signalGuidance !== undefined ? { guidance: signalGuidance } : {}),
1148
- };
1149
- };
1150
- // D4b: a transcript-only session has no live node, so nothing new will ever arrive. Hand over
1151
- // what is unread without waiting; if nothing is, say where the history is.
1152
- if (transcriptOnly) {
1153
- const unread = takeUnread();
1154
- if (unread)
1155
- return deliver(unread, randomUUID());
1156
- return {
1157
- ok: false,
1158
- reason: "session_not_live",
1159
- attendance: attendingNow(agentName),
1160
- guidance: "This session exists only as a stored transcript and nothing in it is unread. Read the whole conversation with cello_transcript.",
1161
- };
1162
- }
1163
- const rawTimeout = params?.timeout_ms;
1164
- const timeoutMs = typeof rawTimeout === "number" && Number.isFinite(rawTimeout) && rawTimeout >= 0
1165
- ? rawTimeout
1166
- : RECEIVE_DEFAULT_TIMEOUT_MS;
1167
- const deadline = Date.now() + timeoutMs;
1168
- // DOD-COATTEND-VISIBLE-1 AC3: before this line the plain blocking receive wrote NOTHING to the
1169
- // log on ANY outcome — the only event in the path was `session.receive.since_seq`, which is the
1170
- // OTHER branch — so a session having its message taken by a sibling left no trace anywhere, for
1171
- // the operator in the moment or for anyone reading the log afterwards. One correlationId threads
1172
- // every exit below.
1173
- const receiveCorrelationId = randomUUID();
1174
- // Recomputed at EVERY exit, never snapshotted here (review MEDIUM): the loop below blocks for
1175
- // up to timeout_ms — 30 s by default — and sessions attach and detach inside that window. A
1176
- // count captured before the wait is stale exactly when it matters, and it is the number the
1177
- // operator reads and the number interpolated into the guidance. It is an O(connections) walk
1178
- // over a handful of entries; there is nothing to save by caching it.
1179
- for (;;) {
1180
- // TERMINAL FIRST (DOD-COATTEND-1). Reading the DURABLE RECORD means a sealed session's rows
1181
- // are still present, so a content read would keep delivering on a session that has already
1182
- // terminated — and F1-b's `session_sealed` answer would never be reached. Under the old
1183
- // destructive queue this ordering did not matter, because the seal EVICTED the buffer and the
1184
- // read found nothing. It matters now, so the terminal answer is checked before the record.
1185
- //
1186
- // F1-b: the session sealed while we were (or before we started) waiting — return the
1187
- // terminal answer instead of hanging to timeout. unread_count reports messages that
1188
- // were evicted unread (still durable — recoverable via cello_get_transcript).
1189
- const terminal = sessionNodeManager.peekTerminalMarker(agentName, sessionId);
1190
- if (terminal) {
1191
- const sealedRoot = sessionNodeManager.getSealedRootHex(agentName, sessionId);
1192
- // ⚠️ Unread messages are deliberately NOT handed over here, although that is the one place
1193
- // "every unread message" does not hold. A sealed conversation's leftover message is not live
1194
- // work: on 2026-08-05 an agent obeyed a [[STANDBY]] from a session that had ended. The
1195
- // operator is pointed at cello_transcript instead (DOD-TERMINAL-WAKE-1).
1196
- // AC3 covers "both outcomes" — got something / got nothing. This is the third exit from the
1197
- // same silent handler, and leaving it silent would reproduce the defect one branch over.
1198
- logger.info("session.receive.sealed", {
1199
- sessionId, agentName, connectionId, attendance: attendanceCount(agentName),
1200
- unreadCount: terminal.unreadCount, correlationId: receiveCorrelationId,
1201
- });
1202
- return {
1203
- ok: true,
1204
- type: "session_sealed",
1205
- session_id: sessionId,
1206
- ...(sealedRoot ? { sealed_root: sealedRoot } : {}),
1207
- unread_count: terminal.unreadCount,
1208
- attendance: attendingNow(agentName),
1209
- // DOD-M15-REFUSED-INBOUND-SILENT-1: the LAST door, and without this it is a closed one.
1210
- // This check runs FIRST in the loop, so once a session is sealed the quiet exit is
1211
- // unreachable for it forever — and the guidance here sends the operator to
1212
- // `cello_transcript`, which cannot show a message that was never ingested. The likely
1213
- // sequence is exactly the bad one: skew, silence, the operator gives up and seals, and the
1214
- // explanation becomes unreachable through every door they are pointed at.
1215
- ...refusalsField(sessionNodeManager, agentName, sessionId, connectionId),
1216
- guidance: terminal.unreadCount > 0
1217
- ? `The session has been sealed by both parties. ${terminal.unreadCount} message(s) arrived that were not read live — call cello_transcript to retrieve the full sealed history. No further actions are required on this session.`
1218
- : "The session has been sealed by both parties. The full history is available via cello_transcript. No further actions are required on this session.",
1219
- };
1220
- }
1221
- const unread = takeUnread();
1222
- if (unread)
1223
- return deliver(unread, receiveCorrelationId);
1224
- // 3) Out of time — non-blocking-equivalent empty answer.
1225
- const remaining = deadline - Date.now();
1226
- if (remaining <= 0) {
1227
- // ─── DOD-COATTEND-1 (review F2): a LOCAL failure must not wear the counterparty's label ───
1228
- //
1229
- // Content arrived, was verified and leafed, and its plaintext failed to reach the
1230
- // transcript. Since Tier 1 the transcript IS the delivery path, so that message can never
1231
- // be handed to any session. Every word of the empty answer below is wrong for this case:
1232
- // waiting cannot help, the transcript does not hold it, and "do not resend your last
1233
- // message" is aimed at the one party who could still fix it. Answer with the actual fault,
1234
- // above the branch that would otherwise substitute for it.
1235
- const undeliverable = sessionNodeManager.getUndeliverableSeqs(agentName, sessionId);
1236
- if (undeliverable.length > 0) {
1237
- logger.error("session.receive.undeliverable", {
1238
- sessionId, agentName, connectionId, sequences: undeliverable,
1239
- attendance: attendanceCount(agentName), correlationId: receiveCorrelationId,
1240
- });
1241
- return {
1242
- ok: true,
1243
- count: 0,
1244
- messages: [],
1245
- reason: "content_undeliverable",
1246
- attendance: attendingNow(agentName),
1247
- // A local write failure and a refused message look identical from the operator's chair —
1248
- // nothing arrived. Carrying the refusal here keeps the two distinguishable.
1249
- ...refusalsField(sessionNodeManager, agentName, sessionId, connectionId),
1250
- undeliverable_sequences: [...undeliverable],
1251
- guidance: `${undeliverable.length} message(s) arrived but could not be written to the local transcript, so they cannot be delivered — this is a fault on THIS machine (check disk space and ~/.cello permissions; see transcript.message.record.failed in the daemon log), not a quiet counterparty. Do not wait: waiting cannot recover them. Ask the counterparty to resend once the local fault is fixed.`,
1252
- };
1253
- }
1254
- const liveness = sessionNodeManager.getSessionLiveness(agentName, sessionId);
1255
- const attendance = attendanceCount(agentName);
1256
- // M8B F16: a dead session must not return the SAME null timeout as a
1257
- // quiet-but-healthy one. The liveness signal (session.liveness.changed → gone,
1258
- // tracked per session by the node manager) finally reaches the MCP surface here.
1259
- if (liveness === "gone") {
1260
- logger.info("session.receive.empty", {
1261
- sessionId, agentName, connectionId, timeoutMs, attendance,
1262
- liveness, correlationId: receiveCorrelationId,
1263
- });
1264
- return {
1265
- ok: true,
1266
- count: 0,
1267
- messages: [],
1268
- attendance: attendingNow(agentName),
1269
- // DOD-M15-NO-SILENT-REFUSAL-1 — the exit that does not merely stay silent, it MISLEADS.
1270
- // A version-skewed peer never gets an ACK, so it eventually drops the direct path and
1271
- // lands HERE, pre-empting the quiet exit. A wrong explanation plus an action is worse
1272
- // than saying nothing at all.
1273
- ...refusalsField(sessionNodeManager, agentName, sessionId, connectionId),
1274
- reason: "counterparty_gone",
1275
- liveness: "gone",
1276
- /**
1277
- * ⚠️ **NAMES WHAT WAS OBSERVED, AND `gone` IS A SMALLER FACT THAN IT SOUNDS.**
1278
- *
1279
- * The only thing that produced this state is `onPeerDisconnect` firing for the peer id
1280
- * recorded as the counterparty's session peer — one libp2p connection went away. It
1281
- * does not establish that they crashed, went offline, or left. The previous wording
1282
- * said "it may have crashed or gone offline" and then told the operator to seal, which
1283
- * is a network story for something that is very often a verification fault: a peer
1284
- * whose messages this side keeps refusing is never acknowledged, drops the direct path,
1285
- * and arrives here looking exactly like a crash.
1286
- *
1287
- * **And it must not lead with the seal.** A seal is irreversible and, taken on this
1288
- * evidence, is precisely the truncated close DOD-M15-WITHHOLD-SEAL-1 exists to stop.
1289
- * The refusals spread above are the thing to read first — when they are present they
1290
- * ARE the reason, and none of them is fixed by sealing.
1291
- */
1292
- guidance: "The direct connection to the counterparty's session peer has dropped (liveness: gone). That is what was observed — it does not establish that they crashed or went offline. No more content will arrive on the direct path and a reply cannot reach them there. CHECK `refusals` — HERE IF PRESENT, AND IN cello_inbox EITHER WAY — BEFORE CONCLUDING ANYTHING: if this side has been refusing their messages, a refused sender is never acknowledged and eventually drops the connection, and that is a fault to fix rather than a counterparty who left. A refusal is shown once per window, so another window may already have taken it and this answer can be empty while the cause is real. Otherwise the ordinary causes are a restart, a network change, or them closing their agent — confirm out of band before concluding anything. Sealing with cello_close_session ENDS the conversation permanently and cannot be undone; do it when you have decided the conversation is over, not to clear this state. If you DO decide it is over and the counterparty never co-closes, a unilateral seal becomes available after the directory's delivery-grace window — that is the exit, not the first move.",
1293
- };
1294
- }
1295
- // DOD-M12B-ACK-1: the same rule one step short of 'gone'. A session whose writes are
1296
- // failing looks EXACTLY like a quiet-but-healthy one from here — nothing arrives, and the
1297
- // old answer said "nothing arrived", so an operator waited. Measured 2026-08-17: one
1298
- // session reported healthy for 70 minutes while every message it sent was parking.
1299
- // Distinct from 'gone' on purpose: the connection is up, content may still arrive FROM
1300
- // them, and the session must not be steered toward a seal on this evidence.
1301
- if (liveness === "impaired") {
1302
- const impairment = sessionNodeManager.getSessionImpairment(agentName, sessionId);
1303
- logger.info("session.receive.empty", {
1304
- sessionId, agentName, connectionId, timeoutMs, attendance,
1305
- liveness, impairmentCause: impairment?.cause, impairmentRetained: impairment?.retained,
1306
- correlationId: receiveCorrelationId,
1307
- });
1308
- // EVERY CLAUSE BELOW IS SOMETHING WE ACTUALLY KNOW. The first version of this branch
1309
- // asserted that the message "was parked for the relay to hand over" and that the caller
1310
- // must not resend — and both are false in real cases: a refused park whose durable
1311
- // enqueue was dropped is GONE, and `cello_send` already told the caller to send it again.
1312
- // A receive that contradicts that, later, while the agent is waiting, is worse than
1313
- // silence. The failing write can also be an ACK we owed THEM, in which case the caller
1314
- // sent nothing at all and has no last message to reason about.
1315
- const what = impairment?.cause === "delivery_ack"
1316
- ? "Our acknowledgement to the counterparty could not be sent (liveness: impaired) — this is about a receipt we owe them, not about anything you sent."
1317
- // `029c` review F7: a content-key fault is LOCAL and the connection is fine. Saying "did
1318
- // not reach the counterparty on the direct path" sends the operator to inspect a network
1319
- // that is working, and to blame a peer who is not involved.
1320
- : impairment?.cause === "content_key"
1321
- ? "Your own last send could not be encrypted for this conversation, so it was never put on the wire (liveness: impaired). THIS IS A FAULT ON THIS MACHINE — the connection is fine and your counterparty is not involved."
1322
- : "Your own last send did not reach the counterparty on the direct path (liveness: impaired).";
1323
- const whatNext = impairment?.retained === "parked" ? " That message went to the relay to hand over instead — do NOT resend it: it is not lost, and a resend takes a second position in the record."
1324
- : impairment?.retained === "durable" ? " That message is queued locally and will be re-sent automatically — do NOT resend it: an identical resend is not separately queued."
1325
- : impairment?.retained === "lost" ? " That message could NOT be queued and is lost — send it again. (cello_send said the same when it failed.)"
1326
- : "";
1327
- return {
1328
- ok: true,
1329
- count: 0,
1330
- messages: [],
1331
- attendance: attendingNow(agentName),
1332
- reason: "delivery_impaired",
1333
- liveness: "impaired",
1334
- // DOD-M15-REFUSED-INBOUND-SILENT-1, the item I filed POST-LAUNCH as "deferred, not
1335
- // lost". Taken now instead: it was only safe to spread refusals into an exit once the
1336
- // notice and its advice travel together (see `refusalsField`), and they do — so this
1337
- // exit cannot carry the reason without also carrying what to do about it.
1338
- ...refusalsField(sessionNodeManager, agentName, sessionId, connectionId),
1339
- ...(impairment ? { impairment } : {}),
1340
- guidance: `Nothing arrived. ${what}${whatNext} Their connection is still up, so content may still arrive and this can clear on its own — call cello_status for this session rather than assuming the counterparty is ignoring you.`,
1341
- };
1342
- }
1343
- logger.info("session.receive.empty", {
1344
- sessionId, agentName, connectionId, timeoutMs, attendance,
1345
- liveness, correlationId: receiveCorrelationId,
1346
- });
1347
- // AC6: the QUIET answer carries it too. This is the exit a session with no doorbell to
1348
- // learn from is most likely to reach — it attached, found nothing waiting, and would
1349
- // otherwise have no way to know another window holds the same agent.
1350
- /**
1351
- * DOD-M15-REFUSED-INBOUND-SILENT-1 — THE exit this line exists for.
1352
- *
1353
- * "I waited and nothing came" is the moment an operator concludes the other person stopped
1354
- * replying. If messages ARE arriving and being refused, the reason is known, it is already
1355
- * written to the log with impact and guidance, and this is the one place the person who
1356
- * needs it is actually looking. Guidance below changes to match: telling someone to "call
1357
- * again and keep waiting" while their peer's every message is being refused for a version
1358
- * skew is advice that cannot work.
1359
- */
1360
- const quietRefusals = refusalsField(sessionNodeManager, agentName, sessionId, connectionId);
1361
- return {
1362
- ok: true,
1363
- // The same shape as a read that found messages, so a caller reads `messages` either way.
1364
- count: 0,
1365
- messages: [],
1366
- attendance: attendingNow(agentName),
1367
- ...quietRefusals,
1368
- // ONE source for the refusal advice (see `refusalsField`). It used to be written out
1369
- // again here, which is how the batch exit came to carry the notice without it.
1370
- // ONE source for the refusal advice (see `refusalsField`), and it is now the header for
1371
- // the kinds actually present rather than one sentence that is false for most of them.
1372
- guidance: quietRefusals.refusal_guidance !== undefined
1373
- ? `No content arrived within timeout_ms. ${quietRefusals.refusal_guidance}`
1374
- : "No content arrived within timeout_ms. Call cello_receive again to keep waiting — do not resend your last message. Or read cello_transcript for the full session history.",
1375
- };
1376
- }
1377
- await new Promise((r) => setTimeout(r, Math.min(20, remaining)));
1378
- }
1379
- };
1380
- handlers.set("cello_receive", handleReceive);
1381
- }
1382
- //# sourceMappingURL=session-content-handlers.js.map