@cello-protocol/daemon 0.0.227 → 0.0.228
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.
- package/dist/agent-admin-handlers.d.ts +56 -0
- package/dist/agent-admin-handlers.d.ts.map +1 -0
- package/dist/agent-admin-handlers.js +73 -0
- package/dist/agent-admin-handlers.js.map +1 -0
- package/dist/agent-handlers.d.ts +72 -0
- package/dist/agent-handlers.d.ts.map +1 -0
- package/dist/agent-handlers.js +604 -0
- package/dist/agent-handlers.js.map +1 -0
- package/dist/agent-id-migration.d.ts +70 -0
- package/dist/agent-id-migration.d.ts.map +1 -0
- package/dist/agent-id-migration.js +468 -0
- package/dist/agent-id-migration.js.map +1 -0
- package/dist/agent-loader.d.ts +37 -0
- package/dist/agent-loader.d.ts.map +1 -0
- package/dist/agent-loader.js +37 -0
- package/dist/agent-loader.js.map +1 -0
- package/dist/agent-selection-root.d.ts +29 -0
- package/dist/agent-selection-root.d.ts.map +1 -0
- package/dist/agent-selection-root.js +126 -0
- package/dist/agent-selection-root.js.map +1 -0
- package/dist/agent-selection.d.ts +73 -0
- package/dist/agent-selection.d.ts.map +1 -0
- package/dist/agent-selection.js +80 -0
- package/dist/agent-selection.js.map +1 -0
- package/dist/agent-settings-keys.d.ts +52 -0
- package/dist/agent-settings-keys.d.ts.map +1 -0
- package/dist/agent-settings-keys.js +114 -0
- package/dist/agent-settings-keys.js.map +1 -0
- package/dist/agent-state.d.ts +67 -0
- package/dist/agent-state.d.ts.map +1 -0
- package/dist/agent-state.js +66 -0
- package/dist/agent-state.js.map +1 -0
- package/dist/assignment-verify.d.ts +90 -0
- package/dist/assignment-verify.d.ts.map +1 -0
- package/dist/assignment-verify.js +301 -0
- package/dist/assignment-verify.js.map +1 -0
- package/dist/attendance-wiring.d.ts +23 -0
- package/dist/attendance-wiring.d.ts.map +1 -0
- package/dist/attendance-wiring.js +248 -0
- package/dist/attendance-wiring.js.map +1 -0
- package/dist/attestation-body.d.ts +47 -0
- package/dist/attestation-body.d.ts.map +1 -0
- package/dist/attestation-body.js +71 -0
- package/dist/attestation-body.js.map +1 -0
- package/dist/authorship-verification.d.ts +91 -0
- package/dist/authorship-verification.d.ts.map +1 -0
- package/dist/authorship-verification.js +532 -0
- package/dist/authorship-verification.js.map +1 -0
- package/dist/away-detection.d.ts +139 -0
- package/dist/away-detection.d.ts.map +1 -0
- package/dist/away-detection.js +186 -0
- package/dist/away-detection.js.map +1 -0
- package/dist/away-inbox-oneshot.d.ts +40 -0
- package/dist/away-inbox-oneshot.d.ts.map +1 -0
- package/dist/away-inbox-oneshot.js +311 -0
- package/dist/away-inbox-oneshot.js.map +1 -0
- package/dist/backup-restore-handlers.d.ts +10 -0
- package/dist/backup-restore-handlers.d.ts.map +1 -0
- package/dist/backup-restore-handlers.js +82 -0
- package/dist/backup-restore-handlers.js.map +1 -0
- package/dist/backup-restore.d.ts +102 -0
- package/dist/backup-restore.d.ts.map +1 -0
- package/dist/backup-restore.js +341 -0
- package/dist/backup-restore.js.map +1 -0
- package/dist/bin/cello-daemon.d.ts +13 -0
- package/dist/bin/cello-daemon.d.ts.map +1 -0
- package/dist/bin/cello-daemon.js.map +1 -0
- package/dist/boot-agents.d.ts +64 -0
- package/dist/boot-agents.d.ts.map +1 -0
- package/dist/boot-agents.js +241 -0
- package/dist/boot-agents.js.map +1 -0
- package/dist/boot-connection-state.d.ts +38 -0
- package/dist/boot-connection-state.d.ts.map +1 -0
- package/dist/boot-connection-state.js +95 -0
- package/dist/boot-connection-state.js.map +1 -0
- package/dist/boot-core.d.ts +36 -0
- package/dist/boot-core.d.ts.map +1 -0
- package/dist/boot-core.js +293 -0
- package/dist/boot-core.js.map +1 -0
- package/dist/boot-parked-content.d.ts +34 -0
- package/dist/boot-parked-content.d.ts.map +1 -0
- package/dist/boot-parked-content.js +528 -0
- package/dist/boot-parked-content.js.map +1 -0
- package/dist/boot-sweeps.d.ts +22 -0
- package/dist/boot-sweeps.d.ts.map +1 -0
- package/dist/boot-sweeps.js +51 -0
- package/dist/boot-sweeps.js.map +1 -0
- package/dist/bundled-consortium-manifest.d.ts +47 -0
- package/dist/bundled-consortium-manifest.d.ts.map +1 -0
- package/dist/bundled-consortium-manifest.js +116 -0
- package/dist/bundled-consortium-manifest.js.map +1 -0
- package/dist/cbor-blob-migration.d.ts +8 -0
- package/dist/cbor-blob-migration.d.ts.map +1 -0
- package/dist/cbor-blob-migration.js +116 -0
- package/dist/cbor-blob-migration.js.map +1 -0
- package/dist/challenge-verifier.d.ts +12 -0
- package/dist/challenge-verifier.d.ts.map +1 -0
- package/dist/challenge-verifier.js +11 -0
- package/dist/challenge-verifier.js.map +1 -0
- package/dist/channel-log-store.d.ts +80 -0
- package/dist/channel-log-store.d.ts.map +1 -0
- package/dist/channel-log-store.js +290 -0
- package/dist/channel-log-store.js.map +1 -0
- package/dist/close-commitment.d.ts +67 -0
- package/dist/close-commitment.d.ts.map +1 -0
- package/dist/close-commitment.js +78 -0
- package/dist/close-commitment.js.map +1 -0
- package/dist/close-session-handler.d.ts +94 -0
- package/dist/close-session-handler.d.ts.map +1 -0
- package/dist/close-session-handler.js +1418 -0
- package/dist/close-session-handler.js.map +1 -0
- package/dist/co-attendance.d.ts +29 -0
- package/dist/co-attendance.d.ts.map +1 -0
- package/dist/co-attendance.js +32 -0
- package/dist/co-attendance.js.map +1 -0
- package/dist/column-birth.d.ts +40 -0
- package/dist/column-birth.d.ts.map +1 -0
- package/dist/column-birth.js +61 -0
- package/dist/column-birth.js.map +1 -0
- package/dist/connect-or-start.d.ts +25 -0
- package/dist/connect-or-start.d.ts.map +1 -0
- package/dist/connect-or-start.js +175 -0
- package/dist/connect-or-start.js.map +1 -0
- package/dist/connection-agents.d.ts +16 -0
- package/dist/connection-agents.d.ts.map +1 -0
- package/dist/connection-agents.js +68 -0
- package/dist/connection-agents.js.map +1 -0
- package/dist/consent-migration.d.ts +49 -0
- package/dist/consent-migration.d.ts.map +1 -0
- package/dist/consent-migration.js +128 -0
- package/dist/consent-migration.js.map +1 -0
- package/dist/consortium-bootstrap.d.ts +138 -0
- package/dist/consortium-bootstrap.d.ts.map +1 -0
- package/dist/consortium-bootstrap.js +339 -0
- package/dist/consortium-bootstrap.js.map +1 -0
- package/dist/consortium-fingerprint.d.ts +115 -0
- package/dist/consortium-fingerprint.d.ts.map +1 -0
- package/dist/consortium-fingerprint.js +175 -0
- package/dist/consortium-fingerprint.js.map +1 -0
- package/dist/contact-handlers.d.ts +59 -0
- package/dist/contact-handlers.d.ts.map +1 -0
- package/dist/contact-handlers.js +343 -0
- package/dist/contact-handlers.js.map +1 -0
- package/dist/contact-pubkey-case.d.ts +65 -0
- package/dist/contact-pubkey-case.d.ts.map +1 -0
- package/dist/contact-pubkey-case.js +136 -0
- package/dist/contact-pubkey-case.js.map +1 -0
- package/dist/contacts-tier-migration.d.ts +90 -0
- package/dist/contacts-tier-migration.d.ts.map +1 -0
- package/dist/contacts-tier-migration.js +150 -0
- package/dist/contacts-tier-migration.js.map +1 -0
- package/dist/content-encryption-status.d.ts +111 -0
- package/dist/content-encryption-status.d.ts.map +1 -0
- package/dist/content-encryption-status.js +158 -0
- package/dist/content-encryption-status.js.map +1 -0
- package/dist/content-park-client.d.ts +90 -0
- package/dist/content-park-client.d.ts.map +1 -0
- package/dist/content-park-client.js +362 -0
- package/dist/content-park-client.js.map +1 -0
- package/dist/content-park.d.ts +52 -0
- package/dist/content-park.d.ts.map +1 -0
- package/dist/content-park.js +1309 -0
- package/dist/content-park.js.map +1 -0
- package/dist/cross-node-negotiation.d.ts +44 -0
- package/dist/cross-node-negotiation.d.ts.map +1 -0
- package/dist/cross-node-negotiation.js +34 -0
- package/dist/cross-node-negotiation.js.map +1 -0
- package/dist/daemon-handle.d.ts +57 -0
- package/dist/daemon-handle.d.ts.map +1 -0
- package/dist/daemon-handle.js +2 -0
- package/dist/daemon-handle.js.map +1 -0
- package/dist/daemon-status-report.d.ts +50 -0
- package/dist/daemon-status-report.d.ts.map +1 -0
- package/dist/daemon-status-report.js +81 -0
- package/dist/daemon-status-report.js.map +1 -0
- package/dist/daemon.d.ts +45 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +1177 -0
- package/dist/daemon.js.map +1 -0
- package/dist/db-identity-store.d.ts +159 -0
- package/dist/db-identity-store.d.ts.map +1 -0
- package/dist/db-identity-store.js +502 -0
- package/dist/db-identity-store.js.map +1 -0
- package/dist/delivery-open-registry.d.ts +92 -0
- package/dist/delivery-open-registry.d.ts.map +1 -0
- package/dist/delivery-open-registry.js +121 -0
- package/dist/delivery-open-registry.js.map +1 -0
- package/dist/delivery-session-suspects.d.ts +56 -0
- package/dist/delivery-session-suspects.d.ts.map +1 -0
- package/dist/delivery-session-suspects.js +94 -0
- package/dist/delivery-session-suspects.js.map +1 -0
- package/dist/directory-auth-posture.d.ts +87 -0
- package/dist/directory-auth-posture.d.ts.map +1 -0
- package/dist/directory-auth-posture.js +134 -0
- package/dist/directory-auth-posture.js.map +1 -0
- package/dist/directory-bootstrap.d.ts +310 -0
- package/dist/directory-bootstrap.d.ts.map +1 -0
- package/dist/directory-bootstrap.js +557 -0
- package/dist/directory-bootstrap.js.map +1 -0
- package/dist/directory-connect.d.ts +27 -0
- package/dist/directory-connect.d.ts.map +1 -0
- package/dist/directory-connect.js +106 -0
- package/dist/directory-connect.js.map +1 -0
- package/dist/disconnect-cleanup.d.ts +51 -0
- package/dist/disconnect-cleanup.d.ts.map +1 -0
- package/dist/disconnect-cleanup.js +72 -0
- package/dist/disconnect-cleanup.js.map +1 -0
- package/dist/document-amendment-store.d.ts +120 -0
- package/dist/document-amendment-store.d.ts.map +1 -0
- package/dist/document-amendment-store.js +266 -0
- package/dist/document-amendment-store.js.map +1 -0
- package/dist/document-delivery-transport.d.ts +168 -0
- package/dist/document-delivery-transport.d.ts.map +1 -0
- package/dist/document-delivery-transport.js +206 -0
- package/dist/document-delivery-transport.js.map +1 -0
- package/dist/document-engine.d.ts +134 -0
- package/dist/document-engine.d.ts.map +1 -0
- package/dist/document-engine.js +282 -0
- package/dist/document-engine.js.map +1 -0
- package/dist/document-flag.d.ts +58 -0
- package/dist/document-flag.d.ts.map +1 -0
- package/dist/document-flag.js +70 -0
- package/dist/document-flag.js.map +1 -0
- package/dist/document-frame-router.d.ts +245 -0
- package/dist/document-frame-router.d.ts.map +1 -0
- package/dist/document-frame-router.js +397 -0
- package/dist/document-frame-router.js.map +1 -0
- package/dist/document-gate-wiring.d.ts +61 -0
- package/dist/document-gate-wiring.d.ts.map +1 -0
- package/dist/document-gate-wiring.js +125 -0
- package/dist/document-gate-wiring.js.map +1 -0
- package/dist/document-gate.d.ts +149 -0
- package/dist/document-gate.d.ts.map +1 -0
- package/dist/document-gate.js +509 -0
- package/dist/document-gate.js.map +1 -0
- package/dist/document-handlers.d.ts +47 -0
- package/dist/document-handlers.d.ts.map +1 -0
- package/dist/document-handlers.js +2203 -0
- package/dist/document-handlers.js.map +1 -0
- package/dist/document-handshake.d.ts +176 -0
- package/dist/document-handshake.d.ts.map +1 -0
- package/dist/document-handshake.js +452 -0
- package/dist/document-handshake.js.map +1 -0
- package/dist/document-inbound.d.ts +162 -0
- package/dist/document-inbound.d.ts.map +1 -0
- package/dist/document-inbound.js +530 -0
- package/dist/document-inbound.js.map +1 -0
- package/dist/document-json.d.ts +120 -0
- package/dist/document-json.d.ts.map +1 -0
- package/dist/document-json.js +191 -0
- package/dist/document-json.js.map +1 -0
- package/dist/document-layer.d.ts +215 -0
- package/dist/document-layer.d.ts.map +1 -0
- package/dist/document-layer.js +1025 -0
- package/dist/document-layer.js.map +1 -0
- package/dist/document-lifecycle.d.ts +52 -0
- package/dist/document-lifecycle.d.ts.map +1 -0
- package/dist/document-lifecycle.js +134 -0
- package/dist/document-lifecycle.js.map +1 -0
- package/dist/document-live-docs.d.ts +58 -0
- package/dist/document-live-docs.d.ts.map +1 -0
- package/dist/document-live-docs.js +126 -0
- package/dist/document-live-docs.js.map +1 -0
- package/dist/document-notify.d.ts +228 -0
- package/dist/document-notify.d.ts.map +1 -0
- package/dist/document-notify.js +580 -0
- package/dist/document-notify.js.map +1 -0
- package/dist/document-profile.d.ts +61 -0
- package/dist/document-profile.d.ts.map +1 -0
- package/dist/document-profile.js +112 -0
- package/dist/document-profile.js.map +1 -0
- package/dist/document-publish.d.ts +87 -0
- package/dist/document-publish.d.ts.map +1 -0
- package/dist/document-publish.js +173 -0
- package/dist/document-publish.js.map +1 -0
- package/dist/document-reachability.d.ts +42 -0
- package/dist/document-reachability.d.ts.map +1 -0
- package/dist/document-reachability.js +80 -0
- package/dist/document-reachability.js.map +1 -0
- package/dist/document-reconcile-engine.d.ts +66 -0
- package/dist/document-reconcile-engine.d.ts.map +1 -0
- package/dist/document-reconcile-engine.js +225 -0
- package/dist/document-reconcile-engine.js.map +1 -0
- package/dist/document-reconcile-scheduler.d.ts +163 -0
- package/dist/document-reconcile-scheduler.d.ts.map +1 -0
- package/dist/document-reconcile-scheduler.js +303 -0
- package/dist/document-reconcile-scheduler.js.map +1 -0
- package/dist/document-rejection.d.ts +251 -0
- package/dist/document-rejection.d.ts.map +1 -0
- package/dist/document-rejection.js +435 -0
- package/dist/document-rejection.js.map +1 -0
- package/dist/document-screen.d.ts +114 -0
- package/dist/document-screen.d.ts.map +1 -0
- package/dist/document-screen.js +223 -0
- package/dist/document-screen.js.map +1 -0
- package/dist/document-store.d.ts +372 -0
- package/dist/document-store.d.ts.map +1 -0
- package/dist/document-store.js +931 -0
- package/dist/document-store.js.map +1 -0
- package/dist/document-surface.d.ts +32 -0
- package/dist/document-surface.d.ts.map +1 -0
- package/dist/document-surface.js +151 -0
- package/dist/document-surface.js.map +1 -0
- package/dist/document-types.d.ts +94 -0
- package/dist/document-types.d.ts.map +1 -0
- package/dist/document-types.js +90 -0
- package/dist/document-types.js.map +1 -0
- package/dist/document-watch.d.ts +69 -0
- package/dist/document-watch.d.ts.map +1 -0
- package/dist/document-watch.js +108 -0
- package/dist/document-watch.js.map +1 -0
- package/dist/document-wiring.d.ts +53 -0
- package/dist/document-wiring.d.ts.map +1 -0
- package/dist/document-wiring.js +323 -0
- package/dist/document-wiring.js.map +1 -0
- package/dist/document-write-guard.d.ts +66 -0
- package/dist/document-write-guard.d.ts.map +1 -0
- package/dist/document-write-guard.js +98 -0
- package/dist/document-write-guard.js.map +1 -0
- package/dist/document-write-path.d.ts +94 -0
- package/dist/document-write-path.d.ts.map +1 -0
- package/dist/document-write-path.js +530 -0
- package/dist/document-write-path.js.map +1 -0
- package/dist/error-message.d.ts +7 -0
- package/dist/error-message.d.ts.map +1 -0
- package/dist/error-message.js +19 -0
- package/dist/error-message.js.map +1 -0
- package/dist/file-manifest-provider.d.ts +37 -0
- package/dist/file-manifest-provider.d.ts.map +1 -0
- package/dist/file-manifest-provider.js +105 -0
- package/dist/file-manifest-provider.js.map +1 -0
- package/dist/frame-values.d.ts +3 -0
- package/dist/frame-values.d.ts.map +1 -0
- package/dist/frame-values.js +84 -0
- package/dist/frame-values.js.map +1 -0
- package/dist/frontier-mismatch.d.ts +73 -0
- package/dist/frontier-mismatch.d.ts.map +1 -0
- package/dist/frontier-mismatch.js +89 -0
- package/dist/frontier-mismatch.js.map +1 -0
- package/dist/gateway-config-handlers.d.ts +26 -0
- package/dist/gateway-config-handlers.d.ts.map +1 -0
- package/dist/gateway-config-handlers.js +429 -0
- package/dist/gateway-config-handlers.js.map +1 -0
- package/dist/held-content.d.ts +145 -0
- package/dist/held-content.d.ts.map +1 -0
- package/dist/held-content.js +389 -0
- package/dist/held-content.js.map +1 -0
- package/dist/http-manifest-poll.d.ts +67 -0
- package/dist/http-manifest-poll.d.ts.map +1 -0
- package/dist/http-manifest-poll.js +150 -0
- package/dist/http-manifest-poll.js.map +1 -0
- package/dist/identity-migration.d.ts +40 -0
- package/dist/identity-migration.d.ts.map +1 -0
- package/dist/identity-migration.js +461 -0
- package/dist/identity-migration.js.map +1 -0
- package/dist/inbound-refusals.d.ts +283 -0
- package/dist/inbound-refusals.d.ts.map +1 -0
- package/dist/inbound-refusals.js +919 -0
- package/dist/inbound-refusals.js.map +1 -0
- package/dist/inbound-seal-request.d.ts +32 -0
- package/dist/inbound-seal-request.d.ts.map +1 -0
- package/dist/inbound-seal-request.js +228 -0
- package/dist/inbound-seal-request.js.map +1 -0
- package/dist/inbound-sessions.d.ts +291 -0
- package/dist/inbound-sessions.d.ts.map +1 -0
- package/dist/inbound-sessions.js +1609 -0
- package/dist/inbound-sessions.js.map +1 -0
- package/dist/inclusion-proof-handlers.d.ts +43 -0
- package/dist/inclusion-proof-handlers.d.ts.map +1 -0
- package/dist/inclusion-proof-handlers.js +565 -0
- package/dist/inclusion-proof-handlers.js.map +1 -0
- package/dist/inclusion-proof.d.ts +151 -0
- package/dist/inclusion-proof.d.ts.map +1 -0
- package/dist/inclusion-proof.js +228 -0
- package/dist/inclusion-proof.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js.map +1 -0
- package/dist/initiate-session-handler.d.ts +55 -0
- package/dist/initiate-session-handler.d.ts.map +1 -0
- package/dist/initiate-session-handler.js +310 -0
- package/dist/initiate-session-handler.js.map +1 -0
- package/dist/ipc-client.d.ts +31 -0
- package/dist/ipc-client.d.ts.map +1 -0
- package/dist/ipc-client.js +113 -0
- package/dist/ipc-client.js.map +1 -0
- package/dist/ipc-server.d.ts +63 -0
- package/dist/ipc-server.d.ts.map +1 -0
- package/dist/ipc-server.js +429 -0
- package/dist/ipc-server.js.map +1 -0
- package/dist/ipc-surface.d.ts +44 -0
- package/dist/ipc-surface.d.ts.map +1 -0
- package/dist/ipc-surface.js +107 -0
- package/dist/ipc-surface.js.map +1 -0
- package/dist/line-lcs.d.ts +51 -0
- package/dist/line-lcs.d.ts.map +1 -0
- package/dist/line-lcs.js +71 -0
- package/dist/line-lcs.js.map +1 -0
- package/dist/lock-file.d.ts +39 -0
- package/dist/lock-file.d.ts.map +1 -0
- package/dist/lock-file.js +120 -0
- package/dist/lock-file.js.map +1 -0
- package/dist/log-collapse.d.ts +66 -0
- package/dist/log-collapse.d.ts.map +1 -0
- package/dist/log-collapse.js +244 -0
- package/dist/log-collapse.js.map +1 -0
- package/dist/log-rotate.d.ts +67 -0
- package/dist/log-rotate.d.ts.map +1 -0
- package/dist/log-rotate.js +134 -0
- package/dist/log-rotate.js.map +1 -0
- package/dist/manifest-deps.d.ts +25 -0
- package/dist/manifest-deps.d.ts.map +1 -0
- package/dist/manifest-deps.js +151 -0
- package/dist/manifest-deps.js.map +1 -0
- package/dist/manifest-poll-scheduler.d.ts +31 -0
- package/dist/manifest-poll-scheduler.d.ts.map +1 -0
- package/dist/manifest-poll-scheduler.js +59 -0
- package/dist/manifest-poll-scheduler.js.map +1 -0
- package/dist/manifest-validity.d.ts +153 -0
- package/dist/manifest-validity.d.ts.map +1 -0
- package/dist/manifest-validity.js +268 -0
- package/dist/manifest-validity.js.map +1 -0
- package/dist/manifest-version-store-db.d.ts +24 -0
- package/dist/manifest-version-store-db.d.ts.map +1 -0
- package/dist/manifest-version-store-db.js +58 -0
- package/dist/manifest-version-store-db.js.map +1 -0
- package/dist/manifest-version-store.d.ts +16 -0
- package/dist/manifest-version-store.d.ts.map +1 -0
- package/dist/manifest-version-store.js +15 -0
- package/dist/manifest-version-store.js.map +1 -0
- package/dist/network-directory-node.d.ts +136 -0
- package/dist/network-directory-node.d.ts.map +1 -0
- package/dist/network-directory-node.js +810 -0
- package/dist/network-directory-node.js.map +1 -0
- package/dist/nonce-dedup.d.ts +68 -0
- package/dist/nonce-dedup.d.ts.map +1 -0
- package/dist/nonce-dedup.js +205 -0
- package/dist/nonce-dedup.js.map +1 -0
- package/dist/notification-dispatcher.d.ts +92 -0
- package/dist/notification-dispatcher.d.ts.map +1 -0
- package/dist/notification-dispatcher.js +210 -0
- package/dist/notification-dispatcher.js.map +1 -0
- package/dist/notification-handlers.d.ts +53 -0
- package/dist/notification-handlers.d.ts.map +1 -0
- package/dist/notification-handlers.js +461 -0
- package/dist/notification-handlers.js.map +1 -0
- package/dist/onboarding-guidance.d.ts +79 -0
- package/dist/onboarding-guidance.d.ts.map +1 -0
- package/dist/onboarding-guidance.js +95 -0
- package/dist/onboarding-guidance.js.map +1 -0
- package/dist/operator-guidance.d.ts +25 -0
- package/dist/operator-guidance.d.ts.map +1 -0
- package/dist/operator-guidance.js +50 -0
- package/dist/operator-guidance.js.map +1 -0
- package/dist/orphan-triage.d.ts +130 -0
- package/dist/orphan-triage.d.ts.map +1 -0
- package/dist/orphan-triage.js +207 -0
- package/dist/orphan-triage.js.map +1 -0
- package/dist/outbound-sessions.d.ts +126 -0
- package/dist/outbound-sessions.d.ts.map +1 -0
- package/dist/outbound-sessions.js +1052 -0
- package/dist/outbound-sessions.js.map +1 -0
- package/dist/park-envelope.d.ts +329 -0
- package/dist/park-envelope.d.ts.map +1 -0
- package/dist/park-envelope.js +509 -0
- package/dist/park-envelope.js.map +1 -0
- package/dist/park-recovery.d.ts +273 -0
- package/dist/park-recovery.d.ts.map +1 -0
- package/dist/park-recovery.js +717 -0
- package/dist/park-recovery.js.map +1 -0
- package/dist/park-refusals.d.ts +147 -0
- package/dist/park-refusals.d.ts.map +1 -0
- package/dist/park-refusals.js +331 -0
- package/dist/park-refusals.js.map +1 -0
- package/dist/quarantine-framing.d.ts +92 -0
- package/dist/quarantine-framing.d.ts.map +1 -0
- package/dist/quarantine-framing.js +111 -0
- package/dist/quarantine-framing.js.map +1 -0
- package/dist/reconnect-drain.d.ts +22 -0
- package/dist/reconnect-drain.d.ts.map +1 -0
- package/dist/reconnect-drain.js +65 -0
- package/dist/reconnect-drain.js.map +1 -0
- package/dist/recovered-position.d.ts +14 -0
- package/dist/recovered-position.d.ts.map +1 -0
- package/dist/recovered-position.js +59 -0
- package/dist/recovered-position.js.map +1 -0
- package/dist/refusal-notices.d.ts +196 -0
- package/dist/refusal-notices.d.ts.map +1 -0
- package/dist/refusal-notices.js +516 -0
- package/dist/refusal-notices.js.map +1 -0
- package/dist/refusal-reasons.d.ts +245 -0
- package/dist/refusal-reasons.d.ts.map +1 -0
- package/dist/refusal-reasons.js +363 -0
- package/dist/refusal-reasons.js.map +1 -0
- package/dist/register-handler.d.ts +36 -0
- package/dist/register-handler.d.ts.map +1 -0
- package/dist/register-handler.js +285 -0
- package/dist/register-handler.js.map +1 -0
- package/dist/registration-context.d.ts +72 -0
- package/dist/registration-context.d.ts.map +1 -0
- package/dist/registration-context.js +126 -0
- package/dist/registration-context.js.map +1 -0
- package/dist/registration-manager.d.ts +94 -0
- package/dist/registration-manager.d.ts.map +1 -0
- package/dist/registration-manager.js +585 -0
- package/dist/registration-manager.js.map +1 -0
- package/dist/registration-persistence.d.ts +183 -0
- package/dist/registration-persistence.d.ts.map +1 -0
- package/dist/registration-persistence.js +263 -0
- package/dist/registration-persistence.js.map +1 -0
- package/dist/registry-poll.d.ts +52 -0
- package/dist/registry-poll.d.ts.map +1 -0
- package/dist/registry-poll.js +140 -0
- package/dist/registry-poll.js.map +1 -0
- package/dist/registry-version-store-db.d.ts +22 -0
- package/dist/registry-version-store-db.d.ts.map +1 -0
- package/dist/registry-version-store-db.js +50 -0
- package/dist/registry-version-store-db.js.map +1 -0
- package/dist/relay-endpoints.d.ts +18 -0
- package/dist/relay-endpoints.d.ts.map +1 -0
- package/dist/relay-endpoints.js +9 -0
- package/dist/relay-endpoints.js.map +1 -0
- package/dist/relay-only.d.ts +140 -0
- package/dist/relay-only.d.ts.map +1 -0
- package/dist/relay-only.js +193 -0
- package/dist/relay-only.js.map +1 -0
- package/dist/relay-receipt-store.d.ts +155 -0
- package/dist/relay-receipt-store.d.ts.map +1 -0
- package/dist/relay-receipt-store.js +284 -0
- package/dist/relay-receipt-store.js.map +1 -0
- package/dist/relay-reconnect.d.ts +32 -0
- package/dist/relay-reconnect.d.ts.map +1 -0
- package/dist/relay-reconnect.js +29 -0
- package/dist/relay-reconnect.js.map +1 -0
- package/dist/reply-lag.d.ts +11 -0
- package/dist/reply-lag.d.ts.map +1 -0
- package/dist/reply-lag.js +46 -0
- package/dist/reply-lag.js.map +1 -0
- package/dist/resolve-named-agent.d.ts +49 -0
- package/dist/resolve-named-agent.d.ts.map +1 -0
- package/dist/resolve-named-agent.js +77 -0
- package/dist/resolve-named-agent.js.map +1 -0
- package/dist/restart-seal-resolver.d.ts +110 -0
- package/dist/restart-seal-resolver.d.ts.map +1 -0
- package/dist/restart-seal-resolver.js +353 -0
- package/dist/restart-seal-resolver.js.map +1 -0
- package/dist/resume-last-seen.d.ts +15 -0
- package/dist/resume-last-seen.d.ts.map +1 -0
- package/dist/resume-last-seen.js +44 -0
- package/dist/resume-last-seen.js.map +1 -0
- package/dist/retry-queue.d.ts +203 -0
- package/dist/retry-queue.d.ts.map +1 -0
- package/dist/retry-queue.js +701 -0
- package/dist/retry-queue.js.map +1 -0
- package/dist/roster-freshness.d.ts +160 -0
- package/dist/roster-freshness.d.ts.map +1 -0
- package/dist/roster-freshness.js +250 -0
- package/dist/roster-freshness.js.map +1 -0
- package/dist/screening-status.d.ts +15 -0
- package/dist/screening-status.d.ts.map +1 -0
- package/dist/screening-status.js +65 -0
- package/dist/screening-status.js.map +1 -0
- package/dist/seal-carried-close.d.ts +37 -0
- package/dist/seal-carried-close.d.ts.map +1 -0
- package/dist/seal-carried-close.js +179 -0
- package/dist/seal-carried-close.js.map +1 -0
- package/dist/seal-certificate-pull.d.ts +79 -0
- package/dist/seal-certificate-pull.d.ts.map +1 -0
- package/dist/seal-certificate-pull.js +186 -0
- package/dist/seal-certificate-pull.js.map +1 -0
- package/dist/seal-certified-root-check.d.ts +37 -0
- package/dist/seal-certified-root-check.d.ts.map +1 -0
- package/dist/seal-certified-root-check.js +127 -0
- package/dist/seal-certified-root-check.js.map +1 -0
- package/dist/seal-coordinator.d.ts +118 -0
- package/dist/seal-coordinator.d.ts.map +1 -0
- package/dist/seal-coordinator.js +927 -0
- package/dist/seal-coordinator.js.map +1 -0
- package/dist/seal-escalation.d.ts +80 -0
- package/dist/seal-escalation.d.ts.map +1 -0
- package/dist/seal-escalation.js +283 -0
- package/dist/seal-escalation.js.map +1 -0
- package/dist/seal-evidence-root-check.d.ts +70 -0
- package/dist/seal-evidence-root-check.d.ts.map +1 -0
- package/dist/seal-evidence-root-check.js +199 -0
- package/dist/seal-evidence-root-check.js.map +1 -0
- package/dist/seal-failure-store.d.ts +139 -0
- package/dist/seal-failure-store.d.ts.map +1 -0
- package/dist/seal-failure-store.js +207 -0
- package/dist/seal-failure-store.js.map +1 -0
- package/dist/seal-flows.d.ts +107 -0
- package/dist/seal-flows.d.ts.map +1 -0
- package/dist/seal-flows.js +638 -0
- package/dist/seal-flows.js.map +1 -0
- package/dist/seal-frontier-verify.d.ts +103 -0
- package/dist/seal-frontier-verify.d.ts.map +1 -0
- package/dist/seal-frontier-verify.js +143 -0
- package/dist/seal-frontier-verify.js.map +1 -0
- package/dist/seal-leaf.d.ts +58 -0
- package/dist/seal-leaf.d.ts.map +1 -0
- package/dist/seal-leaf.js +112 -0
- package/dist/seal-leaf.js.map +1 -0
- package/dist/seal-legibility-tbs.d.ts +25 -0
- package/dist/seal-legibility-tbs.d.ts.map +1 -0
- package/dist/seal-legibility-tbs.js +77 -0
- package/dist/seal-legibility-tbs.js.map +1 -0
- package/dist/seal-local-terminus.d.ts +41 -0
- package/dist/seal-local-terminus.d.ts.map +1 -0
- package/dist/seal-local-terminus.js +170 -0
- package/dist/seal-local-terminus.js.map +1 -0
- package/dist/seal-receipt-upgrade.d.ts +30 -0
- package/dist/seal-receipt-upgrade.d.ts.map +1 -0
- package/dist/seal-receipt-upgrade.js +49 -0
- package/dist/seal-receipt-upgrade.js.map +1 -0
- package/dist/seal-relay-silence.d.ts +51 -0
- package/dist/seal-relay-silence.d.ts.map +1 -0
- package/dist/seal-relay-silence.js +76 -0
- package/dist/seal-relay-silence.js.map +1 -0
- package/dist/seal-settle.d.ts +38 -0
- package/dist/seal-settle.d.ts.map +1 -0
- package/dist/seal-settle.js +33 -0
- package/dist/seal-settle.js.map +1 -0
- package/dist/seal-upgrade.d.ts +107 -0
- package/dist/seal-upgrade.d.ts.map +1 -0
- package/dist/seal-upgrade.js +200 -0
- package/dist/seal-upgrade.js.map +1 -0
- package/dist/sealed-conversation.d.ts +36 -0
- package/dist/sealed-conversation.d.ts.map +1 -0
- package/dist/sealed-conversation.js +171 -0
- package/dist/sealed-conversation.js.map +1 -0
- package/dist/sealed-leaf-set.d.ts +92 -0
- package/dist/sealed-leaf-set.d.ts.map +1 -0
- package/dist/sealed-leaf-set.js +122 -0
- package/dist/sealed-leaf-set.js.map +1 -0
- package/dist/send-claims.d.ts +56 -0
- package/dist/send-claims.d.ts.map +1 -0
- package/dist/send-claims.js +50 -0
- package/dist/send-claims.js.map +1 -0
- package/dist/session-assignment-parser.d.ts +104 -0
- package/dist/session-assignment-parser.d.ts.map +1 -0
- package/dist/session-assignment-parser.js +345 -0
- package/dist/session-assignment-parser.js.map +1 -0
- package/dist/session-category.d.ts +19 -0
- package/dist/session-category.d.ts.map +1 -0
- package/dist/session-category.js +14 -0
- package/dist/session-category.js.map +1 -0
- package/dist/session-ceremony.d.ts +297 -0
- package/dist/session-ceremony.d.ts.map +1 -0
- package/dist/session-ceremony.js +964 -0
- package/dist/session-ceremony.js.map +1 -0
- package/dist/session-closed.d.ts +79 -0
- package/dist/session-closed.d.ts.map +1 -0
- package/dist/session-closed.js +189 -0
- package/dist/session-closed.js.map +1 -0
- package/dist/session-connection-gater.d.ts +148 -0
- package/dist/session-connection-gater.d.ts.map +1 -0
- package/dist/session-connection-gater.js +332 -0
- package/dist/session-connection-gater.js.map +1 -0
- package/dist/session-content-context.d.ts +162 -0
- package/dist/session-content-context.d.ts.map +1 -0
- package/dist/session-content-context.js +2 -0
- package/dist/session-content-context.js.map +1 -0
- package/dist/session-content-handlers.d.ts +82 -0
- package/dist/session-content-handlers.d.ts.map +1 -0
- package/dist/session-content-handlers.js +1382 -0
- package/dist/session-content-handlers.js.map +1 -0
- package/dist/session-content-ingest.d.ts +206 -0
- package/dist/session-content-ingest.d.ts.map +1 -0
- package/dist/session-content-ingest.js +2167 -0
- package/dist/session-content-ingest.js.map +1 -0
- package/dist/session-content-send.d.ts +191 -0
- package/dist/session-content-send.d.ts.map +1 -0
- package/dist/session-content-send.js +1360 -0
- package/dist/session-content-send.js.map +1 -0
- package/dist/session-delivery-acks.d.ts +169 -0
- package/dist/session-delivery-acks.d.ts.map +1 -0
- package/dist/session-delivery-acks.js +569 -0
- package/dist/session-delivery-acks.js.map +1 -0
- package/dist/session-ephemerals.d.ts +279 -0
- package/dist/session-ephemerals.d.ts.map +1 -0
- package/dist/session-ephemerals.js +591 -0
- package/dist/session-ephemerals.js.map +1 -0
- package/dist/session-leaf-records.d.ts +159 -0
- package/dist/session-leaf-records.d.ts.map +1 -0
- package/dist/session-leaf-records.js +408 -0
- package/dist/session-leaf-records.js.map +1 -0
- package/dist/session-lifecycle.d.ts +303 -0
- package/dist/session-lifecycle.d.ts.map +1 -0
- package/dist/session-lifecycle.js +1679 -0
- package/dist/session-lifecycle.js.map +1 -0
- package/dist/session-liveness.d.ts +135 -0
- package/dist/session-liveness.d.ts.map +1 -0
- package/dist/session-liveness.js +347 -0
- package/dist/session-liveness.js.map +1 -0
- package/dist/session-name.d.ts +35 -0
- package/dist/session-name.d.ts.map +1 -0
- package/dist/session-name.js +60 -0
- package/dist/session-name.js.map +1 -0
- package/dist/session-node-factory.d.ts +18 -0
- package/dist/session-node-factory.d.ts.map +1 -0
- package/dist/session-node-factory.js +182 -0
- package/dist/session-node-factory.js.map +1 -0
- package/dist/session-node-manager.d.ts +877 -0
- package/dist/session-node-manager.d.ts.map +1 -0
- package/dist/session-node-manager.js +2998 -0
- package/dist/session-node-manager.js.map +1 -0
- package/dist/session-node-types.d.ts +1057 -0
- package/dist/session-node-types.d.ts.map +1 -0
- package/dist/session-node-types.js +657 -0
- package/dist/session-node-types.js.map +1 -0
- package/dist/session-notify.d.ts +46 -0
- package/dist/session-notify.d.ts.map +1 -0
- package/dist/session-notify.js +116 -0
- package/dist/session-notify.js.map +1 -0
- package/dist/session-own-chain-store.d.ts +65 -0
- package/dist/session-own-chain-store.d.ts.map +1 -0
- package/dist/session-own-chain-store.js +75 -0
- package/dist/session-own-chain-store.js.map +1 -0
- package/dist/session-queries.d.ts +476 -0
- package/dist/session-queries.d.ts.map +1 -0
- package/dist/session-queries.js +1007 -0
- package/dist/session-queries.js.map +1 -0
- package/dist/session-read-handlers.d.ts +87 -0
- package/dist/session-read-handlers.d.ts.map +1 -0
- package/dist/session-read-handlers.js +689 -0
- package/dist/session-read-handlers.js.map +1 -0
- package/dist/session-records.d.ts +341 -0
- package/dist/session-records.d.ts.map +1 -0
- package/dist/session-records.js +858 -0
- package/dist/session-records.js.map +1 -0
- package/dist/session-relay-client.d.ts +659 -0
- package/dist/session-relay-client.d.ts.map +1 -0
- package/dist/session-relay-client.js +2876 -0
- package/dist/session-relay-client.js.map +1 -0
- package/dist/session-relay.d.ts +397 -0
- package/dist/session-relay.d.ts.map +1 -0
- package/dist/session-relay.js +1636 -0
- package/dist/session-relay.js.map +1 -0
- package/dist/session-salt-agreement.d.ts +331 -0
- package/dist/session-salt-agreement.d.ts.map +1 -0
- package/dist/session-salt-agreement.js +472 -0
- package/dist/session-salt-agreement.js.map +1 -0
- package/dist/session-salts.d.ts +432 -0
- package/dist/session-salts.d.ts.map +1 -0
- package/dist/session-salts.js +1540 -0
- package/dist/session-salts.js.map +1 -0
- package/dist/session-schema.d.ts +30 -0
- package/dist/session-schema.d.ts.map +1 -0
- package/dist/session-schema.js +877 -0
- package/dist/session-schema.js.map +1 -0
- package/dist/session-seal-leaf-store.d.ts +70 -0
- package/dist/session-seal-leaf-store.d.ts.map +1 -0
- package/dist/session-seal-leaf-store.js +105 -0
- package/dist/session-seal-leaf-store.js.map +1 -0
- package/dist/session-seal.d.ts +334 -0
- package/dist/session-seal.d.ts.map +1 -0
- package/dist/session-seal.js +1017 -0
- package/dist/session-seal.js.map +1 -0
- package/dist/session-terminal-refusal.d.ts +65 -0
- package/dist/session-terminal-refusal.d.ts.map +1 -0
- package/dist/session-terminal-refusal.js +87 -0
- package/dist/session-terminal-refusal.js.map +1 -0
- package/dist/session-tree.d.ts +110 -0
- package/dist/session-tree.d.ts.map +1 -0
- package/dist/session-tree.js +144 -0
- package/dist/session-tree.js.map +1 -0
- package/dist/session-views.d.ts +47 -0
- package/dist/session-views.d.ts.map +1 -0
- package/dist/session-views.js +278 -0
- package/dist/session-views.js.map +1 -0
- package/dist/signal-handlers.d.ts +63 -0
- package/dist/signal-handlers.d.ts.map +1 -0
- package/dist/signal-handlers.js +980 -0
- package/dist/signal-handlers.js.map +1 -0
- package/dist/signal-requirement-policy.d.ts +51 -0
- package/dist/signal-requirement-policy.d.ts.map +1 -0
- package/dist/signal-requirement-policy.js +89 -0
- package/dist/signal-requirement-policy.js.map +1 -0
- package/dist/signal-revocability.d.ts +49 -0
- package/dist/signal-revocability.d.ts.map +1 -0
- package/dist/signal-revocability.js +93 -0
- package/dist/signal-revocability.js.map +1 -0
- package/dist/signal-submission.d.ts +181 -0
- package/dist/signal-submission.d.ts.map +1 -0
- package/dist/signal-submission.js +368 -0
- package/dist/signal-submission.js.map +1 -0
- package/dist/signaling-connect.d.ts +118 -0
- package/dist/signaling-connect.d.ts.map +1 -0
- package/dist/signaling-connect.js +538 -0
- package/dist/signaling-connect.js.map +1 -0
- package/dist/signaling-wiring.d.ts +105 -0
- package/dist/signaling-wiring.d.ts.map +1 -0
- package/dist/signaling-wiring.js +393 -0
- package/dist/signaling-wiring.js.map +1 -0
- package/dist/singleton-lock.d.ts +85 -0
- package/dist/singleton-lock.d.ts.map +1 -0
- package/dist/singleton-lock.js +219 -0
- package/dist/singleton-lock.js.map +1 -0
- package/dist/sqlcipher-db.d.ts +139 -0
- package/dist/sqlcipher-db.d.ts.map +1 -0
- package/dist/sqlcipher-db.js +357 -0
- package/dist/sqlcipher-db.js.map +1 -0
- package/dist/standing-receivers.d.ts +319 -0
- package/dist/standing-receivers.d.ts.map +1 -0
- package/dist/standing-receivers.js +1295 -0
- package/dist/standing-receivers.js.map +1 -0
- package/dist/start-agent.d.ts +64 -0
- package/dist/start-agent.d.ts.map +1 -0
- package/dist/start-agent.js +136 -0
- package/dist/start-agent.js.map +1 -0
- package/dist/status-handler.d.ts +54 -0
- package/dist/status-handler.d.ts.map +1 -0
- package/dist/status-handler.js +61 -0
- package/dist/status-handler.js.map +1 -0
- package/dist/submission-retry.d.ts +208 -0
- package/dist/submission-retry.d.ts.map +1 -0
- package/dist/submission-retry.js +506 -0
- package/dist/submission-retry.js.map +1 -0
- package/dist/telegram-bot-client.d.ts +34 -0
- package/dist/telegram-bot-client.d.ts.map +1 -0
- package/dist/telegram-bot-client.js +36 -0
- package/dist/telegram-bot-client.js.map +1 -0
- package/dist/telegram-doorbell.d.ts +38 -0
- package/dist/telegram-doorbell.d.ts.map +1 -0
- package/dist/telegram-doorbell.js +140 -0
- package/dist/telegram-doorbell.js.map +1 -0
- package/dist/test-handlers.d.ts +62 -0
- package/dist/test-handlers.d.ts.map +1 -0
- package/dist/test-handlers.js +240 -0
- package/dist/test-handlers.js.map +1 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +10 -0
- package/dist/testing.js.map +1 -0
- package/dist/transport-composition.d.ts +31 -0
- package/dist/transport-composition.d.ts.map +1 -0
- package/dist/transport-composition.js +55 -0
- package/dist/transport-composition.js.map +1 -0
- package/dist/transport-selector.d.ts +202 -0
- package/dist/transport-selector.d.ts.map +1 -0
- package/dist/transport-selector.js +196 -0
- package/dist/transport-selector.js.map +1 -0
- package/dist/trust-signal-pickup-listener.d.ts +43 -0
- package/dist/trust-signal-pickup-listener.d.ts.map +1 -0
- package/dist/trust-signal-pickup-listener.js +48 -0
- package/dist/trust-signal-pickup-listener.js.map +1 -0
- package/dist/trust-signal-store.d.ts +406 -0
- package/dist/trust-signal-store.d.ts.map +1 -0
- package/dist/trust-signal-store.js +939 -0
- package/dist/trust-signal-store.js.map +1 -0
- package/dist/trust-signal-sweep-tick.d.ts +60 -0
- package/dist/trust-signal-sweep-tick.d.ts.map +1 -0
- package/dist/trust-signal-sweep-tick.js +101 -0
- package/dist/trust-signal-sweep-tick.js.map +1 -0
- package/dist/trust-signal-sweep.d.ts +94 -0
- package/dist/trust-signal-sweep.d.ts.map +1 -0
- package/dist/trust-signal-sweep.js +147 -0
- package/dist/trust-signal-sweep.js.map +1 -0
- package/dist/type-registry.d.ts +42 -0
- package/dist/type-registry.d.ts.map +1 -0
- package/dist/type-registry.js +37 -0
- package/dist/type-registry.js.map +1 -0
- package/dist/types.d.ts +746 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/dist/unresolved-nodes-report.d.ts +14 -0
- package/dist/unresolved-nodes-report.d.ts.map +1 -0
- package/dist/unresolved-nodes-report.js +96 -0
- package/dist/unresolved-nodes-report.js.map +1 -0
- package/dist/vocabulary.d.ts +150 -0
- package/dist/vocabulary.d.ts.map +1 -0
- package/dist/vocabulary.js +386 -0
- package/dist/vocabulary.js.map +1 -0
- package/dist/who-label.d.ts +28 -0
- package/dist/who-label.d.ts.map +1 -0
- package/dist/who-label.js +31 -0
- package/dist/who-label.js.map +1 -0
- package/dist/who-resolver.d.ts +15 -0
- package/dist/who-resolver.d.ts.map +1 -0
- package/dist/who-resolver.js +47 -0
- package/dist/who-resolver.js.map +1 -0
- package/dist/wire-content-hash.d.ts +93 -0
- package/dist/wire-content-hash.d.ts.map +1 -0
- package/dist/wire-content-hash.js +116 -0
- package/dist/wire-content-hash.js.map +1 -0
- package/dist/withheld-content.d.ts +13 -0
- package/dist/withheld-content.d.ts.map +1 -0
- package/dist/withheld-content.js +46 -0
- package/dist/withheld-content.js.map +1 -0
- package/dist/witness-alerts.d.ts +40 -0
- package/dist/witness-alerts.d.ts.map +1 -0
- package/dist/witness-alerts.js +102 -0
- package/dist/witness-alerts.js.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,1017 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CELLO Daemon — CLOSING A CONVERSATION, AND PROVING IT CLOSED
|
|
3
|
+
*
|
|
4
|
+
* Split out of `session-node-manager.ts`. The seal is the artefact the whole product exists to
|
|
5
|
+
* produce: when both parties close, each holds a notarized root over the same transcript, and
|
|
6
|
+
* either can later show a third party that the conversation happened and was not altered.
|
|
7
|
+
*
|
|
8
|
+
* What is here: deciding whether a session is ready to seal and telling the operator when it is
|
|
9
|
+
* not, submitting our own SEAL leaf, carrying the counterparty's, persisting the commitment when a
|
|
10
|
+
* close is interrupted, recording the certificate, verifying a certified root against our own tree,
|
|
11
|
+
* and the auto-acknowledgement gate that lets a seal complete without a human on both ends.
|
|
12
|
+
*
|
|
13
|
+
* **Moved verbatim, comments included.**
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ **THE TWO STORES BELOW ARE OPENED LAZILY, and that is why they are read-write on the context
|
|
16
|
+
* rather than passed in.** Both are created on first use, because they need the database and the
|
|
17
|
+
* database is opened long after the manager is constructed. The manager and this file must see the
|
|
18
|
+
* SAME instance — a second `SessionSealLeafStore` over the same rows is two writers that agree only
|
|
19
|
+
* by luck.
|
|
20
|
+
*/
|
|
21
|
+
import { createHash } from "node:crypto";
|
|
22
|
+
import { closeOverCarriedEvidence } from "./seal-carried-close.js";
|
|
23
|
+
import { verifyCertifiedRoot as judgeCertifiedRoot } from "./seal-certified-root-check.js";
|
|
24
|
+
import { judgeFromEvidence } from "./seal-evidence-root-check.js";
|
|
25
|
+
import { encodeSealPayload, decodeStructure1 } from "@cello-protocol/protocol-types";
|
|
26
|
+
import { AUTOACK_BROKER_GRACE_MS } from "./session-node-types.js";
|
|
27
|
+
import { LEAF_KIND_CTRL } from "./session-relay-client.js";
|
|
28
|
+
import { RelayReceiptStore } from "./relay-receipt-store.js";
|
|
29
|
+
import { SessionSealLeafStore } from "./session-seal-leaf-store.js";
|
|
30
|
+
import { withheldPositionsOrNone } from "./withheld-content.js";
|
|
31
|
+
import { extractErrorMessage } from "./error-message.js";
|
|
32
|
+
import { awaitOwnRecordSettled, SEAL_SETTLE_DEADLINE_MS as SEAL_STALE_WAIT_MS } from "./seal-settle.js";
|
|
33
|
+
export class SessionSeal {
|
|
34
|
+
#ctx;
|
|
35
|
+
/**
|
|
36
|
+
* Sessions whose closing leaf THIS PROCESS signed locally, because no relay answered.
|
|
37
|
+
*
|
|
38
|
+
* Kept beside the idempotency mark rather than inside it: a retried close reads the mark and gets
|
|
39
|
+
* `responder_seal_already_submitted`, and without this it would lose the one fact that makes the
|
|
40
|
+
* eleven-minute bilateral wait pointless — so the retry would sit out a window for a ceremony that
|
|
41
|
+
* still cannot begin. In memory only; a restart correctly re-derives it by trying the relay again.
|
|
42
|
+
*/
|
|
43
|
+
#closedViaLocalTerminus = new Set();
|
|
44
|
+
constructor(ctx) {
|
|
45
|
+
this.#ctx = ctx;
|
|
46
|
+
}
|
|
47
|
+
/** A getter so the moved queries still read `this.#db` and narrow exactly as they did. */
|
|
48
|
+
get #db() {
|
|
49
|
+
return this.#ctx.db();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* M12-P15: what a seal leaf actually needs, resolved from a LIVE node when there is one and from
|
|
53
|
+
* durable state when there is not.
|
|
54
|
+
*
|
|
55
|
+
* `submitSealLeaf` used to hard-require an `#activeNodes` entry. But it is reachable — by design —
|
|
56
|
+
* for an `interrupted` session, and EVERY producer of that status deletes the entry. So the guard
|
|
57
|
+
* refused 100% of the calls the seal-interrupted path could ever make, which is what made M12-P15's
|
|
58
|
+
* first fix inert. `submitLeaf(node, sessionId, contentHash, leafKind)` takes everything
|
|
59
|
+
* explicitly; nothing about it needs a per-session node.
|
|
60
|
+
*
|
|
61
|
+
* The fallback is the same shape `startupParkFn` already uses for content: the persisted relay
|
|
62
|
+
* endpoint (`relay_peer_id`/`relay_addrs`, columns that exist for exactly this reason) plus the
|
|
63
|
+
* owning agent's standing receiver. Every failure is named for its own cause rather than collapsed
|
|
64
|
+
* into "no node", because that collapse is what sent this investigation at the session lifecycle
|
|
65
|
+
* instead of at the endpoint.
|
|
66
|
+
*/
|
|
67
|
+
#resolveSealTransport(agentName, sessionId) {
|
|
68
|
+
const entry = this.#ctx.activeNodes.get(this.#ctx.sessionKey(agentName, sessionId));
|
|
69
|
+
if (entry) {
|
|
70
|
+
// The live path is unchanged and takes precedence — a session with its own registered client
|
|
71
|
+
// must never seal through a rebuilt one.
|
|
72
|
+
if (!entry.relayClient || !entry.relaySessionIdBytes)
|
|
73
|
+
return { error: "relay_unavailable" };
|
|
74
|
+
return { node: entry.node, relayClient: entry.relayClient, relaySessionIdBytes: entry.relaySessionIdBytes };
|
|
75
|
+
}
|
|
76
|
+
const ep = this.#ctx.queries.getPersistedRelayEndpoint(agentName, sessionId);
|
|
77
|
+
if (!ep)
|
|
78
|
+
return { error: "no_persisted_relay_endpoint" };
|
|
79
|
+
const node = this.#ctx.receivers.getStandingReceiverNode(agentName);
|
|
80
|
+
if (!node)
|
|
81
|
+
return { error: "standing_receiver_unavailable" };
|
|
82
|
+
// Reuse the agent's existing client for this relay when the process still has one; otherwise ask
|
|
83
|
+
// the composition root to build one. Without the builder this path would work only within the
|
|
84
|
+
// lifetime that created the session — and the case that matters most is precisely a daemon that
|
|
85
|
+
// RESTARTED, which is what marked the session interrupted in the first place.
|
|
86
|
+
const clientKey = `${agentName}::${ep.relayPeerId}`;
|
|
87
|
+
let client = this.#ctx.relayClients.get(clientKey);
|
|
88
|
+
if (!client) {
|
|
89
|
+
// Review HIGH-1: the stores are NOT optional here. Without them `#captureReceipt` silently
|
|
90
|
+
// `return false`s — the submit still reports ok while the relay's signed receipt and our OWN
|
|
91
|
+
// 0x02 ctrl leaf are never persisted. That drops the unilateral-escalation carry chain AND
|
|
92
|
+
// defeats this very unit's ceremony discriminator, which reads `session_seal_leaves`: a seal
|
|
93
|
+
// sent through here would later read as "ceremony unknown" and the peer would decline to
|
|
94
|
+
// sign. The fix would have broken the fix.
|
|
95
|
+
if (!this.#ctx.relayReceiptStore && this.#db)
|
|
96
|
+
this.#ctx.relayReceiptStore = new RelayReceiptStore(this.#db, this.#ctx.logger);
|
|
97
|
+
if (!this.#ctx.sealLeafStore && this.#db)
|
|
98
|
+
this.#ctx.sealLeafStore = new SessionSealLeafStore(this.#db, this.#ctx.logger);
|
|
99
|
+
client = this.#ctx.detachedRelayClientBuilder?.(agentName, ep.relayPeerId, [...ep.relayAddrs], {
|
|
100
|
+
receiptStore: this.#ctx.relayReceiptStore ?? undefined,
|
|
101
|
+
sealLeafStore: this.#ctx.sealLeafStore ?? undefined,
|
|
102
|
+
ownChainStore: this.#ctx.ownChainStore ?? undefined,
|
|
103
|
+
// DOD-M15-RELAYSLOTS-1: read at each auth, never snapshotted — the token expires hourly.
|
|
104
|
+
onlineToken: () => this.#ctx.getDirectoryOnlineToken(agentName),
|
|
105
|
+
});
|
|
106
|
+
if (!client)
|
|
107
|
+
return { error: "relay_client_unavailable" };
|
|
108
|
+
// Review MEDIUM-4: cache it, so a retry loop does not leak one authenticated relay stream per
|
|
109
|
+
// attempt. Safe ONLY because the client above now carries the stores — a store-less client
|
|
110
|
+
// cached under this key would be picked up by the live `#connectSessionRelay` path and poison
|
|
111
|
+
// it for the rest of the process.
|
|
112
|
+
this.#ctx.relayClients.set(clientKey, client);
|
|
113
|
+
}
|
|
114
|
+
// Review HIGH-2: register the session (no assignment — there is nothing to re-present) so the
|
|
115
|
+
// relay's `session_not_found` is interpreted honestly. Unregistered, `recordedBefore` is false,
|
|
116
|
+
// the retry loop runs pointlessly, and the `recordedBefore && session_not_found ->
|
|
117
|
+
// relay_session_gone` branch — which exists to tell "the relay never had it" apart from "the
|
|
118
|
+
// relay swept or sealed it" — can never fire, so the operator is handed a first-message-race
|
|
119
|
+
// label for a swept session.
|
|
120
|
+
/**
|
|
121
|
+
* DOD-M15-RELAYLEAK-1 — **RE-REGISTERING A SESSION THAT IS ALREADY REGISTERED BLINDS IT.**
|
|
122
|
+
*
|
|
123
|
+
* `registerSession` REPLACES the entry's `onLeafDeliver` with `onLeafDeliver ?? (() => {})`, and
|
|
124
|
+
* unlike `assignment` / `recorded` it does NOT carry the existing handler forward. **This path
|
|
125
|
+
* passes no handler.** So a detached seal on a session that still holds a live registration
|
|
126
|
+
* would swap that session's inbound leaf delivery for a no-op: the counterparty's leaves keep
|
|
127
|
+
* arriving at the relay client and are dropped on the floor, while the operator sees a healthy
|
|
128
|
+
* session that has simply gone quiet.
|
|
129
|
+
*
|
|
130
|
+
* A call that finds the session already registered is therefore a PASSENGER: it uses the client
|
|
131
|
+
* and touches nothing. It also does not release — ownership is never inferred, only claimed.
|
|
132
|
+
*
|
|
133
|
+
* ⚠️ **This is NOT justified by a concurrency race, and an earlier version of this comment said
|
|
134
|
+
* it was.** Review checked: `#resolveSealTransport` and everything above the first `await` are
|
|
135
|
+
* synchronous, and a second caller plants/hits `#responderSealSubmitted` and returns
|
|
136
|
+
* `responder_seal_already_submitted` before ever reaching `submitLeaf`. Two callers cannot be in
|
|
137
|
+
* the client at once through the only caller, so "the second one closes the client the first is
|
|
138
|
+
* awaiting" **cannot happen**. The wrong reason mattered: it invites a future reader to delete
|
|
139
|
+
* this guard as defensive clutter once they notice the race is impossible — taking the
|
|
140
|
+
* handler-clobbering protection with it.
|
|
141
|
+
*/
|
|
142
|
+
const claimedRegistration = !client.hasSession(sessionId);
|
|
143
|
+
if (claimedRegistration) {
|
|
144
|
+
// 033-ACKEMIT: the seal transport submits a ctrl leaf like any other, so it needs the same
|
|
145
|
+
// acknowledgement seed. It carries no assignment of its own, so the genesis is supplied here
|
|
146
|
+
// from the session's own active entry rather than derived inside the client.
|
|
147
|
+
// 069-ORDERPROOF: the seal's ctrl leaf is submitted like any other and needs the same anchor.
|
|
148
|
+
// It carries no assignment, so this comes from the session's durable record — without it the
|
|
149
|
+
// relay's attestation for the SEAL leaf is refused and the close cannot settle.
|
|
150
|
+
client.registerSession(sessionId, node, undefined, undefined, this.#ctx.leafRecords.sessionGenesisPrevRoot(agentName, sessionId), this.#ctx.leafRecords.sessionRelayAnchor(agentName, sessionId));
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
/**
|
|
154
|
+
* Review MEDIUM-1 — **A PATH THAT DECLINES TO FIX A LEAK MUST SAY SO.**
|
|
155
|
+
*
|
|
156
|
+
* Reaching here means the session is registered on this client while `#activeNodes` holds no
|
|
157
|
+
* entry for it — and the ways that happens are all orphans: a previous `releaseDetached()`
|
|
158
|
+
* that threw (loud once, then silent forever after), or a revival that registered and then
|
|
159
|
+
* failed to hang the client on an entry. Declining to unregister is right — we cannot prove
|
|
160
|
+
* no live session owns it — but without this line the orphan is invisible, which is the exact
|
|
161
|
+
* shape this whole line exists to remove.
|
|
162
|
+
*/
|
|
163
|
+
this.#ctx.logger.info("session.seal.transport.registration_shared", {
|
|
164
|
+
agentName,
|
|
165
|
+
sessionId,
|
|
166
|
+
impact: "this seal is using a relay registration it did not create, so it will not release it. If " +
|
|
167
|
+
"no live session owns that registration the client is held until process exit.",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* DOD-M15-RELAYLEAK-1 — **`releaseOnDone` IS THE RELEASE SIGNAL, and its absence was the leak.**
|
|
172
|
+
*
|
|
173
|
+
* This branch (no `#activeNodes` entry) CACHES a relay client and registers a session on it, and
|
|
174
|
+
* nothing ever unregistered. `#detachSessionRelay` closes a client only when
|
|
175
|
+
* `!client.hasSessions()`, so a registration that is never removed keeps that predicate false
|
|
176
|
+
* **forever** — the client, its authenticated stream and its reader survive for the process
|
|
177
|
+
* lifetime. The LIVE branch above registers nothing here, so only this one needs releasing, and
|
|
178
|
+
* marking it is what lets the caller tell them apart without guessing.
|
|
179
|
+
*/
|
|
180
|
+
return {
|
|
181
|
+
node,
|
|
182
|
+
relayClient: client,
|
|
183
|
+
relaySessionIdBytes: new Uint8Array(Buffer.from(sessionId, "hex")),
|
|
184
|
+
// Not `true` unconditionally: a passenger call must not release a registration it did not
|
|
185
|
+
// claim — see the note above `claimedRegistration`.
|
|
186
|
+
...(claimedRegistration ? { releaseOnDone: true } : {}),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Does a certificate describe the leaf set this daemon holds? The judgement lives in
|
|
191
|
+
* `seal-certified-root-check.ts`; this binds it to this instance's carry.
|
|
192
|
+
*/
|
|
193
|
+
verifyCertifiedRoot(agentPubkeyHex, sessionIdHex, certifiedRoot, certifiedLeafCount, evidence) {
|
|
194
|
+
const own = judgeCertifiedRoot((pk, sid) => this.getSealCarry(pk, sid), agentPubkeyHex, sessionIdHex, certifiedRoot, certifiedLeafCount);
|
|
195
|
+
if (own.verdict !== "cannot_judge" || !evidence || evidence.length === 0)
|
|
196
|
+
return own;
|
|
197
|
+
return judgeFromEvidence({ ownCarry: this.getSealCarry(agentPubkeyHex, sessionIdHex), db: this.#ctx.db(), logger: this.#ctx.logger }, { ownReason: own.reason, agentPubkeyHex, sessionIdHex, certifiedRoot, certifiedLeafCount, evidence });
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* FED-OPTIONB-SEAL-001: the complete ordered leaf chain (both parties) a UNILATERAL seal carries to the
|
|
201
|
+
* directory for the OFFLINE tree rebuild. Empty when no leaves were logged (e.g. a direct-only session
|
|
202
|
+
* with no relay witness) — the caller then has nothing to carry and the seal stays bilateral/pending.
|
|
203
|
+
*
|
|
204
|
+
* ⚠️ Stranded on `verifyCertifiedRoot` before this split — the third block found doing that, and the
|
|
205
|
+
* reason the rule is now written down: a method reduced to a delegator leaves its documentation
|
|
206
|
+
* behind, and the block below it ends up carrying two descriptions of which the first is a stranger.
|
|
207
|
+
*/
|
|
208
|
+
getSealCarry(agentPubkeyHex, sessionIdHex) {
|
|
209
|
+
if (!this.#ctx.sealLeafStore && this.#db) {
|
|
210
|
+
this.#ctx.sealLeafStore = new SessionSealLeafStore(this.#db, this.#ctx.logger);
|
|
211
|
+
}
|
|
212
|
+
return this.#ctx.sealLeafStore?.getCarry(agentPubkeyHex, sessionIdHex) ?? [];
|
|
213
|
+
}
|
|
214
|
+
/** Fix #1 EXTENSION: inject the broker-connection opener. Setter injection, same construction-order reason. */
|
|
215
|
+
setEnsureSealBroker(cb) {
|
|
216
|
+
this.#ctx.ensureSealBroker = cb;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* DOD-M12B-INTERRUPTED-ESCALATE-1 — flip a session to `sealed`, synchronously, without needing a
|
|
220
|
+
* live node.
|
|
221
|
+
*
|
|
222
|
+
* **`destroySessionNode(…, "sealed")` cannot be relied on to do this.** It returns early at
|
|
223
|
+
* `if (!entry) return`, and the status write lives 26 lines BELOW that guard — so it flips the
|
|
224
|
+
* status only for a session that still has an `#activeNodes` entry. An interrupted session has
|
|
225
|
+
* none by construction: every producer of that status deletes the entry. Before this method, a
|
|
226
|
+
* unilateral seal on an interrupted session stored the notarized root and the certificate and
|
|
227
|
+
* left the row saying `interrupted` — the receipt landed and nothing that represents it moved.
|
|
228
|
+
* `cello_sessions` still showed it stuck, `cello_close_session` still refused it by name, and the
|
|
229
|
+
* restart-seal resolver re-selected it on the next boot to run the whole ceremony again against a
|
|
230
|
+
* session that already held a receipt.
|
|
231
|
+
*
|
|
232
|
+
* STATUS FIRST AND SYNCHRONOUS, teardown second — the order `abandonSession` uses and the one
|
|
233
|
+
* `retireSession` documents. The flip is the load-bearing half; the teardown makes memory agree
|
|
234
|
+
* with it. `#updateSessionStatus` also runs the terminal disposition hooks (held content is
|
|
235
|
+
* annexed, not stranded), which the early return skipped entirely.
|
|
236
|
+
*/
|
|
237
|
+
markSealed(agentName, sessionId) {
|
|
238
|
+
// The terminal guard (abandoned/sealed must not be overwritten) lives in #updateSessionStatus,
|
|
239
|
+
// so it holds for destroySessionNode and retireSession too — not only for callers of this
|
|
240
|
+
// wrapper.
|
|
241
|
+
return this.#ctx.updateSessionStatus(agentName, sessionId, "sealed");
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* M8B FINDING-6 (cascade-2): persist a seal certificate for a session that may have NO local
|
|
245
|
+
* `sessions` row. recordSealCertificate (a manager delegator onto `session-queries.ts`) is an `UPDATE ... WHERE` — a SILENT no-op when the
|
|
246
|
+
* row is absent (the exact trap the cascade-2 reviewer flagged). The ABSENT party (B), learning of
|
|
247
|
+
* a seal on reconnect via seal_unilateral_notification, may never have persisted a row for this
|
|
248
|
+
* session. This ensures a minimal stub row first (INSERT OR IGNORE — a no-op if a row already
|
|
249
|
+
* exists, e.g. an 'interrupted' row after a restart) so B's receipt is actually durable + retrievable
|
|
250
|
+
* via cello_get_sealed_receipt. The counterparty pubkey is required by the schema (NOT NULL); B
|
|
251
|
+
* derives it from the notification's present_pubkey.
|
|
252
|
+
*/
|
|
253
|
+
recordSealCertificateEnsuringRow(agentName, sessionId, counterpartyPubkeyHex, sealedRootHex, legibilityJson) {
|
|
254
|
+
if (!this.#db)
|
|
255
|
+
return;
|
|
256
|
+
const now = Date.now();
|
|
257
|
+
this.#db
|
|
258
|
+
.prepare(`INSERT OR IGNORE INTO sessions
|
|
259
|
+
(session_id, agent_id, counterparty_pubkey, status, created_at, updated_at)
|
|
260
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
261
|
+
.run(sessionId, this.#ctx.requireAgentId(agentName), counterpartyPubkeyHex, "sealed", now, now);
|
|
262
|
+
this.#ctx.queries.recordSealCertificate(agentName, sessionId, sealedRootHex, legibilityJson);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* M7-SESSION-001 (H-1): persist a verified bilateral SEAL-INTERRUPTED
|
|
266
|
+
* commitment and transition the session to 'seal_interrupted_pending'.
|
|
267
|
+
*
|
|
268
|
+
* This is NOT a seal. It records that both parties produced and exchanged
|
|
269
|
+
* K_local-signed SEAL-INTERRUPTED leaves over the same {leafCount, merkleRoot}.
|
|
270
|
+
* The FROST threshold notarization is a separate, currently-unwired step (see
|
|
271
|
+
* daemon.ts handleSealInterruptedFlow H-1 note), which is precisely why the
|
|
272
|
+
* status is 'seal_interrupted_pending' and never 'sealed'.
|
|
273
|
+
*
|
|
274
|
+
* The status update is guarded so it only advances a session out of the
|
|
275
|
+
* 'interrupted' state — it will not overwrite a 'sealed' row.
|
|
276
|
+
*
|
|
277
|
+
* @returns true if the session row was advanced to seal_interrupted_pending.
|
|
278
|
+
*/
|
|
279
|
+
persistSealInterruptedCommitment(opts) {
|
|
280
|
+
if (!this.#db)
|
|
281
|
+
return false;
|
|
282
|
+
const now = Date.now();
|
|
283
|
+
try {
|
|
284
|
+
this.#db
|
|
285
|
+
.prepare(`INSERT OR REPLACE INTO seal_interrupted_artifacts
|
|
286
|
+
(agent_id, session_id, role, own_leaf, counterparty_leaf, merkle_root, nonce, created_at)
|
|
287
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
288
|
+
.run(this.#ctx.requireAgentId(opts.agentName), opts.sessionId, opts.role, JSON.stringify(opts.ownLeaf), JSON.stringify(opts.counterpartyLeaf), opts.merkleRoot, opts.nonce, now);
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
this.#ctx.logger.error("session.interrupted.db.write.failed", {
|
|
292
|
+
sessionId: opts.sessionId,
|
|
293
|
+
error: extractErrorMessage(err),
|
|
294
|
+
});
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
// DAEMON-004: the bilateral commitment advances a session out of either
|
|
298
|
+
// 'interrupted' (SESSION-001 interrupted-seal flow) OR 'active' (DAEMON-004
|
|
299
|
+
// active-session seal). The guard still refuses to overwrite a terminal
|
|
300
|
+
// 'sealed' row or an already-pending one.
|
|
301
|
+
const result = this.#db
|
|
302
|
+
.prepare("UPDATE sessions SET status = 'seal_interrupted_pending', updated_at = ? WHERE agent_id = ? AND session_id = ? AND status IN ('active', 'interrupted')")
|
|
303
|
+
.run(now, this.#ctx.requireAgentId(opts.agentName), opts.sessionId);
|
|
304
|
+
const landed = Number(result.changes) > 0;
|
|
305
|
+
if (landed) {
|
|
306
|
+
// DOD-M12B-SESSION-SEED-1 (review F3): `seal_interrupted_pending` is NOT a state revival
|
|
307
|
+
// exists for, and the first build's comment wrongly grouped it with `interrupted`.
|
|
308
|
+
// `ingestReceivedContent` (in `session-content-ingest.ts`) refuses it outright, and BOTH
|
|
309
|
+
// sweeps that could otherwise close a
|
|
310
|
+
// session — `listRestartOrphanedSessions` and `listExpiredUnrevivableSessions` — filter
|
|
311
|
+
// `status = 'interrupted'`, so a pending-seal session is unrevivable AND unswept. Keeping its
|
|
312
|
+
// identity meant holding it until the process exited. Entry 42's own measurement is that 59%
|
|
313
|
+
// of seals that start never finish, so that is the common path, not a corner.
|
|
314
|
+
this.#ctx.destroySessionSeed(opts.agentName, opts.sessionId);
|
|
315
|
+
}
|
|
316
|
+
return landed;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* M7 DOD-SPINE-7: submit THIS party's SEAL ctrl leaf (0x02) to the relay witness.
|
|
320
|
+
* Structure: content_hash = SHA-256(0x02 || encodeSealPayload({session_id, final_root,
|
|
321
|
+
* close_timestamp, "PENDING"})), where final_root is the daemon's OWN tree root. Two
|
|
322
|
+
* distinct-sender SEAL leaves in the relay's log trigger the relay's #maybeProcessSeal
|
|
323
|
+
* → directory processSeal (rebuild + verify the signed chain) → FROST notarization →
|
|
324
|
+
* session_sealed. Requires an active relay client; the caller falls back to the
|
|
325
|
+
* directory-mediated path when this returns relay_unavailable.
|
|
326
|
+
*/
|
|
327
|
+
/**
|
|
328
|
+
* 070-CARRIEDSEAL — close over evidence this side already holds, when the relay never answered.
|
|
329
|
+
* The reasoning, the gates and the refusals live in `seal-carried-close.ts`; this binds it to
|
|
330
|
+
* this instance's context. `null` means "not that situation" and the caller's own refusal stands.
|
|
331
|
+
*/
|
|
332
|
+
#carriedClose(agentName, sessionId, cause, correlationId, standingRefusal) {
|
|
333
|
+
return closeOverCarriedEvidence({
|
|
334
|
+
ctx: this.#ctx,
|
|
335
|
+
db: this.#db,
|
|
336
|
+
getSealCarry: (pk, sid) => this.getSealCarry(pk, sid),
|
|
337
|
+
}, agentName, sessionId, cause, correlationId, standingRefusal);
|
|
338
|
+
}
|
|
339
|
+
async submitSealLeaf(agentName, sessionId, correlationId) {
|
|
340
|
+
const sealKey = this.#ctx.sessionKey(agentName, sessionId);
|
|
341
|
+
/**
|
|
342
|
+
* DOD-M15-SEALPRECOND-1 — THE PRECONDITION BY CONSTRUCTION, at the one point every seal leaf
|
|
343
|
+
* passes through. Review HIGH-3.
|
|
344
|
+
*
|
|
345
|
+
* The three callers wait for the record to settle and then submit, which leaves a check-then-act
|
|
346
|
+
* window: a `cello_send` can take its position after the caller read readiness and before the
|
|
347
|
+
* root is computed. The window is microseconds rather than the measured 352ms, and microseconds
|
|
348
|
+
* is exactly what this order says not to accept — a 14ms gap and a 14s gap fail identically.
|
|
349
|
+
*
|
|
350
|
+
* So the last word is here. Every present and future seal submission site is gated whether or
|
|
351
|
+
* not its author knew this rule existed, which is the property the enumeration in the order
|
|
352
|
+
* could only give for the sites that existed on the day it was written.
|
|
353
|
+
*
|
|
354
|
+
* Read AFTER nothing and BEFORE everything: no transport is resolved, no idempotency mark is
|
|
355
|
+
* taken, so a refusal here leaves the session exactly as it found it and the caller's retry is
|
|
356
|
+
* a genuine retry.
|
|
357
|
+
*/
|
|
358
|
+
const settling = this.sealReadiness(agentName, sessionId).ownLeavesOrdered;
|
|
359
|
+
if (settling > 0) {
|
|
360
|
+
this.#ctx.logger.warn("session.seal.leaf.refused_settling", {
|
|
361
|
+
agentName, sessionId, ownLeavesOrdered: settling, correlationId,
|
|
362
|
+
impact: "a message of ours has a place in the relay's ordering this record has not taken, so NO leaf was submitted and no root was signed — a root signed short of the relay's leaf set is refused by the directory and the receipt cannot be recovered",
|
|
363
|
+
});
|
|
364
|
+
return { ok: false, reason: "own_record_settling" };
|
|
365
|
+
}
|
|
366
|
+
// M12-P15: resolved, not required. See #resolveSealTransport — an interrupted session has no
|
|
367
|
+
// in-memory node BY CONSTRUCTION, and refusing here is what made the first fix inert.
|
|
368
|
+
const transport = this.#resolveSealTransport(agentName, sessionId);
|
|
369
|
+
if ("error" in transport) {
|
|
370
|
+
// 070-CARRIEDSEAL: there is no relay to hand this leaf to. If the reason is SILENCE rather
|
|
371
|
+
// than a ruling, close over what we already hold instead of losing the receipt.
|
|
372
|
+
const local = await this.#carriedClose(agentName, sessionId, transport.error, correlationId);
|
|
373
|
+
if (!local)
|
|
374
|
+
return { ok: false, reason: transport.error };
|
|
375
|
+
// ⚠️ THE MARK, ON THIS PATH TOO — review MEDIUM-3. The submit-failure branch below records it
|
|
376
|
+
// and this one did not, so a retried close re-entered the terminus builder, hit
|
|
377
|
+
// `seal_carry_own_ctrl_present`, and reported the RELAY as the fault for a session whose
|
|
378
|
+
// closing leaf was already on disk.
|
|
379
|
+
this.#ctx.responderSealSubmitted.set(sealKey, { reportedRootHex: local.reportedRootHex, sequenceNumber: local.sequenceNumber });
|
|
380
|
+
this.#closedViaLocalTerminus.add(sealKey);
|
|
381
|
+
return { ...local, viaLocalTerminus: true };
|
|
382
|
+
}
|
|
383
|
+
const entry = transport;
|
|
384
|
+
/**
|
|
385
|
+
* DOD-M15-RELAYLEAK-1 — release a DETACHED seal transport when this submission is done.
|
|
386
|
+
*
|
|
387
|
+
* Only the detached branch registers a session here, so this can never remove a live one. The
|
|
388
|
+
* client is closed only when it has no sessions left and the cache still holds THIS client —
|
|
389
|
+
* the same two guards `#detachSessionRelay` uses, and for the same reason: a racing teardown
|
|
390
|
+
* must not close a freshly-built replacement for the same key.
|
|
391
|
+
*/
|
|
392
|
+
const releaseDetached = () => {
|
|
393
|
+
if (transport.releaseOnDone !== true)
|
|
394
|
+
return;
|
|
395
|
+
try {
|
|
396
|
+
entry.relayClient.unregisterSession(sessionId);
|
|
397
|
+
if (!entry.relayClient.hasSessions()) {
|
|
398
|
+
for (const [key, cached] of this.#ctx.relayClients) {
|
|
399
|
+
if (cached === entry.relayClient) {
|
|
400
|
+
cached.close();
|
|
401
|
+
this.#ctx.relayClients.delete(key);
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
catch (err) {
|
|
408
|
+
this.#ctx.logger.warn("session.seal.transport.release_failed", {
|
|
409
|
+
agentName,
|
|
410
|
+
sessionId,
|
|
411
|
+
reason: extractErrorMessage(err),
|
|
412
|
+
impact: "a detached seal relay client could not be released; it is held until process exit",
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
/**
|
|
417
|
+
* ⚠️ try/finally, NOT a call at each return. There are three exits today and adding a release
|
|
418
|
+
* to each would be a hand-kept list — the shape this milestone has been bitten by repeatedly,
|
|
419
|
+
* where the FOURTH exit added later quietly leaks. Here the release cannot be bypassed by a new
|
|
420
|
+
* return, and it runs on the throw path too, which is where a leak matters most.
|
|
421
|
+
*/
|
|
422
|
+
try {
|
|
423
|
+
// M7-UPGRADE-002 idempotency: this party submits its responder SEAL leaf AT MOST ONCE per
|
|
424
|
+
// session. BOTH cello_close_session and the auto-acknowledge path call here; the first to reach
|
|
425
|
+
// this point wins, the second short-circuits. The check+set is SYNCHRONOUS (before any await) so
|
|
426
|
+
// two near-simultaneous triggers (e.g. B's own close racing A's delivered SEAL ctrl leaf) cannot
|
|
427
|
+
// both submit. Cleared below on a relay submit failure so a genuine retry can proceed.
|
|
428
|
+
// DOD-M12B-INTERRUPTED-ESCALATE-1 — THE MARK MUST SURVIVE A RESTART, or one automatic retry
|
|
429
|
+
// permanently forfeits the receipt.
|
|
430
|
+
//
|
|
431
|
+
// `#responderSealSubmitted` is in memory. A session whose close was in flight when the daemon
|
|
432
|
+
// stopped already has our SEAL ctrl leaf in the relay log — and on the next boot the mark is
|
|
433
|
+
// empty, so the restart-seal resolver's automatic close would submit a SECOND one. The
|
|
434
|
+
// directory requires exactly one ctrl leaf (`ctrlLeaves.length !== 1 → unilateral_seal_leaf_invalid`)
|
|
435
|
+
// and the carry is durable, so every future attempt would carry both and be refused forever.
|
|
436
|
+
//
|
|
437
|
+
// The durable evidence already exists and was simply not consulted: our own ctrl leaf is in
|
|
438
|
+
// `session_seal_leaves`. Recover the escalation values from it instead of submitting again.
|
|
439
|
+
if (!this.#ctx.responderSealSubmitted.has(sealKey)) {
|
|
440
|
+
const durable = this.#ctx.park.recoverOwnSealCtrlLeaf(agentName, sessionId);
|
|
441
|
+
if (durable === "unknown") {
|
|
442
|
+
// REFUSE, do not submit. A second ctrl leaf makes the session unsealable forever, and the
|
|
443
|
+
// question "is one already there?" just failed to answer. Refusing costs this close; a
|
|
444
|
+
// second leaf costs the receipt permanently.
|
|
445
|
+
return { ok: false, reason: "seal_leaf_recovery_unavailable" };
|
|
446
|
+
}
|
|
447
|
+
if (durable !== "none") {
|
|
448
|
+
this.#ctx.logger.info("session.seal.leaf.already_submitted.recovered", {
|
|
449
|
+
sessionId, agentName, sequenceNumber: durable.sequenceNumber,
|
|
450
|
+
impact: "our SEAL ctrl leaf is already in the relay log from a previous run; submitting a second would make this session unsealable forever",
|
|
451
|
+
});
|
|
452
|
+
this.#ctx.responderSealSubmitted.set(sealKey, durable);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (this.#ctx.responderSealSubmitted.has(sealKey)) {
|
|
456
|
+
// M8B FINDING-1: carry the FIRST submit's reported root/sequence so a retry close can
|
|
457
|
+
// still escalate to a unilateral seal. A null value means that submit is still in
|
|
458
|
+
// flight — return the bare reason and let the caller fall back to the pending path.
|
|
459
|
+
const prior = this.#ctx.responderSealSubmitted.get(sealKey);
|
|
460
|
+
return prior
|
|
461
|
+
? {
|
|
462
|
+
ok: false,
|
|
463
|
+
reason: "responder_seal_already_submitted",
|
|
464
|
+
reportedRootHex: prior.reportedRootHex,
|
|
465
|
+
sequenceNumber: prior.sequenceNumber,
|
|
466
|
+
// Carried so a retry does not sit out a bilateral window that still cannot open.
|
|
467
|
+
...(this.#closedViaLocalTerminus.has(sealKey) ? { viaLocalTerminus: true } : {}),
|
|
468
|
+
}
|
|
469
|
+
: { ok: false, reason: "responder_seal_already_submitted" };
|
|
470
|
+
}
|
|
471
|
+
this.#ctx.responderSealSubmitted.set(sealKey, null);
|
|
472
|
+
// A throw anywhere before the mark is finalized would strand the null in-flight marker
|
|
473
|
+
// and lock every future close out of escalation (a FINDING-1-shaped deadlock via a
|
|
474
|
+
// different trigger) — clear the mark on any unexpected exception.
|
|
475
|
+
try {
|
|
476
|
+
const signClose = () => {
|
|
477
|
+
const finalRootHex = this.#ctx.getSessionTreeRootHex(agentName, sessionId);
|
|
478
|
+
const payload = encodeSealPayload({
|
|
479
|
+
session_id: entry.relaySessionIdBytes,
|
|
480
|
+
final_root: new Uint8Array(Buffer.from(finalRootHex, "hex")),
|
|
481
|
+
close_timestamp: Date.now(),
|
|
482
|
+
attestation: "PENDING",
|
|
483
|
+
});
|
|
484
|
+
// content_hash = SHA-256(0x02 || seal_payload) — the ctrl leaf kind byte is 0x02.
|
|
485
|
+
const hash = new Uint8Array(createHash("sha256").update(new Uint8Array([LEAF_KIND_CTRL])).update(payload).digest());
|
|
486
|
+
return { sealPayload: payload, contentHash: hash };
|
|
487
|
+
};
|
|
488
|
+
let { sealPayload, contentHash } = signClose();
|
|
489
|
+
/**
|
|
490
|
+
* ⚠️ `sealPayload` IS PASSED, AND ITS ABSENCE WAS THE WHOLE DEFECT — `DOD-M15-SEALWIRE-1`
|
|
491
|
+
* bullets 3+4, review pass 1, F1.
|
|
492
|
+
*
|
|
493
|
+
* These exact bytes were computed two lines above, hashed, and then dropped: `submitLeaf` had
|
|
494
|
+
* no parameter for them. So the directory received a SHA-256 pre-image nobody transmitted, and
|
|
495
|
+
* the client's SIGNED `final_root` — the one value in the seal the relay cannot produce — was
|
|
496
|
+
* unrecoverable. Four legs of this line shipped and were reviewed green while the head of the
|
|
497
|
+
* chain did not exist.
|
|
498
|
+
*
|
|
499
|
+
* The payload and the hash MUST come from the same derivation. If they ever diverge the
|
|
500
|
+
* directory reports `seal_payload_unbound`, whose guidance says *"someone between them and here
|
|
501
|
+
* altered or fabricated the payload — the relay is the only party on that path"* — a correct
|
|
502
|
+
* relay accused by name, in an error written to sound like an attack, for a mismatch made here.
|
|
503
|
+
*/
|
|
504
|
+
const relaySidHex = Buffer.from(entry.relaySessionIdBytes).toString("hex");
|
|
505
|
+
const seenBefore = entry.relayClient.lastSeenAck(relaySidHex)?.seq ?? 0;
|
|
506
|
+
// A message the other side filed but never delivered would be claimed by this close and missing from its root; refuse by name (withheld-content.ts).
|
|
507
|
+
const withheld = withheldPositionsOrNone(this.#db, this.#ctx.logger, () => ({ agentId: this.#ctx.requireAgentId(agentName), agentPubkeyHex: entry.relayClient.senderPubkeyHex, sessionId, relaySessionHex: relaySidHex, upToSeq: seenBefore }));
|
|
508
|
+
if (withheld.length > 0) {
|
|
509
|
+
this.#ctx.responderSealSubmitted.delete(sealKey);
|
|
510
|
+
this.#ctx.logger.warn("session.seal.counterparty_content_missing", { sessionId, agentName, positions: withheld, correlationId });
|
|
511
|
+
return { ok: false, reason: "counterparty_content_missing" };
|
|
512
|
+
}
|
|
513
|
+
let result = await entry.relayClient.submitLeaf(entry.node, entry.relaySessionIdBytes, contentHash, LEAF_KIND_CTRL, sealPayload);
|
|
514
|
+
/**
|
|
515
|
+
* `seal_stale`: the relay already filed a message from the other side that this close did not
|
|
516
|
+
* include — it reached the relay just before our close. Signing anyway would notarize a root
|
|
517
|
+
* missing it, and both seals would fail. Wait for that message to land in our record (the
|
|
518
|
+
* acknowledgement moves only when it is placed), then sign ONCE more. A condition on state,
|
|
519
|
+
* bounded so a message that never arrives cannot hold the close; past the bound this falls
|
|
520
|
+
* through to the ordinary failure handling below.
|
|
521
|
+
*/
|
|
522
|
+
if (!result.ok && result.reason === "seal_stale") {
|
|
523
|
+
const deadline = Date.now() + SEAL_STALE_WAIT_MS;
|
|
524
|
+
// Wait for the position the relay named; an older relay names none, so any advance will do.
|
|
525
|
+
const needed = ("awaited_seq" in result && result.awaited_seq !== undefined) ? result.awaited_seq : seenBefore + 1;
|
|
526
|
+
while ((entry.relayClient.lastSeenAck(relaySidHex)?.seq ?? 0) < needed && Date.now() < deadline) {
|
|
527
|
+
await new Promise((r) => { const t = setTimeout(r, 20); t.unref?.(); });
|
|
528
|
+
}
|
|
529
|
+
this.#ctx.logger.info("session.seal.leaf.stale_resign", {
|
|
530
|
+
sessionId, correlationId, advanced: (entry.relayClient.lastSeenAck(relaySidHex)?.seq ?? 0) > seenBefore,
|
|
531
|
+
});
|
|
532
|
+
({ sealPayload, contentHash } = signClose());
|
|
533
|
+
result = await entry.relayClient.submitLeaf(entry.node, entry.relaySessionIdBytes, contentHash, LEAF_KIND_CTRL, sealPayload);
|
|
534
|
+
}
|
|
535
|
+
if (!result.ok) {
|
|
536
|
+
// Clear the idempotency mark so a genuine retry (agent close / reconnect) can proceed (DB-001).
|
|
537
|
+
this.#ctx.responderSealSubmitted.delete(sealKey);
|
|
538
|
+
this.#ctx.logger.warn("session.seal.leaf.submit.failed", { sessionId, reason: result.reason, correlationId });
|
|
539
|
+
// 070-CARRIEDSEAL: the relay was asked and said nothing. Same answer as having no relay at
|
|
540
|
+
// all — write the closing leaf here rather than lose a receipt for a witnessed record.
|
|
541
|
+
// The relay client is in hand here, so its standing verdict can be asked for directly —
|
|
542
|
+
// the reason string above cannot carry it.
|
|
543
|
+
const local = await this.#carriedClose(agentName, sessionId, result.reason, correlationId, entry.relayClient.getLastAuthRefusal());
|
|
544
|
+
if (local) {
|
|
545
|
+
this.#ctx.responderSealSubmitted.set(sealKey, { reportedRootHex: local.reportedRootHex, sequenceNumber: local.sequenceNumber });
|
|
546
|
+
this.#closedViaLocalTerminus.add(sealKey);
|
|
547
|
+
return { ...local, viaLocalTerminus: true };
|
|
548
|
+
}
|
|
549
|
+
return { ok: false, reason: result.reason };
|
|
550
|
+
}
|
|
551
|
+
// SESSION-002: the reported_root for a unilateral seal is the content-hash root the
|
|
552
|
+
// local tree WOULD have with this SEAL ctrl leaf appended — the same root the directory
|
|
553
|
+
// rebuilds from the relay's content-hash chain (the relay records the identical
|
|
554
|
+
// content_hash for this ctrl leaf). Computed without mutating the durable tree /
|
|
555
|
+
// message_count, so the bilateral + interrupted seal paths are unaffected.
|
|
556
|
+
const contentHashHex = Buffer.from(contentHash).toString("hex");
|
|
557
|
+
const reportedRootHex = this.#ctx.getSessionTree(agentName, sessionId).rootWithAppendedHex(contentHashHex);
|
|
558
|
+
// M8B FINDING-1: durably associate the submit's escalation values with the idempotency
|
|
559
|
+
// mark, so any LATER close call can retrieve them via the already-submitted result.
|
|
560
|
+
this.#ctx.responderSealSubmitted.set(sealKey, { reportedRootHex, sequenceNumber: result.sequence_number });
|
|
561
|
+
this.#ctx.logger.info("session.seal.leaf.submitted", {
|
|
562
|
+
sessionId,
|
|
563
|
+
sequenceNumber: result.sequence_number,
|
|
564
|
+
correlationId,
|
|
565
|
+
});
|
|
566
|
+
// M7-UPGRADE-002: #responderSealSubmitted was set synchronously at the top of this method —
|
|
567
|
+
// the guard now blocks any second submit (auto-ack OR a redelivered counterparty SEAL ctrl leaf).
|
|
568
|
+
return { ok: true, sequenceNumber: result.sequence_number, reportedRootHex };
|
|
569
|
+
}
|
|
570
|
+
catch (err) {
|
|
571
|
+
this.#ctx.responderSealSubmitted.delete(sealKey);
|
|
572
|
+
throw err;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
finally {
|
|
576
|
+
releaseDetached();
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* CELLO-M7-UPGRADE-001 (DOD-UP-1): readiness of a session for B to RATIFY a unilateral seal
|
|
581
|
+
* (the returning absent party). This is the SAME verifiability bar as the UP-2 auto-ack gate:
|
|
582
|
+
*
|
|
583
|
+
* - `known`: the session exists locally with its content (B has a transcript to ratify). After a
|
|
584
|
+
* restart B reloads it from SQLite, and autoRecoverForAgent re-pulls any parked content first.
|
|
585
|
+
* - `tampered`: the content cross-check flagged a content_hash mismatch (#contentDesynced) — B
|
|
586
|
+
* must NEVER ratify content it could not integrity-verify (the KERNEL refusal, AC-003).
|
|
587
|
+
*
|
|
588
|
+
* The directory separately verifies B's ack signature is genuine; B separately verifies the
|
|
589
|
+
* unilateral cert signature (R1 is authentic). NOTE: a full "B's frontier covers R1's tail"
|
|
590
|
+
* completeness check (the `desynced` reason) requires the deferred MSG-001-3b canonical-sequence
|
|
591
|
+
* reconciliation — same documented limitation as the UP-2 gate above.
|
|
592
|
+
*/
|
|
593
|
+
getSealUpgradeReadiness(agentName, sessionId) {
|
|
594
|
+
const record = this.#ctx.queries.getSessionRecord(agentName, sessionId);
|
|
595
|
+
return {
|
|
596
|
+
known: !!record,
|
|
597
|
+
/**
|
|
598
|
+
* THE REASON TRAVELS WITH THE VERDICT — review F-A, correcting review F1's fix.
|
|
599
|
+
*
|
|
600
|
+
* F1 made the gate binary and moved the label into the log, and I did that in ONE consumer.
|
|
601
|
+
* This struct feeds a second one (`evaluateSealUpgrade`), which had only a boolean to read and
|
|
602
|
+
* therefore called every cause `content_tamper` — at ERROR, with no guidance. An honest peer on
|
|
603
|
+
* a newer build raised a security alarm on B's reconnect: exactly the harm the F1 fix was
|
|
604
|
+
* written to remove, reached through the consumer it did not check.
|
|
605
|
+
*
|
|
606
|
+
* Returning the LABEL rather than a boolean is what makes that impossible to reintroduce: a
|
|
607
|
+
* caller cannot flatten what it never receives flat.
|
|
608
|
+
*/
|
|
609
|
+
unverifiable: this.#ctx.contentDesynced.get(this.#ctx.sessionKey(agentName, sessionId)) ?? null,
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* M7-UPGRADE-002: auto-acknowledge close (POSTMORTEM Workstream E / C-5). When B's daemon
|
|
614
|
+
* ingests the COUNTERPARTY's SEAL control leaf and B has verified the content, B's OWN node
|
|
615
|
+
* auto-co-signs + submits its responder SEAL leaf WITHOUT waiting for B's agent to call
|
|
616
|
+
* cello_close_session — so a bilateral seal completes promptly instead of degrading to
|
|
617
|
+
* unilateral on a slow/busy/crashed agent.
|
|
618
|
+
*
|
|
619
|
+
* SI-001 (non-negotiable): B's signature is ALWAYS produced by B's own node — submitSealLeaf
|
|
620
|
+
* signs the responder SEAL leaf with B's K_local. We remove the agent PROMPT, never the SIGNER;
|
|
621
|
+
* nothing here lets the directory or the peer synthesize B's acknowledgement.
|
|
622
|
+
*
|
|
623
|
+
* SI-002 (verifiability gate): auto-ack ONLY content B has verified. A session whose content
|
|
624
|
+
* cross-check failed (content_hash_mismatch = tamper, recorded in #contentDesynced) is NEVER
|
|
625
|
+
* auto-signed — it surfaces to the agent as a genuine decision point. DISAGREEMENT with the
|
|
626
|
+
* content is NOT a gate failure (C-6): the gate is "can I verify integrity?", never "do I agree?"
|
|
627
|
+
* — a verified-but-disliked tail is auto-sealed and the transcript speaks for B.
|
|
628
|
+
*
|
|
629
|
+
* Idempotent + non-throwing: marks #responderSealSubmitted BEFORE the async submit so a
|
|
630
|
+
* redelivered ctrl leaf cannot double-submit; clears the mark on submit failure so a later
|
|
631
|
+
* agent close / reconnect can still complete the seal (DB-001 — never a silent half-seal).
|
|
632
|
+
*/
|
|
633
|
+
maybeAutoAcknowledgeSeal(agentName, sessionId, correlationId) {
|
|
634
|
+
const ackKey = this.#ctx.sessionKey(agentName, sessionId);
|
|
635
|
+
// Idempotency: at most one responder seal per session (auto-ack or agent close).
|
|
636
|
+
if (this.#ctx.responderSealSubmitted.has(ackKey))
|
|
637
|
+
return;
|
|
638
|
+
const record = this.#ctx.queries.getSessionRecord(agentName, sessionId);
|
|
639
|
+
// Only an ACTIVE session auto-acks. A committed/sealing/sealed/interrupted session is out of
|
|
640
|
+
// scope (already sealing, or needs the interrupted/upgrade path), not an auto-ack candidate.
|
|
641
|
+
if (!record || record.status !== "active")
|
|
642
|
+
return;
|
|
643
|
+
/**
|
|
644
|
+
* SI-002 verifiability gate: never auto-sign a session whose content we could not verify.
|
|
645
|
+
*
|
|
646
|
+
* ⚠️ THIS COMMENT SAID THE OPPOSITE UNTIL `DOD-M15-SEALWIRE-1` part B1 (review F-C). It read
|
|
647
|
+
* *"Today the ONLY tracked unverifiable cause is a content_hash mismatch = TAMPER"*, which was
|
|
648
|
+
* true when a mismatch was the only way to fail the cross-check and is false now: B1 added an
|
|
649
|
+
* unreadable algorithm name and a salted frame with no salt, and **both are ordinary**.
|
|
650
|
+
*
|
|
651
|
+
* Genuine tamper is a SECURITY event — ERROR, reason `content_tamper`, which is what the AC-008
|
|
652
|
+
* alarm keys on. The other two must NOT wear that name, or the alarm fires on an honest peer
|
|
653
|
+
* running a newer build and the operator learns to dismiss it.
|
|
654
|
+
*
|
|
655
|
+
* 🚨 AND `content_unverifiable` IS RESERVED — DO NOT REUSE IT HERE. It is specced for *parked
|
|
656
|
+
* content unrecoverable*, one of the two reasons (with `desynced`, B's tree behind the canonical
|
|
657
|
+
* sealed tail) awaiting the deferred MSG-001-3b canonical-sequence reconciliation. B1's first
|
|
658
|
+
* attempt emitted exactly that string for a different condition, which would have made the two
|
|
659
|
+
* indistinguishable in the log the day the follow-on landed. Hence
|
|
660
|
+
* `content_verification_unavailable`, deliberately distinct.
|
|
661
|
+
*/
|
|
662
|
+
const unverifiable = this.#ctx.contentDesynced.get(ackKey);
|
|
663
|
+
if (unverifiable) {
|
|
664
|
+
/**
|
|
665
|
+
* DOD-M15-SEALWIRE-1 part B1 (review F1) — THE GATE FIRES FOR BOTH, THE ALARM ONLY FOR ONE.
|
|
666
|
+
*
|
|
667
|
+
* `content_tamper` is what the AC-008 alarm keys on, and it must keep meaning what it says. A
|
|
668
|
+
* frame we could not verify because the peer named an algorithm this build cannot read is an
|
|
669
|
+
* ordinary version difference; raising a tamper alarm for it would train an operator to
|
|
670
|
+
* dismiss the alarm, which costs more than the skew.
|
|
671
|
+
*
|
|
672
|
+
* But the REFUSAL TO AUTO-SIGN is identical in both cases and non-negotiable: SI-002 is "never
|
|
673
|
+
* auto-sign a session whose content we could not verify", and "could not" covers both.
|
|
674
|
+
*/
|
|
675
|
+
this.#ctx.logger.error("session.seal.autoack.skipped", {
|
|
676
|
+
sessionId,
|
|
677
|
+
reason: unverifiable === "tampered" ? "content_tamper" : "content_verification_unavailable",
|
|
678
|
+
correlationId,
|
|
679
|
+
});
|
|
680
|
+
// AC-002: the verifiability gate refused — surface counterparty_closing to B's agent as a
|
|
681
|
+
// GENUINE decision point (the seal will not auto-complete; B must decide). Uses the existing
|
|
682
|
+
// session-state push to the live MCP clients; best-effort (never throws out of this gate).
|
|
683
|
+
try {
|
|
684
|
+
this.#ctx.onSessionStateChanged?.(record.agent_name, sessionId, "counterparty_closing", record.counterparty_pubkey);
|
|
685
|
+
}
|
|
686
|
+
catch (err) {
|
|
687
|
+
this.#ctx.logger.debug("session.state.notify.failed", {
|
|
688
|
+
sessionId,
|
|
689
|
+
reason: extractErrorMessage(err),
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const entry = this.#ctx.activeNodes.get(ackKey);
|
|
695
|
+
const responderPubkey = entry?.relayClient?.senderPubkeyHex ?? "unknown";
|
|
696
|
+
// submitSealLeaf owns the #responderSealSubmitted idempotency mark (set synchronously at its
|
|
697
|
+
// top), so the auto-ack does not pre-mark — it just reacts to the result.
|
|
698
|
+
// Establish the broker visiting connection BEFORE submitting, not after. The directory acts on
|
|
699
|
+
// the leaf in ~60ms and pushes `seal_verified` straight back; if the stream is not up by then it
|
|
700
|
+
// defers the frame and the seal stalls. Proven on GCP: leaf submitted 18:41:56.555, directory
|
|
701
|
+
// deferred at 18:41:56.615 (initiator_stream_absent), the explicit-close path opened the
|
|
702
|
+
// connection at 18:42:01.529 — five seconds too late.
|
|
703
|
+
void (async () => {
|
|
704
|
+
let sealBrokerConn = null;
|
|
705
|
+
try {
|
|
706
|
+
sealBrokerConn = (await this.#ctx.ensureSealBroker?.(agentName, sessionId)) ?? null;
|
|
707
|
+
}
|
|
708
|
+
catch (err) {
|
|
709
|
+
// Best-effort: a same-node session needs no visiting connection, and a failure here must not
|
|
710
|
+
// suppress the seal leaf — losing the leaf is strictly worse than racing the push.
|
|
711
|
+
this.#ctx.logger.warn("session.seal.autoack.broker.failed", {
|
|
712
|
+
sessionId,
|
|
713
|
+
correlationId,
|
|
714
|
+
reason: extractErrorMessage(err),
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* DOD-M15-SEALPRECOND-1 — the responder must not co-sign a record still being written either.
|
|
719
|
+
*
|
|
720
|
+
* This side signs its OWN root over its OWN tree, so a send of ours the relay has ordered and
|
|
721
|
+
* this tree has not placed produces exactly the short root the initiator produced on
|
|
722
|
+
* 2026-09-11. It was the one seal submission site with no gate at all.
|
|
723
|
+
*
|
|
724
|
+
* It WAITS first — the condition clears in milliseconds and declining costs a prompt
|
|
725
|
+
* bilateral seal. The REFUSAL is not written here: `submitSealLeaf` reads the same condition
|
|
726
|
+
* and answers `own_record_settling`, so this waits and then asks, and the one refusal travels
|
|
727
|
+
* out through the ordinary result handling below (review HIGH-1/LOW-5 — an early return here
|
|
728
|
+
* skipped the broker release and logged the same skip twice).
|
|
729
|
+
*/
|
|
730
|
+
await awaitOwnRecordSettled(this, agentName, sessionId);
|
|
731
|
+
const submitted = await this.submitSealLeaf(agentName, sessionId, correlationId);
|
|
732
|
+
// RELEASE AFTER A GRACE WINDOW, not when the submit resolves.
|
|
733
|
+
//
|
|
734
|
+
// `submitSealLeaf` settles at the relay ack plus a local root computation — milliseconds — while
|
|
735
|
+
// the frame this connection exists to catch arrives ~60ms LATER (the timeline in the comment
|
|
736
|
+
// above is the measurement). Releasing on submit therefore closed the stream before the push it
|
|
737
|
+
// was opened for, which is the stall it was written to prevent.
|
|
738
|
+
//
|
|
739
|
+
// It is worse than a lost race. The directory drains its DURABLE notification queue on ANY
|
|
740
|
+
// stream that authenticates — visiting included — and DELETES each row once sent. So a visiting
|
|
741
|
+
// stream that authenticates and dies milliseconds later invites the directory to send-and-delete
|
|
742
|
+
// queued seal frames into a closing stream: the receipt is gone from the queue and never
|
|
743
|
+
// arrived. That is permanent loss, not a retry.
|
|
744
|
+
//
|
|
745
|
+
// The close path holds its connection around the entire bilateral wait; this path has no waiter
|
|
746
|
+
// to hang off, so it uses a bounded grace instead — generous against a ~60ms push, and bounded
|
|
747
|
+
// so a stalled seal cannot leak the connection. Unref'd: it must never hold the process open.
|
|
748
|
+
if (sealBrokerConn) {
|
|
749
|
+
const conn = sealBrokerConn;
|
|
750
|
+
const t = setTimeout(() => { void conn.stop("autoack-seal-grace-elapsed").catch(() => { }); }, AUTOACK_BROKER_GRACE_MS);
|
|
751
|
+
t.unref?.();
|
|
752
|
+
}
|
|
753
|
+
return submitted;
|
|
754
|
+
})()
|
|
755
|
+
.then((result) => {
|
|
756
|
+
if (result.ok) {
|
|
757
|
+
// SI-001: the responder SEAL leaf was signed by B's OWN node (K_local) in submitSealLeaf.
|
|
758
|
+
this.#ctx.logger.info("session.seal.autoacknowledged", {
|
|
759
|
+
sessionId,
|
|
760
|
+
responderPubkey,
|
|
761
|
+
correlationId,
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
else if (result.reason === "responder_seal_already_submitted") {
|
|
765
|
+
// B's agent close already submitted the responder seal (it won the race) — nothing to do.
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
// Submission failed (e.g. relay path down) — the agent close / reconnect can still
|
|
770
|
+
// complete the seal; never a silent half-seal (DB-001).
|
|
771
|
+
this.#ctx.logger.warn("session.seal.autoack.skipped", {
|
|
772
|
+
sessionId,
|
|
773
|
+
reason: result.reason,
|
|
774
|
+
correlationId,
|
|
775
|
+
});
|
|
776
|
+
/**
|
|
777
|
+
* DOD-M15-SEALPRECOND-1 review HIGH-2 — SAY IT TO SOMEBODY WHO CAN ACT ON IT.
|
|
778
|
+
*
|
|
779
|
+
* A refusal that only reaches the log promises a recovery nothing performs: the initiator
|
|
780
|
+
* waits out its unilateral timeout — two hours on the session this order was written from
|
|
781
|
+
* — and the receipt is lost anyway. The SI-002 gate twelve lines up already solved this
|
|
782
|
+
* by pushing `counterparty_closing` so B's agent drives an explicit close, and this is the
|
|
783
|
+
* same situation: a refusal to AUTO-sign, where a human close still completes the seal.
|
|
784
|
+
*
|
|
785
|
+
* Scoped to the settling reason on purpose. The other reasons here (relay down, transport
|
|
786
|
+
* gone) are not conditions a prompt close can fix, and pushing a decision point for them
|
|
787
|
+
* would train the agent to ignore the one that matters.
|
|
788
|
+
*/
|
|
789
|
+
if (result.reason === "own_record_settling") {
|
|
790
|
+
try {
|
|
791
|
+
this.#ctx.onSessionStateChanged?.(record.agent_name, sessionId, "counterparty_closing", record.counterparty_pubkey);
|
|
792
|
+
}
|
|
793
|
+
catch (err) {
|
|
794
|
+
this.#ctx.logger.debug("session.state.notify.failed", { sessionId, reason: extractErrorMessage(err) });
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
})
|
|
799
|
+
.catch((err) => {
|
|
800
|
+
this.#ctx.logger.warn("session.seal.autoack.skipped", {
|
|
801
|
+
sessionId,
|
|
802
|
+
reason: extractErrorMessage(err),
|
|
803
|
+
correlationId,
|
|
804
|
+
});
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* M12-P14: is this side's chain COMPLETE enough to be sealed?
|
|
809
|
+
*
|
|
810
|
+
* A seal is a bilateral signature over the same conversation, so a side that is missing a leaf
|
|
811
|
+
* cannot produce a signable one — the counterparty compares frontiers and refuses with
|
|
812
|
+
* `leaf_count_mismatch`. That refusal is correct and it is also terminal: there is no backfill
|
|
813
|
+
* request in the protocol, so the only exit is a force-abandon, which yields NO notarized receipt.
|
|
814
|
+
* Measured 2026-08-05 on two sessions that died exactly this way (initiator 2 leaves, responder 3).
|
|
815
|
+
*
|
|
816
|
+
* The cheap prevention is to notice BEFORE asking. Two local signals already exist and, until now,
|
|
817
|
+
* nothing read either of them at close time:
|
|
818
|
+
* - `#highWaterSeq` — the largest canonical sequence the RELAY has witnessed for this session.
|
|
819
|
+
* The relay is the ordering authority, so a high-water above our own frontier is proof that a
|
|
820
|
+
* leaf exists which we have not appended. (Its own doc comment called it "reserved … NOT yet
|
|
821
|
+
* consumed by the gate" — this is that consumer.)
|
|
822
|
+
* - `#heldContent` — content we HAVE received and verified but cannot append because it sits
|
|
823
|
+
* behind a gap. Holding content and sealing anyway would seal a chain we know is short.
|
|
824
|
+
*
|
|
825
|
+
* Deliberately NOT a network call: it must work when the counterparty is unreachable, which is
|
|
826
|
+
* the whole situation a seal-interrupted exists for.
|
|
827
|
+
*
|
|
828
|
+
* KNOWN LIMIT, stated rather than hidden: both maps are in-memory and cleared on teardown, so
|
|
829
|
+
* after a daemon restart this returns ready for a session whose gap predates the restart — which
|
|
830
|
+
* is the shape of the 2026-08-05 incident itself. Closing that needs the mailbox drained (or the
|
|
831
|
+
* high-water persisted) before the check; tracked with M12-P14, not claimed here.
|
|
832
|
+
*/
|
|
833
|
+
sealReadiness(agentName, sessionId) {
|
|
834
|
+
const key = this.#ctx.sessionKey(agentName, sessionId);
|
|
835
|
+
// DOD-M12B-STRAND-1: hydrate first. An under-counted `heldCount` reports a gapped session as
|
|
836
|
+
// READY, and this gate's whole purpose is to stop a short chain being signed — the counterparty
|
|
837
|
+
// answers `leaf_count_mismatch`, which is TERMINAL and costs the receipt permanently. Failing
|
|
838
|
+
// open here is the one outcome worse than refusing a healthy close.
|
|
839
|
+
//
|
|
840
|
+
// Hydrate WITHOUT releasing: this is a read path now — the status surface asks it for every
|
|
841
|
+
// active session — and a read that appends leaves, advances the root and rings the doorbell is
|
|
842
|
+
// a diagnostic command that delivers messages. The release still runs on every path that was
|
|
843
|
+
// going to mutate anyway.
|
|
844
|
+
this.#ctx.held.ensureHeldRestored(agentName, sessionId, { release: false });
|
|
845
|
+
const treeSize = this.#ctx.getSessionTree(agentName, sessionId).size();
|
|
846
|
+
const highWaterSeq = this.#ctx.highWaterSeq.get(key) ?? -1;
|
|
847
|
+
const heldCount = this.#ctx.heldContent.get(key)?.size ?? 0;
|
|
848
|
+
// Review HIGH-2: NOT `(highWaterSeq + 1) - treeSize`. That subtraction silently assumes the
|
|
849
|
+
// relay's sequence space and this tree's index space count the same things, and they do not:
|
|
850
|
+
// `relay-node.ts` increments seq_counter for EVERY accepted leaf including CTRL (0x02), while
|
|
851
|
+
// NOTHING APPENDS A CTRL LEAF TO THIS TREE — `submitSealLeaf` deliberately computes its root
|
|
852
|
+
// without mutating the durable tree. So one seal ctrl leaf offsets the two spaces permanently,
|
|
853
|
+
// and any msg witnessed afterwards would read as a missing leaf FOREVER. That is a false
|
|
854
|
+
// positive, and a false positive here is worse than the bug it guards: it makes a healthy
|
|
855
|
+
// session unsealable, leaving force-abandon (no receipt) as the only exit. `seal-upgrade.ts`
|
|
856
|
+
//
|
|
857
|
+
// ⚠️ THIS SENTENCE USED TO READ *"`appendSessionLeaf` is only ever called with 'msg'"*, AND THAT
|
|
858
|
+
// WAS FALSE WHEN IT WAS WRITTEN — corrected, not deleted, per review pass 1 F8. Line ~7730
|
|
859
|
+
// appends "doc", and `WritableSessionTreeLeafKind` permits "ctrl" outright, so the type does not
|
|
860
|
+
// enforce it either. Doc leaves are harmless to this subtraction because they are witnessed by
|
|
861
|
+
// the relay too (LEAF_KIND_DOC) and counted in BOTH spaces; the load-bearing property is only
|
|
862
|
+
// ever about CTRL. Stating it as "msg only" made a narrower claim than the code supports and a
|
|
863
|
+
// stronger one than it holds — so a reader checking it would find a counter-example, conclude
|
|
864
|
+
// the reasoning was stale, and be one step from "fixing" the subtraction back.
|
|
865
|
+
// already documents the same `leaf_count - 1` offset.
|
|
866
|
+
//
|
|
867
|
+
// `#witnessedSeq` answers the question directly instead of inferring it. It gains an entry when
|
|
868
|
+
// the relay witnesses a COUNTERPARTY msg leaf (ctrl leaves are excluded at the call site) and
|
|
869
|
+
// loses it the moment that leaf is appended. So its remaining size IS the count of leaves the
|
|
870
|
+
// ordering authority has committed and this tree has not — no arithmetic, no space mismatch,
|
|
871
|
+
// and it cannot go negative.
|
|
872
|
+
const missingLeaves = this.#ctx.witnessedSeq.get(key)?.size ?? 0;
|
|
873
|
+
// DOD-M12B-INDEX-1: our OWN held sends are counted separately. They block a seal just as a
|
|
874
|
+
// received hold does, but they are not "a message from the counterparty that has not arrived" —
|
|
875
|
+
// and a refusal that calls them that tells the operator to wait for something already in hand,
|
|
876
|
+
// which is how a close-retry loop ends at force-abandon and no receipt.
|
|
877
|
+
let heldOwn = 0;
|
|
878
|
+
for (const e of this.#ctx.heldContent.get(key)?.values() ?? [])
|
|
879
|
+
if (e.origin === "sent")
|
|
880
|
+
heldOwn++;
|
|
881
|
+
// DOD-M15-DIVERGE-1: the third term, and the one that closes the asymmetry. `#diverged` is set
|
|
882
|
+
// only where the parting is PROVEN — an ack came back behind our frontier — never where it is
|
|
883
|
+
// merely suspected, because a gate that refuses a healthy session forever is worse than the bug
|
|
884
|
+
// it guards: force-abandon, with no receipt, becomes the only exit.
|
|
885
|
+
const diverged = this.#ctx.records.isSessionDiverged(agentName, sessionId);
|
|
886
|
+
/**
|
|
887
|
+
* DOD-M15-SEALPRECOND-1. A marker whose position the tree has ALREADY passed is spent — the
|
|
888
|
+
* leaf is in, or something else took the position and `diverged` says so — so it is dropped
|
|
889
|
+
* rather than counted, and no marker outlives its condition with no clock involved.
|
|
890
|
+
*/
|
|
891
|
+
const ordered = this.#ctx.ownLeavesOrdered.get(key);
|
|
892
|
+
let ownLeavesOrdered = 0;
|
|
893
|
+
if (ordered) {
|
|
894
|
+
for (const [hash, seq] of [...ordered]) {
|
|
895
|
+
if (seq < treeSize)
|
|
896
|
+
ordered.delete(hash);
|
|
897
|
+
else
|
|
898
|
+
ownLeavesOrdered++;
|
|
899
|
+
}
|
|
900
|
+
if (ordered.size === 0)
|
|
901
|
+
this.#ctx.ownLeavesOrdered.delete(key);
|
|
902
|
+
}
|
|
903
|
+
return {
|
|
904
|
+
ready: missingLeaves === 0 && heldCount === 0 && !diverged && ownLeavesOrdered === 0,
|
|
905
|
+
treeSize, highWaterSeq, heldCount, missingLeaves,
|
|
906
|
+
heldOwn, heldReceived: heldCount - heldOwn,
|
|
907
|
+
diverged, ownLeavesOrdered,
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* DOD-M12B-SEAL-STUCK-1 — the operator-facing answer to "can this session be closed?".
|
|
912
|
+
*
|
|
913
|
+
* THREE STATES, because there are three answers. `sealReadiness` above returns a boolean plus raw
|
|
914
|
+
* counters, and both of its counters are easy to misread on a surface:
|
|
915
|
+
*
|
|
916
|
+
* - `missingLeaves` is `#witnessedSeq.size`, which is every position the relay witnessed that
|
|
917
|
+
* this tree has not appended — and a HELD frame keeps its witness entry. So it INCLUDES the
|
|
918
|
+
* held ones. Reporting it beside `heldCount` counts the same message twice and labels one copy
|
|
919
|
+
* "never received" when it is sitting on our own disk. Split here into what each actually is.
|
|
920
|
+
* - Neither counter survives a restart on its own: `#witnessedSeq` is memory-only. Held content
|
|
921
|
+
* is durable since DOD-M12B-STRAND-1, but a position the relay witnessed for content that
|
|
922
|
+
* never arrived leaves no trace. So for a session carrying leaves this process did not watch
|
|
923
|
+
* arrive, "clean" is unknowable — and saying `ready` there invites a close that gets
|
|
924
|
+
* `leaf_count_mismatch` back, which is terminal and costs the receipt for good.
|
|
925
|
+
*/
|
|
926
|
+
sealReadinessView(agentName, sessionId) {
|
|
927
|
+
const key = this.#ctx.sessionKey(agentName, sessionId);
|
|
928
|
+
const r = this.sealReadiness(agentName, sessionId);
|
|
929
|
+
// DOD-M15-DIVERGE-1: READ THIS BEFORE THE `!ready` BRANCH, and the order is load-bearing.
|
|
930
|
+
// `diverged` is now a term in `ready`, so a diverged session reaches `!ready` — where it would
|
|
931
|
+
// report `blocked` with awaitingArrival and heldBehindGap both ZERO, replacing an accurate,
|
|
932
|
+
// specific answer with one that describes nothing and invites a retry that can never work.
|
|
933
|
+
// Divergence is permanent and has its own state; the gap cases below are the ones that resolve.
|
|
934
|
+
if (r.diverged) {
|
|
935
|
+
// NOT `ready`. The tree is ahead of the relay's counter for good, so a close here signs a root
|
|
936
|
+
// the counterparty answers `leaf_count_mismatch` to — terminal, and the receipt is gone. The
|
|
937
|
+
// raw counters cannot see this: nothing is missing and nothing is held.
|
|
938
|
+
return { state: "unknown", reason: "record_diverged_from_relay" };
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* DOD-M15-SEALPRECOND-1 — READ BEFORE THE `!ready` BRANCH, for the reason stated above it.
|
|
942
|
+
* A settling record has nothing missing and nothing held, so `blocked` would report zeros for
|
|
943
|
+
* both — describing nothing, and pointing at a counterparty who has done nothing.
|
|
944
|
+
*/
|
|
945
|
+
if (r.ownLeavesOrdered > 0) {
|
|
946
|
+
return { state: "settling", ownSendsInFlight: r.ownLeavesOrdered };
|
|
947
|
+
}
|
|
948
|
+
if (!r.ready) {
|
|
949
|
+
const oldestHeldMs = this.#ctx.queries.oldestHeldMs(agentName, sessionId);
|
|
950
|
+
return {
|
|
951
|
+
state: "blocked",
|
|
952
|
+
// The witness map counts a held frame until it is appended, so subtract the RECEIVED holds
|
|
953
|
+
// to avoid reporting one message twice. NOT the own-sends: the witness map only ever
|
|
954
|
+
// carries counterparty leaves, so subtracting ours would push this count below the truth.
|
|
955
|
+
awaitingArrival: Math.max(0, r.missingLeaves - r.heldReceived),
|
|
956
|
+
heldBehindGap: r.heldCount,
|
|
957
|
+
oldestHeldMs,
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
if (r.treeSize > 0 && !this.#ctx.orderingObserved.has(key)) {
|
|
961
|
+
return {
|
|
962
|
+
state: "unknown",
|
|
963
|
+
reason: "witness_state_predates_daemon_start",
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
return { state: "ready" };
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* WHERE THE MUTUALLY-SIGNED PREFIX ENDS, DERIVED FROM THIS DAEMON'S OWN LEAVES —
|
|
970
|
+
* `DOD-M15-UNILATERAL-1`, review F2.
|
|
971
|
+
*
|
|
972
|
+
* ⚠️ **THE FIRST VERSION COMPUTED THIS FROM THE CERTIFICATE'S OWN PARTICIPANT LIST, AND CALLED
|
|
973
|
+
* THAT "recomputed, cannot be steered".** It could be steered. On the SOLO path the certificate's
|
|
974
|
+
* TBS binds no legibility at all, and the client verifies only the *live* party's frontier — so
|
|
975
|
+
* the absent party's `content_frontier_seq` and every `last_authored_seq` arrived unchecked. One
|
|
976
|
+
* directory node could publish the absent party's frontier as 3 and the receipt would say
|
|
977
|
+
* "mutually signed through 3" over a transcript that party never signed for. That is the precise
|
|
978
|
+
* conflation this field exists to prevent, reintroduced by the field itself.
|
|
979
|
+
*
|
|
980
|
+
* The carry answers it without trusting anybody. This daemon holds the counterparty's own leaves,
|
|
981
|
+
* each carrying, inside the bytes THEY signed, both the sequence they authored and the
|
|
982
|
+
* `last_seen_seq` they acknowledged. So a party's commitment reaches
|
|
983
|
+
* `max(highest sequence they authored, highest sequence they acknowledged)`, and the transcript is
|
|
984
|
+
* mutually signed only as far as the LEAST-committed party reaches.
|
|
985
|
+
*
|
|
986
|
+
* Fewer than two distinct authors ⇒ `0`: nobody countersigned anything, which is the honest floor
|
|
987
|
+
* for a conversation where the other side only ever received. `null` when the carry is empty or
|
|
988
|
+
* unreadable — the caller must then publish NO boundary rather than fall back to a number
|
|
989
|
+
* somebody else supplied.
|
|
990
|
+
*/
|
|
991
|
+
countersignedThroughSeqFromCarry(agentPubkeyHex, sessionIdHex) {
|
|
992
|
+
const carry = this.getSealCarry(agentPubkeyHex, sessionIdHex);
|
|
993
|
+
if (carry.length === 0)
|
|
994
|
+
return null;
|
|
995
|
+
const reach = new Map();
|
|
996
|
+
for (const leaf of carry) {
|
|
997
|
+
// Structure 1 = [version, content_hash, sender_pubkey, session_id, last_seen_seq, timestamp],
|
|
998
|
+
// plus last_seen_hash at 6 on a v2 claim. `last_seen_seq` is index 4 in both — 020-ACKHASH
|
|
999
|
+
// APPENDS, so this read did not move. The hash is not consulted here: this derives a
|
|
1000
|
+
// POSITIONAL boundary, which is the job last_seen_seq keeps doing alongside the new field.
|
|
1001
|
+
const s1 = decodeStructure1(leaf.structure1Cbor);
|
|
1002
|
+
// Unreadable, or a layout this build cannot name: publish no boundary rather than a
|
|
1003
|
+
// half-derived one somebody else could have shaped.
|
|
1004
|
+
if (!s1.ok)
|
|
1005
|
+
return null;
|
|
1006
|
+
const signedLastSeen = Number.isFinite(Number(s1.fields.lastSeenSeq))
|
|
1007
|
+
? Number(s1.fields.lastSeenSeq)
|
|
1008
|
+
: 0;
|
|
1009
|
+
const prior = reach.get(leaf.senderPubkeyHex) ?? 0;
|
|
1010
|
+
reach.set(leaf.senderPubkeyHex, Math.max(prior, leaf.sequenceNumber, signedLastSeen));
|
|
1011
|
+
}
|
|
1012
|
+
if (reach.size < 2)
|
|
1013
|
+
return 0;
|
|
1014
|
+
return Math.min(...reach.values());
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
//# sourceMappingURL=session-seal.js.map
|