@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,196 @@
1
+ /**
2
+ * CELLO Daemon — REFUSALS THE OPERATOR CAN ACTUALLY SEE
3
+ *
4
+ * Split out of `session-node-manager.ts` by 037-SESSIONCORE.
5
+ *
6
+ * ⚠️ THE POINT OF THIS MODULE IS THAT A REFUSAL HAS A READER. Every inbound refusal already logged a
7
+ * reason, an impact and a guidance, and they were good — and they had no consumer. From the
8
+ * receiving operator's chair a refused message simply never arrives: the conversation goes quiet
9
+ * with a full explanation sitting in a file they have no reason to open, and they conclude the other
10
+ * person stopped replying.
11
+ *
12
+ * DURABLE, and that is the half that makes it useful — a restart must not lose the notice, because
13
+ * the question it answers ("why did they go quiet?") outlives the process that refused.
14
+ *
15
+ * Moved verbatim, comments included.
16
+ */
17
+ import type { Logger } from "./types.js";
18
+ import type { DaemonDatabase } from "./sqlcipher-db.js";
19
+ import type { SessionQueries } from "./session-queries.js";
20
+ import { type RefusalKind } from "./refusal-reasons.js";
21
+ import { type RefusalNotice } from "./session-node-types.js";
22
+ /** What the refusal surface needs from the manager. */
23
+ export interface RefusalNoticeContext {
24
+ readonly logger: Logger;
25
+ readonly queries: SessionQueries;
26
+ /** A function: the manager opens its database after construction. Re-exposed below as `#db`. */
27
+ db(): DaemonDatabase | null;
28
+ requireAgentId(agentName: string): string;
29
+ sessionKey(agentName: string, sessionId: string): string;
30
+ unkey(key: string, agentName: string): string | null;
31
+ }
32
+ export declare class RefusalNotices {
33
+ #private;
34
+ constructor(ctx: RefusalNoticeContext);
35
+ /**
36
+ * The one read path behind both doors. `sessionId` narrows it; omitted, it spans the agent.
37
+ *
38
+ * A single implementation on purpose: the per-consumer rule and the order-of-magnitude rule are
39
+ * the two properties this unit must not lose, and two copies of them is two things to keep true.
40
+ */
41
+ drainRefusals(agentName: string, consumerId: string, sessionId?: string): {
42
+ notices: RefusalNotice[];
43
+ truncated: boolean;
44
+ };
45
+ /**
46
+ * ─── DOD-M15-NO-SILENT-REFUSAL-1: refusals the RECEIVING operator can actually see ────────────
47
+ *
48
+ * Every inbound refusal already logs a `reason`, an `impact` and a `guidance` — and they are
49
+ * good. They had no reader. From the receiving operator's chair a refused message simply never
50
+ * arrives: the conversation goes quiet with a full explanation sitting in a file they have no
51
+ * reason to open, and they conclude the other person stopped replying.
52
+ *
53
+ * **DURABLE, and that is the half that makes this useful.** The predecessor kept notices in a
54
+ * `Map` on this instance and drained them on the receive path for one session. So a restart lost
55
+ * them, and an agent NOBODY IS ATTENDING lost them too — the connection is live, the daemon is
56
+ * up, and the notice only ever reaches whoever happens to call `cello_receive` on that exact
57
+ * session. `cello_check_notifications` now reads them as its own inbox category.
58
+ *
59
+ * **DEDUPLICATED PER SESSION PER REASON, and that is the design, not an optimisation.** A skewed
60
+ * peer turns one problem into a flood: the first refusal of a kind is the signal, the ninetieth is
61
+ * noise that trains the operator to ignore the surface. `count` keeps the scale visible without
62
+ * repeating the alert.
63
+ *
64
+ * **NEVER carries the content.** It failed verification; surfacing it is the injection path the
65
+ * cross-check exists to close. The operator learns that a message was refused and why — never
66
+ * what it said.
67
+ */
68
+ /**
69
+ * Record an inbound refusal for the operator. First of its kind per session is the signal.
70
+ *
71
+ * ⚠️ **DOES NOT THROW, and that is a decision with a cost — stated so it is not mistaken for an
72
+ * oversight.** Every call site here has already decided to refuse and is about to return a reason
73
+ * to its caller; a throw would replace that clean refusal with an exception on the ingest path,
74
+ * changing what the SENDER observes because this daemon could not file a note. So a persistence
75
+ * failure is logged at ERROR under `session.refusal.persist.failed`, carrying the reason, the
76
+ * impact and the guidance verbatim — the forensic record survives even when the operator-facing
77
+ * one does not. It is not silent; it is one surface short, and the log says which notice was lost.
78
+ */
79
+ noteContentRefusal(agentName: string, sessionId: string, reason: string,
80
+ /**
81
+ * ALL THREE REQUIRED, and that is the enforcement rather than the convention.
82
+ *
83
+ * The DoD clause is "every reason calls this with an impact and a guidance", and an optional
84
+ * field makes that a thing a reviewer checks by reading thirteen call sites. `kind` is required
85
+ * for the same reason one level up: the header over a list of refusals is composed from it, and
86
+ * a notice that could omit it would silently inherit whichever header happened to be first.
87
+ */
88
+ detail: {
89
+ kind: RefusalKind;
90
+ impact: string;
91
+ guidance: string;
92
+ }): void;
93
+ /**
94
+ * DOD-M15-NO-SILENT-REFUSAL-1 — the per-session byte cap, from the operator's chair.
95
+ *
96
+ * This is the harshest refusal on the inbound path and the one that reads least like a fault:
97
+ * once the cap is crossed, EVERY later message from that sender on that session is refused, for
98
+ * the life of the session. The counterparty is told nothing either, so from both chairs the other
99
+ * person simply stopped replying.
100
+ *
101
+ * One method rather than two copies because the cap is checked twice — once before the screening
102
+ * await and once after, against freshly-read totals — and a notice that differs between the two
103
+ * would describe a different refusal depending on timing.
104
+ */
105
+ /**
106
+ * DOD-M15-REFUSEDEVIDENCE-1 — **THE BYTE CAP RETAINS NOTHING, and that is a ruling, not an
107
+ * oversight.**
108
+ *
109
+ * Retention is universal everywhere else in this method. Here it is not, because retaining would
110
+ * defeat the very bound it enforces: a session already over its storage budget cannot be given
111
+ * more storage as a reward for exceeding it, and `#getReceivedBytesTotal` counts quarantined bytes
112
+ * precisely so that budget is honest.
113
+ *
114
+ * Andre, 2026-09-03: *"The message limit is the message limit, already handled by the cap. If
115
+ * you're unknown and you have 25 MB and you just tried to send me one gig, well that's it."*
116
+ *
117
+ * The ABUSE is still evidenced — this notice records the reason, the cap and the tier, and every
118
+ * message the session did retain is still there. What is not kept is the oversized payload.
119
+ */
120
+ noteSizeCapRefusal(agentName: string, sessionId: string, cap: number, tier: number): void;
121
+ /**
122
+ * Drain the refusals a GIVEN CONSUMER has not been shown yet, and remember what it was shown.
123
+ *
124
+ * ─── Why this is keyed by consumer, and not by a single flag ──────────────────────────────────
125
+ *
126
+ * It used to set one `surfaced: boolean` on the notice. Two MCP windows attending the same agent
127
+ * is the ordinary case, and under that flag whoever read FIRST consumed the notice — the second
128
+ * window was told nothing, permanently. **That is the same defect `takeReceivedContent` had**, and
129
+ * the comment above the delivery loop in `session-content-handlers.ts` spells out why it was
130
+ * removed: *"reading is non-destructive by construction. Nothing one consumer does mutates state
131
+ * another consumer reads."*
132
+ *
133
+ * ─── Why the count has a reader ───────────────────────────────────────────────────────────────
134
+ *
135
+ * A reason RE-ANNOUNCES to a consumer when its count has grown by an order of magnitude since that
136
+ * consumer last saw it (1 → 10 → 100 → …), marked `repeat: true`. That keeps the first refusal the
137
+ * signal and the ninetieth silent, which is the dedup's point, while still making a skew that has
138
+ * swallowed hundreds of messages visible — at a handful of announcements per session, not one per
139
+ * message.
140
+ *
141
+ * ─── What a restart does, deliberately ────────────────────────────────────────────────────────
142
+ *
143
+ * The notices survive; the read state is keyed by IPC connection id, which does not. So after a
144
+ * restart every notice is unseen again and the next reader is told. That is the correct direction:
145
+ * a fresh window has not been told anything, and re-announcing costs one line where staying silent
146
+ * costs the whole point of storing it.
147
+ */
148
+ takeContentRefusals(agentName: string, sessionId: string,
149
+ /**
150
+ * REQUIRED, deliberately — no default.
151
+ *
152
+ * It had one (`"default"`), and a default is the defect this method was rewritten to remove,
153
+ * lying in wait: any future call site that omits the argument silently shares ONE bucket across
154
+ * every window, the first reader consumes the notice for all the others, and nothing fails to
155
+ * compile and no test goes red. The parameter existing is not the protection; being unable to
156
+ * forget it is.
157
+ */
158
+ consumerId: string): Array<Omit<RefusalNotice, "sessionId">>;
159
+ /**
160
+ * DOD-M15-NO-SILENT-REFUSAL-1: the operator has seen these and does not want to see them again.
161
+ *
162
+ * ⚠️ **WITHOUT THIS THE NOTICES ARE PERMANENT, and that is what makes people stop reading the
163
+ * inbox.** "Already shown you" is tracked per WINDOW — a new MCP connection has been told nothing,
164
+ * so it is told everything. Someone on an older build messages you, you sort it out with them,
165
+ * they upgrade, and every new session you ever open still opens with that refusal.
166
+ *
167
+ * Dismissing does NOT turn anything off. If the cause fires again the notice comes back, because
168
+ * a fresh refusal writes a fresh row. The operator is saying "I know", not "stop telling me".
169
+ *
170
+ * Returns how many were cleared, so the caller can say so rather than claiming a silent success.
171
+ */
172
+ dismissContentRefusals(agentName: string, sessionId: string): number;
173
+ /**
174
+ * DOD-M15-NO-SILENT-REFUSAL-1: every unshown refusal for an agent, ACROSS its sessions.
175
+ *
176
+ * The inbox's door. `takeContentRefusals` answers for one session because its caller already holds
177
+ * one; `cello_check_notifications` holds an agent and nothing else, and the case this whole line
178
+ * exists for is that nobody is attending any of that agent's sessions — so a per-session read
179
+ * cannot reach it. Same store, same per-consumer rule, same re-announce.
180
+ */
181
+ takeAgentContentRefusals(agentName: string, consumerId: string): {
182
+ notices: RefusalNotice[];
183
+ truncated: boolean;
184
+ };
185
+ /**
186
+ * Drop the IN-MEMORY fallback notices for one session.
187
+ *
188
+ * ⚠️ THE DURABLE ROWS ARE NOT TOUCHED, and the omission is deliberate rather than forgotten. They
189
+ * live in `content_refusal_notices` keyed on agent_id + session_id, and the question they answer —
190
+ * "why did my counterparty go quiet?" — outlives the session that produced it. Only the in-memory
191
+ * fallback, which exists for the case where the write to disk failed, is dropped here; leaving it
192
+ * would let a store that is already in trouble grow without bound in memory as well.
193
+ */
194
+ evictSession(agentName: string, sessionId: string): void;
195
+ }
196
+ //# sourceMappingURL=refusal-notices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refusal-notices.d.ts","sourceRoot":"","sources":["../src/refusal-notices.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,yBAAyB,CAAC;AAEjC,uDAAuD;AACvD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,gGAAgG;IAChG,EAAE,IAAI,cAAc,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1C,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IACzD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACtD;AAED,qBAAa,cAAc;;gBAGb,GAAG,EAAE,oBAAoB;IAkBrC;;;;;OAKG;IACH,aAAa,CACX,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB;QAAE,OAAO,EAAE,aAAa,EAAE,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE;IAgLnD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH;;;;;;;;;;OAUG;IACH,kBAAkB,CAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM;IACd;;;;;;;OAOG;IACH,MAAM,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAC9D,IAAI;IA0FP;;;;;;;;;;;OAWG;IACH;;;;;;;;;;;;;;OAcG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAuBzF;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,mBAAmB,CACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM;IACjB;;;;;;;;OAQG;IACH,UAAU,EAAE,MAAM,GACjB,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAS1C;;;;;;;;;;;;OAYG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAapE;;;;;;;OAOG;IACH,wBAAwB,CACtB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB;QAAE,OAAO,EAAE,aAAa,EAAE,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE;IAInD;;;;;;;;OAQG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;CAGzD"}