@cello-protocol/daemon 0.0.122 → 0.0.123

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 (57) hide show
  1. package/dist/daemon.js +65 -12
  2. package/dist/daemon.js.map +1 -1
  3. package/dist/document-store.d.ts +0 -88
  4. package/dist/document-store.d.ts.map +1 -1
  5. package/dist/document-store.js +1 -344
  6. package/dist/document-store.js.map +1 -1
  7. package/dist/document-write-path.d.ts.map +1 -1
  8. package/dist/document-write-path.js +43 -10
  9. package/dist/document-write-path.js.map +1 -1
  10. package/dist/reconnect-drain.d.ts +7 -0
  11. package/dist/reconnect-drain.d.ts.map +1 -1
  12. package/dist/reconnect-drain.js +18 -4
  13. package/dist/reconnect-drain.js.map +1 -1
  14. package/dist/retry-queue.d.ts +9 -1
  15. package/dist/retry-queue.d.ts.map +1 -1
  16. package/dist/retry-queue.js +38 -9
  17. package/dist/retry-queue.js.map +1 -1
  18. package/dist/session-content-handlers.d.ts.map +1 -1
  19. package/dist/session-content-handlers.js +7 -1
  20. package/dist/session-content-handlers.js.map +1 -1
  21. package/dist/session-node-manager.d.ts +4 -1
  22. package/dist/session-node-manager.d.ts.map +1 -1
  23. package/dist/session-node-manager.js +64 -8
  24. package/dist/session-node-manager.js.map +1 -1
  25. package/package.json +3 -3
  26. package/dist/document-delivery-transport.d.ts +0 -78
  27. package/dist/document-delivery-transport.d.ts.map +0 -1
  28. package/dist/document-delivery-transport.js +0 -109
  29. package/dist/document-delivery-transport.js.map +0 -1
  30. package/dist/document-delivery.d.ts +0 -130
  31. package/dist/document-delivery.d.ts.map +0 -1
  32. package/dist/document-delivery.js +0 -246
  33. package/dist/document-delivery.js.map +0 -1
  34. package/dist/document-handshake.d.ts +0 -88
  35. package/dist/document-handshake.d.ts.map +0 -1
  36. package/dist/document-handshake.js +0 -239
  37. package/dist/document-handshake.js.map +0 -1
  38. package/dist/document-lifecycle.d.ts +0 -104
  39. package/dist/document-lifecycle.d.ts.map +0 -1
  40. package/dist/document-lifecycle.js +0 -363
  41. package/dist/document-lifecycle.js.map +0 -1
  42. package/dist/document-notify.d.ts +0 -130
  43. package/dist/document-notify.d.ts.map +0 -1
  44. package/dist/document-notify.js +0 -313
  45. package/dist/document-notify.js.map +0 -1
  46. package/dist/document-reachability.d.ts +0 -42
  47. package/dist/document-reachability.d.ts.map +0 -1
  48. package/dist/document-reachability.js +0 -72
  49. package/dist/document-reachability.js.map +0 -1
  50. package/dist/document-rejection.d.ts +0 -224
  51. package/dist/document-rejection.d.ts.map +0 -1
  52. package/dist/document-rejection.js +0 -374
  53. package/dist/document-rejection.js.map +0 -1
  54. package/dist/line-lcs.d.ts +0 -51
  55. package/dist/line-lcs.d.ts.map +0 -1
  56. package/dist/line-lcs.js +0 -71
  57. package/dist/line-lcs.js.map +0 -1
@@ -1,224 +0,0 @@
1
- /**
2
- * DOD-DOC-REJECT-1 — rejection and supersession (§3.2, §16.7-2).
3
- *
4
- * ── WHY SUPERSESSION, AND NOT "BOTH SIDES ROLL BACK" ──────────────────────────────────────────
5
- *
6
- * The naive protocol is: the receiver discards, the sender undoes locally, and both return to the
7
- * pre-update state. It does not work, and the reason is a property of CRDTs rather than a bug.
8
- *
9
- * **Yjs undo adds INVERSES; it does not erase.** The rejected operations stay in the sender's
10
- * document. So every later update the sender computes against the receiver's state vector
11
- * re-transmits them, and the receiver — which refuses to hold them — can never integrate the
12
- * legitimate work stacked causally on top, because Yjs will not apply operations whose
13
- * predecessors are missing. A permanent causal gap, from a protocol that looked symmetric.
14
- *
15
- * The protocol that works (§3.2):
16
- * 1. The receiver rejects with a REASON — a protocol message and its own `0x05` leaf, never a
17
- * silent drop. The update goes to quarantine, held rather than discarded.
18
- * 2. The sender rolls back locally, which emits inverses into its own log and leaves an
19
- * auditable "wrote X, was rejected, undid X" trail.
20
- * 3. The sender publishes a SUPERSEDING update against the receiver's state vector, which
21
- * necessarily carries the rejected operations PLUS their inverses plus any new work.
22
- * 4. The receiver validates the now-clean projected diff — the rejected content nets to zero —
23
- * admits it, and clears the quarantine. Causality intact, both parties converge, and the
24
- * rejected content survives only as inert tombstones.
25
- *
26
- * ── SCOPE ─────────────────────────────────────────────────────────────────────────────────────
27
- *
28
- * This proves the protocol against STORE-1's local envelope log. The CBOR wire encoding is
29
- * DOD-DOC-ENVELOPE-1's job and the cross-daemon proof is DOD-DOC-E2E-REJECT-1's.
30
- */
31
- import * as Y from "yjs";
32
- import type { DocumentStore } from "./document-store.js";
33
- import type { Logger } from "./types.js";
34
- /**
35
- * The document stalls on the THIRD rejected round: the original refusal, one superseding attempt,
36
- * and no more (§16.7-2 "one retry, then freeze").
37
- *
38
- * Counted in rounds rather than retries because the previous spelling — a `REJECTION_RETRY_LIMIT`
39
- * of 1 compared as `round > LIMIT + 1` — permitted two retries under a name that said one, which
40
- * is the kind of thing the next edit gets wrong.
41
- *
42
- * Bounded at all because an unbounded retry loop between two daemons that disagree is not
43
- * convergence, it is a hot loop neither operator can see. Stalling is the visible failure.
44
- */
45
- export declare const MAX_REJECTED_ROUNDS = 3;
46
- export interface RejectionInput {
47
- /** The envelope being rejected — the `0x05` leaf references this hash (§9). */
48
- rejectedEnvelopeHash: string;
49
- /** The bytes, held rather than discarded (§3.2). Supplied by the gate's quarantine verdict. */
50
- quarantined: Uint8Array;
51
- /**
52
- * The refused envelope's OWN chain link — `null` only when the refused envelope was genuinely
53
- * that sender's first. REQUIRED rather than optional: the refused envelope is deliberately never
54
- * written to the log, so this is the only thing keeping the peer's next link resolvable, and an
55
- * omitted value would default every refused envelope to a genesis stub — manufacturing exactly
56
- * the fork the bridge exists to prevent. The caller decoded the envelope; it knows.
57
- */
58
- rejectedDocPrevHash: string | null;
59
- reason: string;
60
- detail?: string;
61
- senderAgentId: string;
62
- /** Which pluggable rule refused, when one did (from the gate's verdict). */
63
- rule?: string;
64
- /** The limit breached, when one was (from the gate's verdict). */
65
- limit?: {
66
- name: string;
67
- limit: number;
68
- actual: number;
69
- };
70
- /**
71
- * The rejection's own signature and state vector.
72
- *
73
- * REQUIRED rather than fabricated. An all-zero placeholder written into an immutable log is
74
- * indistinguishable from a real signature that fails to verify, so a later verifier would send
75
- * an operator to the crypto layer for a value nobody ever signed. Producing these is
76
- * DOD-DOC-ENVELOPE-1's job; this unit refuses to invent them.
77
- */
78
- signature: Uint8Array;
79
- stateVector: Uint8Array;
80
- /** Distinguishes repeat rejections of the same envelope for the same reason. */
81
- nonce: string;
82
- }
83
- export interface RejectionOutcome {
84
- /** The document has exhausted its retries and stopped accepting updates. */
85
- stalled: boolean;
86
- /** How many rejections this document has seen, including this one. */
87
- round: number;
88
- }
89
- export interface QuarantineEntry {
90
- rejectedEnvelopeHash: string;
91
- quarantined: Uint8Array;
92
- reason: string;
93
- detail?: string;
94
- /** Which rule refused, and the number it refused on. Surfaced, not just stored. */
95
- rule?: string;
96
- limitName?: string;
97
- limitValue?: number;
98
- limitActual?: number;
99
- }
100
- /** A handle over the sender's local edits, so a rejection can be rolled back as inverses. */
101
- export interface TrackedEdits {
102
- readonly doc: Y.Doc;
103
- readonly undoManager: Y.UndoManager;
104
- /**
105
- * Release the tracker. Required, not optional hygiene: the depth guard in `rollback` admits
106
- * exactly one stacked edit, so the only workable pattern is a FRESH tracker per publish — which
107
- * means one live UndoManager per publish on a long-lived Y.Doc, each holding `afterTransaction`
108
- * observers and accumulating undo items that retain deleted structs. Call it once the rejection
109
- * is resolved, either way.
110
- */
111
- dispose(): void;
112
- /** Stack depth when tracking began, so `rollback` can prove it is undoing the right item. */
113
- readonly depthAtTracking: number;
114
- }
115
- export declare class DocumentRejections {
116
- #private;
117
- constructor(store: DocumentStore, logger: Logger);
118
- /**
119
- * Record a rejection: a `0x05` row referencing the rejected envelope, the quarantined bytes
120
- * held, and a policy record carrying the reason.
121
- *
122
- * The envelope log is append-only, so this is a NEW ROW — nothing is edited or removed.
123
- *
124
- * ── HOW A REFUSAL IS ACTUALLY REALIZED, AND WHY NOT THE WAY §9 SAYS ─────────────────────────
125
- *
126
- * §9 phrases effectiveness as a replay-time set property: "an update leaf is effective iff no
127
- * rejection leaf references it". Implemented literally that is unsound, and it was measured
128
- * rather than argued. Sender publishes a base, then a refused update, then rolls back and
129
- * supersedes. Replaying the log while SKIPPING the refused leaf gives:
130
- *
131
- * text "agreed base. " pendingStructs PRESENT pendingDs PRESENT
132
- *
133
- * The supersession is causally stacked on the refused operations — the rollback is a DELETION of
134
- * those structs and the new work is positioned after them — so dropping them leaves everything
135
- * later permanently pending. The document reads as complete and is silently missing the
136
- * legitimate work. §16.7-5 already retired §9's "document-log order" phrasing; this retires its
137
- * effectiveness phrasing on the same grounds.
138
- *
139
- * What is sound: the receiver NEVER WRITES the refused payload to its log. There is nothing to
140
- * subtract at replay because it was never added, and the peer's supersession — computed against
141
- * the RECEIVER's state vector per §3.2 step 3 — is self-contained. Measured on the same fixture:
142
- *
143
- * text "agreed base. clean text. " pendingStructs null pendingDs null converged true
144
- *
145
- * The refused bytes do travel again inside that supersession, carrying their own inverses, which
146
- * is precisely "inverses, not erasure" (§3.2) — the content nets to zero and survives only as
147
- * tombstones. The bytes we refused live in `document_quarantine`, and the chain bridges across
148
- * the refused envelope so the peer's next link still resolves (see `verifyChainLinkage`).
149
- */
150
- reject(agentId: string, documentId: string, input: RejectionInput): RejectionOutcome;
151
- /**
152
- * Record a rejection ARRIVING from the peer — the receiving half of §3.2's "both sides".
153
- *
154
- * ── THE ROUTING DECISION (the DoD requires it resolved in-unit) ─────────────────────────────
155
- *
156
- * A document rejection is written **daemon-side**, into this document's own log and quarantine,
157
- * NOT through the gateway record store's `source` discriminator.
158
- *
159
- * The gateway's record store exists for SCREENING verdicts, and most V1 rejection reasons are
160
- * not screening at all — `append_only`, the receiver-local limits, malformed updates, unresolved
161
- * dependencies. Routing every document rejection through a screening store would file structural
162
- * protocol events as policy verdicts, and it would couple this unit to a schema owned by a
163
- * component that is not involved. DOD-DOC-SCREEN-1 is parked, so that coupling would also have
164
- * to be built speculatively and unwound if screening lands differently.
165
- *
166
- * When SCREEN-1 does land, a rejection whose reason came from the screening rule can ADDITIONALLY
167
- * write a gateway record — the discriminator exists for exactly that, and adding it later costs
168
- * nothing, whereas removing a premature coupling costs a migration.
169
- */
170
- recordIncomingRejection(agentId: string, documentId: string, input: {
171
- /** The peer's 0x05 leaf hash — the row's identity, so a redelivery does not advance a round. */
172
- rejectionEnvelopeHash: string;
173
- rejectedEnvelopeHash: string;
174
- reason: string;
175
- detail?: string;
176
- fromAgentId: string;
177
- }): {
178
- stalled: boolean;
179
- round: number;
180
- };
181
- /** Entries held for this document — never admitted, never discarded (§3.2). From the store. */
182
- quarantined(agentId: string, documentId: string): QuarantineEntry[];
183
- /** Clear one entry once its superseding update has been admitted (§3.2 step 4). */
184
- clearQuarantine(agentId: string, documentId: string, rejectedEnvelopeHash: string): void;
185
- /**
186
- * Whether this document still accepts updates.
187
- *
188
- * A stalled document REFUSES, naming the reason it stalled — both operators need to see why,
189
- * because a document that silently stops converging is the failure this exists to prevent.
190
- */
191
- acceptsUpdates(agentId: string, documentId: string): {
192
- ok: true;
193
- } | {
194
- ok: false;
195
- reason: string;
196
- detail: string;
197
- };
198
- /**
199
- * Start tracking local edits so a rejection can be rolled back.
200
- *
201
- * Yjs's own UndoManager, deliberately: rolling back by hand would mean computing inverses, and
202
- * the inverse of a CRDT operation is not something to hand-roll — the whole reason supersession
203
- * works is that Yjs's undo produces operations that compose correctly with everything stacked
204
- * on top of them.
205
- */
206
- trackLocalEdits(doc: Y.Doc): TrackedEdits;
207
- /**
208
- * Roll back the last tracked edit, as INVERSES.
209
- *
210
- * The sender's history grows rather than shrinking. That is not a limitation to work around: it
211
- * is what leaves an auditable "wrote X, was rejected, undid X" trail, and what lets the
212
- * superseding update carry the rejected operations plus their inverses so causality survives.
213
- *
214
- * **PRECONDITION: roll back before making further local edits.** Yjs's UndoManager undoes the
215
- * most recent stack item, and it cannot undo one out of order — so a sender that keeps editing
216
- * after a rejection arrives and then rolls back would undo the WRONG transaction. §3.2's
217
- * ordering is steps 2 then 3 for exactly this reason: roll back, THEN do new work, THEN
218
- * publish the supersession that carries all three. A caller that needs to interleave has a
219
- * genuine design question, not a call-order detail, and it belongs in the unit that wires
220
- * publish to the receive path.
221
- */
222
- rollback(tracked: TrackedEdits): void;
223
- }
224
- //# sourceMappingURL=document-rejection.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"document-rejection.d.ts","sourceRoot":"","sources":["../src/document-rejection.ts"],"names":[],"mappings":"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"}
@@ -1,374 +0,0 @@
1
- /**
2
- * DOD-DOC-REJECT-1 — rejection and supersession (§3.2, §16.7-2).
3
- *
4
- * ── WHY SUPERSESSION, AND NOT "BOTH SIDES ROLL BACK" ──────────────────────────────────────────
5
- *
6
- * The naive protocol is: the receiver discards, the sender undoes locally, and both return to the
7
- * pre-update state. It does not work, and the reason is a property of CRDTs rather than a bug.
8
- *
9
- * **Yjs undo adds INVERSES; it does not erase.** The rejected operations stay in the sender's
10
- * document. So every later update the sender computes against the receiver's state vector
11
- * re-transmits them, and the receiver — which refuses to hold them — can never integrate the
12
- * legitimate work stacked causally on top, because Yjs will not apply operations whose
13
- * predecessors are missing. A permanent causal gap, from a protocol that looked symmetric.
14
- *
15
- * The protocol that works (§3.2):
16
- * 1. The receiver rejects with a REASON — a protocol message and its own `0x05` leaf, never a
17
- * silent drop. The update goes to quarantine, held rather than discarded.
18
- * 2. The sender rolls back locally, which emits inverses into its own log and leaves an
19
- * auditable "wrote X, was rejected, undid X" trail.
20
- * 3. The sender publishes a SUPERSEDING update against the receiver's state vector, which
21
- * necessarily carries the rejected operations PLUS their inverses plus any new work.
22
- * 4. The receiver validates the now-clean projected diff — the rejected content nets to zero —
23
- * admits it, and clears the quarantine. Causality intact, both parties converge, and the
24
- * rejected content survives only as inert tombstones.
25
- *
26
- * ── SCOPE ─────────────────────────────────────────────────────────────────────────────────────
27
- *
28
- * This proves the protocol against STORE-1's local envelope log. The CBOR wire encoding is
29
- * DOD-DOC-ENVELOPE-1's job and the cross-daemon proof is DOD-DOC-E2E-REJECT-1's.
30
- */
31
- import { createHash } from "node:crypto";
32
- import * as Y from "yjs";
33
- /**
34
- * The document stalls on the THIRD rejected round: the original refusal, one superseding attempt,
35
- * and no more (§16.7-2 "one retry, then freeze").
36
- *
37
- * Counted in rounds rather than retries because the previous spelling — a `REJECTION_RETRY_LIMIT`
38
- * of 1 compared as `round > LIMIT + 1` — permitted two retries under a name that said one, which
39
- * is the kind of thing the next edit gets wrong.
40
- *
41
- * Bounded at all because an unbounded retry loop between two daemons that disagree is not
42
- * convergence, it is a hot loop neither operator can see. Stalling is the visible failure.
43
- */
44
- export const MAX_REJECTED_ROUNDS = 3;
45
- export class DocumentRejections {
46
- #store;
47
- #logger;
48
- constructor(store, logger) {
49
- this.#store = store;
50
- this.#logger = logger;
51
- }
52
- /**
53
- * Record a rejection: a `0x05` row referencing the rejected envelope, the quarantined bytes
54
- * held, and a policy record carrying the reason.
55
- *
56
- * The envelope log is append-only, so this is a NEW ROW — nothing is edited or removed.
57
- *
58
- * ── HOW A REFUSAL IS ACTUALLY REALIZED, AND WHY NOT THE WAY §9 SAYS ─────────────────────────
59
- *
60
- * §9 phrases effectiveness as a replay-time set property: "an update leaf is effective iff no
61
- * rejection leaf references it". Implemented literally that is unsound, and it was measured
62
- * rather than argued. Sender publishes a base, then a refused update, then rolls back and
63
- * supersedes. Replaying the log while SKIPPING the refused leaf gives:
64
- *
65
- * text "agreed base. " pendingStructs PRESENT pendingDs PRESENT
66
- *
67
- * The supersession is causally stacked on the refused operations — the rollback is a DELETION of
68
- * those structs and the new work is positioned after them — so dropping them leaves everything
69
- * later permanently pending. The document reads as complete and is silently missing the
70
- * legitimate work. §16.7-5 already retired §9's "document-log order" phrasing; this retires its
71
- * effectiveness phrasing on the same grounds.
72
- *
73
- * What is sound: the receiver NEVER WRITES the refused payload to its log. There is nothing to
74
- * subtract at replay because it was never added, and the peer's supersession — computed against
75
- * the RECEIVER's state vector per §3.2 step 3 — is self-contained. Measured on the same fixture:
76
- *
77
- * text "agreed base. clean text. " pendingStructs null pendingDs null converged true
78
- *
79
- * The refused bytes do travel again inside that supersession, carrying their own inverses, which
80
- * is precisely "inverses, not erasure" (§3.2) — the content nets to zero and survives only as
81
- * tombstones. The bytes we refused live in `document_quarantine`, and the chain bridges across
82
- * the refused envelope so the peer's next link still resolves (see `verifyChainLinkage`).
83
- */
84
- reject(agentId, documentId, input) {
85
- // CHAIN IT. Writing `docPrevHash: null` made every rejection a second GENESIS row for this
86
- // agent, so two rejections forked the chain — and the retry protocol guarantees at least two
87
- // before a stall. `verifyChainLinkage` then refuses, and since `rebuildSnapshot` is how a
88
- // document survives a restart, the document rebuilt until the next daemon start and was
89
- // permanently unopenable after it. Measured. A rejection is this agent's own authored act, so
90
- // it belongs in this agent's own chain.
91
- const rejectionEnvelopeHash = rejectionHash(input.rejectedEnvelopeHash, input.reason, input.nonce);
92
- const appended = this.#store.appendEnvelope(agentId, {
93
- envelopeHash: rejectionEnvelopeHash,
94
- documentId,
95
- senderAgentId: agentId, // WE authored the rejection, whoever authored the update
96
- docPrevHash: this.#store.lastEnvelopeHashBySender(agentId, documentId, agentId),
97
- epochId: 0,
98
- signature: input.signature,
99
- stateVector: input.stateVector,
100
- payload: null, // an audit record carries no content
101
- kind: "rejection",
102
- referencesEnvelopeHash: input.rejectedEnvelopeHash,
103
- createdAtMs: Date.now(),
104
- });
105
- if (!appended) {
106
- // The store tells callers whether a row was written precisely so this is not inferred. A
107
- // duplicate must not advance the retry round, or a document reaches `stalled` with fewer
108
- // rejection leaves than rounds and an auditor replaying the log cannot see why.
109
- this.#logger.warn("document.rejection.duplicate", {
110
- documentId,
111
- rejectedEnvelopeHash: input.rejectedEnvelopeHash,
112
- reason: input.reason,
113
- });
114
- return { stalled: this.#isStalled(agentId, documentId), round: this.#round(agentId, documentId) };
115
- }
116
- // PERSISTED, not remembered. The 0x05 leaf references these bytes; holding them in a Map
117
- // meant the reference outlived the thing it referenced across a restart.
118
- const held = this.#store.holdQuarantined(agentId, {
119
- documentId,
120
- rejectionEnvelopeHash,
121
- rejectedEnvelopeHash: input.rejectedEnvelopeHash,
122
- // The refused envelope's own author and chain link, so `verifyChainLinkage` can bridge it —
123
- // the peer chains its supersession onto an envelope our log deliberately never holds.
124
- rejectedSenderAgentId: input.senderAgentId,
125
- rejectedDocPrevHash: input.rejectedDocPrevHash,
126
- // COPY: the caller's buffer may be a pooled network read, and a 0x05 leaf must reference
127
- // the bytes that were actually refused.
128
- payload: new Uint8Array(input.quarantined),
129
- reason: input.reason,
130
- detail: input.detail,
131
- // The gate produces these deliberately; dropping them leaves an operator unable to see
132
- // WHICH rule refused or WHAT number was exceeded.
133
- rule: input.rule,
134
- limitName: input.limit?.name,
135
- limitValue: input.limit?.limit,
136
- limitActual: input.limit?.actual,
137
- createdAtMs: Date.now(),
138
- });
139
- if (!held) {
140
- // Cannot happen while the leaf hash is unique per rejection, which the append above already
141
- // established. Logged rather than assumed: the previous key silently dropped every round
142
- // after the first, and the way that stayed invisible was precisely that nothing said so.
143
- this.#logger.error("document.rejection.quarantine_not_written", {
144
- documentId,
145
- rejectionEnvelopeHash,
146
- rejectedEnvelopeHash: input.rejectedEnvelopeHash,
147
- });
148
- }
149
- const round = this.#round(agentId, documentId);
150
- // The policy record — on BOTH sides, per §3.2. This is the sending half; the receiving half
151
- // is written when a rejection arrives.
152
- this.#logger.warn("document.rejection.sent", {
153
- documentId,
154
- senderAgentId: input.senderAgentId,
155
- reason: input.reason,
156
- detail: input.detail,
157
- // Carried, not merely stored: an operator asking "why was this refused" needs the rule and
158
- // the number, and a column no surface reads is a column that is not there.
159
- rule: input.rule,
160
- limitName: input.limit?.name,
161
- limitValue: input.limit?.limit,
162
- limitActual: input.limit?.actual,
163
- round,
164
- });
165
- const stalled = round >= MAX_REJECTED_ROUNDS;
166
- const alreadyStalled = this.#store.getDocument(agentId, documentId)?.status === "stalled";
167
- if (stalled && !alreadyStalled) {
168
- this.#store.setDocumentStatus(agentId, documentId, "stalled");
169
- // Once, not on every subsequent refusal — a stalled document that keeps shouting is noise
170
- // an operator learns to filter.
171
- this.#logger.error("document.stalled", {
172
- documentId,
173
- reason: input.reason,
174
- detail: input.detail,
175
- rounds: round,
176
- });
177
- }
178
- return { stalled, round };
179
- }
180
- /**
181
- * Record a rejection ARRIVING from the peer — the receiving half of §3.2's "both sides".
182
- *
183
- * ── THE ROUTING DECISION (the DoD requires it resolved in-unit) ─────────────────────────────
184
- *
185
- * A document rejection is written **daemon-side**, into this document's own log and quarantine,
186
- * NOT through the gateway record store's `source` discriminator.
187
- *
188
- * The gateway's record store exists for SCREENING verdicts, and most V1 rejection reasons are
189
- * not screening at all — `append_only`, the receiver-local limits, malformed updates, unresolved
190
- * dependencies. Routing every document rejection through a screening store would file structural
191
- * protocol events as policy verdicts, and it would couple this unit to a schema owned by a
192
- * component that is not involved. DOD-DOC-SCREEN-1 is parked, so that coupling would also have
193
- * to be built speculatively and unwound if screening lands differently.
194
- *
195
- * When SCREEN-1 does land, a rejection whose reason came from the screening rule can ADDITIONALLY
196
- * write a gateway record — the discriminator exists for exactly that, and adding it later costs
197
- * nothing, whereas removing a premature coupling costs a migration.
198
- */
199
- recordIncomingRejection(agentId, documentId, input) {
200
- // DURABLE, not a log line. Everything the PUBLISHING operator needs depends on this surviving
201
- // a restart: why their work was refused, and how many rounds remain before the document
202
- // stalls. It also has to exist for the retry bound to bind at all — the round was counted from
203
- // rejections this agent AUTHORED, which on a pure publisher is zero forever, so the loop the
204
- // limit exists to stop was the one side that had no limit.
205
- const written = this.#store.recordRejectionReceived(agentId, {
206
- documentId,
207
- rejectionEnvelopeHash: input.rejectionEnvelopeHash,
208
- rejectedEnvelopeHash: input.rejectedEnvelopeHash,
209
- fromAgentId: input.fromAgentId,
210
- reason: input.reason,
211
- detail: input.detail,
212
- createdAtMs: Date.now(),
213
- });
214
- const round = this.#store.countRejectionsReceived(agentId, documentId);
215
- if (!written) {
216
- this.#logger.warn("document.rejection.received_duplicate", {
217
- documentId,
218
- rejectionEnvelopeHash: input.rejectionEnvelopeHash,
219
- round,
220
- });
221
- return { stalled: this.#isStalled(agentId, documentId), round };
222
- }
223
- this.#logger.warn("document.rejection.received", {
224
- documentId,
225
- fromAgentId: input.fromAgentId,
226
- rejectedEnvelopeHash: input.rejectedEnvelopeHash,
227
- reason: input.reason,
228
- detail: input.detail,
229
- round,
230
- });
231
- // The publisher stops superseding on the same threshold the receiver stops accepting on. Two
232
- // sides of one bound: without this, the receiver freezes and the sender keeps retrying into a
233
- // document that will never take it.
234
- const stalled = round >= MAX_REJECTED_ROUNDS;
235
- if (stalled && !this.#isStalled(agentId, documentId)) {
236
- this.#store.setDocumentStatus(agentId, documentId, "stalled");
237
- this.#logger.error("document.stalled", {
238
- documentId,
239
- reason: input.reason,
240
- detail: input.detail,
241
- rounds: round,
242
- side: "publisher",
243
- });
244
- }
245
- return { stalled, round };
246
- }
247
- /** Entries held for this document — never admitted, never discarded (§3.2). From the store. */
248
- quarantined(agentId, documentId) {
249
- return this.#store.listQuarantined(agentId, documentId).map((r) => ({
250
- rejectedEnvelopeHash: r.rejectedEnvelopeHash,
251
- quarantined: r.payload,
252
- reason: r.reason,
253
- detail: r.detail,
254
- rule: r.rule,
255
- limitName: r.limitName,
256
- limitValue: r.limitValue,
257
- limitActual: r.limitActual,
258
- }));
259
- }
260
- /** Clear one entry once its superseding update has been admitted (§3.2 step 4). */
261
- clearQuarantine(agentId, documentId, rejectedEnvelopeHash) {
262
- // Only announce an admission that actually happened — an event that fires on a no-op is a
263
- // signal on the wrong case.
264
- if (this.#store.releaseQuarantined(agentId, documentId, rejectedEnvelopeHash)) {
265
- this.#logger.info("document.supersession.admitted", { documentId, rejectedEnvelopeHash });
266
- }
267
- }
268
- /**
269
- * Whether this document still accepts updates.
270
- *
271
- * A stalled document REFUSES, naming the reason it stalled — both operators need to see why,
272
- * because a document that silently stops converging is the failure this exists to prevent.
273
- */
274
- acceptsUpdates(agentId, documentId) {
275
- // Read the STORE, not memory. The status was persisted while the flag that gated this check
276
- // was not, so after a restart the document row said `stalled` while the daemon happily
277
- // accepted updates on it — the system reporting two contradictory states at once.
278
- if (this.#isStalled(agentId, documentId)) {
279
- const held = this.#store.listQuarantined(agentId, documentId);
280
- const last = held[held.length - 1];
281
- return {
282
- ok: false,
283
- reason: "document_stalled",
284
- detail: `this document stopped accepting updates after ` +
285
- `${this.#round(agentId, documentId)} rejected rounds` +
286
- (last ? `; the most recent reason was ${last.reason}` : ""),
287
- };
288
- }
289
- return { ok: true };
290
- }
291
- /**
292
- * Start tracking local edits so a rejection can be rolled back.
293
- *
294
- * Yjs's own UndoManager, deliberately: rolling back by hand would mean computing inverses, and
295
- * the inverse of a CRDT operation is not something to hand-roll — the whole reason supersession
296
- * works is that Yjs's undo produces operations that compose correctly with everything stacked
297
- * on top of them.
298
- */
299
- trackLocalEdits(doc) {
300
- // The two roots this codebase's write path projects from, taken through their TYPED getters.
301
- //
302
- // Not the `doc.share` placeholders: `doc.get(name)` hands back the untyped AbstractType, and
303
- // the typed getter later instantiates a DIFFERENT object — so the UndoManager would watch a
304
- // root nobody edits and `undo()` would silently do nothing. Caught by the out-of-order guard
305
- // below, which is the guard earning its keep on its first outing.
306
- //
307
- // Instantiating these two as Text and Map is not the guessed-type hazard GATE-1 measured:
308
- // the write path DEFINES them as Text and Map. A document that puts content under any other
309
- // root is not tracked here, and that is a real gap — recorded rather than papered over,
310
- // because it belongs with whichever unit lets a document declare its own roots.
311
- const undoManager = new Y.UndoManager([doc.getText("content"), doc.getMap("data")], {
312
- captureTimeout: 0,
313
- });
314
- return {
315
- doc,
316
- undoManager,
317
- depthAtTracking: undoManager.undoStack.length,
318
- dispose: () => undoManager.destroy(),
319
- };
320
- }
321
- /**
322
- * Roll back the last tracked edit, as INVERSES.
323
- *
324
- * The sender's history grows rather than shrinking. That is not a limitation to work around: it
325
- * is what leaves an auditable "wrote X, was rejected, undid X" trail, and what lets the
326
- * superseding update carry the rejected operations plus their inverses so causality survives.
327
- *
328
- * **PRECONDITION: roll back before making further local edits.** Yjs's UndoManager undoes the
329
- * most recent stack item, and it cannot undo one out of order — so a sender that keeps editing
330
- * after a rejection arrives and then rolls back would undo the WRONG transaction. §3.2's
331
- * ordering is steps 2 then 3 for exactly this reason: roll back, THEN do new work, THEN
332
- * publish the supersession that carries all three. A caller that needs to interleave has a
333
- * genuine design question, not a call-order detail, and it belongs in the unit that wires
334
- * publish to the receive path.
335
- */
336
- rollback(tracked) {
337
- // REFUSE rather than undo the wrong thing. Measured, the unguarded version had three failure
338
- // modes that all reported success: nothing tracked (silent no-op), an untracked root (silent
339
- // no-op), and — the damaging one — a sender that kept editing after the rejection arrived,
340
- // where undo removed the agent's LEGITIMATE later work and KEPT the refused content. The
341
- // supersession then re-ships the refused bytes, is rejected again, and the document stalls
342
- // with a reason pointing at the peer while the operator's writing is gone.
343
- const depth = tracked.undoManager.undoStack.length;
344
- if (depth !== tracked.depthAtTracking + 1) {
345
- throw new Error(`document_rollback_out_of_order: ${depth - tracked.depthAtTracking} local edit(s) are ` +
346
- `stacked since tracking began, and Yjs can only undo the most recent — rolling back now ` +
347
- `would discard the wrong work. Roll back before making further local edits (§3.2 step 2).`);
348
- }
349
- if (tracked.undoManager.undo() === null) {
350
- throw new Error("document_rollback_nothing_tracked: no tracked edit to roll back — the rejected update " +
351
- "was not produced through this tracker");
352
- }
353
- }
354
- /** Derived from the log, not remembered — so it survives a restart. */
355
- #round(agentId, documentId) {
356
- // Scoped to the rejections THIS agent authored. A mutual exchange puts both directions' 0x05
357
- // leaves in one document log, so an unscoped count conflated them and a document stalled at
358
- // half the intended rounds the moment the peer also rejected something.
359
- return this.#store.countRejections(agentId, documentId, agentId);
360
- }
361
- #isStalled(agentId, documentId) {
362
- return this.#store.getDocument(agentId, documentId)?.status === "stalled";
363
- }
364
- }
365
- /** A rejection's own envelope hash — distinct per rejected envelope and reason. */
366
- function rejectionHash(rejectedEnvelopeHash, reason, nonce) {
367
- // The nonce is what stops two rejections of the same envelope for the same reason collapsing
368
- // into one row — which would let a document reach `stalled` with fewer leaves than rounds.
369
- // DELIBERATELY a different construction from ENVELOPE-1's update hash (a CBOR-array digest), though both land in the envelope_hash column and the same per-sender chain. The preimage shapes cannot collide, and unifying them would mean signing a rejection as a document update.
370
- return createHash("sha256")
371
- .update(`rejection:${rejectedEnvelopeHash}:${reason}:${nonce}`, "utf8")
372
- .digest("hex");
373
- }
374
- //# sourceMappingURL=document-rejection.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"document-rejection.js","sourceRoot":"","sources":["../src/document-rejection.ts"],"names":[],"mappings":"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"}