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,600 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ResumeQueue — the durable, ordered queue of mid-work reaped sessions
|
|
3
|
+
* awaiting revival (reap-notify spec R2.2/R2.3, parts of R2.9/R2.10).
|
|
4
|
+
*
|
|
5
|
+
* One queue per machine, JSON-file backed (`state/resume-queue.json`),
|
|
6
|
+
* in-memory authoritative with SYNCHRONOUS persist on every mutation using
|
|
7
|
+
* the crash-durable discipline: write temp → fsync temp → rename → fsync
|
|
8
|
+
* parent dir. A crash loses at most the latest mutation, which boot
|
|
9
|
+
* reconciliation absorbs (a lost enqueue is re-created from the reap-log; a
|
|
10
|
+
* lost transition replays as a failed attempt).
|
|
11
|
+
*
|
|
12
|
+
* Single-writer is ENFORCED, not assumed: a lockfile
|
|
13
|
+
* (`state/resume-queue.lock`, pid + hostname + heartbeat mtime) is taken at
|
|
14
|
+
* start. Stale-lock recovery is automatic on the SAME host (dead pid or old
|
|
15
|
+
* heartbeat ⇒ reclaim + log); a LIVE other process disables the queue loudly.
|
|
16
|
+
* HARD INVARIANT: a lock whose hostname differs from this host is NEVER
|
|
17
|
+
* liveness-probed or reclaimed — pid checks are meaningless cross-host — it
|
|
18
|
+
* disables the queue loudly instead, and the disable message documents the
|
|
19
|
+
* operational recovery (verify nothing else uses the state dir, delete the
|
|
20
|
+
* lock, restart).
|
|
21
|
+
*
|
|
22
|
+
* Eligibility (R2.2) is stricter than midWork: terminal + autonomous +
|
|
23
|
+
* (≥1 strong signal, OR topic-bound with ≥2 distinct weak signals); jobs
|
|
24
|
+
* must opt in (`resumeOnReap:true`, default false); sessions with neither a
|
|
25
|
+
* topic binding nor a jobSlug are excluded at enqueue; operator kills
|
|
26
|
+
* excluded by default; watchdog stuck-kills and topic-moved closeouts never
|
|
27
|
+
* queue. The resurrection LEDGER (keyed on stable identity
|
|
28
|
+
* `topicId ?? jobSlug ?? tmuxSession`, tombstones surviving dequeue, 24h
|
|
29
|
+
* reset window) caps kill-resume-kill loops at `maxResurrections`.
|
|
30
|
+
*
|
|
31
|
+
* Dry-run posture (the fleet's shipped default): entries ARE durably
|
|
32
|
+
* enqueued (observable in `GET /sessions/resume-queue` — the soak needs real
|
|
33
|
+
* midWork entries), but the drainer never spawns (it audits `would-resume`)
|
|
34
|
+
* and nothing user-facing claims a queued resume. Deliberate interpretation
|
|
35
|
+
* of "observe-only", recorded in the side-effects review.
|
|
36
|
+
*/
|
|
37
|
+
import fs from 'node:fs';
|
|
38
|
+
import os from 'node:os';
|
|
39
|
+
import path from 'node:path';
|
|
40
|
+
import { SafeFsExecutor } from '../core/SafeFsExecutor.js';
|
|
41
|
+
import { evidenceEligible, clampWorkEvidence } from '../core/WorkEvidence.js';
|
|
42
|
+
export const DEFAULT_RESUME_QUEUE_CONFIG = {
|
|
43
|
+
enabled: true,
|
|
44
|
+
dryRun: true, // code default — the fleet ships observe-only (decision 2)
|
|
45
|
+
maxAttempts: 3,
|
|
46
|
+
maxResurrections: 2,
|
|
47
|
+
entryTtlHours: 24,
|
|
48
|
+
maxQueueSize: 50,
|
|
49
|
+
includeOperatorKills: false,
|
|
50
|
+
};
|
|
51
|
+
const RESURRECTION_WINDOW_MS = 24 * 3600_000;
|
|
52
|
+
const REASON_CAP = 500;
|
|
53
|
+
/** Pure eligibility classifier (R2.2) — exported for tests. */
|
|
54
|
+
export function classifyEligibility(input, cfg) {
|
|
55
|
+
if (input.disposition !== 'terminal')
|
|
56
|
+
return { eligible: false, why: 'not-terminal' };
|
|
57
|
+
if (input.origin === 'operator' && !cfg.includeOperatorKills) {
|
|
58
|
+
return { eligible: false, why: 'operator-kill' };
|
|
59
|
+
}
|
|
60
|
+
// A stuck session is not interrupted work; resuming recreates the wedge —
|
|
61
|
+
// watchdog escalation owns that recovery (R2.1).
|
|
62
|
+
if (input.reason === 'watchdog-stuck')
|
|
63
|
+
return { eligible: false, why: 'watchdog-kill' };
|
|
64
|
+
// Post-transfer closeouts: the conversation continues on the owning machine.
|
|
65
|
+
if (input.reason.startsWith('topic moved'))
|
|
66
|
+
return { eligible: false, why: 'topic-moved' };
|
|
67
|
+
const topicBound = input.topicId != null;
|
|
68
|
+
if (!topicBound && !input.jobSlug)
|
|
69
|
+
return { eligible: false, why: 'no-resume-path' };
|
|
70
|
+
if (!topicBound && input.jobSlug && !input.jobResumeOptIn) {
|
|
71
|
+
return { eligible: false, why: 'job-not-opted-in' };
|
|
72
|
+
}
|
|
73
|
+
if (!evidenceEligible(input.workEvidence, topicBound)) {
|
|
74
|
+
return { eligible: false, why: 'insufficient-evidence' };
|
|
75
|
+
}
|
|
76
|
+
return { eligible: true };
|
|
77
|
+
}
|
|
78
|
+
export class ResumeQueue {
|
|
79
|
+
deps;
|
|
80
|
+
cfg;
|
|
81
|
+
now;
|
|
82
|
+
statePath;
|
|
83
|
+
lockPath;
|
|
84
|
+
state = { version: 1, paused: false, entries: [], tombstones: [] };
|
|
85
|
+
seq = 0;
|
|
86
|
+
/** Non-null ⇒ the queue is disabled (lock conflict / foreign lock). */
|
|
87
|
+
disabledReason = null;
|
|
88
|
+
lockHeld = false;
|
|
89
|
+
constructor(deps, cfg) {
|
|
90
|
+
this.deps = deps;
|
|
91
|
+
this.cfg = { ...DEFAULT_RESUME_QUEUE_CONFIG, ...(cfg ?? {}) };
|
|
92
|
+
this.now = deps.now ?? (() => Date.now());
|
|
93
|
+
const stateRoot = path.join(deps.stateDir, 'state');
|
|
94
|
+
this.statePath = path.join(stateRoot, 'resume-queue.json');
|
|
95
|
+
this.lockPath = path.join(stateRoot, 'resume-queue.lock');
|
|
96
|
+
}
|
|
97
|
+
config() {
|
|
98
|
+
return { ...this.cfg };
|
|
99
|
+
}
|
|
100
|
+
isDisabled() {
|
|
101
|
+
return this.disabledReason;
|
|
102
|
+
}
|
|
103
|
+
isPaused() {
|
|
104
|
+
return this.state.paused;
|
|
105
|
+
}
|
|
106
|
+
isDryRun() {
|
|
107
|
+
return this.cfg.dryRun;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Acquire the single-writer lock + load the durable state. Returns false
|
|
111
|
+
* (queue disabled, reason in `isDisabled()`) on a live-other-process or
|
|
112
|
+
* foreign-host lock — never throws for those.
|
|
113
|
+
*/
|
|
114
|
+
start() {
|
|
115
|
+
if (!this.acquireLock())
|
|
116
|
+
return false;
|
|
117
|
+
this.load();
|
|
118
|
+
this.reconcileStartingEntries();
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
stop() {
|
|
122
|
+
if (this.lockHeld) {
|
|
123
|
+
try {
|
|
124
|
+
SafeFsExecutor.safeUnlinkSync(this.lockPath, { operation: 'ResumeQueue.stop lock release' });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
/* already gone */
|
|
128
|
+
}
|
|
129
|
+
this.lockHeld = false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** Refresh the lock heartbeat (drainer calls this every tick). */
|
|
133
|
+
heartbeat() {
|
|
134
|
+
if (!this.lockHeld)
|
|
135
|
+
return;
|
|
136
|
+
try {
|
|
137
|
+
const t = new Date(this.now());
|
|
138
|
+
fs.utimesSync(this.lockPath, t, t);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
/* @silent-fallback-ok — heartbeat touch is best-effort; a missing lock
|
|
142
|
+
is re-created on next start, and a stale heartbeat only makes THIS
|
|
143
|
+
holder's lock reclaimable (the safe direction). */
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
acquireLock() {
|
|
147
|
+
const hostname = this.deps.hostname?.() ?? os.hostname();
|
|
148
|
+
const pidAlive = this.deps.pidAlive ??
|
|
149
|
+
((pid) => {
|
|
150
|
+
try {
|
|
151
|
+
process.kill(pid, 0);
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// @silent-fallback-ok — not a fallback: kill(pid, 0) throwing IS the
|
|
156
|
+
// "pid is dead" answer this probe exists to produce.
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
try {
|
|
161
|
+
fs.mkdirSync(path.dirname(this.lockPath), { recursive: true });
|
|
162
|
+
if (fs.existsSync(this.lockPath)) {
|
|
163
|
+
let lock = {};
|
|
164
|
+
try {
|
|
165
|
+
lock = JSON.parse(fs.readFileSync(this.lockPath, 'utf-8'));
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// @silent-fallback-ok — corrupt/unreadable lock ⇒ no pid/hostname ⇒
|
|
169
|
+
// the stale-reclaim path below runs and AUDITS the reclaim.
|
|
170
|
+
lock = {};
|
|
171
|
+
}
|
|
172
|
+
if (lock.hostname && lock.hostname !== hostname) {
|
|
173
|
+
// HARD INVARIANT: never probe/reclaim a foreign-host lock.
|
|
174
|
+
this.disabledReason =
|
|
175
|
+
`resume-queue disabled: lock at ${this.lockPath} belongs to host "${lock.hostname}" ` +
|
|
176
|
+
`(this host: "${hostname}"). The queue's state dir must be host-local; shared volumes are ` +
|
|
177
|
+
`unsupported. Recovery: after verifying nothing else uses this state dir (host renamed, or ` +
|
|
178
|
+
`restored from a backup), delete state/resume-queue.lock and restart.`;
|
|
179
|
+
this.audit({ event: 'lock-foreign-host', lockHost: lock.hostname, thisHost: hostname });
|
|
180
|
+
this.deps.raiseAggregated?.('lock-foreign-host', this.disabledReason);
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
const mtime = (() => {
|
|
184
|
+
try {
|
|
185
|
+
return fs.statSync(this.lockPath).mtimeMs;
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// @silent-fallback-ok — unreadable mtime ⇒ heartbeat treated as
|
|
189
|
+
// stale ⇒ the audited reclaim path, never a silent hold.
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
})();
|
|
193
|
+
const heartbeatFresh = this.now() - mtime < 5 * 60_000;
|
|
194
|
+
const live = typeof lock.pid === 'number' && lock.pid !== process.pid && pidAlive(lock.pid) && heartbeatFresh;
|
|
195
|
+
if (live) {
|
|
196
|
+
this.disabledReason =
|
|
197
|
+
`resume-queue disabled: another live process (pid ${lock.pid}) holds ${this.lockPath} ` +
|
|
198
|
+
`with a fresh heartbeat. Only one queue owner per machine is supported.`;
|
|
199
|
+
this.audit({ event: 'lock-live-other', otherPid: lock.pid });
|
|
200
|
+
this.deps.raiseAggregated?.('lock-live-other', this.disabledReason);
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
// Dead pid or stale heartbeat — safe automatic reclaim.
|
|
204
|
+
this.audit({ event: 'lock-stale-reclaimed', priorPid: lock.pid, heartbeatFresh });
|
|
205
|
+
}
|
|
206
|
+
fs.writeFileSync(this.lockPath, JSON.stringify({ pid: process.pid, hostname }), 'utf-8');
|
|
207
|
+
this.lockHeld = true;
|
|
208
|
+
this.disabledReason = null;
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
// @silent-fallback-ok — not silent: the failure is stored as
|
|
213
|
+
// disabledReason, surfaced by isDisabled() and the /sessions/resume-queue
|
|
214
|
+
// route, and the queue refuses to start (safe side).
|
|
215
|
+
this.disabledReason = `resume-queue disabled: lock acquisition raised: ${err instanceof Error ? err.message : String(err)}`;
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
load() {
|
|
220
|
+
let raw = null;
|
|
221
|
+
try {
|
|
222
|
+
raw = fs.readFileSync(this.statePath, 'utf-8');
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
raw = null; // first run — empty queue
|
|
226
|
+
}
|
|
227
|
+
if (raw == null)
|
|
228
|
+
return;
|
|
229
|
+
try {
|
|
230
|
+
const parsed = JSON.parse(raw);
|
|
231
|
+
if (parsed && parsed.version === 1 && Array.isArray(parsed.entries)) {
|
|
232
|
+
this.state = {
|
|
233
|
+
version: 1,
|
|
234
|
+
paused: !!parsed.paused,
|
|
235
|
+
pausedAt: parsed.pausedAt,
|
|
236
|
+
pauseReason: parsed.pauseReason,
|
|
237
|
+
entries: parsed.entries,
|
|
238
|
+
tombstones: Array.isArray(parsed.tombstones) ? parsed.tombstones : [],
|
|
239
|
+
};
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
throw new Error('unrecognized shape');
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
// Corrupt file: sidecar-preserve, start empty, surface loudly — never a
|
|
246
|
+
// silent reset, never a crash (R2.3).
|
|
247
|
+
const sidecar = path.join(path.dirname(this.statePath), `resume-queue.corrupt-${this.now().toString(36)}.json`);
|
|
248
|
+
try {
|
|
249
|
+
fs.copyFileSync(this.statePath, sidecar);
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
/* keep going — the original may be unreadable */
|
|
253
|
+
}
|
|
254
|
+
this.state = { version: 1, paused: false, entries: [], tombstones: [] };
|
|
255
|
+
this.audit({ event: 'state-corrupt', sidecar, error: err instanceof Error ? err.message : String(err) });
|
|
256
|
+
this.deps.raiseAggregated?.('state-corrupt', `resume-queue.json was unreadable and has been preserved at ${sidecar}; the queue restarted empty. ` +
|
|
257
|
+
`Losing the resurrection ledger in this rare path is accepted and surfaced.`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/** Crash-durable persist: temp → fsync temp → rename → fsync parent dir. */
|
|
261
|
+
persist() {
|
|
262
|
+
const dir = path.dirname(this.statePath);
|
|
263
|
+
const tmp = path.join(dir, `.resume-queue.tmp-${process.pid}`);
|
|
264
|
+
try {
|
|
265
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
266
|
+
const fd = fs.openSync(tmp, 'w');
|
|
267
|
+
try {
|
|
268
|
+
fs.writeSync(fd, JSON.stringify(this.state, null, 2));
|
|
269
|
+
fs.fsyncSync(fd);
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
fs.closeSync(fd);
|
|
273
|
+
}
|
|
274
|
+
fs.renameSync(tmp, this.statePath);
|
|
275
|
+
try {
|
|
276
|
+
const dirFd = fs.openSync(dir, 'r');
|
|
277
|
+
try {
|
|
278
|
+
fs.fsyncSync(dirFd);
|
|
279
|
+
}
|
|
280
|
+
finally {
|
|
281
|
+
fs.closeSync(dirFd);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
/* dir-fsync unsupported on some platforms — rename already landed */
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
this.audit({ event: 'persist-failed', error: err instanceof Error ? err.message : String(err) });
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
audit(event) {
|
|
293
|
+
try {
|
|
294
|
+
this.deps.audit?.({ ts: new Date(this.now()).toISOString(), ...event });
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
/* @silent-fallback-ok — the audit sink never endangers the queue; the
|
|
298
|
+
decision the audit row describes still happened and is persisted. */
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/** Boot reconciliation half 1 (R2.4): `starting` found at load = failed attempt. */
|
|
302
|
+
reconcileStartingEntries() {
|
|
303
|
+
let changed = false;
|
|
304
|
+
for (const entry of this.state.entries) {
|
|
305
|
+
if (entry.status === 'starting') {
|
|
306
|
+
entry.attempts += 1;
|
|
307
|
+
entry.status = entry.attempts >= this.cfg.maxAttempts ? 'gave-up:max-attempts' : 'queued';
|
|
308
|
+
entry.nextAttemptAt = undefined;
|
|
309
|
+
this.audit({ event: 'boot-reconcile-starting', id: entry.id, attempts: entry.attempts, status: entry.status });
|
|
310
|
+
changed = true;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (changed)
|
|
314
|
+
this.persist();
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Boot reconciliation half 2 (R2.4): recent reap-log midWork terminal
|
|
318
|
+
* autonomous entries with no queue entry AND no tombstone are re-enqueued —
|
|
319
|
+
* closing the crash window where an enqueue's persist was lost. The caller
|
|
320
|
+
* supplies reconstruction (session records, resume map) — a candidate that
|
|
321
|
+
* cannot be reconstructed is skipped (the next re-reap recreates it).
|
|
322
|
+
*/
|
|
323
|
+
reconcileFromReapLog(candidates) {
|
|
324
|
+
let enqueued = 0;
|
|
325
|
+
for (const candidate of candidates) {
|
|
326
|
+
const stableKey = this.stableKeyFor(candidate);
|
|
327
|
+
const known = this.state.entries.some((e) => e.stableKey === stableKey) ||
|
|
328
|
+
this.state.tombstones.some((t) => t.stableKey === stableKey);
|
|
329
|
+
if (known)
|
|
330
|
+
continue;
|
|
331
|
+
const decision = this.considerEnqueue(candidate, { source: 'boot-reconcile' });
|
|
332
|
+
if (decision.enqueued)
|
|
333
|
+
enqueued++;
|
|
334
|
+
}
|
|
335
|
+
return enqueued;
|
|
336
|
+
}
|
|
337
|
+
stableKeyFor(input) {
|
|
338
|
+
if (input.topicId != null)
|
|
339
|
+
return `topic:${input.topicId}`;
|
|
340
|
+
if (input.jobSlug)
|
|
341
|
+
return `job:${input.jobSlug}`;
|
|
342
|
+
return `tmux:${input.tmuxSession}`;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* The enqueue decision (R2.2 + R2.3 + R2.9 resurrection cap). Audited on
|
|
346
|
+
* every outcome. In dry-run the entry is still durably enqueued (the soak's
|
|
347
|
+
* observable), but nothing downstream spawns or claims a resume.
|
|
348
|
+
*/
|
|
349
|
+
considerEnqueue(input, opts) {
|
|
350
|
+
if (this.disabledReason)
|
|
351
|
+
return { enqueued: false, why: 'queue-disabled' };
|
|
352
|
+
if (!this.cfg.enabled)
|
|
353
|
+
return { enqueued: false, why: 'queue-off' };
|
|
354
|
+
const verdict = classifyEligibility(input, this.cfg);
|
|
355
|
+
if (!verdict.eligible) {
|
|
356
|
+
this.audit({ event: 'enqueue-skipped', why: verdict.why, session: input.sessionName, source: opts?.source });
|
|
357
|
+
return { enqueued: false, why: verdict.why };
|
|
358
|
+
}
|
|
359
|
+
const stableKey = this.stableKeyFor(input);
|
|
360
|
+
// Dedupe on stable identity: one open entry per topic/job/session.
|
|
361
|
+
const open = this.state.entries.find((e) => e.stableKey === stableKey && (e.status === 'queued' || e.status === 'starting'));
|
|
362
|
+
if (open) {
|
|
363
|
+
this.audit({ event: 'enqueue-skipped', why: 'duplicate-open-entry', stableKey, source: opts?.source });
|
|
364
|
+
return { enqueued: false, why: 'duplicate-open-entry' };
|
|
365
|
+
}
|
|
366
|
+
// Resurrection cap (R2.9): a re-reap AFTER a successful resume within the
|
|
367
|
+
// window increments the ledger; at the cap the enqueue is refused LOUDLY —
|
|
368
|
+
// the most diagnostic event this feature produces (P14).
|
|
369
|
+
const tombstone = this.tombstoneFor(stableKey);
|
|
370
|
+
if (tombstone?.lastResumeAt) {
|
|
371
|
+
const windowFresh = this.now() - Date.parse(tombstone.windowStartAt) < RESURRECTION_WINDOW_MS;
|
|
372
|
+
if (!windowFresh) {
|
|
373
|
+
// The prior resume is outside the 24h window — stale history, not a
|
|
374
|
+
// kill-resume-kill loop. Reset the ledger; this re-reap starts fresh.
|
|
375
|
+
tombstone.resurrections = 0;
|
|
376
|
+
tombstone.windowStartAt = new Date(this.now()).toISOString();
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
tombstone.resurrections += 1;
|
|
380
|
+
}
|
|
381
|
+
if (windowFresh && tombstone.resurrections >= this.cfg.maxResurrections) {
|
|
382
|
+
this.persist();
|
|
383
|
+
this.audit({ event: 'resurrection-cap', stableKey, resurrections: tombstone.resurrections });
|
|
384
|
+
this.deps.raiseAggregated?.('resurrection-cap', `${stableKey} was reaped again after ${tombstone.resurrections} resume(s) in 24h — ` +
|
|
385
|
+
`not resuming it again automatically (something keeps killing it). Message the topic to bring ` +
|
|
386
|
+
`it back, or ask me to retry it.`);
|
|
387
|
+
return { enqueued: false, why: 'resurrection-cap' };
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// Bound (R2.3): overflow drops the oldest LOW-priority entry into the
|
|
391
|
+
// aggregated surface — never silently.
|
|
392
|
+
const openEntries = this.state.entries.filter((e) => e.status === 'queued' || e.status === 'starting');
|
|
393
|
+
if (openEntries.length >= this.cfg.maxQueueSize) {
|
|
394
|
+
const dropOrder = ['other', 'job', 'interactive'];
|
|
395
|
+
let dropped;
|
|
396
|
+
for (const cls of dropOrder) {
|
|
397
|
+
dropped = openEntries.filter((e) => e.priorityClass === cls).sort((a, b) => a.queuedAt.localeCompare(b.queuedAt))[0];
|
|
398
|
+
if (dropped)
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
if (dropped) {
|
|
402
|
+
dropped.status = 'gave-up:overflow';
|
|
403
|
+
this.audit({ event: 'overflow-drop', id: dropped.id, stableKey: dropped.stableKey });
|
|
404
|
+
this.deps.raiseAggregated?.('overflow', `The resume queue hit its cap (${this.cfg.maxQueueSize}); the oldest low-priority entry ` +
|
|
405
|
+
`(${dropped.sessionName}) was dropped.`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const entry = {
|
|
409
|
+
id: `rq-${this.now().toString(36)}-${(this.seq++).toString(36)}`,
|
|
410
|
+
queuedAt: new Date(this.now()).toISOString(),
|
|
411
|
+
stableKey,
|
|
412
|
+
sessionName: input.sessionName,
|
|
413
|
+
tmuxSession: input.tmuxSession,
|
|
414
|
+
...(input.topicId != null ? { topicId: input.topicId } : {}),
|
|
415
|
+
...(input.resumeUuid ? { resumeUuid: input.resumeUuid } : {}),
|
|
416
|
+
...(input.jobSlug ? { jobSlug: input.jobSlug } : {}),
|
|
417
|
+
cwd: input.cwd,
|
|
418
|
+
...(input.worktreePath ? { worktreePath: input.worktreePath } : {}),
|
|
419
|
+
priorityClass: input.topicId != null ? 'interactive' : input.jobSlug ? 'job' : 'other',
|
|
420
|
+
reason: input.reason.slice(0, REASON_CAP),
|
|
421
|
+
workEvidence: clampWorkEvidence(input.workEvidence),
|
|
422
|
+
attempts: 0,
|
|
423
|
+
status: 'queued',
|
|
424
|
+
};
|
|
425
|
+
this.state.entries.push(entry);
|
|
426
|
+
this.persist();
|
|
427
|
+
this.audit({
|
|
428
|
+
event: 'enqueued',
|
|
429
|
+
id: entry.id,
|
|
430
|
+
stableKey,
|
|
431
|
+
priorityClass: entry.priorityClass,
|
|
432
|
+
midWorkEvidence: entry.workEvidence,
|
|
433
|
+
dryRun: this.cfg.dryRun,
|
|
434
|
+
source: opts?.source,
|
|
435
|
+
});
|
|
436
|
+
return { enqueued: true, entry };
|
|
437
|
+
}
|
|
438
|
+
tombstoneFor(stableKey) {
|
|
439
|
+
return this.state.tombstones.find((t) => t.stableKey === stableKey);
|
|
440
|
+
}
|
|
441
|
+
/** Record a successful resume (drainer, after spawn verification). */
|
|
442
|
+
recordResumeSuccess(stableKey) {
|
|
443
|
+
let tombstone = this.tombstoneFor(stableKey);
|
|
444
|
+
if (!tombstone) {
|
|
445
|
+
tombstone = {
|
|
446
|
+
stableKey,
|
|
447
|
+
resurrections: 0,
|
|
448
|
+
windowStartAt: new Date(this.now()).toISOString(),
|
|
449
|
+
};
|
|
450
|
+
this.state.tombstones.push(tombstone);
|
|
451
|
+
}
|
|
452
|
+
tombstone.lastResumeAt = new Date(this.now()).toISOString();
|
|
453
|
+
this.persist();
|
|
454
|
+
}
|
|
455
|
+
/** Ordered open entries: interactive → job → other, FIFO inside each (R2.5). */
|
|
456
|
+
nextCandidates() {
|
|
457
|
+
const order = { interactive: 0, job: 1, other: 2 };
|
|
458
|
+
return this.state.entries
|
|
459
|
+
.filter((e) => e.status === 'queued')
|
|
460
|
+
.sort((a, b) => order[a.priorityClass] - order[b.priorityClass] || a.queuedAt.localeCompare(b.queuedAt));
|
|
461
|
+
}
|
|
462
|
+
list() {
|
|
463
|
+
return [...this.state.entries];
|
|
464
|
+
}
|
|
465
|
+
get(id) {
|
|
466
|
+
return this.state.entries.find((e) => e.id === id);
|
|
467
|
+
}
|
|
468
|
+
/** State-transition helpers (each persists + audits the TRANSITION). */
|
|
469
|
+
transition(id, status, extra) {
|
|
470
|
+
const entry = this.get(id);
|
|
471
|
+
if (!entry)
|
|
472
|
+
return false;
|
|
473
|
+
const from = entry.status;
|
|
474
|
+
entry.status = status;
|
|
475
|
+
if (extra)
|
|
476
|
+
Object.assign(entry, extra);
|
|
477
|
+
this.persist();
|
|
478
|
+
this.audit({ event: 'transition', id, from, to: status, attempts: entry.attempts });
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
/** Operator/API cancel (an explicit per-topic stop cancels that topic's entries — R2.7). */
|
|
482
|
+
cancel(id) {
|
|
483
|
+
const entry = this.get(id);
|
|
484
|
+
if (!entry || (entry.status !== 'queued' && entry.status !== 'starting'))
|
|
485
|
+
return false;
|
|
486
|
+
return this.transition(id, 'cancelled');
|
|
487
|
+
}
|
|
488
|
+
cancelByTopic(topicId) {
|
|
489
|
+
let n = 0;
|
|
490
|
+
for (const entry of this.state.entries) {
|
|
491
|
+
if (entry.topicId === topicId && (entry.status === 'queued' || entry.status === 'starting')) {
|
|
492
|
+
this.transition(entry.id, 'cancelled');
|
|
493
|
+
n++;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return n;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Requeue clamps (R2.10): eligible from gave-up:* ONLY — never `cancelled`
|
|
500
|
+
* (an operator stop) and refused while paused (callers enforce the 409).
|
|
501
|
+
* Resets attempts and RE-ANCHORS the TTL clock while preserving the original
|
|
502
|
+
* queuedAt for the R2.6 operator-stop / job-ran-since checks. Requeueing a
|
|
503
|
+
* gave-up:resurrection-cap entry grants exactly ONE audited override.
|
|
504
|
+
*/
|
|
505
|
+
requeue(id) {
|
|
506
|
+
if (this.state.paused)
|
|
507
|
+
return { ok: false, why: 'queue-paused' };
|
|
508
|
+
const entry = this.get(id);
|
|
509
|
+
if (!entry)
|
|
510
|
+
return { ok: false, why: 'not-found' };
|
|
511
|
+
if (!entry.status.startsWith('gave-up:'))
|
|
512
|
+
return { ok: false, why: 'not-gave-up' };
|
|
513
|
+
if (entry.status === 'gave-up:resurrection-cap') {
|
|
514
|
+
// The requeue itself IS the one audited override (it bypasses the
|
|
515
|
+
// considerEnqueue cap check); the next re-reap re-caps (R2.10).
|
|
516
|
+
this.audit({ event: 'resurrection-override-granted', stableKey: entry.stableKey, id });
|
|
517
|
+
}
|
|
518
|
+
entry.attempts = 0;
|
|
519
|
+
entry.requeuedAt = new Date(this.now()).toISOString();
|
|
520
|
+
entry.nextAttemptAt = undefined;
|
|
521
|
+
entry.pressureStarved = false;
|
|
522
|
+
return this.transition(id, 'queued') ? { ok: true } : { ok: false, why: 'transition-failed' };
|
|
523
|
+
}
|
|
524
|
+
/** Queue-global pause (R2.7): entries keep their states; TTLs freeze. */
|
|
525
|
+
pause(reason) {
|
|
526
|
+
if (this.state.paused)
|
|
527
|
+
return;
|
|
528
|
+
this.state.paused = true;
|
|
529
|
+
this.state.pausedAt = new Date(this.now()).toISOString();
|
|
530
|
+
this.state.pauseReason = reason;
|
|
531
|
+
this.persist();
|
|
532
|
+
this.audit({ event: 'paused', reason });
|
|
533
|
+
}
|
|
534
|
+
/** Explicit unpause lever (R2.7) — accumulates the pause into frozenMs. */
|
|
535
|
+
unpause() {
|
|
536
|
+
if (!this.state.paused)
|
|
537
|
+
return;
|
|
538
|
+
const pausedMs = this.state.pausedAt ? this.now() - Date.parse(this.state.pausedAt) : 0;
|
|
539
|
+
for (const entry of this.state.entries) {
|
|
540
|
+
if (entry.status === 'queued' || entry.status === 'starting') {
|
|
541
|
+
entry.frozenMs = (entry.frozenMs ?? 0) + pausedMs;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
this.state.paused = false;
|
|
545
|
+
this.state.pausedAt = undefined;
|
|
546
|
+
this.state.pauseReason = undefined;
|
|
547
|
+
this.persist();
|
|
548
|
+
this.audit({ event: 'unpaused', pausedMs });
|
|
549
|
+
}
|
|
550
|
+
pauseInfo() {
|
|
551
|
+
return { paused: this.state.paused, pausedAt: this.state.pausedAt, reason: this.state.pauseReason };
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* TTL sweep (R2.9): INCIDENT-AGE semantics — wall clock since
|
|
555
|
+
* max(queuedAt, requeuedAt), minus operator-pause freeze, NOT frozen by
|
|
556
|
+
* pressure. Expiries under sustained pressure carry the pressure-starved
|
|
557
|
+
* marker so a day-long overload reads differently from ordinary staleness.
|
|
558
|
+
* No sweep while paused (an operator pause must not silently expire the queue).
|
|
559
|
+
*/
|
|
560
|
+
expireTtl(pressureCalm) {
|
|
561
|
+
if (this.state.paused)
|
|
562
|
+
return [];
|
|
563
|
+
const expired = [];
|
|
564
|
+
const ttlMs = this.cfg.entryTtlHours * 3600_000;
|
|
565
|
+
for (const entry of this.state.entries) {
|
|
566
|
+
if (entry.status !== 'queued')
|
|
567
|
+
continue;
|
|
568
|
+
const anchor = Date.parse(entry.requeuedAt ?? entry.queuedAt);
|
|
569
|
+
const ageMs = this.now() - anchor - (entry.frozenMs ?? 0);
|
|
570
|
+
if (ageMs > ttlMs) {
|
|
571
|
+
entry.pressureStarved = !pressureCalm;
|
|
572
|
+
entry.status = 'gave-up:ttl';
|
|
573
|
+
expired.push(entry);
|
|
574
|
+
this.audit({ event: 'ttl-expired', id: entry.id, pressureStarved: entry.pressureStarved, ageMs });
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
if (expired.length > 0)
|
|
578
|
+
this.persist();
|
|
579
|
+
return expired;
|
|
580
|
+
}
|
|
581
|
+
/** Snapshot for the API surface (R2.10). */
|
|
582
|
+
snapshot() {
|
|
583
|
+
return {
|
|
584
|
+
paused: this.state.paused,
|
|
585
|
+
pauseReason: this.state.pauseReason,
|
|
586
|
+
disabled: this.disabledReason,
|
|
587
|
+
dryRun: this.cfg.dryRun,
|
|
588
|
+
entries: this.list(),
|
|
589
|
+
tombstones: [...this.state.tombstones],
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
/** True when a LIVE (non-dry-run) queued entry exists for this tmux session
|
|
593
|
+
* — feeds the notifier's "restart is queued" line (R1.2). */
|
|
594
|
+
hasLiveQueuedEntryFor(tmuxSession) {
|
|
595
|
+
if (this.cfg.dryRun || this.disabledReason || !this.cfg.enabled)
|
|
596
|
+
return false;
|
|
597
|
+
return this.state.entries.some((e) => e.tmuxSession === tmuxSession && (e.status === 'queued' || e.status === 'starting'));
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
//# sourceMappingURL=ResumeQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResumeQueue.js","sourceRoot":"","sources":["../../src/monitoring/ResumeQueue.ts"],"names":[],"mappings":"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"}
|