opencode-swarm 7.143.5 → 7.144.0

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 (58) hide show
  1. package/.opencode/skills/swarm-pr-review/SKILL.md +5 -5
  2. package/.opencode/skills/swarm-pr-review/references/lane-output-recoverability.md +129 -0
  3. package/dist/background/delegation-health.d.ts +213 -0
  4. package/dist/background/pending-delegations.d.ts +164 -16
  5. package/dist/background/pr-review-trigger-contract.d.ts +17 -0
  6. package/dist/cli/{config-doctor-y8wfw196.js → config-doctor-7gy47evn.js} +2 -2
  7. package/dist/cli/{core-zszmexgm.js → core-cpcspaw5.js} +1 -1
  8. package/dist/cli/{curator-llm-factory-xsg7wesn.js → curator-llm-factory-fyjmgxyp.js} +18 -18
  9. package/dist/cli/{curator-e2sp925h.js → curator-v97jnwn2.js} +18 -18
  10. package/dist/cli/{evidence-summary-service-pfppq7mv.js → evidence-summary-service-79mtxzhd.js} +6 -6
  11. package/dist/cli/{gate-evidence-23jnh3mb.js → gate-evidence-kgyqz1g1.js} +2 -2
  12. package/dist/cli/{guardrail-explain-byzmrgg1.js → guardrail-explain-9ry66z5g.js} +19 -19
  13. package/dist/cli/{guardrail-log-nr2g7hbw.js → guardrail-log-fe6smme1.js} +3 -3
  14. package/dist/cli/{hive-promoter-cw08380z.js → hive-promoter-vwq1dbh1.js} +18 -18
  15. package/dist/cli/{index-qdarzed6.js → index-0ck3e366.js} +1 -1
  16. package/dist/cli/{index-xmje20we.js → index-1pr8x10a.js} +2 -2
  17. package/dist/cli/{index-p844tcrm.js → index-269b52r3.js} +3 -3
  18. package/dist/cli/{index-04x9wx7d.js → index-3q9w6e6v.js} +1 -1
  19. package/dist/cli/{index-5866smj5.js → index-3v3dxf75.js} +3 -3
  20. package/dist/cli/{index-8aabbfhv.js → index-4fda8kkw.js} +1057 -92
  21. package/dist/cli/{index-jqxgdvr9.js → index-6p09gyra.js} +1 -1
  22. package/dist/cli/{index-mnj0ter5.js → index-8xertnqz.js} +3 -3
  23. package/dist/cli/{index-a1p87gew.js → index-d45d4zyq.js} +1 -1
  24. package/dist/cli/{index-y8r7z30j.js → index-d45yrzkg.js} +1 -1
  25. package/dist/cli/{index-1kr1vey5.js → index-e70d3xr7.js} +20 -20
  26. package/dist/cli/{index-a4dkd7m7.js → index-evvbmbbv.js} +1 -1
  27. package/dist/cli/{index-dg1v2gnh.js → index-ewzmjm7m.js} +1 -1
  28. package/dist/cli/{index-47z3jbxk.js → index-ez18gjk2.js} +3 -3
  29. package/dist/cli/{index-51axj9vd.js → index-j1scj25g.js} +481 -80
  30. package/dist/cli/{index-m7v7gggs.js → index-jqabjy7t.js} +4 -4
  31. package/dist/cli/{index-7en3eq3k.js → index-jvbfrwt2.js} +1 -1
  32. package/dist/cli/{index-tmc43mkc.js → index-mw6p3nt6.js} +1 -1
  33. package/dist/cli/{index-x64vt6sc.js → index-rd2082y4.js} +2 -2
  34. package/dist/cli/{index-q2nd6q9e.js → index-tfkfyshg.js} +1 -1
  35. package/dist/cli/{index-mbczeqs3.js → index-vb9cpaz4.js} +5 -5
  36. package/dist/cli/{index-at0h6cd6.js → index-zv4pwyas.js} +2 -2
  37. package/dist/cli/index.js +18 -18
  38. package/dist/cli/{knowledge-escalator-1g4p844a.js → knowledge-escalator-rmy3jcx4.js} +6 -6
  39. package/dist/cli/{knowledge-events-5699zzw0.js → knowledge-events-1tqpbwvj.js} +4 -4
  40. package/dist/cli/{knowledge-store-m5qjn5kd.js → knowledge-store-389ck792.js} +1 -1
  41. package/dist/cli/{knowledge-validator-xxnp8ear.js → knowledge-validator-kvtk6633.js} +2 -2
  42. package/dist/cli/{pending-delegations-b3pt3w5w.js → pending-delegations-thy8g30k.js} +27 -1
  43. package/dist/cli/{scan-cursor-qvky2yem.js → scan-cursor-ahgm4f5p.js} +2 -2
  44. package/dist/cli/{schema-wgb37f83.js → schema-epdq7ykx.js} +1 -1
  45. package/dist/cli/{scope-persistence-0wrb7ptt.js → scope-persistence-37s9n40v.js} +4 -4
  46. package/dist/cli/{skill-generator-khaw3jjw.js → skill-generator-4d2t5gem.js} +7 -7
  47. package/dist/cli/{worktree-collision-ownership-bfz3drxm.js → worktree-collision-ownership-j6d33p49.js} +1 -1
  48. package/dist/cli/{worktree-isolation-bv41gn3k.js → worktree-isolation-4628yaka.js} +18 -18
  49. package/dist/evaluation/contracts.d.ts +4 -4
  50. package/dist/evaluation/gate-ground-truth.d.ts +1 -1
  51. package/dist/hooks/init-orphan-recovery.d.ts +2 -0
  52. package/dist/hooks/pr-workflow-gate.d.ts +135 -1
  53. package/dist/index.js +446 -441
  54. package/dist/services/status-service.d.ts +9 -0
  55. package/dist/tools/complete-pr-workflow.d.ts +3 -1
  56. package/dist/tools/pr-workflow-status.d.ts +2 -2
  57. package/dist/tools/write-pr-review-trigger-eval.d.ts +2 -1
  58. package/package.json +1 -1
@@ -20,20 +20,225 @@ import {
20
20
  // src/background/pending-delegations.ts
21
21
  init_zod();
22
22
  import { createHash } from "crypto";
23
- import * as fs from "fs";
24
- import * as path from "path";
23
+ import * as fs2 from "fs";
24
+ import * as path2 from "path";
25
25
  import { isDeepStrictEqual } from "util";
26
26
  init_logger();
27
+
28
+ // src/background/delegation-health.ts
29
+ init_zod();
30
+ import * as fs from "fs";
31
+ import * as path from "path";
32
+ var BACKGROUND_DELEGATIONS_HEALTH_FILE = "background-delegations-health.json";
33
+ var MAX_RECOVERY_LEDGER_BYTES = 4 * 1024 * 1024;
34
+ var DelegationCheckpointAuditSchema = exports_external.object({
35
+ dispatchCount: exports_external.number().int().nonnegative(),
36
+ terminalsByStatus: exports_external.object({
37
+ completed: exports_external.number().int().nonnegative(),
38
+ error: exports_external.number().int().nonnegative(),
39
+ cancelled: exports_external.number().int().nonnegative(),
40
+ stale: exports_external.number().int().nonnegative()
41
+ }).strict(),
42
+ settledCount: exports_external.number().int().nonnegative(),
43
+ preservedCount: exports_external.number().int().nonnegative(),
44
+ lateTerminalCount: exports_external.number().int().nonnegative(),
45
+ compactedTransitionCount: exports_external.number().int().nonnegative(),
46
+ compactedRecordCount: exports_external.number().int().nonnegative(),
47
+ firstDispatchAt: exports_external.number().int().nonnegative().nullable(),
48
+ lastTerminalAt: exports_external.number().int().nonnegative().nullable(),
49
+ lastCompactionAt: exports_external.number().int().nonnegative()
50
+ }).strict();
51
+ var CheckpointSectionSchema = exports_external.object({
52
+ sequence: exports_external.number().int().positive(),
53
+ createdAt: exports_external.number().int().nonnegative(),
54
+ liveRecords: exports_external.number().int().nonnegative(),
55
+ closedSummaries: exports_external.number().int().nonnegative(),
56
+ bytes: exports_external.number().int().nonnegative(),
57
+ audit: DelegationCheckpointAuditSchema
58
+ }).strict();
59
+ var RecoverySectionSchema = exports_external.object({
60
+ source: exports_external.enum([
61
+ "checkpoint+tail",
62
+ "checkpoint+ledger-suffix",
63
+ "legacy-ledger",
64
+ "unknown"
65
+ ]),
66
+ at: exports_external.number().int().nonnegative(),
67
+ ok: exports_external.boolean(),
68
+ reason: exports_external.string().min(1).max(2000).optional(),
69
+ repairHint: exports_external.string().min(1).max(2000).optional()
70
+ }).strict();
71
+ var UncertaintySectionSchema = exports_external.object({
72
+ reason: exports_external.string().min(1).max(2000),
73
+ at: exports_external.number().int().nonnegative(),
74
+ source: exports_external.string().min(1).max(256),
75
+ repairHint: exports_external.string().min(1).max(2000).optional()
76
+ }).strict();
77
+ var DelegationLedgerHealthSchema = exports_external.object({
78
+ schemaVersion: exports_external.literal(1),
79
+ updatedAt: exports_external.number().int().nonnegative(),
80
+ ledger: exports_external.object({
81
+ bytes: exports_external.number().int().nonnegative(),
82
+ limitBytes: exports_external.number().int().positive(),
83
+ pressurePct: exports_external.number().min(0).max(100),
84
+ band: exports_external.enum(["ok", "nominal", "compact-overdue", "fail-closed"])
85
+ }).strict(),
86
+ checkpoint: CheckpointSectionSchema.nullable(),
87
+ recovery: RecoverySectionSchema.nullable(),
88
+ lastUncertainty: UncertaintySectionSchema.nullable(),
89
+ counts: exports_external.object({
90
+ activeOwners: exports_external.number().int().nonnegative(),
91
+ pendingAdvisories: exports_external.number().int().nonnegative(),
92
+ lateTerminals: exports_external.number().int().nonnegative(),
93
+ orphanWorktreeOwners: exports_external.number().int().nonnegative()
94
+ }).strict()
95
+ }).strict();
96
+ function sleepSync(ms) {
97
+ try {
98
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
99
+ } catch {
100
+ const start = Date.now();
101
+ while (Date.now() - start < ms) {}
102
+ }
103
+ }
104
+ var _healthInternals = {
105
+ renameOnce: (from, to) => {
106
+ fs.renameSync(from, to);
107
+ }
108
+ };
109
+ function healthArtifactPath(directory) {
110
+ return validateSwarmPath(directory, BACKGROUND_DELEGATIONS_HEALTH_FILE);
111
+ }
112
+ function readDelegationHealthArtifact(directory) {
113
+ let raw;
114
+ try {
115
+ raw = fs.readFileSync(healthArtifactPath(directory), "utf-8");
116
+ } catch {
117
+ return null;
118
+ }
119
+ try {
120
+ const parsed = DelegationLedgerHealthSchema.safeParse(JSON.parse(raw));
121
+ return parsed.success ? parsed.data : null;
122
+ } catch {
123
+ return null;
124
+ }
125
+ }
126
+ function writeDelegationHealthArtifact(directory, update) {
127
+ const existing = readDelegationHealthArtifact(directory);
128
+ const base = existing ?? {
129
+ schemaVersion: 1,
130
+ updatedAt: 0,
131
+ ledger: {
132
+ bytes: 0,
133
+ limitBytes: MAX_RECOVERY_LEDGER_BYTES,
134
+ pressurePct: 0,
135
+ band: "ok"
136
+ },
137
+ checkpoint: null,
138
+ recovery: null,
139
+ lastUncertainty: null,
140
+ counts: {
141
+ activeOwners: 0,
142
+ pendingAdvisories: 0,
143
+ lateTerminals: 0,
144
+ orphanWorktreeOwners: 0
145
+ }
146
+ };
147
+ const next = {
148
+ schemaVersion: 1,
149
+ updatedAt: Date.now(),
150
+ ledger: update.ledger ?? base.ledger,
151
+ checkpoint: update.checkpoint === undefined ? base.checkpoint : update.checkpoint,
152
+ recovery: update.recovery === undefined ? base.recovery : update.recovery,
153
+ lastUncertainty: update.lastUncertainty ?? base.lastUncertainty,
154
+ counts: update.counts ?? base.counts
155
+ };
156
+ if (update.uncertainty) {
157
+ next.lastUncertainty = update.uncertainty;
158
+ }
159
+ const parsed = DelegationLedgerHealthSchema.safeParse(next);
160
+ if (!parsed.success)
161
+ return null;
162
+ try {
163
+ fs.mkdirSync(path.resolve(directory, ".swarm"), { recursive: true });
164
+ const target = healthArtifactPath(directory);
165
+ const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2, 10)}`;
166
+ fs.writeFileSync(tmp, `${JSON.stringify(parsed.data)}
167
+ `, "utf-8");
168
+ let lastError;
169
+ for (let attempt = 0;attempt < 5; attempt++) {
170
+ try {
171
+ _healthInternals.renameOnce(tmp, target);
172
+ lastError = undefined;
173
+ break;
174
+ } catch (err) {
175
+ lastError = err;
176
+ const code = err.code;
177
+ if (code !== "EEXIST" && code !== "EBUSY" && code !== "EPERM") {
178
+ break;
179
+ }
180
+ if (attempt < 4)
181
+ sleepSync(15);
182
+ }
183
+ }
184
+ if (lastError !== undefined) {
185
+ try {
186
+ fs.rmSync(tmp, { force: true });
187
+ } catch {}
188
+ return null;
189
+ }
190
+ return parsed.data;
191
+ } catch {
192
+ return null;
193
+ }
194
+ }
195
+ function collectDelegationLedgerHealth(directory, options) {
196
+ const artifact = readDelegationHealthArtifact(directory);
197
+ let ledgerBytes = 0;
198
+ let ledgerExists = false;
199
+ try {
200
+ ledgerBytes = fs.statSync(validateSwarmPath(directory, "background-delegations.jsonl")).size;
201
+ ledgerExists = true;
202
+ } catch {
203
+ ledgerExists = false;
204
+ }
205
+ if (!artifact && !ledgerExists)
206
+ return null;
207
+ const limitBytes = options.ledgerLimitBytes;
208
+ const pressurePct = Math.min(100, Math.round(ledgerBytes / limitBytes * 1000) / 10);
209
+ const band = ledgerBytes > limitBytes ? "fail-closed" : ledgerBytes > options.highWaterBytes ? "compact-overdue" : ledgerBytes > options.lowWaterBytes ? "nominal" : "ok";
210
+ return {
211
+ schemaVersion: 1,
212
+ updatedAt: artifact?.updatedAt ?? 0,
213
+ ledger: { bytes: ledgerBytes, limitBytes, pressurePct, band },
214
+ checkpoint: artifact?.checkpoint ?? null,
215
+ recovery: artifact?.recovery ?? null,
216
+ lastUncertainty: artifact?.lastUncertainty ?? null,
217
+ counts: artifact?.counts ?? {
218
+ activeOwners: 0,
219
+ pendingAdvisories: 0,
220
+ lateTerminals: 0,
221
+ orphanWorktreeOwners: 0
222
+ }
223
+ };
224
+ }
225
+ // src/background/pending-delegations.ts
27
226
  var BACKGROUND_DELEGATIONS_FILE = "background-delegations.jsonl";
28
227
  var BACKGROUND_DELEGATION_FALLBACK_DIR = "background-delegation-fallback";
29
228
  var BACKGROUND_CODER_RESERVATIONS_FILE = "background-coder-reservations.json";
229
+ var BACKGROUND_DELEGATIONS_CHECKPOINT_FILE = "background-delegations.checkpoint.json";
230
+ var BACKGROUND_DELEGATIONS_MANIFEST_FILE = "background-delegations.manifest.json";
30
231
  var MAX_LIVE_BACKGROUND_FALLBACKS = 256;
31
232
  var MAX_LIVE_BACKGROUND_CODER_RESERVATIONS = 256;
32
233
  var MAX_BACKGROUND_OBSERVED_FILES = 5000;
33
234
  var MAX_BACKGROUND_ADVISORY_CHARS = 4000;
34
235
  var MAX_BACKGROUND_DELEGATION_GENERATION = 1e6;
35
- var MAX_RECOVERY_LEDGER_BYTES = 4 * 1024 * 1024;
36
236
  var MAX_RECOVERY_FALLBACK_BYTES = 1024 * 1024;
237
+ var DELEGATION_COMPACTION_LOW_WATER_BYTES = 256 * 1024;
238
+ var DELEGATION_COMPACTION_HIGH_WATER_BYTES = 1024 * 1024;
239
+ var MAX_CHECKPOINT_BYTES = 2 * 1024 * 1024;
240
+ var MAX_CHECKPOINT_RECORDS = 2048;
241
+ var TOMBSTONE_MIN_AGE_MS = 72 * 60 * 60 * 1000;
37
242
  var STORE_LOCK_AGENT = "background";
38
243
  var STORE_LOCK_TASK = "background-delegations";
39
244
  var FALLBACK_LOCK_TASK = "background-delegation-fallback";
@@ -41,6 +246,8 @@ var RESERVATION_LOCK_TASK = "background-coder-reservations";
41
246
  var ADVISORY_PREPARE_LEASE_MS = 30000;
42
247
  var INGESTION_CLAIM_LEASE_MS = 30000;
43
248
  var BACKGROUND_INGESTION_LEASE_MS = 30000;
249
+ var DEFAULT_STALE_DELEGATION_TIMEOUT_MS = 30 * 60000;
250
+ var DEFAULT_SWEEPABLE_DELEGATION_STATUSES = new Set(["pending", "running", "ingestion_error"]);
44
251
  var ResultSchema = exports_external.object({
45
252
  text: exports_external.string().optional(),
46
253
  error: exports_external.string().optional(),
@@ -289,43 +496,359 @@ var FallbackArtifactSchema = exports_external.object({
289
496
  function storePath(directory) {
290
497
  return validateSwarmPath(directory, BACKGROUND_DELEGATIONS_FILE);
291
498
  }
292
- function ensureSwarmDir(directory) {
293
- fs.mkdirSync(path.resolve(directory, ".swarm"), { recursive: true });
499
+ function checkpointPath(directory) {
500
+ return validateSwarmPath(directory, BACKGROUND_DELEGATIONS_CHECKPOINT_FILE);
294
501
  }
295
- function readDelegations(directory) {
502
+ function manifestPath(directory) {
503
+ return validateSwarmPath(directory, BACKGROUND_DELEGATIONS_MANIFEST_FILE);
504
+ }
505
+ var SHA256_HEX = /^[0-9a-f]{64}$/;
506
+ var CheckpointSchema = exports_external.object({
507
+ schemaVersion: exports_external.literal(1),
508
+ sequence: exports_external.number().int().positive(),
509
+ writerId: exports_external.string().min(1).max(128),
510
+ rootPath: exports_external.string().min(1).max(4096),
511
+ createdAt: exports_external.number().int().nonnegative(),
512
+ cutLedgerBytes: exports_external.number().int().nonnegative(),
513
+ cutLedgerDigest: exports_external.string().regex(SHA256_HEX),
514
+ records: exports_external.array(RecordSchema).max(MAX_CHECKPOINT_RECORDS),
515
+ closed: exports_external.array(RecordSchema),
516
+ audit: DelegationCheckpointAuditSchema,
517
+ payloadChecksum: exports_external.string().regex(SHA256_HEX)
518
+ }).strict();
519
+ var ManifestSchema = exports_external.object({
520
+ schemaVersion: exports_external.literal(1),
521
+ sequence: exports_external.number().int().positive(),
522
+ checkpointChecksum: exports_external.string().regex(SHA256_HEX),
523
+ writerId: exports_external.string().min(1).max(128),
524
+ rootPath: exports_external.string().min(1).max(4096),
525
+ updatedAt: exports_external.number().int().nonnegative()
526
+ }).strict();
527
+ var WRITER_ID = `w-${process.pid}-${Math.random().toString(36).slice(2, 10)}`;
528
+ var _checkpointInternals = {
529
+ renameWithRetry: (from, to) => {
530
+ let lastError;
531
+ for (let attempt = 0;attempt < 5; attempt++) {
532
+ try {
533
+ _checkpointInternals.renameOnce(from, to);
534
+ return;
535
+ } catch (err) {
536
+ lastError = err;
537
+ const code = err.code;
538
+ if (code !== "EEXIST" && code !== "EBUSY" && code !== "EPERM") {
539
+ throw err;
540
+ }
541
+ _checkpointInternals.syncSleep(15);
542
+ }
543
+ }
544
+ throw lastError;
545
+ },
546
+ renameOnce: (from, to) => {
547
+ fs2.renameSync(from, to);
548
+ },
549
+ syncSleep: (ms) => {
550
+ try {
551
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
552
+ } catch {
553
+ const start = Date.now();
554
+ while (Date.now() - start < ms) {}
555
+ }
556
+ }
557
+ };
558
+ function writeDurableFileSync(target, contents) {
559
+ const tmp = `${target}.tmp-${process.pid}-${Math.random().toString(36).slice(2, 10)}`;
560
+ try {
561
+ const fd = fs2.openSync(tmp, "w");
562
+ try {
563
+ if (typeof contents === "string") {
564
+ fs2.writeSync(fd, contents);
565
+ } else {
566
+ fs2.writeSync(fd, contents, 0, contents.length);
567
+ }
568
+ fs2.fsyncSync(fd);
569
+ } finally {
570
+ fs2.closeSync(fd);
571
+ }
572
+ _checkpointInternals.renameWithRetry(tmp, target);
573
+ } catch (err) {
574
+ try {
575
+ fs2.rmSync(tmp, { force: true });
576
+ } catch {}
577
+ throw err;
578
+ }
579
+ try {
580
+ const dfd = fs2.openSync(path2.dirname(target), "r");
581
+ try {
582
+ fs2.fsyncSync(dfd);
583
+ } finally {
584
+ fs2.closeSync(dfd);
585
+ }
586
+ } catch {}
587
+ }
588
+ function readJsonFileWithRetry(target) {
296
589
  let raw;
297
590
  try {
298
- raw = fs.readFileSync(storePath(directory), "utf-8");
591
+ raw = fs2.readFileSync(target, "utf-8");
299
592
  } catch (err) {
300
- if (err.code === "ENOENT")
301
- return [];
302
- warn(`[background] readDelegations failed: ${err instanceof Error ? err.message : String(err)}`);
303
- return [];
593
+ const code = err.code;
594
+ if (code === "ENOENT")
595
+ return { status: "absent" };
596
+ return {
597
+ status: "invalid",
598
+ reason: `unreadable (${code ?? "unknown error"})`
599
+ };
600
+ }
601
+ try {
602
+ return { status: "ok", value: JSON.parse(raw) };
603
+ } catch (err) {
604
+ return {
605
+ status: "invalid",
606
+ reason: `malformed JSON (${err instanceof Error ? err.message : String(err)})`
607
+ };
608
+ }
609
+ }
610
+ function readDelegationManifest(directory) {
611
+ const read = readJsonFileWithRetry(manifestPath(directory));
612
+ if (read.status === "absent")
613
+ return { kind: "absent" };
614
+ if (read.status === "invalid")
615
+ return { kind: "invalid", reason: read.reason };
616
+ const parsed = ManifestSchema.safeParse(read.value);
617
+ if (!parsed.success) {
618
+ return { kind: "invalid", reason: "manifest fails schema validation" };
619
+ }
620
+ return { kind: "ok", manifest: parsed.data };
621
+ }
622
+ function readDelegationCheckpoint(directory) {
623
+ let bytes = 0;
624
+ try {
625
+ bytes = fs2.statSync(checkpointPath(directory)).size;
626
+ } catch {}
627
+ if (bytes > MAX_CHECKPOINT_BYTES) {
628
+ return {
629
+ kind: "invalid",
630
+ reason: `checkpoint exceeds the ${MAX_CHECKPOINT_BYTES}-byte bound`
631
+ };
632
+ }
633
+ const read = readJsonFileWithRetry(checkpointPath(directory));
634
+ if (read.status === "absent")
635
+ return { kind: "absent" };
636
+ if (read.status === "invalid")
637
+ return { kind: "invalid", reason: read.reason };
638
+ const parsed = CheckpointSchema.safeParse(read.value);
639
+ if (!parsed.success) {
640
+ return { kind: "invalid", reason: "checkpoint fails schema validation" };
641
+ }
642
+ return { kind: "ok", checkpoint: parsed.data, bytes };
643
+ }
644
+ function sha256Hex(data) {
645
+ return createHash("sha256").update(data).digest("hex");
646
+ }
647
+ function checkpointPayloadChecksum(checkpoint) {
648
+ return sha256Hex(JSON.stringify([
649
+ checkpoint.schemaVersion,
650
+ checkpoint.sequence,
651
+ checkpoint.writerId,
652
+ checkpoint.rootPath,
653
+ checkpoint.createdAt,
654
+ checkpoint.cutLedgerBytes,
655
+ checkpoint.cutLedgerDigest,
656
+ checkpoint.records,
657
+ checkpoint.closed,
658
+ checkpoint.audit
659
+ ]));
660
+ }
661
+ var CHECKPOINT_REBIND_HINT = "remove .swarm/background-delegations.manifest.json (manifest only) after verifying no in-flight background delegations; recovery then falls back to the full-ledger read. Only if you also want to discard pre-cut closed summaries and audit history \u2014 which for a compacted (rolled) ledger exist ONLY in .swarm/background-delegations.checkpoint.json \u2014 remove the checkpoint too or use the full reset below";
662
+ var CHECKPOINT_RESET_HINT = "the rolled tail no longer carries pre-checkpoint state: stop swarm processes, verify no in-flight background delegations, and remove .swarm/background-delegations.manifest.json, .swarm/background-delegations.checkpoint.json, and .swarm/background-delegations.jsonl to reset the store (or restore them from backup)";
663
+ function loadFoldedState(directory, options) {
664
+ const manifestRead = readDelegationManifest(directory);
665
+ if (manifestRead.kind === "invalid") {
666
+ return {
667
+ status: "uncertain",
668
+ reason: `background delegation manifest is invalid: ${manifestRead.reason}`,
669
+ repairHint: CHECKPOINT_RESET_HINT
670
+ };
671
+ }
672
+ if (manifestRead.kind === "absent") {
673
+ return loadLegacyLedger(directory, options.strict);
674
+ }
675
+ const manifest = manifestRead.manifest;
676
+ if (manifest.rootPath !== path2.resolve(directory)) {
677
+ return {
678
+ status: "uncertain",
679
+ reason: "background delegation checkpoint is bound to a different project root",
680
+ repairHint: CHECKPOINT_REBIND_HINT
681
+ };
682
+ }
683
+ const checkpointRead = readDelegationCheckpoint(directory);
684
+ if (checkpointRead.kind === "invalid" || checkpointRead.kind === "absent") {
685
+ const detail = checkpointRead.kind === "invalid" ? `: ${checkpointRead.reason}` : " (file missing)";
686
+ return {
687
+ status: "uncertain",
688
+ reason: `background delegation checkpoint is invalid${detail} while a manifest is published`,
689
+ repairHint: CHECKPOINT_RESET_HINT
690
+ };
691
+ }
692
+ const checkpoint = checkpointRead.checkpoint;
693
+ if (checkpoint.sequence !== manifest.sequence && checkpoint.sequence !== manifest.sequence + 1) {
694
+ return {
695
+ status: "uncertain",
696
+ reason: `background delegation checkpoint/manifest sequence mismatch (checkpoint ${checkpoint.sequence}, manifest ${manifest.sequence})`,
697
+ repairHint: CHECKPOINT_RESET_HINT
698
+ };
699
+ }
700
+ if (checkpoint.sequence === manifest.sequence && manifest.checkpointChecksum !== checkpoint.payloadChecksum) {
701
+ return {
702
+ status: "uncertain",
703
+ reason: "background delegation manifest checksum does not match its checkpoint",
704
+ repairHint: CHECKPOINT_RESET_HINT
705
+ };
706
+ }
707
+ if (checkpointPayloadChecksum(checkpoint) !== checkpoint.payloadChecksum) {
708
+ return {
709
+ status: "uncertain",
710
+ reason: "background delegation checkpoint payload checksum mismatch",
711
+ repairHint: CHECKPOINT_RESET_HINT
712
+ };
713
+ }
714
+ let stat;
715
+ try {
716
+ stat = fs2.statSync(storePath(directory));
717
+ } catch (error) {
718
+ return {
719
+ status: "uncertain",
720
+ reason: `background delegation ledger metadata is unreadable: ${error instanceof Error ? error.message : String(error)}`
721
+ };
722
+ }
723
+ let tail;
724
+ let mode;
725
+ if (stat.size >= checkpoint.cutLedgerBytes && checkpoint.cutLedgerBytes > 0) {
726
+ const prefix = readLedgerRegion(directory, 0, checkpoint.cutLedgerBytes);
727
+ if (sha256Hex(prefix) === checkpoint.cutLedgerDigest) {
728
+ const suffixBytes = stat.size - checkpoint.cutLedgerBytes;
729
+ if (suffixBytes > MAX_RECOVERY_LEDGER_BYTES) {
730
+ return {
731
+ status: "uncertain",
732
+ reason: `background delegation ledger changed beyond the ${MAX_RECOVERY_LEDGER_BYTES}-byte recovery bound`
733
+ };
734
+ }
735
+ tail = suffixBytes === 0 ? Buffer.alloc(0) : readLedgerRegion(directory, checkpoint.cutLedgerBytes, suffixBytes);
736
+ mode = "checkpoint+ledger-suffix";
737
+ } else {
738
+ tail = readBoundedRecentLedgerWindow(directory, stat.size);
739
+ mode = "checkpoint+tail";
740
+ }
741
+ } else {
742
+ tail = readBoundedRecentLedgerWindow(directory, stat.size);
743
+ mode = "checkpoint+tail";
744
+ }
745
+ const records = new Map;
746
+ for (const record of checkpoint.records) {
747
+ records.set(record.correlationId, record);
748
+ }
749
+ for (const summary of checkpoint.closed) {
750
+ records.set(summary.correlationId, summary);
751
+ }
752
+ const foldError = foldLedgerTail(records, tail, options.strict, checkpoint);
753
+ if (foldError)
754
+ return { status: "uncertain", reason: foldError };
755
+ return {
756
+ status: "ok",
757
+ mode,
758
+ records,
759
+ manifest,
760
+ checkpoint
761
+ };
762
+ }
763
+ function readLedgerRegion(directory, offset, length) {
764
+ const fd = fs2.openSync(storePath(directory), "r");
765
+ try {
766
+ const buffer = Buffer.alloc(length);
767
+ let read = 0;
768
+ while (read < length) {
769
+ const n = fs2.readSync(fd, buffer, read, length - read, offset + read);
770
+ if (n <= 0)
771
+ break;
772
+ read += n;
773
+ }
774
+ return read === length ? buffer : buffer.subarray(0, read);
775
+ } finally {
776
+ fs2.closeSync(fd);
777
+ }
778
+ }
779
+ function readBoundedRecentLedgerWindow(directory, size) {
780
+ if (size === 0)
781
+ return Buffer.alloc(0);
782
+ if (size <= MAX_RECOVERY_LEDGER_BYTES) {
783
+ return readLedgerRegion(directory, 0, size);
304
784
  }
305
- const folded = new Map;
306
- for (const line of raw.split(`
785
+ const window = readLedgerRegion(directory, size - MAX_RECOVERY_LEDGER_BYTES, MAX_RECOVERY_LEDGER_BYTES);
786
+ const firstNewline = window.indexOf(10);
787
+ return firstNewline === -1 ? Buffer.alloc(0) : window.subarray(firstNewline + 1);
788
+ }
789
+ function foldLedgerTail(records, tail, strict, checkpoint) {
790
+ let lineNumber = 0;
791
+ for (const line of tail.toString("utf-8").split(`
307
792
  `)) {
793
+ lineNumber += 1;
308
794
  const trimmed = line.trim();
309
- if (trimmed.length === 0)
795
+ if (!trimmed)
310
796
  continue;
311
797
  let parsedJson;
312
798
  try {
313
799
  parsedJson = JSON.parse(trimmed);
314
800
  } catch {
801
+ if (strict) {
802
+ return `background delegation ledger has malformed JSON at line ${lineNumber}`;
803
+ }
804
+ continue;
805
+ }
806
+ const parsed = RecordSchema.safeParse(parsedJson);
807
+ if (!parsed.success) {
808
+ if (strict) {
809
+ return `background delegation ledger has an invalid record at line ${lineNumber}`;
810
+ }
315
811
  continue;
316
812
  }
317
- const result = RecordSchema.safeParse(parsedJson);
318
- if (!result.success)
813
+ const existing = checkpoint ? records.get(parsed.data.correlationId) : undefined;
814
+ if (checkpoint && existing && !(parsed.data.updatedAt > existing.updatedAt) && !(parsed.data.updatedAt === existing.updatedAt && parsed.data.updatedAt > checkpoint.createdAt)) {
319
815
  continue;
320
- folded.set(result.data.correlationId, result.data);
816
+ }
817
+ records.set(parsed.data.correlationId, parsed.data);
321
818
  }
322
- return [...folded.values()];
819
+ return null;
323
820
  }
324
- function scanDelegationsForRecovery(directory) {
821
+ function loadLegacyLedger(directory, strict) {
822
+ if (!strict) {
823
+ let raw2;
824
+ try {
825
+ raw2 = fs2.readFileSync(storePath(directory), "utf-8");
826
+ } catch (err) {
827
+ if (err.code !== "ENOENT") {
828
+ warn(`[background] readDelegations failed: ${err instanceof Error ? err.message : String(err)}`);
829
+ }
830
+ return {
831
+ status: "ok",
832
+ mode: "legacy",
833
+ records: new Map,
834
+ manifest: null,
835
+ checkpoint: null
836
+ };
837
+ }
838
+ const records2 = new Map;
839
+ const foldError2 = foldLedgerTail(records2, Buffer.from(raw2, "utf-8"), false);
840
+ return {
841
+ status: "ok",
842
+ mode: "legacy",
843
+ records: records2,
844
+ manifest: null,
845
+ checkpoint: null
846
+ };
847
+ }
325
848
  let absolutePath;
326
849
  try {
327
850
  absolutePath = storePath(directory);
328
- const stat = fs.statSync(absolutePath);
851
+ const stat = fs2.statSync(absolutePath);
329
852
  if (stat.size > MAX_RECOVERY_LEDGER_BYTES) {
330
853
  return {
331
854
  status: "uncertain",
@@ -334,7 +857,13 @@ function scanDelegationsForRecovery(directory) {
334
857
  }
335
858
  } catch (error) {
336
859
  if (error.code === "ENOENT") {
337
- return { status: "ok", owners: [] };
860
+ return {
861
+ status: "ok",
862
+ mode: "legacy",
863
+ records: new Map,
864
+ manifest: null,
865
+ checkpoint: null
866
+ };
338
867
  }
339
868
  return {
340
869
  status: "uncertain",
@@ -343,7 +872,7 @@ function scanDelegationsForRecovery(directory) {
343
872
  }
344
873
  let raw;
345
874
  try {
346
- raw = fs.readFileSync(absolutePath, "utf-8");
875
+ raw = fs2.readFileSync(absolutePath, "utf-8");
347
876
  } catch (error) {
348
877
  return {
349
878
  status: "uncertain",
@@ -356,33 +885,392 @@ function scanDelegationsForRecovery(directory) {
356
885
  reason: `background delegation ledger changed beyond the ${MAX_RECOVERY_LEDGER_BYTES}-byte recovery bound`
357
886
  };
358
887
  }
359
- const folded = new Map;
360
- let lineNumber = 0;
361
- for (const line of raw.split(`
362
- `)) {
363
- lineNumber += 1;
364
- const trimmed = line.trim();
365
- if (!trimmed)
888
+ const records = new Map;
889
+ const foldError = foldLedgerTail(records, Buffer.from(raw, "utf-8"), true);
890
+ if (foldError)
891
+ return { status: "uncertain", reason: foldError };
892
+ return {
893
+ status: "ok",
894
+ mode: "legacy",
895
+ records,
896
+ manifest: null,
897
+ checkpoint: null
898
+ };
899
+ }
900
+ function loadRecordsForWrite(directory) {
901
+ const load = loadFoldedState(directory, { strict: false });
902
+ if (load.status === "uncertain") {
903
+ recordLedgerUncertainty(directory, load.reason, "mutation", load.repairHint);
904
+ return null;
905
+ }
906
+ return [...load.records.values()];
907
+ }
908
+ function findRecordForWrite(records, correlationId) {
909
+ if (!records)
910
+ return null;
911
+ for (const record of records) {
912
+ if (record.correlationId === correlationId)
913
+ return record;
914
+ }
915
+ return null;
916
+ }
917
+ function recordLedgerUncertainty(directory, reason, source, repairHint) {
918
+ try {
919
+ writeDelegationHealthArtifact(directory, {
920
+ uncertainty: {
921
+ reason,
922
+ at: Date.now(),
923
+ source,
924
+ ...repairHint ? { repairHint } : {}
925
+ }
926
+ });
927
+ } catch {}
928
+ }
929
+ function isUnsettledWorktreeOwner(record) {
930
+ return Boolean(record.worktree) && !(record.coderSettlement?.state === "settled" && record.coderSettlement.outcome?.kind === "standard-worktree" && (record.coderSettlement.outcome.result === "merged" || record.coderSettlement.outcome.result === "unchanged"));
931
+ }
932
+ function isCheckpointLiveRecord(record) {
933
+ if (!isTerminal(record.status))
934
+ return true;
935
+ if (record.advisoryInbox?.state === "pending")
936
+ return true;
937
+ const settlement = record.coderSettlement;
938
+ if (settlement && settlement.state !== "settled")
939
+ return true;
940
+ if (settlement?.state === "settled" && isUnsettledWorktreeOwner(record)) {
941
+ return true;
942
+ }
943
+ if (isActiveCoderOwner(record))
944
+ return true;
945
+ return false;
946
+ }
947
+ function buildClosedSummary(record) {
948
+ const summary = { ...record };
949
+ delete summary.prompt;
950
+ delete summary.taskChangeContext;
951
+ if (summary.result) {
952
+ summary.result = stripResultBody(summary.result);
953
+ }
954
+ if (summary.terminalResult) {
955
+ summary.terminalResult = {
956
+ ...summary.terminalResult,
957
+ result: stripResultBody(summary.terminalResult.result)
958
+ };
959
+ }
960
+ const parsed = RecordSchema.safeParse(summary);
961
+ return parsed.success ? parsed.data : null;
962
+ }
963
+ function stripResultBody(result) {
964
+ const { text: _text, error: _error, ...rest } = result;
965
+ return rest;
966
+ }
967
+ function emptyAudit() {
968
+ return {
969
+ dispatchCount: 0,
970
+ terminalsByStatus: { completed: 0, error: 0, cancelled: 0, stale: 0 },
971
+ settledCount: 0,
972
+ preservedCount: 0,
973
+ lateTerminalCount: 0,
974
+ compactedTransitionCount: 0,
975
+ compactedRecordCount: 0,
976
+ firstDispatchAt: null,
977
+ lastTerminalAt: null,
978
+ lastCompactionAt: 0
979
+ };
980
+ }
981
+ function terminalEventStatusOf(record) {
982
+ if (record.terminalResult) {
983
+ return record.terminalResult.status;
984
+ }
985
+ if (record.status === "completed" || record.status === "error" || record.status === "cancelled" || record.status === "stale") {
986
+ return record.status;
987
+ }
988
+ return null;
989
+ }
990
+ function mergeCheckpointAudit(previous, previousCheckpoint, folded, healthLateTerminals, retiredLineCount, newlySummarizedCount, now) {
991
+ const prev = previous ?? emptyAudit();
992
+ const prevById = new Map;
993
+ if (previousCheckpoint) {
994
+ for (const record of previousCheckpoint.records) {
995
+ prevById.set(record.correlationId, record);
996
+ }
997
+ for (const summary of previousCheckpoint.closed) {
998
+ prevById.set(summary.correlationId, summary);
999
+ }
1000
+ }
1001
+ const audit = {
1002
+ dispatchCount: prev.dispatchCount,
1003
+ terminalsByStatus: { ...prev.terminalsByStatus },
1004
+ settledCount: prev.settledCount,
1005
+ preservedCount: prev.preservedCount,
1006
+ lateTerminalCount: Math.max(prev.lateTerminalCount, healthLateTerminals),
1007
+ compactedTransitionCount: capCounter(prev.compactedTransitionCount, retiredLineCount),
1008
+ compactedRecordCount: capCounter(prev.compactedRecordCount, newlySummarizedCount),
1009
+ firstDispatchAt: prev.firstDispatchAt,
1010
+ lastTerminalAt: prev.lastTerminalAt,
1011
+ lastCompactionAt: now
1012
+ };
1013
+ let minCreated = Number.POSITIVE_INFINITY;
1014
+ let maxTerminal = 0;
1015
+ for (const record of folded) {
1016
+ const prevRecord = prevById.get(record.correlationId);
1017
+ if (!prevRecord) {
1018
+ audit.dispatchCount += 1;
1019
+ }
1020
+ const terminalStatus = terminalEventStatusOf(record);
1021
+ if (terminalStatus) {
1022
+ const prevStatus = prevRecord ? terminalEventStatusOf(prevRecord) : null;
1023
+ if (prevStatus !== terminalStatus) {
1024
+ audit.terminalsByStatus[terminalStatus] += 1;
1025
+ }
1026
+ maxTerminal = Math.max(maxTerminal, record.terminalResult?.recordedAt ?? record.completedAt ?? 0);
1027
+ }
1028
+ if (record.coderSettlement?.state === "settled" && prevRecord?.coderSettlement?.state !== "settled") {
1029
+ audit.settledCount += 1;
1030
+ }
1031
+ if (record.coderSettlement?.state === "preserved" && prevRecord?.coderSettlement?.state !== "preserved") {
1032
+ audit.preservedCount += 1;
1033
+ }
1034
+ minCreated = Math.min(minCreated, record.createdAt);
1035
+ }
1036
+ audit.firstDispatchAt = Number.isFinite(minCreated) ? Math.min(prev.firstDispatchAt ?? Number.POSITIVE_INFINITY, minCreated) : prev.firstDispatchAt;
1037
+ audit.lastTerminalAt = Math.max(prev.lastTerminalAt ?? 0, maxTerminal) || null;
1038
+ return audit;
1039
+ }
1040
+ function capCounter(previous, delta) {
1041
+ return Number.isSafeInteger(previous + delta) ? previous + delta : Number.MAX_SAFE_INTEGER;
1042
+ }
1043
+ async function compactBackgroundDelegations(directory, options = {}) {
1044
+ try {
1045
+ let outcome = {
1046
+ status: "skipped",
1047
+ reason: "not attempted"
1048
+ };
1049
+ await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
1050
+ outcome = compactDelegationsLocked(directory, options);
1051
+ });
1052
+ return outcome;
1053
+ } catch (err) {
1054
+ const message = err instanceof Error ? err.message : String(err);
1055
+ warn(`[background] compactBackgroundDelegations failed: ${message}`);
1056
+ return { status: "uncertain", reason: message };
1057
+ }
1058
+ }
1059
+ function compactDelegationsLocked(directory, options) {
1060
+ const load = loadFoldedState(directory, { strict: false });
1061
+ if (load.status === "uncertain") {
1062
+ recordLedgerUncertainty(directory, load.reason, "compaction", load.repairHint);
1063
+ return { status: "uncertain", reason: load.reason };
1064
+ }
1065
+ let ledgerBytes;
1066
+ try {
1067
+ ledgerBytes = fs2.readFileSync(storePath(directory));
1068
+ } catch (err) {
1069
+ if (err.code === "ENOENT") {
1070
+ return { status: "skipped", reason: "no ledger to compact" };
1071
+ }
1072
+ return {
1073
+ status: "uncertain",
1074
+ reason: err instanceof Error ? err.message : String(err)
1075
+ };
1076
+ }
1077
+ if (ledgerBytes.length <= DELEGATION_COMPACTION_HIGH_WATER_BYTES && !options.force) {
1078
+ return {
1079
+ status: "skipped",
1080
+ reason: "ledger below the compaction high-water mark"
1081
+ };
1082
+ }
1083
+ const cutLedgerBytes = ledgerBytes.length;
1084
+ const retiredLineCount = countCompleteLines(ledgerBytes);
1085
+ const now = Date.now();
1086
+ const folded = [...load.records.values()];
1087
+ const live = [];
1088
+ const closedCandidates = [];
1089
+ for (const record of folded) {
1090
+ if (isCheckpointLiveRecord(record)) {
1091
+ live.push(record);
1092
+ } else {
1093
+ closedCandidates.push(buildClosedSummary(record) ?? record);
1094
+ }
1095
+ }
1096
+ if (live.length > MAX_CHECKPOINT_RECORDS) {
1097
+ recordLedgerUncertainty(directory, `checkpoint live-record budget exceeded (${live.length} > ${MAX_CHECKPOINT_RECORDS}); compaction skipped`, "compaction");
1098
+ return {
1099
+ status: "skipped",
1100
+ reason: `live record count ${live.length} exceeds the checkpoint budget ${MAX_CHECKPOINT_RECORDS}`
1101
+ };
1102
+ }
1103
+ closedCandidates.sort((a, b) => b.updatedAt - a.updatedAt);
1104
+ const baseOverhead = Buffer.byteLength(JSON.stringify({
1105
+ schemaVersion: 1,
1106
+ sequence: 1,
1107
+ writerId: WRITER_ID,
1108
+ rootPath: path2.resolve(directory),
1109
+ createdAt: now,
1110
+ cutLedgerBytes,
1111
+ cutLedgerDigest: sha256Hex(ledgerBytes),
1112
+ records: live,
1113
+ closed: [],
1114
+ audit: emptyAudit(),
1115
+ payloadChecksum: "0".repeat(64)
1116
+ }), "utf-8");
1117
+ let used = baseOverhead;
1118
+ const keptClosed = [];
1119
+ let evicted = 0;
1120
+ for (const entry of closedCandidates) {
1121
+ const cost = Buffer.byteLength(JSON.stringify(entry), "utf-8") + 1;
1122
+ if (used + cost > MAX_CHECKPOINT_BYTES) {
1123
+ if (now - entry.updatedAt < TOMBSTONE_MIN_AGE_MS) {
1124
+ recordLedgerUncertainty(directory, "checkpoint byte budget would evict a young closed summary; compaction skipped", "compaction");
1125
+ return {
1126
+ status: "skipped",
1127
+ reason: "checkpoint byte budget would evict a young closed summary"
1128
+ };
1129
+ }
1130
+ evicted += 1;
366
1131
  continue;
367
- let parsedJson;
368
- try {
369
- parsedJson = JSON.parse(trimmed);
370
- } catch {
371
- return {
372
- status: "uncertain",
373
- reason: `background delegation ledger has malformed JSON at line ${lineNumber}`
374
- };
375
1132
  }
376
- const parsed = RecordSchema.safeParse(parsedJson);
377
- if (!parsed.success) {
378
- return {
379
- status: "uncertain",
380
- reason: `background delegation ledger has an invalid record at line ${lineNumber}`
381
- };
1133
+ used += cost;
1134
+ keptClosed.push(entry);
1135
+ }
1136
+ const sequence = Math.max(load.manifest?.sequence ?? 0, load.checkpoint?.sequence ?? 0, 0) + 1;
1137
+ let healthLateTerminals = 0;
1138
+ try {
1139
+ const artifact = readDelegationHealthArtifact(directory);
1140
+ healthLateTerminals = artifact?.counts.lateTerminals ?? 0;
1141
+ } catch {
1142
+ healthLateTerminals = 0;
1143
+ }
1144
+ const previousClosedIds = new Set((load.checkpoint?.closed ?? []).map((entry) => entry.correlationId));
1145
+ const newlySummarized = keptClosed.filter((entry) => !previousClosedIds.has(entry.correlationId)).length;
1146
+ const audit = mergeCheckpointAudit(load.checkpoint?.audit ?? null, load.checkpoint, folded, healthLateTerminals, retiredLineCount, newlySummarized + evicted, now);
1147
+ const checkpoint = {
1148
+ schemaVersion: 1,
1149
+ sequence,
1150
+ writerId: WRITER_ID,
1151
+ rootPath: path2.resolve(directory),
1152
+ createdAt: now,
1153
+ cutLedgerBytes,
1154
+ cutLedgerDigest: sha256Hex(ledgerBytes),
1155
+ records: live,
1156
+ closed: keptClosed,
1157
+ audit,
1158
+ payloadChecksum: ""
1159
+ };
1160
+ checkpoint.payloadChecksum = checkpointPayloadChecksum(checkpoint);
1161
+ const checkpointJson = `${JSON.stringify(checkpoint)}
1162
+ `;
1163
+ if (Buffer.byteLength(checkpointJson, "utf-8") > MAX_CHECKPOINT_BYTES) {
1164
+ recordLedgerUncertainty(directory, "serialized checkpoint exceeds the byte budget; compaction skipped", "compaction");
1165
+ return {
1166
+ status: "skipped",
1167
+ reason: "serialized checkpoint exceeds the byte budget"
1168
+ };
1169
+ }
1170
+ writeDurableFileSync(checkpointPath(directory), checkpointJson);
1171
+ writeDurableFileSync(manifestPath(directory), `${JSON.stringify({
1172
+ schemaVersion: 1,
1173
+ sequence,
1174
+ checkpointChecksum: checkpoint.payloadChecksum,
1175
+ writerId: WRITER_ID,
1176
+ rootPath: checkpoint.rootPath,
1177
+ updatedAt: now
1178
+ })}
1179
+ `);
1180
+ let currentSize;
1181
+ try {
1182
+ currentSize = fs2.statSync(storePath(directory)).size;
1183
+ } catch (err) {
1184
+ return {
1185
+ status: "uncertain",
1186
+ reason: `ledger vanished during compaction: ${err instanceof Error ? err.message : String(err)}`
1187
+ };
1188
+ }
1189
+ if (currentSize < cutLedgerBytes) {
1190
+ return {
1191
+ status: "skipped",
1192
+ reason: "ledger shrank during compaction; checkpoint published unrolled"
1193
+ };
1194
+ }
1195
+ const tailContent = currentSize > cutLedgerBytes ? readLedgerRegion(directory, cutLedgerBytes, currentSize - cutLedgerBytes) : Buffer.alloc(0);
1196
+ writeDurableFileSync(storePath(directory), tailContent);
1197
+ try {
1198
+ const pressurePct = Math.min(100, Math.round(tailContent.length / MAX_RECOVERY_LEDGER_BYTES * 1000) / 10);
1199
+ writeDelegationHealthArtifact(directory, {
1200
+ ledger: {
1201
+ bytes: tailContent.length,
1202
+ limitBytes: MAX_RECOVERY_LEDGER_BYTES,
1203
+ pressurePct,
1204
+ band: tailContent.length > DELEGATION_COMPACTION_HIGH_WATER_BYTES ? "compact-overdue" : tailContent.length > DELEGATION_COMPACTION_LOW_WATER_BYTES ? "nominal" : "ok"
1205
+ },
1206
+ checkpoint: {
1207
+ sequence,
1208
+ createdAt: now,
1209
+ liveRecords: live.length,
1210
+ closedSummaries: keptClosed.length,
1211
+ bytes: Buffer.byteLength(checkpointJson, "utf-8"),
1212
+ audit
1213
+ },
1214
+ counts: {
1215
+ activeOwners: folded.filter((record) => isActiveCoderOwner(record)).length,
1216
+ pendingAdvisories: folded.filter((record) => record.advisoryInbox?.state === "pending").length,
1217
+ lateTerminals: audit.lateTerminalCount,
1218
+ orphanWorktreeOwners: folded.filter(isUnsettledWorktreeOwner).length
1219
+ }
1220
+ });
1221
+ } catch {}
1222
+ return {
1223
+ status: "compacted",
1224
+ sequence,
1225
+ tailBytes: tailContent.length,
1226
+ checkpointBytes: Buffer.byteLength(checkpointJson, "utf-8")
1227
+ };
1228
+ }
1229
+ function countCompleteLines(buffer) {
1230
+ let count = 0;
1231
+ for (const byte of buffer) {
1232
+ if (byte === 10)
1233
+ count += 1;
1234
+ }
1235
+ return count;
1236
+ }
1237
+ function maybeCompactDelegationsLocked(directory) {
1238
+ try {
1239
+ const stat = fs2.statSync(storePath(directory));
1240
+ if (stat.size <= DELEGATION_COMPACTION_HIGH_WATER_BYTES)
1241
+ return;
1242
+ const outcome = compactDelegationsLocked(directory, {});
1243
+ if (outcome.status === "uncertain") {
1244
+ warn(`[background] post-append compaction skipped: ${outcome.reason}`);
382
1245
  }
383
- folded.set(parsed.data.correlationId, parsed.data);
1246
+ } catch (err) {
1247
+ warn(`[background] post-append compaction check failed: ${err instanceof Error ? err.message : String(err)}`);
1248
+ }
1249
+ }
1250
+ function ensureSwarmDir(directory) {
1251
+ fs2.mkdirSync(path2.resolve(directory, ".swarm"), { recursive: true });
1252
+ }
1253
+ function readDelegations(directory) {
1254
+ const load = loadFoldedState(directory, { strict: false });
1255
+ if (load.status === "uncertain") {
1256
+ warn(`[background] readDelegations: authoritative state uncertain (${load.reason}); returning empty`);
1257
+ return [];
1258
+ }
1259
+ return [...load.records.values()];
1260
+ }
1261
+ function scanDelegationsForRecovery(directory) {
1262
+ const load = loadFoldedState(directory, { strict: true });
1263
+ if (load.status === "uncertain") {
1264
+ const manifestKind = readDelegationManifest(directory).kind;
1265
+ return {
1266
+ status: "uncertain",
1267
+ reason: load.reason,
1268
+ source: manifestKind === "absent" ? "legacy-ledger" : "unknown",
1269
+ ...load.repairHint ? { repairHint: load.repairHint } : {}
1270
+ };
384
1271
  }
385
- return { status: "ok", owners: [...folded.values()] };
1272
+ const source = load.mode === "legacy" ? "legacy-ledger" : load.mode;
1273
+ return { status: "ok", owners: [...load.records.values()], source };
386
1274
  }
387
1275
  function findByCorrelationId(directory, correlationId) {
388
1276
  if (!correlationId)
@@ -395,7 +1283,7 @@ function findByCorrelationId(directory, correlationId) {
395
1283
  }
396
1284
  function appendRecord(directory, record) {
397
1285
  ensureSwarmDir(directory);
398
- fs.appendFileSync(storePath(directory), `${JSON.stringify(record)}
1286
+ fs2.appendFileSync(storePath(directory), `${JSON.stringify(record)}
399
1287
  `, "utf-8");
400
1288
  }
401
1289
  function buildPendingRecord(input, now) {
@@ -428,7 +1316,7 @@ function buildPendingRecord(input, now) {
428
1316
  ...input.generation !== undefined ? { generation: input.generation } : {}
429
1317
  };
430
1318
  }
431
- function pendingLaunchIdentity(record) {
1319
+ function pendingLaunchIdentity(record, summaryAware) {
432
1320
  return {
433
1321
  correlationId: record.correlationId,
434
1322
  jobId: record.jobId,
@@ -446,16 +1334,19 @@ function pendingLaunchIdentity(record) {
446
1334
  ownedWorkflowLanes: record.ownedWorkflowLanes,
447
1335
  promptHash: record.promptHash,
448
1336
  workspace: record.workspace,
449
- taskChangeContext: record.taskChangeContext,
450
- workflowGeneration: record.workflowGeneration,
451
- worktree: record.worktree,
452
- coderReservationId: record.coderReservationId,
453
- prompt: record.prompt,
454
- generation: record.generation ?? 1
1337
+ ...summaryAware ? {} : {
1338
+ taskChangeContext: record.taskChangeContext,
1339
+ workflowGeneration: record.workflowGeneration,
1340
+ worktree: record.worktree,
1341
+ coderReservationId: record.coderReservationId,
1342
+ prompt: record.prompt,
1343
+ generation: record.generation ?? 1
1344
+ }
455
1345
  };
456
1346
  }
457
1347
  function samePendingLaunchIdentity(left, right) {
458
- return isDeepStrictEqual(pendingLaunchIdentity(left), pendingLaunchIdentity(right));
1348
+ const summaryAware = isTerminal(left.status) && left.prompt === undefined && left.taskChangeContext === undefined;
1349
+ return isDeepStrictEqual(pendingLaunchIdentity(left, summaryAware), pendingLaunchIdentity(right, summaryAware));
459
1350
  }
460
1351
  async function recordPendingDelegationDetailed(directory, input, options = {}) {
461
1352
  const now = Date.now();
@@ -474,7 +1365,10 @@ async function recordPendingDelegationDetailed(directory, input, options = {}) {
474
1365
  if (options.staleTimeoutMs && options.staleTimeoutMs > 0) {
475
1366
  sweepStaleLocked(directory, options.staleTimeoutMs, now);
476
1367
  }
477
- const existing = findByCorrelationId(directory, parsedRecord.data.correlationId);
1368
+ const records = loadRecordsForWrite(directory);
1369
+ if (records === null)
1370
+ return;
1371
+ const existing = findRecordForWrite(records, parsedRecord.data.correlationId);
478
1372
  if (existing) {
479
1373
  outcome = {
480
1374
  status: samePendingLaunchIdentity(existing, parsedRecord.data) ? "duplicate" : "conflict",
@@ -483,6 +1377,7 @@ async function recordPendingDelegationDetailed(directory, input, options = {}) {
483
1377
  return;
484
1378
  }
485
1379
  appendRecord(directory, parsedRecord.data);
1380
+ maybeCompactDelegationsLocked(directory);
486
1381
  outcome = { status: "recorded", record: parsedRecord.data };
487
1382
  });
488
1383
  return outcome;
@@ -511,7 +1406,10 @@ async function appendDelegationTransition(directory, correlationId, transition)
511
1406
  try {
512
1407
  let next = null;
513
1408
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
514
- const current = findByCorrelationId(directory, correlationId);
1409
+ const records = loadRecordsForWrite(directory);
1410
+ if (records === null)
1411
+ return;
1412
+ const current = findRecordForWrite(records, correlationId);
515
1413
  if (!current)
516
1414
  return;
517
1415
  if (isTerminal(current.status) && transition.status !== "consumed" && transition.status !== "ingestion_error" && !(current.status === "completed" && transition.status === "stale")) {
@@ -527,6 +1425,7 @@ async function appendDelegationTransition(directory, correlationId, transition)
527
1425
  ...transition.result ? { result: transition.result } : {}
528
1426
  };
529
1427
  appendRecord(directory, next);
1428
+ maybeCompactDelegationsLocked(directory);
530
1429
  });
531
1430
  return next;
532
1431
  } catch (err) {
@@ -547,7 +1446,10 @@ function sameJson(left, right) {
547
1446
  return JSON.stringify(left) === JSON.stringify(right);
548
1447
  }
549
1448
  function sameTerminalEvent(left, right) {
550
- return left.eventId === right.eventId && left.status === right.status && sameJson(left.result, right.result);
1449
+ return left.eventId === right.eventId && left.status === right.status && sameRetainedResult(left.result, right.result);
1450
+ }
1451
+ function sameRetainedResult(left, right) {
1452
+ return left.chars === right.chars && left.truncated === right.truncated && left.digest === right.digest && left.outputRef === right.outputRef && left.outputPreviewChars === right.outputPreviewChars && left.outputDegraded === right.outputDegraded && left.outputArtifactError === right.outputArtifactError && left.transcriptIncomplete === right.transcriptIncomplete && left.messageCount === right.messageCount && sameJson(left.salvagedWorkflowLanes, right.salvagedWorkflowLanes);
551
1453
  }
552
1454
  function settlementProvenanceFor(record) {
553
1455
  const baseline = record.taskChangeContext?.baseline;
@@ -580,12 +1482,16 @@ async function claimTerminalResult(directory, correlationId, terminalResult) {
580
1482
  let claim = null;
581
1483
  try {
582
1484
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
583
- const current = findByCorrelationId(directory, correlationId);
1485
+ const records = loadRecordsForWrite(directory);
1486
+ if (records === null)
1487
+ return;
1488
+ const current = findRecordForWrite(records, correlationId);
584
1489
  if (!current)
585
1490
  return;
586
1491
  if (current.terminalResult) {
587
1492
  if (!sameTerminalEvent(current.terminalResult, parsedTerminal.data)) {
588
1493
  warn(`[background] claimTerminalResult: different terminal event for ` + `correlationId=${correlationId}; ` + `existing={status: ${current.terminalResult.status}, eventId: ${current.terminalResult.eventId}} ` + `incoming={status: ${parsedTerminal.data.status}, eventId: ${parsedTerminal.data.eventId}}; ` + `rejected`);
1494
+ incrementLateTerminalCount(directory);
589
1495
  return;
590
1496
  }
591
1497
  claim = {
@@ -609,6 +1515,7 @@ async function claimTerminalResult(directory, correlationId, terminalResult) {
609
1515
  };
610
1516
  }
611
1517
  }
1518
+ const foldUpdatedAt = Math.max(parsedTerminal.data.recordedAt, current.updatedAt);
612
1519
  const next = {
613
1520
  ...current,
614
1521
  schemaVersion: 3,
@@ -616,12 +1523,13 @@ async function claimTerminalResult(directory, correlationId, terminalResult) {
616
1523
  terminalResult: parsedTerminal.data,
617
1524
  result: parsedTerminal.data.result,
618
1525
  completedAt: parsedTerminal.data.recordedAt,
619
- updatedAt: parsedTerminal.data.recordedAt,
1526
+ updatedAt: foldUpdatedAt,
620
1527
  ...coderSettlement ? { coderSettlement } : {}
621
1528
  };
622
1529
  if (!RecordSchema.safeParse(next).success)
623
1530
  return;
624
1531
  appendRecord(directory, next);
1532
+ maybeCompactDelegationsLocked(directory);
625
1533
  claim = { disposition: "claimed", record: next };
626
1534
  });
627
1535
  return claim;
@@ -630,13 +1538,30 @@ async function claimTerminalResult(directory, correlationId, terminalResult) {
630
1538
  return null;
631
1539
  }
632
1540
  }
1541
+ function incrementLateTerminalCount(directory) {
1542
+ try {
1543
+ const artifact = readDelegationHealthArtifact(directory);
1544
+ const current = artifact?.counts.lateTerminals ?? 0;
1545
+ writeDelegationHealthArtifact(directory, {
1546
+ counts: {
1547
+ activeOwners: artifact?.counts.activeOwners ?? 0,
1548
+ pendingAdvisories: artifact?.counts.pendingAdvisories ?? 0,
1549
+ lateTerminals: current + 1,
1550
+ orphanWorktreeOwners: artifact?.counts.orphanWorktreeOwners ?? 0
1551
+ }
1552
+ });
1553
+ } catch {}
1554
+ }
633
1555
  async function claimCoderSettlement(directory, correlationId, operationId, input = {}) {
634
1556
  if (!correlationId || !operationId || operationId.length > 256)
635
1557
  return null;
636
1558
  let claim = null;
637
1559
  try {
638
1560
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
639
- const current = findByCorrelationId(directory, correlationId);
1561
+ const records = loadRecordsForWrite(directory);
1562
+ if (records === null)
1563
+ return;
1564
+ const current = findRecordForWrite(records, correlationId);
640
1565
  if (!current || current.normalizedAgent !== "coder" || current.terminalResult?.status !== "completed") {
641
1566
  return;
642
1567
  }
@@ -682,6 +1607,7 @@ async function claimCoderSettlement(directory, correlationId, operationId, input
682
1607
  if (!RecordSchema.safeParse(next).success)
683
1608
  return;
684
1609
  appendRecord(directory, next);
1610
+ maybeCompactDelegationsLocked(directory);
685
1611
  claim = {
686
1612
  disposition: existing.state === "settling" ? "resume" : "claimed",
687
1613
  record: next
@@ -697,10 +1623,10 @@ function normalizeObservedFile(value) {
697
1623
  if (typeof value !== "string")
698
1624
  return null;
699
1625
  const trimmed = value.trim().replace(/\\/g, "/");
700
- if (trimmed.length === 0 || trimmed.length > 4096 || trimmed.includes("\x00") || path.posix.isAbsolute(trimmed) || /^[A-Za-z]:\//.test(trimmed)) {
1626
+ if (trimmed.length === 0 || trimmed.length > 4096 || trimmed.includes("\x00") || path2.posix.isAbsolute(trimmed) || /^[A-Za-z]:\//.test(trimmed)) {
701
1627
  return null;
702
1628
  }
703
- const normalized = path.posix.normalize(trimmed).replace(/^\.\//, "");
1629
+ const normalized = path2.posix.normalize(trimmed).replace(/^\.\//, "");
704
1630
  if (normalized === "." || normalized === ".." || normalized.startsWith("../") || normalized.endsWith("/")) {
705
1631
  return null;
706
1632
  }
@@ -725,7 +1651,10 @@ async function updateCoderSettlement(directory, correlationId, input) {
725
1651
  let result = null;
726
1652
  try {
727
1653
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
728
- const current = findByCorrelationId(directory, correlationId);
1654
+ const records = loadRecordsForWrite(directory);
1655
+ if (records === null)
1656
+ return;
1657
+ const current = findRecordForWrite(records, correlationId);
729
1658
  const existing = current?.coderSettlement;
730
1659
  if (!current || !existing)
731
1660
  return;
@@ -786,6 +1715,7 @@ async function updateCoderSettlement(directory, correlationId, input) {
786
1715
  if (!RecordSchema.safeParse(next).success)
787
1716
  return;
788
1717
  appendRecord(directory, next);
1718
+ maybeCompactDelegationsLocked(directory);
789
1719
  result = next;
790
1720
  });
791
1721
  return result;
@@ -802,7 +1732,10 @@ async function claimDelegationIngestion(directory, correlationId, options) {
802
1732
  let claim = null;
803
1733
  try {
804
1734
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
805
- const current = findByCorrelationId(directory, correlationId);
1735
+ const records = loadRecordsForWrite(directory);
1736
+ if (records === null)
1737
+ return;
1738
+ const current = findRecordForWrite(records, correlationId);
806
1739
  if (!current?.terminalResult)
807
1740
  return;
808
1741
  if (current.status === "consumed") {
@@ -841,6 +1774,7 @@ async function claimDelegationIngestion(directory, correlationId, options) {
841
1774
  updatedAt: now
842
1775
  };
843
1776
  appendRecord(directory, next);
1777
+ maybeCompactDelegationsLocked(directory);
844
1778
  claim = { disposition, record: next };
845
1779
  });
846
1780
  return claim;
@@ -855,7 +1789,10 @@ async function recordDelegationIngestionResult(directory, correlationId, claimTo
855
1789
  let result = null;
856
1790
  try {
857
1791
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
858
- const current = findByCorrelationId(directory, correlationId);
1792
+ const records = loadRecordsForWrite(directory);
1793
+ if (records === null)
1794
+ return;
1795
+ const current = findRecordForWrite(records, correlationId);
859
1796
  if (!current)
860
1797
  return;
861
1798
  if (success && current.status === "consumed" && current.ingestion?.state === "consumed" && current.ingestion.claimToken === claimToken || !success && current.status === "ingestion_error" && current.ingestion?.state === "retryable" && current.ingestion.claimToken === claimToken) {
@@ -878,6 +1815,7 @@ async function recordDelegationIngestionResult(directory, correlationId, claimTo
878
1815
  updatedAt
879
1816
  };
880
1817
  appendRecord(directory, next);
1818
+ maybeCompactDelegationsLocked(directory);
881
1819
  result = next;
882
1820
  });
883
1821
  return result;
@@ -900,7 +1838,10 @@ async function putPendingBackgroundAdvisory(directory, correlationId, input) {
900
1838
  let result = null;
901
1839
  try {
902
1840
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
903
- const current = findByCorrelationId(directory, correlationId);
1841
+ const records = loadRecordsForWrite(directory);
1842
+ if (records === null)
1843
+ return;
1844
+ const current = findRecordForWrite(records, correlationId);
904
1845
  if (!current?.terminalResult || current.terminalResult.eventId !== parsed.data.eventId || current.parentSessionId !== parsed.data.parentSessionId) {
905
1846
  return;
906
1847
  }
@@ -917,6 +1858,7 @@ async function putPendingBackgroundAdvisory(directory, correlationId, input) {
917
1858
  updatedAt: createdAt
918
1859
  };
919
1860
  appendRecord(directory, next);
1861
+ maybeCompactDelegationsLocked(directory);
920
1862
  result = parsed.data;
921
1863
  });
922
1864
  return result;
@@ -933,7 +1875,10 @@ async function preparePendingBackgroundAdvisories(directory, parentSessionId, op
933
1875
  const prepared = [];
934
1876
  try {
935
1877
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
936
- for (const current of readDelegations(directory)) {
1878
+ const records = loadRecordsForWrite(directory);
1879
+ if (records === null)
1880
+ return;
1881
+ for (const current of records) {
937
1882
  if (prepared.length >= 1)
938
1883
  break;
939
1884
  const advisory = current.advisoryInbox;
@@ -958,6 +1903,7 @@ async function preparePendingBackgroundAdvisories(directory, parentSessionId, op
958
1903
  updatedAt: now
959
1904
  };
960
1905
  appendRecord(directory, next);
1906
+ maybeCompactDelegationsLocked(directory);
961
1907
  prepared.push(nextAdvisory);
962
1908
  }
963
1909
  });
@@ -974,8 +1920,11 @@ async function releaseBackgroundAdvisoryPreparation(directory, parentSessionId,
974
1920
  }
975
1921
  try {
976
1922
  return await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
1923
+ const records = loadRecordsForWrite(directory);
1924
+ if (records === null)
1925
+ return false;
977
1926
  const byEvent = new Map;
978
- for (const current of readDelegations(directory)) {
1927
+ for (const current of records) {
979
1928
  const advisory = current.advisoryInbox;
980
1929
  if (advisory?.parentSessionId === parentSessionId && uniqueEventIds.includes(advisory.eventId)) {
981
1930
  byEvent.set(advisory.eventId, current);
@@ -1003,6 +1952,7 @@ async function releaseBackgroundAdvisoryPreparation(directory, parentSessionId,
1003
1952
  };
1004
1953
  appendRecord(directory, next);
1005
1954
  }
1955
+ maybeCompactDelegationsLocked(directory);
1006
1956
  return true;
1007
1957
  });
1008
1958
  } catch (err) {
@@ -1016,8 +1966,11 @@ async function acknowledgeObservedBackgroundAdvisories(directory, parentSessionI
1016
1966
  let acknowledged = 0;
1017
1967
  try {
1018
1968
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
1969
+ const records = loadRecordsForWrite(directory);
1970
+ if (records === null)
1971
+ return;
1019
1972
  const now = Date.now();
1020
- for (const current of readDelegations(directory)) {
1973
+ for (const current of records) {
1021
1974
  const advisory = current.advisoryInbox;
1022
1975
  if (!advisory || advisory.parentSessionId !== parentSessionId || advisory.state !== "pending" || !observedTexts.some((text) => {
1023
1976
  const advisoryBlock = text.match(/\[ADVISORIES\]([\s\S]*?)\[\/ADVISORIES\]/);
@@ -1044,6 +1997,8 @@ async function acknowledgeObservedBackgroundAdvisories(directory, parentSessionI
1044
1997
  appendRecord(directory, next);
1045
1998
  acknowledged += 1;
1046
1999
  }
2000
+ if (acknowledged > 0)
2001
+ maybeCompactDelegationsLocked(directory);
1047
2002
  });
1048
2003
  return acknowledged;
1049
2004
  } catch (err) {
@@ -1065,10 +2020,13 @@ function findOpenAsyncLaneBatches(directory) {
1065
2020
  function isTerminal(status) {
1066
2021
  return status === "completed" || status === "error" || status === "cancelled" || status === "stale" || status === "consumed";
1067
2022
  }
1068
- function sweepStaleLocked(directory, timeoutMs, now) {
2023
+ function sweepStaleLocked(directory, timeoutMs, now, statuses = DEFAULT_SWEEPABLE_DELEGATION_STATUSES) {
1069
2024
  let swept = 0;
1070
- for (const record of readDelegations(directory)) {
1071
- if (record.status !== "pending" && record.status !== "running" && record.status !== "ingestion_error")
2025
+ const records = loadRecordsForWrite(directory);
2026
+ if (records === null)
2027
+ return 0;
2028
+ for (const record of records) {
2029
+ if (!statuses.has(record.status))
1072
2030
  continue;
1073
2031
  if (now - record.updatedAt <= timeoutMs)
1074
2032
  continue;
@@ -1079,13 +2037,16 @@ function sweepStaleLocked(directory, timeoutMs, now) {
1079
2037
  });
1080
2038
  swept += 1;
1081
2039
  }
2040
+ if (swept > 0)
2041
+ maybeCompactDelegationsLocked(directory);
1082
2042
  return swept;
1083
2043
  }
1084
- async function sweepStaleDelegations(directory, timeoutMs) {
2044
+ async function sweepStaleDelegations(directory, timeoutMs, options = {}) {
1085
2045
  if (!timeoutMs || timeoutMs <= 0)
1086
2046
  return 0;
2047
+ const statuses = options.statuses ?? DEFAULT_SWEEPABLE_DELEGATION_STATUSES;
1087
2048
  try {
1088
- return await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => sweepStaleLocked(directory, timeoutMs, Date.now()));
2049
+ return await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => sweepStaleLocked(directory, timeoutMs, Date.now(), statuses));
1089
2050
  } catch (err) {
1090
2051
  warn(`[background] sweepStaleDelegations failed: ${err instanceof Error ? err.message : String(err)}`);
1091
2052
  return 0;
@@ -1093,18 +2054,18 @@ async function sweepStaleDelegations(directory, timeoutMs) {
1093
2054
  }
1094
2055
  function fallbackRelativePath(correlationId) {
1095
2056
  const digest = createHash("sha256").update(correlationId).digest("hex");
1096
- return path.join(BACKGROUND_DELEGATION_FALLBACK_DIR, `${digest}.json`);
2057
+ return path2.join(BACKGROUND_DELEGATION_FALLBACK_DIR, `${digest}.json`);
1097
2058
  }
1098
2059
  function fallbackPath(directory, correlationId) {
1099
2060
  return validateSwarmPath(directory, fallbackRelativePath(correlationId));
1100
2061
  }
1101
2062
  function fallbackDirectoryPath(directory) {
1102
- return path.dirname(validateSwarmPath(directory, path.join(BACKGROUND_DELEGATION_FALLBACK_DIR, ".containment-anchor")));
2063
+ return path2.dirname(validateSwarmPath(directory, path2.join(BACKGROUND_DELEGATION_FALLBACK_DIR, ".containment-anchor")));
1103
2064
  }
1104
2065
  async function readFallbackFile(directory, correlationId) {
1105
2066
  for (let attempt = 0;attempt < 5; attempt++) {
1106
2067
  try {
1107
- const raw = await fs.promises.readFile(fallbackPath(directory, correlationId), "utf-8");
2068
+ const raw = await fs2.promises.readFile(fallbackPath(directory, correlationId), "utf-8");
1108
2069
  const parsedJson = JSON.parse(raw);
1109
2070
  const parsed = FallbackArtifactSchema.safeParse(parsedJson);
1110
2071
  if (!parsed.success || parsed.data.correlationId !== correlationId) {
@@ -1114,7 +2075,7 @@ async function readFallbackFile(directory, correlationId) {
1114
2075
  } catch (err) {
1115
2076
  const code = err.code;
1116
2077
  if (code === "ENOENT" && attempt < 4) {
1117
- await new Promise((resolve2) => setTimeout(resolve2, 10));
2078
+ await new Promise((resolve3) => setTimeout(resolve3, 10));
1118
2079
  continue;
1119
2080
  }
1120
2081
  return null;
@@ -1130,7 +2091,7 @@ async function readDelegationFallback(directory, correlationId) {
1130
2091
  async function listDelegationFallbacks(directory) {
1131
2092
  let entries;
1132
2093
  try {
1133
- entries = fs.readdirSync(fallbackDirectoryPath(directory), {
2094
+ entries = fs2.readdirSync(fallbackDirectoryPath(directory), {
1134
2095
  withFileTypes: true
1135
2096
  }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).slice(0, MAX_LIVE_BACKGROUND_FALLBACKS);
1136
2097
  } catch {
@@ -1139,7 +2100,7 @@ async function listDelegationFallbacks(directory) {
1139
2100
  const artifacts = [];
1140
2101
  for (const entry of entries) {
1141
2102
  try {
1142
- const raw = await fs.promises.readFile(path.join(fallbackDirectoryPath(directory), entry.name), "utf-8");
2103
+ const raw = await fs2.promises.readFile(path2.join(fallbackDirectoryPath(directory), entry.name), "utf-8");
1143
2104
  const parsed = FallbackArtifactSchema.safeParse(JSON.parse(raw));
1144
2105
  if (parsed.success)
1145
2106
  artifacts.push(parsed.data);
@@ -1152,7 +2113,7 @@ async function scanDelegationFallbacksForRecovery(directory) {
1152
2113
  let entries;
1153
2114
  try {
1154
2115
  fallbackDir = fallbackDirectoryPath(directory);
1155
- entries = fs.readdirSync(fallbackDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json"));
2116
+ entries = fs2.readdirSync(fallbackDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json"));
1156
2117
  } catch (error) {
1157
2118
  if (error.code === "ENOENT") {
1158
2119
  return { status: "ok", owners: [] };
@@ -1170,17 +2131,17 @@ async function scanDelegationFallbacksForRecovery(directory) {
1170
2131
  }
1171
2132
  const artifacts = [];
1172
2133
  for (const entry of entries) {
1173
- const artifactPath = path.join(fallbackDir, entry.name);
2134
+ const artifactPath = path2.join(fallbackDir, entry.name);
1174
2135
  let raw;
1175
2136
  try {
1176
- const stat = fs.statSync(artifactPath);
2137
+ const stat = fs2.statSync(artifactPath);
1177
2138
  if (stat.size > MAX_RECOVERY_FALLBACK_BYTES) {
1178
2139
  return {
1179
2140
  status: "uncertain",
1180
2141
  reason: `background fallback artifact "${entry.name}" exceeds the recovery size bound`
1181
2142
  };
1182
2143
  }
1183
- raw = await fs.promises.readFile(artifactPath, "utf-8");
2144
+ raw = await fs2.promises.readFile(artifactPath, "utf-8");
1184
2145
  } catch (error) {
1185
2146
  return {
1186
2147
  status: "uncertain",
@@ -1215,7 +2176,7 @@ async function scanDelegationFallbacksForRecovery(directory) {
1215
2176
  }
1216
2177
  function countFallbackFiles(directory) {
1217
2178
  try {
1218
- return fs.readdirSync(fallbackDirectoryPath(directory), {
2179
+ return fs2.readdirSync(fallbackDirectoryPath(directory), {
1219
2180
  withFileTypes: true
1220
2181
  }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).length;
1221
2182
  } catch (err) {
@@ -1250,7 +2211,7 @@ async function writeDelegationFallback(directory, input, options = {}) {
1250
2211
  if (countFallbackFiles(directory) >= maxLive)
1251
2212
  return null;
1252
2213
  const absPath = fallbackPath(directory, input.correlationId);
1253
- fs.mkdirSync(path.dirname(absPath), { recursive: true });
2214
+ fs2.mkdirSync(path2.dirname(absPath), { recursive: true });
1254
2215
  await bunWrite(absPath, `${JSON.stringify(parsed.data)}
1255
2216
  `);
1256
2217
  return parsed.data;
@@ -1266,7 +2227,7 @@ async function removeDelegationFallback(directory, correlationId) {
1266
2227
  try {
1267
2228
  return await withEvidenceLock(directory, BACKGROUND_DELEGATION_FALLBACK_DIR, STORE_LOCK_AGENT, FALLBACK_LOCK_TASK, async () => {
1268
2229
  try {
1269
- await fs.promises.unlink(fallbackPath(directory, correlationId));
2230
+ await fs2.promises.unlink(fallbackPath(directory, correlationId));
1270
2231
  return true;
1271
2232
  } catch (err) {
1272
2233
  return err.code === "ENOENT";
@@ -1314,7 +2275,10 @@ async function promoteDelegationFallback(directory, correlationId) {
1314
2275
  }
1315
2276
  let promoted = null;
1316
2277
  await withEvidenceLock(directory, BACKGROUND_DELEGATIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
1317
- const current = findByCorrelationId(directory, correlationId);
2278
+ const records = loadRecordsForWrite(directory);
2279
+ if (records === null)
2280
+ return;
2281
+ const current = findRecordForWrite(records, correlationId);
1318
2282
  if (current) {
1319
2283
  if (samePromotionIdentity(current, fallback.record)) {
1320
2284
  promoted = current;
@@ -1322,12 +2286,13 @@ async function promoteDelegationFallback(directory, correlationId) {
1322
2286
  return;
1323
2287
  }
1324
2288
  appendRecord(directory, fallback.record);
2289
+ maybeCompactDelegationsLocked(directory);
1325
2290
  promoted = fallback.record;
1326
2291
  });
1327
2292
  if (!promoted)
1328
2293
  return null;
1329
2294
  try {
1330
- await fs.promises.unlink(fallbackPath(directory, correlationId));
2295
+ await fs2.promises.unlink(fallbackPath(directory, correlationId));
1331
2296
  } catch (err) {
1332
2297
  if (err.code !== "ENOENT") {
1333
2298
  return null;
@@ -1353,14 +2318,14 @@ function scanBackgroundCoderReservationsForAdmission(directory) {
1353
2318
  let raw;
1354
2319
  try {
1355
2320
  absolutePath = reservationStorePath(directory);
1356
- const stat = fs.statSync(absolutePath);
2321
+ const stat = fs2.statSync(absolutePath);
1357
2322
  if (stat.size > MAX_BACKGROUND_CODER_RESERVATION_STORE_BYTES) {
1358
2323
  return {
1359
2324
  status: "uncertain",
1360
2325
  reason: `background coder reservation store exceeds the ${MAX_BACKGROUND_CODER_RESERVATION_STORE_BYTES}-byte safety bound`
1361
2326
  };
1362
2327
  }
1363
- raw = fs.readFileSync(absolutePath, "utf-8");
2328
+ raw = fs2.readFileSync(absolutePath, "utf-8");
1364
2329
  } catch (error) {
1365
2330
  if (error.code === "ENOENT") {
1366
2331
  return { status: "ok", reservations: [] };
@@ -1674,4 +2639,4 @@ async function releaseBackgroundCoderReservation(directory, input) {
1674
2639
  }
1675
2640
  }
1676
2641
 
1677
- export { BACKGROUND_DELEGATIONS_FILE, BACKGROUND_DELEGATION_FALLBACK_DIR, BACKGROUND_CODER_RESERVATIONS_FILE, MAX_LIVE_BACKGROUND_FALLBACKS, MAX_LIVE_BACKGROUND_CODER_RESERVATIONS, MAX_BACKGROUND_OBSERVED_FILES, MAX_BACKGROUND_ADVISORY_CHARS, BACKGROUND_INGESTION_LEASE_MS, readDelegations, scanDelegationsForRecovery, findByCorrelationId, recordPendingDelegationDetailed, recordPendingDelegation, buildPromptSnapshot, appendDelegationTransition, buildBackgroundCompletionEventId, claimTerminalResult, claimCoderSettlement, normalizeBackgroundObservedFiles, updateCoderSettlement, claimDelegationIngestion, recordDelegationIngestionResult, putPendingBackgroundAdvisory, preparePendingBackgroundAdvisories, acknowledgeObservedBackgroundAdvisories, releasePreparedBackgroundAdvisories, findByBatchId, findOpenAsyncLaneBatches, sweepStaleDelegations, readDelegationFallback, listDelegationFallbacks, scanDelegationFallbacksForRecovery, writeDelegationFallback, removeDelegationFallback, findDelegationForCompletion, promoteDelegationFallback, buildBackgroundCoderReservationId, scanBackgroundCoderReservationsForAdmission, reserveBackgroundCoderSlot, bindBackgroundCoderReservation, releaseBackgroundCoderReservation };
2642
+ export { MAX_RECOVERY_LEDGER_BYTES, collectDelegationLedgerHealth, BACKGROUND_DELEGATIONS_FILE, BACKGROUND_DELEGATION_FALLBACK_DIR, BACKGROUND_CODER_RESERVATIONS_FILE, BACKGROUND_DELEGATIONS_CHECKPOINT_FILE, BACKGROUND_DELEGATIONS_MANIFEST_FILE, MAX_LIVE_BACKGROUND_FALLBACKS, MAX_LIVE_BACKGROUND_CODER_RESERVATIONS, MAX_BACKGROUND_OBSERVED_FILES, MAX_BACKGROUND_ADVISORY_CHARS, DELEGATION_COMPACTION_LOW_WATER_BYTES, DELEGATION_COMPACTION_HIGH_WATER_BYTES, MAX_CHECKPOINT_BYTES, MAX_CHECKPOINT_RECORDS, TOMBSTONE_MIN_AGE_MS, BACKGROUND_INGESTION_LEASE_MS, DEFAULT_STALE_DELEGATION_TIMEOUT_MS, DEFAULT_SWEEPABLE_DELEGATION_STATUSES, _checkpointInternals, isUnsettledWorktreeOwner, compactBackgroundDelegations, readDelegations, scanDelegationsForRecovery, findByCorrelationId, recordPendingDelegationDetailed, recordPendingDelegation, buildPromptSnapshot, appendDelegationTransition, buildBackgroundCompletionEventId, claimTerminalResult, claimCoderSettlement, normalizeBackgroundObservedFiles, updateCoderSettlement, claimDelegationIngestion, recordDelegationIngestionResult, putPendingBackgroundAdvisory, preparePendingBackgroundAdvisories, acknowledgeObservedBackgroundAdvisories, releasePreparedBackgroundAdvisories, findByBatchId, findOpenAsyncLaneBatches, sweepStaleDelegations, readDelegationFallback, listDelegationFallbacks, scanDelegationFallbacksForRecovery, writeDelegationFallback, removeDelegationFallback, findDelegationForCompletion, promoteDelegationFallback, buildBackgroundCoderReservationId, scanBackgroundCoderReservationsForAdmission, reserveBackgroundCoderSlot, bindBackgroundCoderReservation, releaseBackgroundCoderReservation };