instar 1.3.499 → 1.3.501
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/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +407 -6
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +10 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +1 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +69 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/ReapGuard.d.ts +24 -0
- package/dist/core/ReapGuard.d.ts.map +1 -1
- package/dist/core/ReapGuard.js +62 -0
- package/dist/core/ReapGuard.js.map +1 -1
- package/dist/core/SessionManager.d.ts +32 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +74 -2
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/WorkEvidence.d.ts +45 -0
- package/dist/core/WorkEvidence.d.ts.map +1 -0
- package/dist/core/WorkEvidence.js +88 -0
- package/dist/core/WorkEvidence.js.map +1 -0
- package/dist/core/componentCategories.d.ts.map +1 -1
- package/dist/core/componentCategories.js +3 -0
- package/dist/core/componentCategories.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +5 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/types.d.ts +50 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/messaging/NotificationBatcher.d.ts +12 -0
- package/dist/messaging/NotificationBatcher.d.ts.map +1 -1
- package/dist/messaging/NotificationBatcher.js +36 -0
- package/dist/messaging/NotificationBatcher.js.map +1 -1
- package/dist/messaging/pending-relay-store.d.ts +67 -8
- package/dist/messaging/pending-relay-store.d.ts.map +1 -1
- package/dist/messaging/pending-relay-store.js +151 -14
- package/dist/messaging/pending-relay-store.js.map +1 -1
- package/dist/messaging/reap-notice-delivery-id.d.ts +37 -0
- package/dist/messaging/reap-notice-delivery-id.d.ts.map +1 -0
- package/dist/messaging/reap-notice-delivery-id.js +52 -0
- package/dist/messaging/reap-notice-delivery-id.js.map +1 -0
- package/dist/monitoring/QuotaManager.d.ts +6 -0
- package/dist/monitoring/QuotaManager.d.ts.map +1 -1
- package/dist/monitoring/QuotaManager.js +11 -0
- package/dist/monitoring/QuotaManager.js.map +1 -1
- package/dist/monitoring/ReapLog.d.ts +39 -4
- package/dist/monitoring/ReapLog.d.ts.map +1 -1
- package/dist/monitoring/ReapLog.js +54 -4
- package/dist/monitoring/ReapLog.js.map +1 -1
- package/dist/monitoring/ReapNoticeDrain.d.ts +113 -0
- package/dist/monitoring/ReapNoticeDrain.d.ts.map +1 -0
- package/dist/monitoring/ReapNoticeDrain.js +231 -0
- package/dist/monitoring/ReapNoticeDrain.js.map +1 -0
- package/dist/monitoring/ReapNotifier.d.ts +89 -18
- package/dist/monitoring/ReapNotifier.d.ts.map +1 -1
- package/dist/monitoring/ReapNotifier.js +329 -22
- package/dist/monitoring/ReapNotifier.js.map +1 -1
- package/dist/monitoring/ResumeQueue.d.ts +223 -0
- package/dist/monitoring/ResumeQueue.d.ts.map +1 -0
- package/dist/monitoring/ResumeQueue.js +600 -0
- package/dist/monitoring/ResumeQueue.js.map +1 -0
- package/dist/monitoring/ResumeQueueDrainer.d.ts +151 -0
- package/dist/monitoring/ResumeQueueDrainer.d.ts.map +1 -0
- package/dist/monitoring/ResumeQueueDrainer.js +420 -0
- package/dist/monitoring/ResumeQueueDrainer.js.map +1 -0
- package/dist/monitoring/SessionMigrator.d.ts +10 -0
- package/dist/monitoring/SessionMigrator.d.ts.map +1 -1
- package/dist/monitoring/SessionMigrator.js +43 -1
- package/dist/monitoring/SessionMigrator.js.map +1 -1
- package/dist/monitoring/SessionReaper.d.ts +1 -0
- package/dist/monitoring/SessionReaper.d.ts.map +1 -1
- package/dist/monitoring/SessionReaper.js +5 -0
- package/dist/monitoring/SessionReaper.js.map +1 -1
- package/dist/monitoring/delivery-failure-sentinel.d.ts.map +1 -1
- package/dist/monitoring/delivery-failure-sentinel.js +7 -3
- package/dist/monitoring/delivery-failure-sentinel.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +4 -3
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +5 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +3 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +8 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +94 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/skills/spec-converge/SKILL.md +23 -0
- package/src/data/builtin-manifest.json +65 -65
- package/src/data/state-coherence-registry.json +14 -1
- package/src/scaffold/templates.ts +4 -3
- package/upgrades/1.3.500.md +43 -0
- package/upgrades/1.3.501.md +51 -0
- package/upgrades/side-effects/conformance-gate-autoinvoke.md +58 -0
- package/upgrades/side-effects/reap-notify-resume-queue.md +89 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReapNoticeDrain — the ALWAYS-ON delivery loop for reap notices
|
|
3
|
+
* (reap-notify spec R1.3, tier0 supervision — deterministic delivery of
|
|
4
|
+
* pre-authored template content, declared per P7).
|
|
5
|
+
*
|
|
6
|
+
* Why it exists: the durable layer's existing drain (DeliveryFailureSentinel)
|
|
7
|
+
* is default-OFF fleet-wide, so "DFS will retry it" is false on a default
|
|
8
|
+
* agent — the round-2 foundation audit's central finding. The R1 guarantee
|
|
9
|
+
* ("every non-silent reap produces a durable, retried, recorded notice")
|
|
10
|
+
* therefore ships its OWN small always-on drain, independent of the DFS flag.
|
|
11
|
+
*
|
|
12
|
+
* Contract:
|
|
13
|
+
* - Claims ONLY rows inside the `reap-notify:` PK range (index-compatible
|
|
14
|
+
* range predicate; DFS claims the complement). The claim itself is a CAS
|
|
15
|
+
* UPDATE — two drains can never double-claim a row.
|
|
16
|
+
* - 30s tick; idle cost is one indexed claim query (~zero on an empty store).
|
|
17
|
+
* - Per-pass send cap (15) keeps a 500-topic storm under Telegram's
|
|
18
|
+
* per-group rate: 500 durable rows drain over ~17 minutes (R1.5's global
|
|
19
|
+
* release throttle); the remainder is picked up next tick.
|
|
20
|
+
* - Delivery is the DIRECT adapter send (`sendToTopic`) — NOT the
|
|
21
|
+
* /telegram/reply relay — so the relay's tone gate, whoami check, and
|
|
22
|
+
* duplicate-suppression are structurally off this path (notices carry
|
|
23
|
+
* per-notice distinct content anyway).
|
|
24
|
+
* - Bounded retries: store-backed exponential backoff on the existing
|
|
25
|
+
* attempts/next_attempt_at columns; at `maxAttempts` (8) the row is
|
|
26
|
+
* escalated terminally into ONE aggregated attention item (updated in
|
|
27
|
+
* place — never per-row items; P17).
|
|
28
|
+
* - Outcome records (R1.3 pairs): the terminal record (`sent` /
|
|
29
|
+
* `send-failed-escalated`) is appended HERE, event-driven from the drain
|
|
30
|
+
* that owns the terminal transition.
|
|
31
|
+
* - Loop brakes (P19, declared): backoff + maxAttempts + per-pass cap +
|
|
32
|
+
* terminal escalation; plus a bounded terminal-row cleanup so the
|
|
33
|
+
* always-on lane cannot grow the store unboundedly while DFS's retention
|
|
34
|
+
* pass is off.
|
|
35
|
+
*/
|
|
36
|
+
import { parseReapNotifyDeliveryId } from '../messaging/reap-notice-delivery-id.js';
|
|
37
|
+
export const DEFAULT_REAP_NOTICE_DRAIN_OPTIONS = {
|
|
38
|
+
tickIntervalMs: 30_000,
|
|
39
|
+
perPassSendCap: 15,
|
|
40
|
+
maxAttempts: 8,
|
|
41
|
+
leaseDurationMs: 120_000,
|
|
42
|
+
backoffBaseMs: 30_000,
|
|
43
|
+
backoffMaxMs: 30 * 60_000,
|
|
44
|
+
terminalRetentionMs: 24 * 3600_000,
|
|
45
|
+
};
|
|
46
|
+
const ESCALATION_ATTENTION_ID = 'reap-notice-drain:escalations';
|
|
47
|
+
export class ReapNoticeDrain {
|
|
48
|
+
deps;
|
|
49
|
+
opts;
|
|
50
|
+
now;
|
|
51
|
+
timer = null;
|
|
52
|
+
ticking = false;
|
|
53
|
+
/** Rolling escalation aggregate since boot (feeds the ONE attention item). */
|
|
54
|
+
escalations = [];
|
|
55
|
+
lastCleanupAt = 0;
|
|
56
|
+
constructor(deps, opts) {
|
|
57
|
+
this.deps = deps;
|
|
58
|
+
this.opts = { ...DEFAULT_REAP_NOTICE_DRAIN_OPTIONS, ...(opts ?? {}) };
|
|
59
|
+
this.now = deps.now ?? (() => Date.now());
|
|
60
|
+
}
|
|
61
|
+
start() {
|
|
62
|
+
if (this.timer)
|
|
63
|
+
return;
|
|
64
|
+
this.timer = setInterval(() => {
|
|
65
|
+
void this.tick().catch(() => {
|
|
66
|
+
/* @silent-fallback-ok — last-resort belt: tick() already guards and
|
|
67
|
+
records every per-row failure durably (attempts/backoff/escalation);
|
|
68
|
+
a throw here would only kill the interval timer. */
|
|
69
|
+
});
|
|
70
|
+
}, this.opts.tickIntervalMs);
|
|
71
|
+
if (typeof this.timer.unref === 'function')
|
|
72
|
+
this.timer.unref();
|
|
73
|
+
}
|
|
74
|
+
stop() {
|
|
75
|
+
if (this.timer) {
|
|
76
|
+
clearInterval(this.timer);
|
|
77
|
+
this.timer = null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** One drain pass. Public so tests (and a manual flush) can drive it. */
|
|
81
|
+
async tick() {
|
|
82
|
+
const counters = { sent: 0, retried: 0, escalated: 0 };
|
|
83
|
+
if (this.ticking)
|
|
84
|
+
return counters; // re-entrancy guard
|
|
85
|
+
this.ticking = true;
|
|
86
|
+
try {
|
|
87
|
+
const nowMs = this.now();
|
|
88
|
+
const nowIso = new Date(nowMs).toISOString();
|
|
89
|
+
let candidates = [];
|
|
90
|
+
try {
|
|
91
|
+
candidates = this.deps.store
|
|
92
|
+
.selectClaimableReapNotices(nowIso, this.opts.perPassSendCap * 2)
|
|
93
|
+
.filter((row) => row.state === 'queued' || this.isLeaseStale(row, nowMs));
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
console.warn('[reap-notice-drain] select raised:', err);
|
|
97
|
+
return counters;
|
|
98
|
+
}
|
|
99
|
+
let processed = 0;
|
|
100
|
+
for (const row of candidates) {
|
|
101
|
+
if (processed >= this.opts.perPassSendCap)
|
|
102
|
+
break;
|
|
103
|
+
const leaseUntil = new Date(nowMs + this.opts.leaseDurationMs).toISOString();
|
|
104
|
+
const claimedBy = `${this.deps.bootId}:${process.pid}:${leaseUntil}`;
|
|
105
|
+
let won = false;
|
|
106
|
+
try {
|
|
107
|
+
won = this.deps.store.claimCas(row.delivery_id, claimedBy, {
|
|
108
|
+
state: row.state,
|
|
109
|
+
claimed_by: row.claimed_by,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
won = false;
|
|
114
|
+
}
|
|
115
|
+
if (!won)
|
|
116
|
+
continue; // lost the race (or the row moved) — next tick re-selects
|
|
117
|
+
processed++;
|
|
118
|
+
const noticeId = parseReapNotifyDeliveryId(row.delivery_id) ?? row.delivery_id;
|
|
119
|
+
const text = Buffer.isBuffer(row.text) ? row.text.toString('utf-8') : String(row.text ?? '');
|
|
120
|
+
try {
|
|
121
|
+
await this.deps.sendToTopic(row.topic_id, text);
|
|
122
|
+
this.safeTransition(row.delivery_id, 'delivered-recovered', { claimed_by: null });
|
|
123
|
+
this.safeRecord({ noticeId, topicId: row.topic_id, outcome: 'sent' });
|
|
124
|
+
counters.sent++;
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
128
|
+
const attempts = (row.attempts ?? 1) + 1;
|
|
129
|
+
if (attempts >= this.opts.maxAttempts) {
|
|
130
|
+
this.safeTransition(row.delivery_id, 'escalated', {
|
|
131
|
+
attempts,
|
|
132
|
+
claimed_by: null,
|
|
133
|
+
error_body: errMsg.slice(0, 512),
|
|
134
|
+
});
|
|
135
|
+
this.safeRecord({
|
|
136
|
+
noticeId,
|
|
137
|
+
topicId: row.topic_id,
|
|
138
|
+
outcome: 'send-failed-escalated',
|
|
139
|
+
detail: `after ${attempts} attempts: ${errMsg.slice(0, 200)}`,
|
|
140
|
+
});
|
|
141
|
+
counters.escalated++;
|
|
142
|
+
await this.escalate(noticeId, row.topic_id, nowIso);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
const backoff = Math.min(this.opts.backoffBaseMs * 2 ** Math.max(0, attempts - 1), this.opts.backoffMaxMs);
|
|
146
|
+
this.safeTransition(row.delivery_id, 'queued', {
|
|
147
|
+
attempts,
|
|
148
|
+
claimed_by: null,
|
|
149
|
+
next_attempt_at: new Date(nowMs + backoff).toISOString(),
|
|
150
|
+
error_body: errMsg.slice(0, 512),
|
|
151
|
+
});
|
|
152
|
+
counters.retried++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Bounded terminal-row cleanup (≤ once/hour).
|
|
157
|
+
if (nowMs - this.lastCleanupAt > 3600_000) {
|
|
158
|
+
this.lastCleanupAt = nowMs;
|
|
159
|
+
try {
|
|
160
|
+
this.deps.store.purgeTerminalReapNotices(new Date(nowMs - this.opts.terminalRetentionMs).toISOString());
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
/* cleanup is best-effort */
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return counters;
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
this.ticking = false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/** Lease format mirrors DFS: `<bootId>:<pid>:<leaseUntilIso>`. */
|
|
173
|
+
isLeaseStale(row, nowMs) {
|
|
174
|
+
if (!row.claimed_by)
|
|
175
|
+
return true;
|
|
176
|
+
const parts = row.claimed_by.split(':');
|
|
177
|
+
if (parts.length < 3)
|
|
178
|
+
return true;
|
|
179
|
+
const bootId = parts[0];
|
|
180
|
+
const leaseUntilIso = parts.slice(2).join(':');
|
|
181
|
+
if (bootId !== this.deps.bootId)
|
|
182
|
+
return true; // prior boot — reclaimable
|
|
183
|
+
const lease = Date.parse(leaseUntilIso);
|
|
184
|
+
if (Number.isNaN(lease))
|
|
185
|
+
return true;
|
|
186
|
+
return lease < nowMs;
|
|
187
|
+
}
|
|
188
|
+
safeTransition(deliveryId, state, fields) {
|
|
189
|
+
try {
|
|
190
|
+
this.deps.store.transition(deliveryId, state, fields);
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
console.warn(`[reap-notice-drain] transition(${deliveryId}, ${state}) raised:`, err);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
safeRecord(e) {
|
|
197
|
+
try {
|
|
198
|
+
this.deps.recordNotify(e);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
/* the audit sink never endangers delivery */
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/** ONE rolling deduped attention item, updated in place (P17). */
|
|
205
|
+
async escalate(noticeId, topicId, atIso) {
|
|
206
|
+
this.escalations.push({ noticeId, topicId, at: atIso });
|
|
207
|
+
if (this.escalations.length > 50)
|
|
208
|
+
this.escalations.shift();
|
|
209
|
+
if (!this.deps.emitAttention)
|
|
210
|
+
return;
|
|
211
|
+
const topics = [...new Set(this.escalations.map((e) => e.topicId))];
|
|
212
|
+
try {
|
|
213
|
+
await this.deps.emitAttention({
|
|
214
|
+
id: ESCALATION_ATTENTION_ID,
|
|
215
|
+
title: `Reap notices could not be delivered (${this.escalations.length} since startup)`,
|
|
216
|
+
summary: `Delivery of session-shutdown notices failed after all retries for topic(s) ${topics.join(', ')}.`,
|
|
217
|
+
description: `I tried to tell the affected conversation(s) that sessions were shut down, but the messages ` +
|
|
218
|
+
`could not be delivered after repeated attempts. The shutdowns themselves are all recorded — ` +
|
|
219
|
+
`ask me "what happened to my sessions?" and I can reconstruct it. Most recent failure: notice ` +
|
|
220
|
+
`${noticeId} for topic ${topicId} at ${atIso}.`,
|
|
221
|
+
category: 'delivery',
|
|
222
|
+
priority: 'medium',
|
|
223
|
+
sourceContext: 'reap-notice-drain',
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
console.warn('[reap-notice-drain] attention emit failed:', err);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=ReapNoticeDrain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReapNoticeDrain.js","sourceRoot":"","sources":["../../src/monitoring/ReapNoticeDrain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AAuDpF,MAAM,CAAC,MAAM,iCAAiC,GAA2B;IACvE,cAAc,EAAE,MAAM;IACtB,cAAc,EAAE,EAAE;IAClB,WAAW,EAAE,CAAC;IACd,eAAe,EAAE,OAAO;IACxB,aAAa,EAAE,MAAM;IACrB,YAAY,EAAE,EAAE,GAAG,MAAM;IACzB,mBAAmB,EAAE,EAAE,GAAG,QAAQ;CACnC,CAAC;AAEF,MAAM,uBAAuB,GAAG,+BAA+B,CAAC;AAEhE,MAAM,OAAO,eAAe;IACT,IAAI,CAAsB;IAC1B,IAAI,CAAyB;IAC7B,GAAG,CAAe;IAC3B,KAAK,GAA0B,IAAI,CAAC;IACpC,OAAO,GAAG,KAAK,CAAC;IACxB,8EAA8E;IACtE,WAAW,GAA6D,EAAE,CAAC;IAC3E,aAAa,GAAG,CAAC,CAAC;IAE1B,YAAY,IAAyB,EAAE,IAAsC;QAC3E,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,iCAAiC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;QACtE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC5B,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;gBAC1B;;sEAEsD;YACxD,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC7B,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,UAAU;YAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACjE,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,KAAK,CAAC,IAAI;QACR,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;QACvD,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,QAAQ,CAAC,CAAC,oBAAoB;QACvD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;YAE7C,IAAI,UAAU,GAAsB,EAAE,CAAC;YACvC,IAAI,CAAC;gBACH,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK;qBACzB,0BAA0B,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;qBAChE,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;YAC9E,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;gBACxD,OAAO,QAAQ,CAAC;YAClB,CAAC;YAED,IAAI,SAAS,GAAG,CAAC,CAAC;YAClB,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;gBAC7B,IAAI,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc;oBAAE,MAAM;gBACjD,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,WAAW,EAAE,CAAC;gBAC7E,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,CAAC;gBACrE,IAAI,GAAG,GAAG,KAAK,CAAC;gBAChB,IAAI,CAAC;oBACH,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,EAAE;wBACzD,KAAK,EAAE,GAAG,CAAC,KAAK;wBAChB,UAAU,EAAE,GAAG,CAAC,UAAU;qBAC3B,CAAC,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC;oBACP,GAAG,GAAG,KAAK,CAAC;gBACd,CAAC;gBACD,IAAI,CAAC,GAAG;oBAAE,SAAS,CAAC,0DAA0D;gBAC9E,SAAS,EAAE,CAAC;gBAEZ,MAAM,QAAQ,GAAG,yBAAyB,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,WAAW,CAAC;gBAC/E,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;gBAC7F,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;oBAChD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,EAAE,qBAAqB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;oBAClF,IAAI,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;oBACtE,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAClB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAChE,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;oBACzC,IAAI,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;wBACtC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE;4BAChD,QAAQ;4BACR,UAAU,EAAE,IAAI;4BAChB,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;yBACjC,CAAC,CAAC;wBACH,IAAI,CAAC,UAAU,CAAC;4BACd,QAAQ;4BACR,OAAO,EAAE,GAAG,CAAC,QAAQ;4BACrB,OAAO,EAAE,uBAAuB;4BAChC,MAAM,EAAE,SAAS,QAAQ,cAAc,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;yBAC9D,CAAC,CAAC;wBACH,QAAQ,CAAC,SAAS,EAAE,CAAC;wBACrB,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBACtD,CAAC;yBAAM,CAAC;wBACN,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CACtB,IAAI,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,EACxD,IAAI,CAAC,IAAI,CAAC,YAAY,CACvB,CAAC;wBACF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,EAAE;4BAC7C,QAAQ;4BACR,UAAU,EAAE,IAAI;4BAChB,eAAe,EAAE,IAAI,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,WAAW,EAAE;4BACxD,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;yBACjC,CAAC,CAAC;wBACH,QAAQ,CAAC,OAAO,EAAE,CAAC;oBACrB,CAAC;gBACH,CAAC;YACH,CAAC;YAED,8CAA8C;YAC9C,IAAI,KAAK,GAAG,IAAI,CAAC,aAAa,GAAG,QAAQ,EAAE,CAAC;gBAC1C,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;gBAC3B,IAAI,CAAC;oBACH,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,wBAAwB,CACtC,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,WAAW,EAAE,CAC9D,CAAC;gBACJ,CAAC;gBAAC,MAAM,CAAC;oBACP,4BAA4B;gBAC9B,CAAC;YACH,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACvB,CAAC;IACH,CAAC;IAED,kEAAkE;IAC1D,YAAY,CAAC,GAAoB,EAAE,KAAa;QACtD,IAAI,CAAC,GAAG,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,CAAC,2BAA2B;QACzE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACrC,OAAO,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;IAEO,cAAc,CACpB,UAAkB,EAClB,KAAoB,EACpB,MAA4H;QAE5H,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,kCAAkC,UAAU,KAAK,KAAK,WAAW,EAAE,GAAG,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,CAA4F;QAC7G,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,6CAA6C;QAC/C,CAAC;IACH,CAAC;IAED,kEAAkE;IAC1D,KAAK,CAAC,QAAQ,CAAC,QAAgB,EAAE,OAAe,EAAE,KAAa;QACrE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACxD,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,EAAE;YAAE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QAC3D,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,OAAO;QACrC,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;gBAC5B,EAAE,EAAE,uBAAuB;gBAC3B,KAAK,EAAE,wCAAwC,IAAI,CAAC,WAAW,CAAC,MAAM,iBAAiB;gBACvF,OAAO,EAAE,8EAA8E,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBAC3G,WAAW,EACT,8FAA8F;oBAC9F,8FAA8F;oBAC9F,+FAA+F;oBAC/F,GAAG,QAAQ,cAAc,OAAO,OAAO,KAAK,GAAG;gBACjD,QAAQ,EAAE,UAAU;gBACpB,QAAQ,EAAE,QAAQ;gBAClB,aAAa,EAAE,mBAAmB;aACnC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,4CAA4C,EAAE,GAAG,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,50 +1,103 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ReapNotifier — the single coalescing listener for `sessionReaped`
|
|
3
|
-
* (UNIFIED-SESSION-LIFECYCLE §P3).
|
|
3
|
+
* (UNIFIED-SESSION-LIFECYCLE §P3; v2 per reap-notify spec R1.1–R1.5).
|
|
4
4
|
*
|
|
5
5
|
* `SessionManager.terminateSession` emits `sessionReaped` exactly once per kill
|
|
6
|
-
* at the one chokepoint. This listener turns
|
|
7
|
-
*
|
|
8
|
-
* vanishes (the 2026-05-27 incident). It stays SILENT for:
|
|
6
|
+
* at the one chokepoint. This listener turns TERMINAL reaps of user-facing
|
|
7
|
+
* sessions into "your session was shut down" notices so a session never
|
|
8
|
+
* silently vanishes (the 2026-05-27 incident). It stays SILENT for:
|
|
9
9
|
* - `recovery-bounce` reaps (a kill-to-respawn is a bounce, not a disappearance),
|
|
10
10
|
* - `origin:'operator'` reaps (the user clicked kill — telling them is noise).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* topic
|
|
16
|
-
* -
|
|
17
|
-
*
|
|
18
|
-
*
|
|
12
|
+
* v2 (perTopic: true, the shipped default):
|
|
13
|
+
* - Per-topic coalescing (R1.1): every topic that lost a session gets ONE
|
|
14
|
+
* notice in THAT topic; the lifeline gets unbound sessions plus — when >1
|
|
15
|
+
* topic is affected — a one-line cross-topic index. Never creates topics.
|
|
16
|
+
* - Affected-set tracking is SEPARATE from the bounded detail buffer, so in
|
|
17
|
+
* a storm larger than the buffer every affected topic still gets at least
|
|
18
|
+
* a correct count (count-only notice when its detail was dropped).
|
|
19
|
+
* - Durable delivery (R1.3): notices become PendingRelayStore rows keyed
|
|
20
|
+
* `reap-notify:<noticeId>` with the release hold riding `next_attempt_at`;
|
|
21
|
+
* the always-on ReapNoticeDrain delivers them. Outcome records land in
|
|
22
|
+
* the reap-log as append-only pairs. Enqueue failure degrades LOUDLY to
|
|
23
|
+
* one direct send attempt, recorded `enqueue-failed`.
|
|
24
|
+
* - Release tiers (decision 1 + R1.5): a mid-work reap with a QUEUED resume
|
|
25
|
+
* releases IMMEDIATE outside quiet hours (quiet-hours end inside them —
|
|
26
|
+
* never wakes the user; a queued resume means the system is already
|
|
27
|
+
* handling it); everything else releases on the SUMMARY window. At most
|
|
28
|
+
* `maxImmediatePerFlush` immediate releases per flush.
|
|
29
|
+
* - Plain English (R1.2): reason slugs map to human sentences (unknown slug
|
|
30
|
+
* ⇒ generic sentence with the slug parenthesized); no curl/API pointers
|
|
31
|
+
* in any user-facing body.
|
|
32
|
+
*
|
|
33
|
+
* Legacy (perTopic: false — the rollback lever): byte-compatible with the
|
|
34
|
+
* pre-v2 behavior (single buffer; burst ⇒ ONE consolidated lifeline message).
|
|
19
35
|
*
|
|
20
36
|
* Sanitization: session names follow user-controlled topic renames, so the
|
|
21
|
-
* dynamic fields (name, reason) are wrapped as inline-code spans — the
|
|
22
|
-
* Telegram formatter renders code spans as literal, HTML-escaped
|
|
23
|
-
* markup. The notifier never emits raw markup around
|
|
37
|
+
* dynamic fields (name, reason) are wrapped as inline-code spans — the
|
|
38
|
+
* downstream Telegram formatter renders code spans as literal, HTML-escaped
|
|
39
|
+
* text, never markup. The notifier never emits raw markup around
|
|
40
|
+
* user-controlled values.
|
|
24
41
|
*/
|
|
25
42
|
import type { Session } from '../core/types.js';
|
|
43
|
+
import type { ReapNotifyOutcome } from './ReapLog.js';
|
|
26
44
|
export interface ReapEvent {
|
|
27
45
|
session: Pick<Session, 'name' | 'tmuxSession'>;
|
|
28
46
|
reason: string;
|
|
29
47
|
disposition?: 'terminal' | 'recovery-bounce';
|
|
30
48
|
origin?: 'operator' | 'autonomous';
|
|
49
|
+
/** Mid-work stamp from the kill chokepoint (reap-notify spec R2.1). */
|
|
50
|
+
midWork?: boolean;
|
|
51
|
+
/** Clamped work-evidence names behind midWork. */
|
|
52
|
+
workEvidence?: string[];
|
|
31
53
|
}
|
|
32
54
|
export interface ReapNotifierDeps {
|
|
33
55
|
/** Bound messaging topic for a session, or null if unbound. */
|
|
34
56
|
resolveTopic: (tmuxSession: string) => number | null;
|
|
35
57
|
/** The always-on system/lifeline topic, or null if none is configured. */
|
|
36
58
|
lifelineTopic: () => number | null;
|
|
37
|
-
/**
|
|
59
|
+
/** Legacy delivery (perTopic:false and drainEnabled:false modes). */
|
|
38
60
|
send: (topicId: number, text: string) => void | Promise<void>;
|
|
61
|
+
/** Durable store enqueue (v2). Returns false on PK-dedupe no-op. */
|
|
62
|
+
enqueueNotice?: (input: {
|
|
63
|
+
delivery_id: string;
|
|
64
|
+
topic_id: number;
|
|
65
|
+
text: string;
|
|
66
|
+
next_attempt_at: string;
|
|
67
|
+
}) => boolean;
|
|
68
|
+
/** Append a notify outcome record to the reap-log (R1.3 pairs). */
|
|
69
|
+
recordNotify?: (e: {
|
|
70
|
+
noticeId: string;
|
|
71
|
+
topicId: number | null;
|
|
72
|
+
outcome: ReapNotifyOutcome;
|
|
73
|
+
detail?: string;
|
|
74
|
+
}) => void;
|
|
75
|
+
/** Epoch ms when the current quiet-hours window ends; null = not in quiet hours. */
|
|
76
|
+
quietHoursEndAt?: (nowMs: number) => number | null;
|
|
77
|
+
/** Epoch ms of the next SUMMARY-window release (≤30 min out — R1.5). */
|
|
78
|
+
summaryReleaseAt?: (nowMs: number) => number;
|
|
79
|
+
/** True when a resume-queue entry is QUEUED for this session AND the queue is
|
|
80
|
+
* LIVE (not dry-run) — gates the "resume queued" line (R1.2). */
|
|
81
|
+
resumeQueuedFor?: (tmuxSession: string) => boolean;
|
|
82
|
+
/** Loud degradation surface for enqueue failures (aggregated upstream). */
|
|
83
|
+
reportDegradation?: (reason: string, impact: string) => void;
|
|
39
84
|
now?: () => number;
|
|
40
85
|
}
|
|
41
86
|
export interface ReapNotifierOptions {
|
|
42
87
|
enabled: boolean;
|
|
43
88
|
coalesceWindowMs: number;
|
|
44
|
-
/** Max reaps retained for
|
|
89
|
+
/** Max reaps retained for detail lists (counts stay exact regardless). */
|
|
45
90
|
maxBuffer: number;
|
|
91
|
+
/** v2 per-topic grouping (R1.1). false = legacy single-buffer behavior. */
|
|
92
|
+
perTopic: boolean;
|
|
93
|
+
/** Max notices released IMMEDIATE in one flush (R1.5). */
|
|
94
|
+
maxImmediatePerFlush: number;
|
|
95
|
+
/** Durable delivery via store + drain (R1.3). false = legacy direct send
|
|
96
|
+
* (grouping unaffected; the durability guarantee lapses — stated rollback). */
|
|
97
|
+
drainEnabled: boolean;
|
|
46
98
|
}
|
|
47
99
|
export declare const DEFAULT_REAP_NOTIFIER_OPTIONS: ReapNotifierOptions;
|
|
100
|
+
export declare function plainEnglishReason(slug: string): string;
|
|
48
101
|
export declare class ReapNotifier {
|
|
49
102
|
private readonly deps;
|
|
50
103
|
private readonly opts;
|
|
@@ -52,15 +105,33 @@ export declare class ReapNotifier {
|
|
|
52
105
|
private timer;
|
|
53
106
|
private buffer;
|
|
54
107
|
private windowCount;
|
|
108
|
+
/** v2 affected-set (R1.1) — tracked separately from the detail buffer. */
|
|
109
|
+
private affected;
|
|
110
|
+
private affectedOverflow;
|
|
111
|
+
private unbound;
|
|
112
|
+
private noticeSeq;
|
|
55
113
|
constructor(deps: ReapNotifierDeps, opts?: Partial<ReapNotifierOptions>);
|
|
56
114
|
/** The `sessionReaped` event handler. */
|
|
57
115
|
onReaped(event: ReapEvent): void;
|
|
116
|
+
private trackAffected;
|
|
117
|
+
/** Remove a buffer-evicted event from its topic's detail list (count stays). */
|
|
118
|
+
private dropDetail;
|
|
119
|
+
private safeResolveTopic;
|
|
120
|
+
private safeResumeQueued;
|
|
58
121
|
/**
|
|
59
122
|
* Emit the coalesced notice(s) for the closed window and reset. Public so the
|
|
60
123
|
* lifecycle (and tests) can drive it deterministically.
|
|
61
124
|
*/
|
|
62
125
|
flush(): Promise<void>;
|
|
63
|
-
|
|
64
|
-
private
|
|
126
|
+
/** Legacy (pre-v2) flush — byte-compatible single-buffer behavior. */
|
|
127
|
+
private flushLegacy;
|
|
128
|
+
private nextNoticeId;
|
|
129
|
+
private releaseAt;
|
|
130
|
+
private deliver;
|
|
131
|
+
private formatTopicNotice;
|
|
132
|
+
private formatUnboundNotice;
|
|
133
|
+
private formatCrossTopicIndex;
|
|
134
|
+
private formatSingleLegacy;
|
|
135
|
+
private formatBurstLegacy;
|
|
65
136
|
}
|
|
66
137
|
//# sourceMappingURL=ReapNotifier.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReapNotifier.d.ts","sourceRoot":"","sources":["../../src/monitoring/ReapNotifier.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ReapNotifier.d.ts","sourceRoot":"","sources":["../../src/monitoring/ReapNotifier.ts"],"names":[],"mappings":"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"}
|