@cello-protocol/daemon 0.0.160 → 0.0.162
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/daemon.js +10 -4
- package/dist/daemon.js.map +1 -1
- package/dist/document-ack-inbound.d.ts +8 -1
- package/dist/document-ack-inbound.d.ts.map +1 -1
- package/dist/document-ack-inbound.js +31 -8
- package/dist/document-ack-inbound.js.map +1 -1
- package/dist/document-amendment-store.d.ts +72 -0
- package/dist/document-amendment-store.d.ts.map +1 -0
- package/dist/document-amendment-store.js +151 -0
- package/dist/document-amendment-store.js.map +1 -0
- package/dist/document-delivery-transport.d.ts +2 -1
- package/dist/document-delivery-transport.d.ts.map +1 -1
- package/dist/document-delivery-transport.js +1 -1
- package/dist/document-delivery-transport.js.map +1 -1
- package/dist/document-delivery.d.ts +6 -1
- package/dist/document-delivery.d.ts.map +1 -1
- package/dist/document-delivery.js +167 -201
- package/dist/document-delivery.js.map +1 -1
- package/dist/document-frame-router.d.ts +15 -1
- package/dist/document-frame-router.d.ts.map +1 -1
- package/dist/document-frame-router.js +22 -1
- package/dist/document-frame-router.js.map +1 -1
- package/dist/document-gate.js +1 -1
- package/dist/document-gate.js.map +1 -1
- package/dist/document-handlers.d.ts.map +1 -1
- package/dist/document-handlers.js +552 -2
- package/dist/document-handlers.js.map +1 -1
- package/dist/document-handshake.d.ts +13 -0
- package/dist/document-handshake.d.ts.map +1 -1
- package/dist/document-handshake.js +24 -0
- package/dist/document-handshake.js.map +1 -1
- package/dist/document-inbound.d.ts +12 -0
- package/dist/document-inbound.d.ts.map +1 -1
- package/dist/document-inbound.js +141 -10
- package/dist/document-inbound.js.map +1 -1
- package/dist/document-join-store.d.ts +80 -0
- package/dist/document-join-store.d.ts.map +1 -0
- package/dist/document-join-store.js +197 -0
- package/dist/document-join-store.js.map +1 -0
- package/dist/document-layer.d.ts +35 -1
- package/dist/document-layer.d.ts.map +1 -1
- package/dist/document-layer.js +417 -11
- package/dist/document-layer.js.map +1 -1
- package/dist/document-lifecycle.d.ts.map +1 -1
- package/dist/document-lifecycle.js +24 -4
- package/dist/document-lifecycle.js.map +1 -1
- package/dist/document-publish.d.ts +7 -0
- package/dist/document-publish.d.ts.map +1 -1
- package/dist/document-publish.js +20 -4
- package/dist/document-publish.js.map +1 -1
- package/dist/document-rejection.js +1 -1
- package/dist/document-rejection.js.map +1 -1
- package/dist/document-store.d.ts +97 -4
- package/dist/document-store.d.ts.map +1 -1
- package/dist/document-store.js +319 -21
- package/dist/document-store.js.map +1 -1
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +2 -0
- package/dist/vocabulary.js.map +1 -1
- package/package.json +5 -5
|
@@ -95,14 +95,15 @@ export class DocumentDelivery {
|
|
|
95
95
|
* unreachable peer must not stop delivery to every other peer, which is precisely the "works
|
|
96
96
|
* only when all nodes are healthy" shape the project forbids.
|
|
97
97
|
*/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
/**
|
|
99
|
+
* One pass over what is due, PER (document, holder). Returns counts rather than throwing on a
|
|
100
|
+
* per-target failure: one unreachable HOLDER must not stop delivery to any other — the same
|
|
101
|
+
* "works only when all nodes are healthy" shape the project forbids, now per holder.
|
|
102
|
+
*/
|
|
103
|
+
async tick(ownerAgentId, holdersFor, nowMs, opts = {}) {
|
|
103
104
|
if (this.#inFlight)
|
|
104
105
|
return this.#inFlight;
|
|
105
|
-
const run = this.#run(ownerAgentId,
|
|
106
|
+
const run = this.#run(ownerAgentId, holdersFor, nowMs, opts);
|
|
106
107
|
this.#inFlight = run;
|
|
107
108
|
try {
|
|
108
109
|
return await run;
|
|
@@ -111,239 +112,204 @@ export class DocumentDelivery {
|
|
|
111
112
|
this.#inFlight = null;
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
|
-
async #run(ownerAgentId,
|
|
115
|
-
// THE PASS BUDGET. Spent down by every envelope that opens its own session and waits for an
|
|
116
|
-
// ack; once it is gone the rest of the pass delivers without waiting rather than stalling
|
|
117
|
-
// behind whoever exhausted it. See DELIVERY_ACK_GRACE_BUDGET_MS.
|
|
115
|
+
async #run(ownerAgentId, holdersFor, nowMs, opts) {
|
|
118
116
|
let graceBudgetRemainingMs = DELIVERY_ACK_GRACE_BUDGET_MS;
|
|
119
|
-
// Minted once per pass and threaded through every event, so an operator can tie a failure back
|
|
120
|
-
// to the lookup that preceded it and the session that carried it. Delivery is precisely the
|
|
121
|
-
// async multi-step flow the convention exists for: lookup, dial, deliver, ack — across ticks
|
|
122
|
-
// and across restarts.
|
|
123
117
|
const correlationId = opts.correlationId ?? `dlv-${ownerAgentId.slice(0, 8)}-${nowMs}`;
|
|
124
|
-
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
|
|
118
|
+
const senderAgentId = opts.senderAgentId ?? ownerAgentId;
|
|
119
|
+
// LEGACY bilateral rows gain their per-holder twin before anything is read — idempotent
|
|
120
|
+
// insurance, journaled (Entry 14): pre-fan-out backlogs are near-empty at alpha.
|
|
121
|
+
this.#store.backfillBilateralDeliveries(ownerAgentId, senderAgentId, nowMs);
|
|
122
|
+
const pending = this.#store.pendingHolderDeliveries(ownerAgentId, nowMs);
|
|
128
123
|
const result = {
|
|
129
124
|
attempted: 0, delivered: 0, sent: 0, rejected: 0, deferred: 0, failed: 0,
|
|
130
125
|
};
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
// largest exactly when the peer has been away longest.
|
|
126
|
+
// Grouped (document, holder): one derivation and one reachability probe serve every pending
|
|
127
|
+
// envelope for that pair.
|
|
134
128
|
const byDocument = new Map();
|
|
135
|
-
for (const
|
|
136
|
-
|
|
129
|
+
for (const p of pending) {
|
|
130
|
+
let holders = byDocument.get(p.documentId);
|
|
131
|
+
if (!holders) {
|
|
132
|
+
holders = new Map();
|
|
133
|
+
byDocument.set(p.documentId, holders);
|
|
134
|
+
}
|
|
135
|
+
const list = holders.get(p.holderAgentId);
|
|
137
136
|
if (list)
|
|
138
|
-
list.push(
|
|
137
|
+
list.push(p);
|
|
139
138
|
else
|
|
140
|
-
|
|
139
|
+
holders.set(p.holderAgentId, [p]);
|
|
141
140
|
}
|
|
142
|
-
for (const [documentId,
|
|
143
|
-
const
|
|
144
|
-
if (
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
// every tick forever, emitting an error line each time, and — because the pending window
|
|
149
|
-
// is ordered and bounded — they filled it and starved every other document. The operator's
|
|
150
|
-
// work on an unrelated document would silently never leave the machine, with the only
|
|
151
|
-
// signal being an error naming a different one.
|
|
152
|
-
this.#logger.error("document.delivery.no_peer", {
|
|
141
|
+
for (const [documentId, holderGroups] of byDocument) {
|
|
142
|
+
const currentHolders = holdersFor(documentId);
|
|
143
|
+
if (currentHolders === null) {
|
|
144
|
+
// The document row is gone or its chain does not derive — NOT transient. Scheduled at
|
|
145
|
+
// the cap so the rows never starve anything, exactly the old no_peer discipline.
|
|
146
|
+
this.#logger.error("document.delivery.no_holders", {
|
|
153
147
|
documentId,
|
|
154
|
-
pending:
|
|
148
|
+
pending: [...holderGroups.values()].reduce((n, l) => n + l.length, 0),
|
|
155
149
|
correlationId,
|
|
156
150
|
});
|
|
157
|
-
for (const
|
|
158
|
-
|
|
151
|
+
for (const [holder, rows] of holderGroups) {
|
|
152
|
+
for (const r of rows) {
|
|
153
|
+
this.#store.scheduleHolderRetry(ownerAgentId, documentId, r.envelope.envelopeHash, holder, nowMs + DELIVERY_UNRESOLVABLE_RETRY_MS);
|
|
154
|
+
}
|
|
155
|
+
result.failed += rows.length;
|
|
159
156
|
}
|
|
160
|
-
result.failed += envelopes.length;
|
|
161
157
|
continue;
|
|
162
158
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
});
|
|
177
|
-
this.#defer(ownerAgentId, documentId, envelopes, nowMs);
|
|
178
|
-
result.deferred += envelopes.length;
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
if (!reach.reachable) {
|
|
182
|
-
// The unknown-agent case is announced AGAINST THE DOCUMENT, not in a separate line that
|
|
183
|
-
// cannot be joined to it. "This address does not resolve" and "your collaborator stepped
|
|
184
|
-
// away" are different things to tell an operator, and the second is what they saw for both.
|
|
185
|
-
this.#logger.info(reach.unknownAgent ? "document.delivery.peer_unknown" : "document.delivery.peer_unreachable", { documentId, peerAgentId, pending: envelopes.length, correlationId });
|
|
186
|
-
this.#defer(ownerAgentId, documentId, envelopes, nowMs);
|
|
187
|
-
result.deferred += envelopes.length;
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
for (const envelope of envelopes) {
|
|
191
|
-
result.attempted += 1;
|
|
192
|
-
// CLAIM THE ROW BEFORE DIALING. Scheduling only on the outcome leaves the row due for the
|
|
193
|
-
// whole duration of the dial, and leaves it due FOREVER if the daemon dies mid-dial. The
|
|
194
|
-
// claim is corrected below when the outcome lands.
|
|
195
|
-
const attempts = this.#store.recordDeliveryAttempt(ownerAgentId, documentId, envelope.envelopeHash, nowMs + backoffFor(envelope.attempts ?? 0));
|
|
196
|
-
let outcome;
|
|
197
|
-
const graceStartedAt = Date.now();
|
|
198
|
-
try {
|
|
199
|
-
outcome = await this.#transport.deliver({
|
|
200
|
-
peerAgentId,
|
|
201
|
-
documentId,
|
|
202
|
-
envelope,
|
|
203
|
-
// WHAT IS LEFT OF THE PASS BUDGET, never a fresh allowance. One unresponsive peer can
|
|
204
|
-
// exhaust it, and then every later envelope in the sweep is delivered without a wait
|
|
205
|
-
// rather than the sweep stalling behind it.
|
|
206
|
-
ackGraceMs: Math.max(0, graceBudgetRemainingMs),
|
|
207
|
-
// Per DOCUMENT. One hint applied to every envelope in the pass refused every OTHER
|
|
208
|
-
// document's delivery — their peer's active sessions cannot contain this document's
|
|
209
|
-
// session — so an unrelated update failed and backed off, citing a session the
|
|
210
|
-
// operator never associated with it.
|
|
211
|
-
sessionHint: opts.sessionHints?.get(documentId),
|
|
212
|
-
correlationId,
|
|
159
|
+
const currentSet = new Set(currentHolders);
|
|
160
|
+
for (const [holderAgentId, rows] of holderGroups) {
|
|
161
|
+
// A holder the arrangement no longer includes — removed, or never derivable — is
|
|
162
|
+
// RETIRED, announced: our decision, not evidence about them (DOD-MP-REMOVE-1's
|
|
163
|
+
// delivery-stop clause, generalized per holder).
|
|
164
|
+
if (!currentSet.has(holderAgentId) ||
|
|
165
|
+
this.#store.memberRemoved(ownerAgentId, documentId, holderAgentId).removed) {
|
|
166
|
+
const retiredHashes = this.#store.abandonHolderDeliveries(ownerAgentId, documentId, holderAgentId, nowMs);
|
|
167
|
+
for (const hash of retiredHashes) {
|
|
168
|
+
this.#store.reconcileEnvelopeSettlement(ownerAgentId, documentId, hash, nowMs);
|
|
169
|
+
}
|
|
170
|
+
this.#logger.info("document.delivery.peer_removed", {
|
|
171
|
+
documentId, holderAgentId, retired: retiredHashes.length, correlationId,
|
|
213
172
|
});
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
let reach;
|
|
176
|
+
try {
|
|
177
|
+
reach = await this.#transport.isPeerReachable(holderAgentId, correlationId);
|
|
214
178
|
}
|
|
215
179
|
catch (err) {
|
|
216
|
-
// A
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
180
|
+
// A FAILED LOOKUP IS NOT AN OFFLINE HOLDER — deferred, per holder, without an attempt.
|
|
181
|
+
this.#logger.warn("document.delivery.lookup_failed", {
|
|
182
|
+
documentId, holderAgentId, correlationId,
|
|
183
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
184
|
+
});
|
|
185
|
+
for (const r of rows) {
|
|
186
|
+
// Deferrals ESCALATE the schedule (an offline holder must not be redialed at full
|
|
187
|
+
// rate forever) without touching the SENDS ceiling — waiting is not sending.
|
|
188
|
+
this.#store.recordHolderAttempt(ownerAgentId, documentId, r.envelope.envelopeHash, holderAgentId, nowMs + backoffFor(r.attempts));
|
|
189
|
+
}
|
|
190
|
+
result.deferred += rows.length;
|
|
191
|
+
continue;
|
|
223
192
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
193
|
+
if (!reach.reachable) {
|
|
194
|
+
this.#logger.info(reach.unknownAgent ? "document.delivery.peer_unknown" : "document.delivery.peer_unreachable", { documentId, holderAgentId, pending: rows.length, correlationId });
|
|
195
|
+
for (const r of rows) {
|
|
196
|
+
this.#store.recordHolderAttempt(ownerAgentId, documentId, r.envelope.envelopeHash, holderAgentId, nowMs + backoffFor(r.attempts));
|
|
197
|
+
}
|
|
198
|
+
result.deferred += rows.length;
|
|
199
|
+
continue;
|
|
230
200
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
// Caught by the no-chat enforcer flipping red when unrelated edits shifted timing by
|
|
243
|
-
// milliseconds: the update parked onto a session the peer had just left, and the next
|
|
244
|
-
// attempt was outside any window a person would wait.
|
|
245
|
-
const parked = outcome.parked;
|
|
246
|
-
this.#store.recordDeliveryAttempt(ownerAgentId, documentId, envelope.envelopeHash, nowMs + (parked ? backoffFor(envelope.attempts ?? 0) : DELIVERY_ACK_TIMEOUT_MS));
|
|
247
|
-
this.#logger.info("document.delivery.sent", {
|
|
248
|
-
documentId,
|
|
249
|
-
envelopeHash: envelope.envelopeHash,
|
|
250
|
-
sessionId: outcome.sessionId,
|
|
251
|
-
sessionOpened: outcome.sessionOpened,
|
|
252
|
-
unackedSends: attempts,
|
|
253
|
-
correlationId,
|
|
254
|
-
});
|
|
255
|
-
result.sent += 1;
|
|
256
|
-
if (attempts >= DELIVERY_MAX_UNACKED_SENDS) {
|
|
257
|
-
// A peer that will never answer must stop being a transient. Otherwise this envelope is
|
|
258
|
-
// re-sent forever and looks, in the log and in `list`, exactly like one about to land.
|
|
259
|
-
//
|
|
260
|
-
// AND IT DID, because setting the status was never what stopped it. The selection above
|
|
261
|
-
// is `pendingDeliveries`, which filters on `acked_at IS NULL` and reads no status at
|
|
262
|
-
// all — so `stalled` changed what the surface SAID and nothing about what the worker
|
|
263
|
-
// DID. Every subsequent tick re-entered this branch, re-set the same status, and sent
|
|
264
|
-
// again. Measured on the operator's daemon: `sends: 74` against a documented cap of 5,
|
|
265
|
-
// while both the log line and the comment above claimed publishing had stopped.
|
|
266
|
-
//
|
|
267
|
-
// Retiring the envelope is what actually stops it — and it is retired as ABANDONED,
|
|
268
|
-
// not as acked. `markAcked` was the first spelling and it was wrong: `acked_at` means
|
|
269
|
-
// "the peer's daemon answered", so reusing it made `withdraw` tell the operator "your
|
|
270
|
-
// peer holds it, so it cannot be withdrawn" about an envelope the peer may never have
|
|
271
|
-
// seen. Giving up is our decision; it is not evidence about them.
|
|
272
|
-
this.#store.setDocumentStatus(ownerAgentId, documentId, "stalled");
|
|
273
|
-
this.#store.markAbandoned(ownerAgentId, documentId, envelope.envelopeHash, nowMs);
|
|
274
|
-
this.#logger.error("document.delivery.unacked_limit", {
|
|
201
|
+
for (const row of rows) {
|
|
202
|
+
const envelope = row.envelope;
|
|
203
|
+
result.attempted += 1;
|
|
204
|
+
// CLAIM THE ROW BEFORE DIALING — due-forever-on-crash-mid-dial is the same hazard it
|
|
205
|
+
// always was, per holder now.
|
|
206
|
+
this.#store.recordHolderAttempt(ownerAgentId, documentId, envelope.envelopeHash, holderAgentId, nowMs + backoffFor(row.attempts));
|
|
207
|
+
let outcome;
|
|
208
|
+
const graceStartedAt = Date.now();
|
|
209
|
+
try {
|
|
210
|
+
outcome = await this.#transport.deliver({
|
|
211
|
+
peerAgentId: holderAgentId,
|
|
275
212
|
documentId,
|
|
276
|
-
|
|
277
|
-
|
|
213
|
+
envelope,
|
|
214
|
+
ackGraceMs: Math.max(0, graceBudgetRemainingMs),
|
|
215
|
+
sessionHint: opts.sessionHints?.get(documentId),
|
|
278
216
|
correlationId,
|
|
279
|
-
// WHAT WAS OBSERVED, not a guess about whose fault it is. This said "Their client may
|
|
280
|
-
// not support shared documents yet" — an assertion about the PEER'S SOFTWARE for a
|
|
281
|
-
// failure whose measured cause was our own teardown deleting an ack that had already
|
|
282
|
-
// arrived and been verified. An exit-point label presented as a diagnosis, and it
|
|
283
|
-
// sent the one operator who hit it looking at the wrong machine.
|
|
284
|
-
//
|
|
285
|
-
// Both named events are ours and are upstream of this line, so the operator has
|
|
286
|
-
// somewhere to go before concluding anything about the counterparty.
|
|
287
|
-
detail: `this update has been delivered ${attempts} times without the peer's daemon ever ` +
|
|
288
|
-
`confirming it — the document has stopped publishing and this update will not be ` +
|
|
289
|
-
`retried. The cause may be local: check document.delivery.ack_grace_expired and ` +
|
|
290
|
-
`session.content.held.discarded for this session before concluding the peer's ` +
|
|
291
|
-
`client is at fault.`,
|
|
292
217
|
});
|
|
293
218
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
219
|
+
catch (err) {
|
|
220
|
+
outcome = {
|
|
221
|
+
ok: false,
|
|
222
|
+
reason: "document_delivery_threw",
|
|
223
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
graceBudgetRemainingMs -= Date.now() - graceStartedAt;
|
|
228
|
+
}
|
|
229
|
+
if (outcome.ok && outcome.admitted === null) {
|
|
230
|
+
// IN FLIGHT for THIS holder. Parked and live sends want DIFFERENT retry schedules,
|
|
231
|
+
// but both LEFT the machine — the sent-vs-never-left surface counts either (review
|
|
232
|
+
// M7: reporting relay-parked content as "never left" mislabels a delivery that the
|
|
233
|
+
// relay is holding for them).
|
|
234
|
+
this.#store.markHolderDelivered(ownerAgentId, documentId, envelope.envelopeHash, holderAgentId, nowMs);
|
|
235
|
+
const sends = this.#store.recordHolderSend(ownerAgentId, documentId, envelope.envelopeHash, holderAgentId);
|
|
236
|
+
this.#store.scheduleHolderRetry(ownerAgentId, documentId, envelope.envelopeHash, holderAgentId, nowMs + (outcome.parked ? backoffFor(row.attempts) : DELIVERY_ACK_TIMEOUT_MS));
|
|
237
|
+
this.#logger.info("document.delivery.sent", {
|
|
309
238
|
documentId,
|
|
310
239
|
envelopeHash: envelope.envelopeHash,
|
|
240
|
+
holderAgentId,
|
|
311
241
|
sessionId: outcome.sessionId,
|
|
312
|
-
|
|
242
|
+
sessionOpened: outcome.sessionOpened,
|
|
243
|
+
unackedSends: sends,
|
|
313
244
|
correlationId,
|
|
314
245
|
});
|
|
315
|
-
result.
|
|
246
|
+
result.sent += 1;
|
|
247
|
+
if (sends >= DELIVERY_MAX_UNACKED_SENDS) {
|
|
248
|
+
// THIS HOLDER is exhausted — retired, announced, and only theirs. The document
|
|
249
|
+
// stalls ONLY when every current holder is exhausted: one silent peer stopping a
|
|
250
|
+
// living collaboration is the exact availability failure the milestone forbids.
|
|
251
|
+
this.#store.abandonSingleHolderDelivery(ownerAgentId, documentId, envelope.envelopeHash, holderAgentId, nowMs);
|
|
252
|
+
this.#store.reconcileEnvelopeSettlement(ownerAgentId, documentId, envelope.envelopeHash, nowMs);
|
|
253
|
+
this.#logger.error("document.delivery.unacked_limit", {
|
|
254
|
+
documentId,
|
|
255
|
+
envelopeHash: envelope.envelopeHash,
|
|
256
|
+
holderAgentId,
|
|
257
|
+
sends,
|
|
258
|
+
correlationId,
|
|
259
|
+
detail: `this update has been delivered ${sends} times to this holder without their ` +
|
|
260
|
+
`daemon ever confirming it — delivery TO THEM is retired; every other holder ` +
|
|
261
|
+
`is unaffected. Check document.delivery.ack_grace_expired, ` +
|
|
262
|
+
`session.content.held.discarded, and whether their daemon has yet received ` +
|
|
263
|
+
`the amendment that added you (their log would show ` +
|
|
264
|
+
`document.inbound.sender_unknown_epoch_ahead) before concluding their client ` +
|
|
265
|
+
`is at fault.`,
|
|
266
|
+
});
|
|
267
|
+
const allExhausted = currentHolders
|
|
268
|
+
.filter((h) => h !== senderAgentId)
|
|
269
|
+
.every((h) => !this.#store.holderHasPending(ownerAgentId, documentId, h));
|
|
270
|
+
if (allExhausted) {
|
|
271
|
+
this.#store.setDocumentStatus(ownerAgentId, documentId, "stalled");
|
|
272
|
+
this.#logger.error("document.delivery.stalled_all_holders", {
|
|
273
|
+
documentId, correlationId,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else if (outcome.ok) {
|
|
279
|
+
const first = this.#store.ackHolderDelivery(ownerAgentId, documentId, envelope.envelopeHash, holderAgentId, nowMs);
|
|
280
|
+
// The envelope-level record follows the ONE terminal rule (review M3).
|
|
281
|
+
this.#store.reconcileEnvelopeSettlement(ownerAgentId, documentId, envelope.envelopeHash, nowMs);
|
|
282
|
+
this.#logger.info("document.delivery.session", {
|
|
283
|
+
documentId, holderAgentId, sessionId: outcome.sessionId,
|
|
284
|
+
opened: outcome.sessionOpened, correlationId,
|
|
285
|
+
});
|
|
286
|
+
if (outcome.admitted) {
|
|
287
|
+
this.#logger.info("document.delivery.acked", {
|
|
288
|
+
documentId, envelopeHash: envelope.envelopeHash, holderAgentId,
|
|
289
|
+
sessionId: outcome.sessionId, firstAck: first, correlationId,
|
|
290
|
+
});
|
|
291
|
+
result.delivered += 1;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
this.#logger.warn("document.delivery.rejected", {
|
|
295
|
+
documentId, envelopeHash: envelope.envelopeHash, holderAgentId,
|
|
296
|
+
sessionId: outcome.sessionId, reason: outcome.rejectionReason, correlationId,
|
|
297
|
+
});
|
|
298
|
+
result.rejected += 1;
|
|
299
|
+
}
|
|
316
300
|
}
|
|
317
301
|
else {
|
|
318
|
-
this.#logger.warn("document.delivery.
|
|
319
|
-
documentId,
|
|
320
|
-
|
|
321
|
-
sessionId: outcome.sessionId,
|
|
322
|
-
reason: outcome.rejectionReason,
|
|
302
|
+
this.#logger.warn("document.delivery.failed", {
|
|
303
|
+
documentId, envelopeHash: envelope.envelopeHash, holderAgentId,
|
|
304
|
+
reason: outcome.reason, detail: outcome.detail, attempts: row.attempts + 1,
|
|
323
305
|
correlationId,
|
|
324
306
|
});
|
|
325
|
-
result.
|
|
307
|
+
result.failed += 1;
|
|
326
308
|
}
|
|
327
309
|
}
|
|
328
|
-
else {
|
|
329
|
-
this.#logger.warn("document.delivery.failed", {
|
|
330
|
-
documentId,
|
|
331
|
-
envelopeHash: envelope.envelopeHash,
|
|
332
|
-
reason: outcome.reason,
|
|
333
|
-
detail: outcome.detail,
|
|
334
|
-
attempts,
|
|
335
|
-
correlationId,
|
|
336
|
-
});
|
|
337
|
-
result.failed += 1;
|
|
338
|
-
}
|
|
339
310
|
}
|
|
340
311
|
}
|
|
341
312
|
return result;
|
|
342
313
|
}
|
|
343
|
-
#defer(ownerAgentId, documentId, envelopes, nowMs) {
|
|
344
|
-
for (const e of envelopes) {
|
|
345
|
-
this.#store.recordDeliveryAttempt(ownerAgentId, documentId, e.envelopeHash, nowMs + backoffFor(e.attempts ?? 0));
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
314
|
}
|
|
349
315
|
//# sourceMappingURL=document-delivery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-delivery.js","sourceRoot":"","sources":["../src/document-delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAgHH;;;;;;;;;;;GAWG;AACH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC;AAEnD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAU,CAAC;AACrF,MAAM,CAAC,MAAM,uBAAuB,GAAG,mBAAmB,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAE3F;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,uBAAuB,CAAC;AAE/D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAE5C;;;GAGG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,uBAAuB,CAAC;AAEtE,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5E,OAAO,mBAAmB,CAAC,GAAG,CAAE,CAAC;AACnC,CAAC;AAaD,MAAM,OAAO,gBAAgB;IAClB,MAAM,CAAgB;IACtB,UAAU,CAA4B;IACtC,OAAO,CAAS;IACzB,SAAS,GAAuC,IAAI,CAAC;IAErD,YAAY,KAAoB,EAAE,SAAoC,EAAE,MAAc;QACpF,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI,CACR,YAAoB,EACpB,
|
|
1
|
+
{"version":3,"file":"document-delivery.js","sourceRoot":"","sources":["../src/document-delivery.ts"],"names":[],"mappings":"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"}
|
|
@@ -76,7 +76,7 @@ import type { Logger } from "./types.js";
|
|
|
76
76
|
* message and fires the doorbell exactly as before. Nothing about the conversation path changes.
|
|
77
77
|
*/
|
|
78
78
|
/** Every document frame kind that can arrive on the session channel. */
|
|
79
|
-
export type DocumentFrameKind = "update" | "ack" | "proposal" | "rejection" | "proposal_ack" | "control";
|
|
79
|
+
export type DocumentFrameKind = "update" | "ack" | "proposal" | "rejection" | "proposal_ack" | "control" | "join_offer" | "join_answer" | "amendment";
|
|
80
80
|
export type FrameRouting = {
|
|
81
81
|
consumed: false;
|
|
82
82
|
} | {
|
|
@@ -122,6 +122,20 @@ export interface DocumentFrameRouterDeps {
|
|
|
122
122
|
* with nothing on their screen explaining why.
|
|
123
123
|
*/
|
|
124
124
|
recordControl(ownerAgentId: string, wire: Uint8Array, nowMs: number): void;
|
|
125
|
+
/**
|
|
126
|
+
* M14B / DOD-MP-JOIN-1 — an admin's offer to a third party. Validated (the invitee REPLAYS the
|
|
127
|
+
* carried bytes) and recorded — pending or refused-with-reason, never dropped.
|
|
128
|
+
*/
|
|
129
|
+
recordJoinOffer(ownerAgentId: string, wire: Uint8Array, nowMs: number): void;
|
|
130
|
+
/** The invitee's signed answer to an offer we authored. Settle-once. */
|
|
131
|
+
recordJoinAnswer(ownerAgentId: string, wire: Uint8Array, nowMs: number): void;
|
|
132
|
+
/**
|
|
133
|
+
* An amendment reaching an EXISTING holder — validated against our own chain
|
|
134
|
+
* (validate-before-append) and appended, so our derived participant set does not silently
|
|
135
|
+
* diverge from the amender's (§7-1's hazard). Best-effort delivery at P1; the inbound epoch
|
|
136
|
+
* gate makes a missed one loud.
|
|
137
|
+
*/
|
|
138
|
+
recordAmendment(ownerAgentId: string, wire: Uint8Array, nowMs: number): void;
|
|
125
139
|
/**
|
|
126
140
|
* Tell the sender what happened to their envelope — admitted or refused, both of which SETTLE it.
|
|
127
141
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-frame-router.d.ts","sourceRoot":"","sources":["../src/document-frame-router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;
|
|
1
|
+
{"version":3,"file":"document-frame-router.d.ts","sourceRoot":"","sources":["../src/document-frame-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
*
|
|
67
67
|
* The guard must never again be described as what makes hostile input safe. It was, and it was not.
|
|
68
68
|
*/
|
|
69
|
-
import { decodeCbor, decodeDocumentUpdateEnvelope, decodeDocumentAck, decodeDocumentProposal, decodeDocumentRejection, decodeDocumentProposalAck, decodeDocumentControl, } from "@cello-protocol/protocol-types";
|
|
69
|
+
import { decodeCbor, decodeDocumentUpdateEnvelope, decodeDocumentAck, decodeDocumentProposal, decodeDocumentRejection, decodeDocumentProposalAck, decodeDocumentControl, decodeDocumentJoinOffer, decodeDocumentJoinAnswer, decodeDocumentAmendment, } from "@cello-protocol/protocol-types";
|
|
70
70
|
export class DocumentFrameRouter {
|
|
71
71
|
#d;
|
|
72
72
|
/** One promise chain per owning agent — the serialization point. See `#enqueue`. */
|
|
@@ -295,6 +295,18 @@ export class DocumentFrameRouter {
|
|
|
295
295
|
this.#d.recordControl(ownerAgentId, content, nowMs);
|
|
296
296
|
return { consumed: true, kind, ok: true };
|
|
297
297
|
}
|
|
298
|
+
if (kind === "join_offer") {
|
|
299
|
+
this.#d.recordJoinOffer(ownerAgentId, content, nowMs);
|
|
300
|
+
return { consumed: true, kind, ok: true };
|
|
301
|
+
}
|
|
302
|
+
if (kind === "join_answer") {
|
|
303
|
+
this.#d.recordJoinAnswer(ownerAgentId, content, nowMs);
|
|
304
|
+
return { consumed: true, kind, ok: true };
|
|
305
|
+
}
|
|
306
|
+
if (kind === "amendment") {
|
|
307
|
+
this.#d.recordAmendment(ownerAgentId, content, nowMs);
|
|
308
|
+
return { consumed: true, kind, ok: true };
|
|
309
|
+
}
|
|
298
310
|
const res = this.#d.ackInbound.receive(ownerAgentId, content, nowMs, correlationId);
|
|
299
311
|
return { consumed: true, kind, ok: res.ok, reason: res.ok ? undefined : res.reason };
|
|
300
312
|
}
|
|
@@ -415,6 +427,15 @@ function classify(content) {
|
|
|
415
427
|
case "document_control":
|
|
416
428
|
decodeDocumentControl(content);
|
|
417
429
|
return "control";
|
|
430
|
+
case "document_join_offer":
|
|
431
|
+
decodeDocumentJoinOffer(content);
|
|
432
|
+
return "join_offer";
|
|
433
|
+
case "document_join_answer":
|
|
434
|
+
decodeDocumentJoinAnswer(content);
|
|
435
|
+
return "join_answer";
|
|
436
|
+
case "document_amendment":
|
|
437
|
+
decodeDocumentAmendment(content);
|
|
438
|
+
return "amendment";
|
|
418
439
|
default:
|
|
419
440
|
// A frame type this build does not know. Reported by the caller rather than silently
|
|
420
441
|
// treated as conversation — see `routeSync`.
|