@cello-protocol/daemon 0.0.194 → 0.0.195

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/assignment-verify.d.ts +39 -11
  2. package/dist/assignment-verify.d.ts.map +1 -1
  3. package/dist/assignment-verify.js +133 -17
  4. package/dist/assignment-verify.js.map +1 -1
  5. package/dist/authorship-verification.d.ts +70 -0
  6. package/dist/authorship-verification.d.ts.map +1 -0
  7. package/dist/authorship-verification.js +441 -0
  8. package/dist/authorship-verification.js.map +1 -0
  9. package/dist/db-identity-store.d.ts +1 -0
  10. package/dist/db-identity-store.d.ts.map +1 -1
  11. package/dist/db-identity-store.js +19 -1
  12. package/dist/db-identity-store.js.map +1 -1
  13. package/dist/held-content.d.ts +141 -0
  14. package/dist/held-content.d.ts.map +1 -0
  15. package/dist/held-content.js +388 -0
  16. package/dist/held-content.js.map +1 -0
  17. package/dist/inbound-refusals.d.ts +283 -0
  18. package/dist/inbound-refusals.d.ts.map +1 -0
  19. package/dist/inbound-refusals.js +919 -0
  20. package/dist/inbound-refusals.js.map +1 -0
  21. package/dist/inbound-sessions.d.ts.map +1 -1
  22. package/dist/inbound-sessions.js +65 -27
  23. package/dist/inbound-sessions.js.map +1 -1
  24. package/dist/initiate-session-handler.d.ts.map +1 -1
  25. package/dist/initiate-session-handler.js +63 -0
  26. package/dist/initiate-session-handler.js.map +1 -1
  27. package/dist/outbound-sessions.d.ts.map +1 -1
  28. package/dist/outbound-sessions.js +108 -8
  29. package/dist/outbound-sessions.js.map +1 -1
  30. package/dist/park-recovery.d.ts +205 -0
  31. package/dist/park-recovery.d.ts.map +1 -0
  32. package/dist/park-recovery.js +600 -0
  33. package/dist/park-recovery.js.map +1 -0
  34. package/dist/refusal-notices.d.ts +196 -0
  35. package/dist/refusal-notices.d.ts.map +1 -0
  36. package/dist/refusal-notices.js +496 -0
  37. package/dist/refusal-notices.js.map +1 -0
  38. package/dist/refusal-reasons.d.ts +11 -0
  39. package/dist/refusal-reasons.d.ts.map +1 -1
  40. package/dist/refusal-reasons.js +18 -0
  41. package/dist/refusal-reasons.js.map +1 -1
  42. package/dist/registration-manager.d.ts.map +1 -1
  43. package/dist/registration-manager.js +126 -5
  44. package/dist/registration-manager.js.map +1 -1
  45. package/dist/registration-persistence.d.ts +18 -0
  46. package/dist/registration-persistence.d.ts.map +1 -1
  47. package/dist/registration-persistence.js +6 -0
  48. package/dist/registration-persistence.js.map +1 -1
  49. package/dist/session-assignment-parser.d.ts.map +1 -1
  50. package/dist/session-assignment-parser.js +23 -1
  51. package/dist/session-assignment-parser.js.map +1 -1
  52. package/dist/session-ceremony.d.ts +12 -7
  53. package/dist/session-ceremony.d.ts.map +1 -1
  54. package/dist/session-ceremony.js +12 -7
  55. package/dist/session-ceremony.js.map +1 -1
  56. package/dist/session-ephemerals.d.ts +271 -0
  57. package/dist/session-ephemerals.d.ts.map +1 -0
  58. package/dist/session-ephemerals.js +546 -0
  59. package/dist/session-ephemerals.js.map +1 -0
  60. package/dist/session-leaf-records.d.ts +132 -0
  61. package/dist/session-leaf-records.d.ts.map +1 -0
  62. package/dist/session-leaf-records.js +320 -0
  63. package/dist/session-leaf-records.js.map +1 -0
  64. package/dist/session-liveness.d.ts +135 -0
  65. package/dist/session-liveness.d.ts.map +1 -0
  66. package/dist/session-liveness.js +347 -0
  67. package/dist/session-liveness.js.map +1 -0
  68. package/dist/session-node-manager.d.ts +300 -1670
  69. package/dist/session-node-manager.d.ts.map +1 -1
  70. package/dist/session-node-manager.js +871 -9951
  71. package/dist/session-node-manager.js.map +1 -1
  72. package/dist/session-node-types.d.ts +933 -0
  73. package/dist/session-node-types.d.ts.map +1 -0
  74. package/dist/session-node-types.js +576 -0
  75. package/dist/session-node-types.js.map +1 -0
  76. package/dist/session-queries.d.ts +476 -0
  77. package/dist/session-queries.d.ts.map +1 -0
  78. package/dist/session-queries.js +1006 -0
  79. package/dist/session-queries.js.map +1 -0
  80. package/dist/session-records.d.ts +320 -0
  81. package/dist/session-records.d.ts.map +1 -0
  82. package/dist/session-records.js +792 -0
  83. package/dist/session-records.js.map +1 -0
  84. package/dist/session-salts.d.ts +390 -0
  85. package/dist/session-salts.d.ts.map +1 -0
  86. package/dist/session-salts.js +1457 -0
  87. package/dist/session-salts.js.map +1 -0
  88. package/dist/session-schema.d.ts +30 -0
  89. package/dist/session-schema.d.ts.map +1 -0
  90. package/dist/session-schema.js +786 -0
  91. package/dist/session-schema.js.map +1 -0
  92. package/dist/standing-receivers.d.ts +280 -0
  93. package/dist/standing-receivers.d.ts.map +1 -0
  94. package/dist/standing-receivers.js +1100 -0
  95. package/dist/standing-receivers.js.map +1 -0
  96. package/dist/transport-selector.d.ts +13 -0
  97. package/dist/transport-selector.d.ts.map +1 -1
  98. package/dist/transport-selector.js.map +1 -1
  99. package/dist/witness-alerts.d.ts +40 -0
  100. package/dist/witness-alerts.d.ts.map +1 -0
  101. package/dist/witness-alerts.js +102 -0
  102. package/dist/witness-alerts.js.map +1 -0
  103. package/package.json +5 -5
@@ -0,0 +1,141 @@
1
+ /**
2
+ * CELLO Daemon — CONTENT WE HAVE BUT CANNOT SHOW YET
3
+ *
4
+ * Split out of `session-node-manager.ts` by 037-SESSIONCORE. A message that arrives out of order is
5
+ * verified and kept, not delivered: showing it would put the conversation in the wrong sequence, and
6
+ * dropping it would lose a message the sender believes landed. It is HELD until the gap ahead of it
7
+ * closes, then released down the path it came from.
8
+ *
9
+ * Moved verbatim, comments included.
10
+ *
11
+ * ⚠️ `origin` DECIDES THE RELEASE PATH, AND GETTING IT WRONG IS NOT COSMETIC. A held frame of OUR OWN
12
+ * must be released down the SENT path — appended and transcribed as sent. Releasing it down the
13
+ * received path would put our own words in the counterparty's mouth in the sealed record, and hand
14
+ * them back to our own agent through `cello_receive` as though they had just arrived.
15
+ */
16
+ import type { Logger } from "./types.js";
17
+ import type { DaemonDatabase } from "./sqlcipher-db.js";
18
+ import type { SessionQueries } from "./session-queries.js";
19
+ import type { SessionRecords } from "./session-records.js";
20
+ import type { SessionTree, WritableSessionTreeLeafKind } from "./session-tree.js";
21
+ import type { SentAuthorship } from "./session-node-types.js";
22
+ /** One piece of content held behind an ordering gap. */
23
+ type HeldEntry = {
24
+ content: Uint8Array;
25
+ originalContent?: Uint8Array;
26
+ contentHashHex: string;
27
+ correlationId?: string;
28
+ screenedOut?: boolean;
29
+ origin?: "sent";
30
+ kind?: WritableSessionTreeLeafKind;
31
+ authorship?: SentAuthorship;
32
+ restoredAcrossRestart?: boolean;
33
+ };
34
+ /** What held content needs from the manager. */
35
+ export interface HeldContentContext {
36
+ readonly logger: Logger;
37
+ readonly queries: SessionQueries;
38
+ readonly records: SessionRecords;
39
+ /** A function: the manager opens its database after construction. Re-exposed below as `#db`. */
40
+ db(): DaemonDatabase | null;
41
+ sessionKey(agentName: string, sessionId: string): string;
42
+ requireAgentId(agentName: string): string;
43
+ /**
44
+ * ⚠️ THE HELD MAP ITSELF, shared by reference rather than owned here — `ingestReceivedContent`,
45
+ * `placeOwnLeaf`, `sealReadiness` and `getUndeliverableSeqs` all read it and all stayed behind.
46
+ * Splitting the map would have meant two sources of truth for "what are we holding", which is
47
+ * worse than sharing one. It is only ever ASSIGNED once, at construction, so there is one Map
48
+ * object and no two-writer divergence.
49
+ */
50
+ readonly heldContent: Map<string, Map<number, HeldEntry>>;
51
+ readonly witnessedSeq: Map<string, Map<string, number>>;
52
+ getSessionTree(agentName: string, sessionId: string): SessionTree;
53
+ appendSessionLeaf(agentName: string, sessionId: string, kind: WritableSessionTreeLeafKind, leafHashHex: string, correlationId?: string): {
54
+ leafIndex: number;
55
+ newRootHex: string;
56
+ };
57
+ appendVerifiedContent(agentName: string, sessionId: string, content: Uint8Array, contentHashHex: string, senderPubkey: string, correlationId?: string, originalContent?: Uint8Array, verifiedAuthorship?: {
58
+ senderPubkey: Uint8Array;
59
+ senderSig: Uint8Array;
60
+ }): {
61
+ leafIndex: number;
62
+ };
63
+ }
64
+ export declare class HeldContent {
65
+ #private;
66
+ constructor(ctx: HeldContentContext);
67
+ /** M8C-ABUSE-1 (reviewer HIGH fix, D18): bytes currently sitting in the out-of-order hold
68
+ * buffer for this session — NOT yet committed leaves, but real bytes in memory that would
69
+ * otherwise let multiple held chunks each individually pass the size gate while cumulatively
70
+ * exceeding it once #releaseHeld drains them. */
71
+ getHeldBytesTotal(agentName: string, sessionId: string): number;
72
+ /**
73
+ * DOD-M12B-STRAND-1 — restore this session's held frames into memory.
74
+ *
75
+ * Called when a session node is (re)created, which is the moment the session becomes able to
76
+ * append again. Loading at daemon boot instead would be wrong for the same reason the old code
77
+ * was wrong: a frame is only releasable against a tree, and the tree is loaded per session.
78
+ *
79
+ * A frame whose content the tree ALREADY HOLDS at that position is dropped — re-appending it
80
+ * would change the root a seal signs over. That test is `hashAt`, not `canonical_seq < frontier`:
81
+ * the two counters are different spaces and this file documents them drifting, so the index
82
+ * comparison alone would destroy a frame the tree never held. See the drift branch below.
83
+ */
84
+ ensureHeldRestored(agentName: string, sessionId: string, opts?: {
85
+ release?: boolean;
86
+ }): void;
87
+ restoreHeldContent(agentName: string, sessionId: string): void;
88
+ /**
89
+ * DOD-MSG-4: drain held out-of-order content in canonical order. After a leaf is appended, any
90
+ * held entry whose canonical sequence equals the new next-expected index is now in order — append
91
+ * it, then check again (a single fill can release a run of consecutive held messages).
92
+ */
93
+ releaseHeld(agentName: string, sessionId: string, senderPubkey: string): number;
94
+ /**
95
+ * Test seam: put an own leaf in the HELD state instead of the tree — 033-ACKEMIT.
96
+ *
97
+ * The state `placeOwnLeaf` produces when the relay assigns a position ahead of our tail: the leaf
98
+ * exists on this side and is not in the tree, while the counterparty already has it from the relay
99
+ * and can acknowledge it. Reproducing it through the real hold map rather than by asserting the
100
+ * tree is short is what makes the acknowledgement test measure the case instead of a neighbour of
101
+ * it.
102
+ */
103
+ holdOwnLeafForTest(agentName: string, sessionId: string, canonicalSeq: number, contentHashHex: string): void;
104
+ /**
105
+ * ⚠️ **ORPHANED COMMENT, OWNER UNKNOWN — do not attach it to the method below.** It reads
106
+ * *"@returns true iff the UPDATE was executed without error (a failed write is logged, never
107
+ * thrown)"*, and `annexHeldContentOnTerminal` returns `void` and runs no such UPDATE. It was
108
+ * already stranded in `session-node-manager.ts` before 037 moved this code, and Rule C carried it
109
+ * verbatim rather than dropping a sentence that is true of SOMETHING.
110
+ *
111
+ * Kept, marked, and NOT reattached: the nearest candidate by behaviour is
112
+ * `SessionQueries.markCounterpartyAbandoned`, which already has its own doc — so attaching it
113
+ * there on a guess is the same defect this marker exists to stop. Delete it only once its owner is
114
+ * identified, or reattach it then.
115
+ */
116
+ /**
117
+ * DOD-M12B-STRAND-1 — move a terminal session's held frames to the annex.
118
+ *
119
+ * A held frame is content this agent RECEIVED and VERIFIED. When its session ends it can never
120
+ * join that chain (appending behind a committed root is not an option, and ingest refuses a
121
+ * terminal session outright), but it is still the operator's mail and no other copy exists —
122
+ * the sender was never acknowledged for it. `sealed_session_annex` is where M12-P17 already puts
123
+ * content that arrives for an ended session; this is the same content arriving slightly earlier.
124
+ *
125
+ * ANNEX FIRST, DELETE SECOND, per row. A crash between them costs a duplicate the annex's
126
+ * INSERT OR IGNORE absorbs; the other order costs the message. A row whose annex write fails is
127
+ * KEPT — the retention sweep will find it again, and a leftover row is cheaper than a lost one.
128
+ */
129
+ annexHeldContentOnTerminal(agentName: string, sessionId: string, status: "sealed" | "abandoned"): void;
130
+ /**
131
+ * Forget the restore/release bookkeeping for a torn-down session.
132
+ *
133
+ * The held CONTENT itself is not dropped here — the map is shared and the manager's eviction still
134
+ * owns that line. What goes is this module's memory of whether a session was already hydrated from
135
+ * disk and already released, which must not survive a teardown: a revived session has to re-read
136
+ * from durable state rather than trust a flag about a process that is gone.
137
+ */
138
+ evictSession(agentName: string, sessionId: string): void;
139
+ }
140
+ export {};
141
+ //# sourceMappingURL=held-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"held-content.d.ts","sourceRoot":"","sources":["../src/held-content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,388 @@
1
+ export class HeldContent {
2
+ #ctx;
3
+ constructor(ctx) {
4
+ this.#ctx = ctx;
5
+ }
6
+ /** A getter so the moved queries still read `this.#db` and narrow exactly as they did. */
7
+ get #db() {
8
+ return this.#ctx.db();
9
+ }
10
+ #heldRestored = new Set();
11
+ #heldReleased = new Set();
12
+ /** M8C-ABUSE-1 (reviewer HIGH fix, D18): bytes currently sitting in the out-of-order hold
13
+ * buffer for this session — NOT yet committed leaves, but real bytes in memory that would
14
+ * otherwise let multiple held chunks each individually pass the size gate while cumulatively
15
+ * exceeding it once #releaseHeld drains them. */
16
+ getHeldBytesTotal(agentName, sessionId) {
17
+ // DOD-M12B-STRAND-1: hydrate first. Reading the Map before the durable holds are back
18
+ // under-counts, and this gate exists to stop several held chunks each passing the size cap
19
+ // individually while cumulatively exceeding it — an under-count is the bypass.
20
+ this.ensureHeldRestored(agentName, sessionId);
21
+ const held = this.#ctx.heldContent.get(this.#ctx.sessionKey(agentName, sessionId));
22
+ if (!held)
23
+ return 0;
24
+ let total = 0;
25
+ for (const entry of held.values())
26
+ total += entry.content.length;
27
+ return total;
28
+ }
29
+ /**
30
+ * DOD-M12B-STRAND-1 — restore this session's held frames into memory.
31
+ *
32
+ * Called when a session node is (re)created, which is the moment the session becomes able to
33
+ * append again. Loading at daemon boot instead would be wrong for the same reason the old code
34
+ * was wrong: a frame is only releasable against a tree, and the tree is loaded per session.
35
+ *
36
+ * A frame whose content the tree ALREADY HOLDS at that position is dropped — re-appending it
37
+ * would change the root a seal signs over. That test is `hashAt`, not `canonical_seq < frontier`:
38
+ * the two counters are different spaces and this file documents them drifting, so the index
39
+ * comparison alone would destroy a frame the tree never held. See the drift branch below.
40
+ */
41
+ ensureHeldRestored(agentName, sessionId, opts) {
42
+ const key = this.#ctx.sessionKey(agentName, sessionId);
43
+ if (!this.#heldRestored.has(key)) {
44
+ // Set BEFORE restoring, so the #ensureHeldRestored inside #releaseHeld below returns straight
45
+ // away instead of recursing.
46
+ this.#heldRestored.add(key);
47
+ this.restoreHeldContent(agentName, sessionId);
48
+ }
49
+ // A RESTORED FRAME MAY ALREADY BE IN ORDER, and nothing else would ever notice.
50
+ //
51
+ // #releaseHeld has one caller: the tail of a successful inbound ingest. Every other way the tree
52
+ // grows — an outbound send leaf, a queued or rejected leaf — advances the frontier without
53
+ // draining. While holds died with the session node that cost seconds; now the hold is durable,
54
+ // so the stall is durable too: the counterparty's message sits on disk at exactly the next slot,
55
+ // is never delivered, and `sealReadiness` counts it, so the session cannot close either.
56
+ // Undeliverable AND unsealable, forever, from one restart.
57
+ //
58
+ // TRACKED SEPARATELY FROM THE HYDRATION. A read-only caller (the status surface) hydrates and
59
+ // must NOT release — otherwise `cello status` appends leaves, advances the session root, writes
60
+ // transcript rows and rings the doorbell, which makes a diagnostic command the thing that
61
+ // delivers messages. One shared flag would also let that read CONSUME the release the next real
62
+ // ingest was going to perform, which is the stall above, reintroduced.
63
+ if (opts?.release === false)
64
+ return;
65
+ if (this.#heldReleased.has(key))
66
+ return;
67
+ this.#heldReleased.add(key);
68
+ if (this.#ctx.heldContent.get(key)?.size) {
69
+ const counterparty = this.#ctx.queries.getSessionRecord(agentName, sessionId)?.counterparty_pubkey;
70
+ if (counterparty)
71
+ this.releaseHeld(agentName, sessionId, counterparty);
72
+ }
73
+ }
74
+ restoreHeldContent(agentName, sessionId) {
75
+ if (!this.#db)
76
+ return;
77
+ let rows;
78
+ try {
79
+ rows = this.#db.prepare(`SELECT canonical_seq, content_blob, original_blob, content_hash_hex, screened_out, correlation_id, origin, leaf_kind
80
+ FROM held_content WHERE agent_id = ? AND session_id = ? ORDER BY canonical_seq ASC`).all(this.#ctx.requireAgentId(agentName), sessionId);
81
+ }
82
+ catch (err) {
83
+ this.#ctx.logger.error("session.content.held.restore.failed", {
84
+ agentName, sessionId,
85
+ impact: "verified content held before the restart is not in memory and cannot be released",
86
+ error: err instanceof Error ? err.message : String(err),
87
+ });
88
+ return;
89
+ }
90
+ if (rows.length === 0)
91
+ return;
92
+ const key = this.#ctx.sessionKey(agentName, sessionId);
93
+ let held = this.#ctx.heldContent.get(key);
94
+ if (!held) {
95
+ held = new Map();
96
+ this.#ctx.heldContent.set(key, held);
97
+ }
98
+ const tree = this.#ctx.getSessionTree(agentName, sessionId);
99
+ const frontier = tree.size();
100
+ let restored = 0;
101
+ let superseded = 0;
102
+ let drifted = 0;
103
+ for (const row of rows) {
104
+ // ASK THE TREE WHAT IS AT THAT POSITION — do not infer it from the index.
105
+ //
106
+ // `canonical_seq` is the RELAY's sequence space; `frontier` is this tree's msg-leaf count.
107
+ // The two drift, on purpose and by documented cases: the relay counts CTRL leaves the tree
108
+ // never appends, and a first message whose relay submit failed leaves the tree one ahead.
109
+ // Under drift `canonical_seq < frontier` is TRUE for a frame the tree has never held, and
110
+ // deleting on that comparison destroys verified content while reporting it as tidy-up —
111
+ // the exact failure this unit exists to end, reintroduced on the recovery path.
112
+ const occupant = tree.hashAt(row.canonical_seq);
113
+ if (occupant === row.content_hash_hex) {
114
+ this.#ctx.queries.deleteHeldContent(agentName, sessionId, row.canonical_seq);
115
+ superseded++;
116
+ continue;
117
+ }
118
+ if (row.canonical_seq < frontier) {
119
+ // The position is taken by DIFFERENT content. The frame cannot be appended (that would
120
+ // rewrite a committed leaf) and must not be deleted (it is verified content nobody else
121
+ // holds), so it goes to the annex that exists for exactly this — content that arrived for
122
+ // a chain that can no longer carry it — and only then does the row go.
123
+ const annexed = this.#ctx.queries.recordSealedAnnex(agentName, sessionId, row.content_hash_hex, new Uint8Array(row.content_blob),
124
+ // DOD-M12B-INDEX-1: our own held send is attributed to US, never to the counterparty.
125
+ row.origin === "sent"
126
+ ? this.#ctx.queries.ownPubkeyHex(agentName)
127
+ : this.#ctx.queries.getSessionRecord(agentName, sessionId)?.counterparty_pubkey ?? null);
128
+ this.#ctx.logger.error("session.content.held.position_drifted", {
129
+ agentName, sessionId, canonicalSeq: row.canonical_seq, frontier,
130
+ contentHash: row.content_hash_hex, occupant, annexed,
131
+ correlationId: row.correlation_id ?? undefined,
132
+ impact: annexed
133
+ ? "the relay's position for this frame is occupied by different content — it cannot join the chain and is readable only from the annex"
134
+ : "the relay's position for this frame is occupied by different content AND the annex write failed — the durable row is kept rather than destroyed",
135
+ });
136
+ if (annexed)
137
+ this.#ctx.queries.deleteHeldContent(agentName, sessionId, row.canonical_seq);
138
+ drifted++;
139
+ continue;
140
+ }
141
+ held.set(row.canonical_seq, {
142
+ content: new Uint8Array(row.content_blob),
143
+ ...(row.original_blob ? { originalContent: new Uint8Array(row.original_blob) } : {}),
144
+ contentHashHex: row.content_hash_hex,
145
+ ...(row.correlation_id ? { correlationId: row.correlation_id } : {}),
146
+ ...(row.screened_out ? { screenedOut: true } : {}),
147
+ ...(row.origin === "sent" ? { origin: "sent" } : {}),
148
+ ...(row.leaf_kind === "doc" ? { kind: "doc" } : {}),
149
+ /**
150
+ * ⚠️ `restoredAcrossRestart` EXISTS TO NAME A LOSS, NOT TO CHANGE BEHAVIOUR — review pass 2, H1.
151
+ *
152
+ * `held_content` has no authorship columns, so a SENT message held behind a gap and released
153
+ * after a daemon restart comes back with **no signature** — its transcript row records
154
+ * `self_authored` with no proof, indistinguishable from an unwitnessed send. That is the
155
+ * defect bullet 5 exists to end, reappearing on the recovery path, and it was silent.
156
+ *
157
+ * The proof cannot be reconstructed here: it was made over Structure-1 bytes this process no
158
+ * longer holds. **So the honest move is to say so, not to fabricate one** — a proof that
159
+ * cannot be checked, presented as one that can, is worse than the absence.
160
+ *
161
+ * Two BLOB columns would close it properly (this table already carries two `ALTER TABLE …
162
+ * ADD COLUMN` migrations, so the pattern exists). Under a frozen gate a log is additive and
163
+ * tightenable where a schema change is neither, so this announces the loss now and
164
+ * `DOD-M15-HELD-AUTHORSHIP-1` carries the column.
165
+ */
166
+ restoredAcrossRestart: true,
167
+ });
168
+ restored++;
169
+ }
170
+ if (held.size === 0)
171
+ this.#ctx.heldContent.delete(key);
172
+ this.#ctx.logger.info("session.content.held.restored", {
173
+ agentName, sessionId, restored, superseded, drifted, frontier,
174
+ canonicalSeqs: [...held.keys()].sort((a, b) => a - b),
175
+ // The flow ids of the frames that came back, so a restored message ties to the
176
+ // `session.content.held` that opened its flow before the restart.
177
+ correlationIds: rows.map((r) => r.correlation_id).filter((c) => c !== null),
178
+ });
179
+ }
180
+ /**
181
+ * DOD-MSG-4: drain held out-of-order content in canonical order. After a leaf is appended, any
182
+ * held entry whose canonical sequence equals the new next-expected index is now in order — append
183
+ * it, then check again (a single fill can release a run of consecutive held messages).
184
+ */
185
+ releaseHeld(agentName, sessionId, senderPubkey) {
186
+ const key = this.#ctx.sessionKey(agentName, sessionId);
187
+ // DOD-M12B-STRAND-1: hydrate before scanning. Restoring eagerly at session-node creation put
188
+ // it behind writes that can fail — one failed `sessions` row upsert and the frames stayed on
189
+ // disk, invisible, which is the same outcome as losing them.
190
+ this.ensureHeldRestored(agentName, sessionId);
191
+ const held = this.#ctx.heldContent.get(key);
192
+ if (!held)
193
+ return 0;
194
+ let released = 0;
195
+ for (;;) {
196
+ const nextExpected = this.#ctx.getSessionTree(agentName, sessionId).size();
197
+ const entry = held.get(nextExpected);
198
+ if (!entry)
199
+ break;
200
+ held.delete(nextExpected);
201
+ // DOD-M12B-STRAND-1: released content leaves the durable store in the same breath. A row
202
+ // that outlives its release would re-append the same content on the next boot — growing the
203
+ // tree and changing a root that has already been signed.
204
+ this.#ctx.queries.deleteHeldContent(agentName, sessionId, nextExpected);
205
+ // DOD-M12B-INDEX-1: OUR OWN held message. It leafs at its canonical index and is transcribed
206
+ // as SENT — never routed down the received path, which would attribute our words to the
207
+ // counterparty in the sealed record and hand them back to our own agent as inbound.
208
+ if (entry.origin === "sent") {
209
+ // The KIND the leaf was placed with, not a hardcoded "msg" — a document leaf that had to
210
+ // wait for its position must come back as a document leaf, or the two sides disagree about
211
+ // what the chain contains.
212
+ this.#ctx.appendSessionLeaf(agentName, sessionId, entry.kind ?? "msg", entry.contentHashHex, entry.correlationId);
213
+ // A DOCUMENT frame takes a leaf and NO transcript row — matching what the immediate-append
214
+ // path does for one. Writing one would put raw CBOR into the operator's transcript as
215
+ // something they said, which is the same attribution failure as releasing it inbound.
216
+ if (entry.kind === "doc") {
217
+ released++;
218
+ this.#ctx.logger.info("session.content.released", {
219
+ sessionId, sequenceNumber: nextExpected, leafKind: "doc", correlationId: entry.correlationId,
220
+ });
221
+ if (held.size === 0) {
222
+ this.#ctx.heldContent.delete(key);
223
+ break;
224
+ }
225
+ continue;
226
+ }
227
+ // OBSERVED, not assumed — the received path already does this. The leaf commits either way,
228
+ // so a dropped transcript write means the operator's OWN message is missing from their own
229
+ // transcript with the chain saying it is there, and nothing anywhere said so.
230
+ // bullet 5: the proof was captured at submit time and rides the held entry — see #heldContent.
231
+ /**
232
+ * THE RESTART LOSS, ANNOUNCED — review pass 2, H1. Only for an entry that actually crossed a
233
+ * restart: an in-memory held entry carries its proof, and an unwitnessed send legitimately
234
+ * has none, so warning on every absent proof would fire on a designed benign state and bury
235
+ * the one occurrence that means something.
236
+ */
237
+ if (entry.restoredAcrossRestart === true && entry.authorship === undefined) {
238
+ this.#ctx.logger.warn("session.content.released.authorship.lost", {
239
+ agentName, sessionId, sequenceNumber: nextExpected, correlationId: entry.correlationId,
240
+ impact: "this message was held behind a gap, survived a daemon restart, and is now committed with " +
241
+ "attribution 'self_authored' and NO signature. Its transcript row asserts its author rather " +
242
+ "than proving one, and is indistinguishable from a send the relay never witnessed.",
243
+ guidance: "Not recoverable after the fact — the signature covered Structure-1 bytes this process no longer " +
244
+ "holds, and fabricating one would be worse than the absence. Tracked as DOD-M15-HELD-AUTHORSHIP-1: " +
245
+ "held_content needs the two proof columns so a restart carries them.",
246
+ });
247
+ }
248
+ if (!this.#ctx.records.recordTranscriptMessage(agentName, sessionId, nextExpected, "sent", entry.content, entry.correlationId, entry.authorship)) {
249
+ this.#ctx.logger.error("session.content.released.transcript.failed", {
250
+ agentName, sessionId, sequenceNumber: nextExpected, correlationId: entry.correlationId,
251
+ impact: "this side's own message is committed to the chain but missing from its transcript",
252
+ });
253
+ }
254
+ }
255
+ else if (entry.screenedOut) {
256
+ this.#ctx.appendSessionLeaf(agentName, sessionId, "msg", entry.contentHashHex, entry.correlationId);
257
+ // The SAME witness leak as the immediate-append terminal-block branch (see the block comment
258
+ // at the `if (terminalBlock)` append in `ingestReceivedContent`), on the held path. This
259
+ // branch also bypasses `#appendVerifiedContent`, where the drop lives — so a blocked message
260
+ // that arrived out of order left `missingLeaves` stuck at 1 and the session unsealable.
261
+ this.#ctx.witnessedSeq.get(key)?.delete(entry.contentHashHex);
262
+ }
263
+ else {
264
+ this.#ctx.appendVerifiedContent(agentName, sessionId, entry.content, entry.contentHashHex, senderPubkey, entry.correlationId, entry.originalContent);
265
+ }
266
+ released++;
267
+ this.#ctx.logger.info("session.content.released", {
268
+ sessionId,
269
+ sequenceNumber: nextExpected,
270
+ screenedOut: entry.screenedOut === true,
271
+ correlationId: entry.correlationId,
272
+ });
273
+ if (held.size === 0) {
274
+ this.#ctx.heldContent.delete(key);
275
+ break;
276
+ }
277
+ }
278
+ return released;
279
+ }
280
+ /**
281
+ * Test seam: put an own leaf in the HELD state instead of the tree — 033-ACKEMIT.
282
+ *
283
+ * The state `placeOwnLeaf` produces when the relay assigns a position ahead of our tail: the leaf
284
+ * exists on this side and is not in the tree, while the counterparty already has it from the relay
285
+ * and can acknowledge it. Reproducing it through the real hold map rather than by asserting the
286
+ * tree is short is what makes the acknowledgement test measure the case instead of a neighbour of
287
+ * it.
288
+ */
289
+ holdOwnLeafForTest(agentName, sessionId, canonicalSeq, contentHashHex) {
290
+ const key = this.#ctx.sessionKey(agentName, sessionId);
291
+ let held = this.#ctx.heldContent.get(key);
292
+ if (!held) {
293
+ held = new Map();
294
+ this.#ctx.heldContent.set(key, held);
295
+ }
296
+ held.set(canonicalSeq, { content: new Uint8Array(), contentHashHex, origin: "sent", kind: "msg" });
297
+ }
298
+ /**
299
+ * ⚠️ **ORPHANED COMMENT, OWNER UNKNOWN — do not attach it to the method below.** It reads
300
+ * *"@returns true iff the UPDATE was executed without error (a failed write is logged, never
301
+ * thrown)"*, and `annexHeldContentOnTerminal` returns `void` and runs no such UPDATE. It was
302
+ * already stranded in `session-node-manager.ts` before 037 moved this code, and Rule C carried it
303
+ * verbatim rather than dropping a sentence that is true of SOMETHING.
304
+ *
305
+ * Kept, marked, and NOT reattached: the nearest candidate by behaviour is
306
+ * `SessionQueries.markCounterpartyAbandoned`, which already has its own doc — so attaching it
307
+ * there on a guess is the same defect this marker exists to stop. Delete it only once its owner is
308
+ * identified, or reattach it then.
309
+ */
310
+ /**
311
+ * DOD-M12B-STRAND-1 — move a terminal session's held frames to the annex.
312
+ *
313
+ * A held frame is content this agent RECEIVED and VERIFIED. When its session ends it can never
314
+ * join that chain (appending behind a committed root is not an option, and ingest refuses a
315
+ * terminal session outright), but it is still the operator's mail and no other copy exists —
316
+ * the sender was never acknowledged for it. `sealed_session_annex` is where M12-P17 already puts
317
+ * content that arrives for an ended session; this is the same content arriving slightly earlier.
318
+ *
319
+ * ANNEX FIRST, DELETE SECOND, per row. A crash between them costs a duplicate the annex's
320
+ * INSERT OR IGNORE absorbs; the other order costs the message. A row whose annex write fails is
321
+ * KEPT — the retention sweep will find it again, and a leftover row is cheaper than a lost one.
322
+ */
323
+ annexHeldContentOnTerminal(agentName, sessionId, status) {
324
+ if (!this.#db)
325
+ return;
326
+ let rows;
327
+ try {
328
+ rows = this.#db.prepare(`SELECT canonical_seq, content_blob, content_hash_hex, held_at, origin
329
+ FROM held_content WHERE agent_id = ? AND session_id = ? ORDER BY canonical_seq ASC`).all(this.#ctx.requireAgentId(agentName), sessionId);
330
+ }
331
+ catch (err) {
332
+ this.#ctx.logger.error("session.content.held.annex.scan.failed", {
333
+ agentName, sessionId, status,
334
+ impact: "held frames for a terminal session were not moved to the annex and remain unreadable",
335
+ error: err instanceof Error ? err.message : String(err),
336
+ });
337
+ return;
338
+ }
339
+ if (rows.length === 0)
340
+ return;
341
+ const counterparty = this.#ctx.queries.getSessionRecord(agentName, sessionId)?.counterparty_pubkey ?? null;
342
+ let annexed = 0;
343
+ let kept = 0;
344
+ for (const row of rows) {
345
+ // DOD-M12B-INDEX-1: ATTRIBUTION. A `sent` row is our own message. Stamping the counterparty's
346
+ // pubkey on it would put our words in their mouth in the one record that survives the
347
+ // session — the same failure the release path was changed to avoid, on the drain it did not
348
+ // touch. `#ownPubkeyHex` is null only when the identity cannot be resolved, and a null sender
349
+ // reads as "unattributed", which is true, rather than as a false attribution.
350
+ const sender = row.origin === "sent" ? this.#ctx.queries.ownPubkeyHex(agentName) : counterparty;
351
+ if (this.#ctx.queries.recordSealedAnnex(agentName, sessionId, row.content_hash_hex, new Uint8Array(row.content_blob), sender)) {
352
+ this.#ctx.queries.deleteHeldContent(agentName, sessionId, row.canonical_seq);
353
+ // AND OUT OF THE IN-MEMORY MAP. Measured live 2026-08-17 on daemon 0.0.170: this frame is
354
+ // now safe in the annex and its durable row is gone — but teardown still found it in the
355
+ // map, counted `held_content` for the session, got 0, and fired
356
+ // `session.content.held.lost`: "verified content was destroyed". Ten frames were annexed
357
+ // and the same ten were reported destroyed, in the same second. A false alarm on the most
358
+ // serious event in the system is worse than no alarm, because the next investigation goes
359
+ // looking for content that was never lost.
360
+ this.#ctx.heldContent.get(this.#ctx.sessionKey(agentName, sessionId))?.delete(row.canonical_seq);
361
+ annexed++;
362
+ }
363
+ else {
364
+ kept++;
365
+ }
366
+ }
367
+ this.#ctx.logger.warn("session.content.held.annexed", {
368
+ agentName, sessionId, status, annexed, kept,
369
+ // The consumer of `held_at`: how long the oldest frame waited before its session ended.
370
+ oldestHeldMs: Date.now() - Math.min(...rows.map((r) => r.held_at)),
371
+ impact: "these messages arrived and verified but never joined the chain — they are readable from the annex, not the transcript",
372
+ });
373
+ }
374
+ /**
375
+ * Forget the restore/release bookkeeping for a torn-down session.
376
+ *
377
+ * The held CONTENT itself is not dropped here — the map is shared and the manager's eviction still
378
+ * owns that line. What goes is this module's memory of whether a session was already hydrated from
379
+ * disk and already released, which must not survive a teardown: a revived session has to re-read
380
+ * from durable state rather than trust a flag about a process that is gone.
381
+ */
382
+ evictSession(agentName, sessionId) {
383
+ const key = this.#ctx.sessionKey(agentName, sessionId);
384
+ this.#heldRestored.delete(key);
385
+ this.#heldReleased.delete(key);
386
+ }
387
+ }
388
+ //# sourceMappingURL=held-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"held-content.js","sourceRoot":"","sources":["../src/held-content.ts"],"names":[],"mappings":"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"}