opencode-swarm 7.158.0 → 7.158.1

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 (52) hide show
  1. package/dist/background/pr-subscriptions.d.ts +31 -15
  2. package/dist/cli/{coder-settlement-5sexsmqz.js → coder-settlement-nrtcjr0h.js} +3 -3
  3. package/dist/cli/{config-doctor-ewn2kw6d.js → config-doctor-hs0x10ty.js} +2 -2
  4. package/dist/cli/{core-72wdmzps.js → core-a42bexs1.js} +1 -1
  5. package/dist/cli/{curator-llm-factory-r8q84m4g.js → curator-llm-factory-21vqqvn3.js} +20 -20
  6. package/dist/cli/{curator-g06sa98p.js → curator-yawrnk3t.js} +20 -20
  7. package/dist/cli/{evidence-summary-service-ttd0ntm0.js → evidence-summary-service-kmc92b95.js} +6 -6
  8. package/dist/cli/{gate-evidence-agnxf7md.js → gate-evidence-6tzhdxb2.js} +2 -2
  9. package/dist/cli/{guardrail-explain-qf4k176t.js → guardrail-explain-7xrdp18c.js} +21 -21
  10. package/dist/cli/{guardrail-log-g4qc595v.js → guardrail-log-f16sdc3p.js} +3 -3
  11. package/dist/cli/{guardrail-reset-zpxk0p1j.js → guardrail-reset-0ks08s0t.js} +20 -20
  12. package/dist/cli/{hive-promoter-zxy07gjg.js → hive-promoter-d661k3qq.js} +20 -20
  13. package/dist/cli/{index-6xxpwk5x.js → index-203fqkqk.js} +1 -1
  14. package/dist/cli/{index-fwe1wh6r.js → index-2j07670d.js} +1 -1
  15. package/dist/cli/{index-745dh1z1.js → index-4wy9kzjg.js} +22 -22
  16. package/dist/cli/{index-f036tggv.js → index-5erwyk1b.js} +3 -3
  17. package/dist/cli/{index-gm10kvne.js → index-6x9jq0cd.js} +2 -2
  18. package/dist/cli/{index-bv24pbaj.js → index-7qvfkgyk.js} +3 -3
  19. package/dist/cli/{index-rd324153.js → index-86vvhe8m.js} +1 -1
  20. package/dist/cli/{index-rac2gkvr.js → index-ac8rwjsg.js} +50 -50
  21. package/dist/cli/{index-vwx0by4y.js → index-azx50qge.js} +5 -5
  22. package/dist/cli/{index-nvta6kcv.js → index-dr2tfawg.js} +2 -2
  23. package/dist/cli/{index-rc93mm6e.js → index-ff8xjr1c.js} +1 -1
  24. package/dist/cli/{index-c57cyrwn.js → index-hrrzxz3q.js} +3 -3
  25. package/dist/cli/{index-663wnh64.js → index-jz216dhj.js} +1 -1
  26. package/dist/cli/{index-x4ftmdha.js → index-mc9qgkwd.js} +531 -100
  27. package/dist/cli/{index-5tchehv7.js → index-mfv7mfgg.js} +1 -1
  28. package/dist/cli/{index-f776m4r5.js → index-mt6qjp4c.js} +1 -1
  29. package/dist/cli/{index-pvs2zw1y.js → index-nphnjeh8.js} +2 -2
  30. package/dist/cli/{index-a1884hh4.js → index-t8g88esk.js} +1 -1
  31. package/dist/cli/{index-y3hdwh66.js → index-tc14d2zy.js} +3 -3
  32. package/dist/cli/{index-dmfbmnp7.js → index-tppnfxkm.js} +1 -1
  33. package/dist/cli/{index-x71shq8j.js → index-xscjecyq.js} +4 -4
  34. package/dist/cli/{index-1vxmqvpt.js → index-xzhk2hav.js} +1 -1
  35. package/dist/cli/{index-zawd71cg.js → index-ygxb3jw4.js} +3 -3
  36. package/dist/cli/{index-yfbp4q09.js → index-zy60xd05.js} +1 -1
  37. package/dist/cli/index.js +20 -20
  38. package/dist/cli/{knowledge-escalator-22zaj224.js → knowledge-escalator-9py5r6c9.js} +6 -6
  39. package/dist/cli/{knowledge-events-xbx1k408.js → knowledge-events-vcbece74.js} +4 -4
  40. package/dist/cli/{knowledge-store-fnm8xh9c.js → knowledge-store-0rdfjv20.js} +1 -1
  41. package/dist/cli/{knowledge-validator-t2jztjy1.js → knowledge-validator-nwjnjgf5.js} +2 -2
  42. package/dist/cli/{pending-delegations-29rtv1gb.js → pending-delegations-ht1vgaze.js} +1 -1
  43. package/dist/cli/{pr-review-reentry-authorization-25dep81m.js → pr-review-reentry-authorization-857b9rvv.js} +20 -20
  44. package/dist/cli/{pr-subscriptions-cgac3ydd.js → pr-subscriptions-j9j70bmd.js} +1 -1
  45. package/dist/cli/{scan-cursor-8acs9kwe.js → scan-cursor-59yj7tp9.js} +2 -2
  46. package/dist/cli/{schema-rjhassd0.js → schema-8a7fyp87.js} +1 -1
  47. package/dist/cli/{scope-persistence-jb1a5dzh.js → scope-persistence-prdxtcr3.js} +4 -4
  48. package/dist/cli/{skill-generator-frgppk1w.js → skill-generator-v2jkgp63.js} +7 -7
  49. package/dist/cli/{worktree-collision-ownership-f5sj6ffa.js → worktree-collision-ownership-6x03w8h7.js} +1 -1
  50. package/dist/cli/{worktree-isolation-5b0w6bha.js → worktree-isolation-s0setq2a.js} +20 -20
  51. package/dist/index.js +97 -96
  52. package/package.json +1 -1
@@ -29,12 +29,14 @@ var PR_SUBSCRIPTIONS_AUDIT_FILE = "pr-monitor/subscriptions.audit.jsonl";
29
29
  var LEGACY_ARCHIVE_FILE = "pr-monitor/subscriptions.legacy.jsonl";
30
30
  var FOREIGN_CHECKPOINT_FILE = "pr-monitor/subscriptions.checkpoint.foreign.json";
31
31
  var CORRUPT_CHECKPOINT_FILE = "pr-monitor/subscriptions.checkpoint.corrupt.json";
32
+ var FOREIGN_LEGACY_FILE = "pr-monitor/subscriptions.legacy.foreign.jsonl";
32
33
  var STORE_LOCK_AGENT = "pr-monitor";
33
34
  var STORE_LOCK_TASK = "pr-subscriptions";
34
35
  var PR_SUBSCRIPTION_LIMITS = {
35
36
  readChunkBytes: 64 * 1024,
36
37
  maxRecordBytes: 64 * 1024,
37
38
  migrationChunkBytes: 1024 * 1024,
39
+ migrationMaxBytesPerOperation: 8 * 1024 * 1024,
38
40
  legacySourceMaxBytes: 64 * 1024 * 1024,
39
41
  defaultMaxActiveSubscriptions: 20,
40
42
  maxCheckpointRecords: 512,
@@ -76,7 +78,7 @@ var RecordSchema = exports_external.object({
76
78
  errorCount: exports_external.number().int().min(0),
77
79
  customPollIntervalSeconds: exports_external.number().int().positive().optional(),
78
80
  customFailureThreshold: exports_external.number().int().min(0).optional(),
79
- customCooldownSeconds: exports_external.number().int().positive().optional()
81
+ customCooldownSeconds: exports_external.number().int().min(0).optional()
80
82
  }).strict();
81
83
  var TerminalSummarySchema = exports_external.object({
82
84
  removed: exports_external.number().int().min(0),
@@ -88,6 +90,13 @@ var MigrationSchema = exports_external.object({
88
90
  sourceBytes: exports_external.number().int().nonnegative(),
89
91
  sourceMtimeMs: exports_external.number().nonnegative(),
90
92
  corruptLines: exports_external.number().int().nonnegative(),
93
+ discardingOversizeLine: exports_external.boolean().optional().default(false),
94
+ baselineRecords: exports_external.record(exports_external.string(), RecordSchema).optional().default({}),
95
+ baselineTerminalSummary: TerminalSummarySchema.optional().default({
96
+ removed: 0,
97
+ expired: 0,
98
+ lastTerminalAt: null
99
+ }),
91
100
  done: exports_external.boolean(),
92
101
  archived: exports_external.boolean(),
93
102
  startedAt: exports_external.number().int().nonnegative()
@@ -121,12 +130,31 @@ function auditPath(directory) {
121
130
  function legacyArchivePath(directory) {
122
131
  return validateSwarmPath(directory, LEGACY_ARCHIVE_FILE);
123
132
  }
133
+ function legacyArchiveNextPath(directory) {
134
+ return `${legacyArchivePath(directory)}.next`;
135
+ }
136
+ function legacyArchivePreviousPath(directory) {
137
+ return `${legacyArchivePath(directory)}.previous`;
138
+ }
139
+ function fileExistsStrict(filePath) {
140
+ try {
141
+ fs.statSync(filePath);
142
+ return true;
143
+ } catch (err) {
144
+ if (err.code === "ENOENT")
145
+ return false;
146
+ throw err;
147
+ }
148
+ }
124
149
  function foreignSlotPath(directory) {
125
150
  return validateSwarmPath(directory, FOREIGN_CHECKPOINT_FILE);
126
151
  }
127
152
  function corruptSlotPath(directory) {
128
153
  return validateSwarmPath(directory, CORRUPT_CHECKPOINT_FILE);
129
154
  }
155
+ function foreignLegacySlotPath(directory) {
156
+ return validateSwarmPath(directory, FOREIGN_LEGACY_FILE);
157
+ }
130
158
  function ensureSwarmDir(directory) {
131
159
  fs.mkdirSync(path.resolve(directory, ".swarm", "pr-monitor"), {
132
160
  recursive: true
@@ -167,20 +195,22 @@ function renameWithRetry(from, to) {
167
195
  }
168
196
  throw lastError;
169
197
  }
170
- function foldLegacyRegion(filePath, startByte, maxBytes) {
198
+ function foldLegacyRegion(filePath, startByte, maxBytes, discardingOversizeLine = false) {
171
199
  const folded = new Map;
172
200
  let corruptLines = 0;
173
201
  let consumedTo = startByte;
174
202
  let fd;
175
203
  try {
176
204
  fd = fs.openSync(filePath, "r");
177
- } catch {
205
+ } catch (err) {
178
206
  return {
179
207
  folded,
180
208
  nextByte: startByte,
181
209
  eof: true,
182
210
  aborted: true,
183
- corruptLines
211
+ corruptLines,
212
+ ioError: err instanceof Error ? err.message : String(err),
213
+ discardingOversizeLine
184
214
  };
185
215
  }
186
216
  const processLineBytes = (line) => {
@@ -210,25 +240,25 @@ function foldLegacyRegion(filePath, startByte, maxBytes) {
210
240
  folded.set(rec.correlationId, rec);
211
241
  };
212
242
  try {
213
- const size = fs.fstatSync(fd).size;
243
+ const size = _internals.legacyFstatSync(fd).size;
214
244
  if (startByte >= size) {
215
245
  return {
216
246
  folded,
217
247
  nextByte: startByte,
218
248
  eof: true,
219
249
  aborted: false,
220
- corruptLines
250
+ corruptLines,
251
+ ioError: null,
252
+ discardingOversizeLine: false
221
253
  };
222
254
  }
223
255
  const chunk = Buffer.alloc(PR_SUBSCRIPTION_LIMITS.readChunkBytes);
224
256
  let pending = [];
225
257
  let pendingLen = 0;
226
- let oversize = false;
258
+ let oversize = discardingOversizeLine;
227
259
  let pos = startByte;
228
260
  const flushPendingAtEof = () => {
229
- if (oversize) {
230
- corruptLines += 1;
231
- } else if (pendingLen > 0) {
261
+ if (!oversize && pendingLen > 0) {
232
262
  processLineBytes(Buffer.concat(pending));
233
263
  }
234
264
  consumedTo = Math.max(consumedTo, pos);
@@ -240,14 +270,16 @@ function foldLegacyRegion(filePath, startByte, maxBytes) {
240
270
  nextByte: consumedTo,
241
271
  eof: true,
242
272
  aborted: false,
243
- corruptLines
273
+ corruptLines,
274
+ ioError: null,
275
+ discardingOversizeLine: false
244
276
  };
245
277
  };
246
278
  while (true) {
247
279
  const want = Math.min(chunk.length, size - pos);
248
280
  if (want <= 0)
249
281
  return flushPendingAtEof();
250
- const n = fs.readSync(fd, chunk, 0, want, pos);
282
+ const n = _internals.readSync(fd, chunk, 0, want, pos);
251
283
  if (n <= 0)
252
284
  return flushPendingAtEof();
253
285
  const data = chunk.subarray(0, n);
@@ -257,14 +289,16 @@ function foldLegacyRegion(filePath, startByte, maxBytes) {
257
289
  while (scan < data.length) {
258
290
  const nl = data.indexOf(10, scan);
259
291
  if (nl === -1) {
260
- pending.push(Buffer.from(data.subarray(scan)));
261
- pendingLen += data.length - scan;
292
+ if (!oversize) {
293
+ pending.push(Buffer.from(data.subarray(scan)));
294
+ pendingLen += data.length - scan;
295
+ }
262
296
  break;
263
297
  }
264
298
  const lineLen = pendingLen + (nl - scan);
265
- if (oversize || lineLen > PR_SUBSCRIPTION_LIMITS.maxRecordBytes) {
299
+ if (!oversize && lineLen > PR_SUBSCRIPTION_LIMITS.maxRecordBytes) {
266
300
  corruptLines += 1;
267
- } else {
301
+ } else if (!oversize) {
268
302
  const pieces = pending.length > 0 ? [...pending, data.subarray(scan, nl)] : [data.subarray(scan, nl)];
269
303
  processLineBytes(Buffer.concat(pieces));
270
304
  }
@@ -273,9 +307,21 @@ function foldLegacyRegion(filePath, startByte, maxBytes) {
273
307
  oversize = false;
274
308
  consumedTo = base + nl + 1;
275
309
  scan = nl + 1;
310
+ if (consumedTo - startByte >= maxBytes) {
311
+ return {
312
+ folded,
313
+ nextByte: consumedTo,
314
+ eof: consumedTo >= size,
315
+ aborted: false,
316
+ corruptLines,
317
+ ioError: null,
318
+ discardingOversizeLine: false
319
+ };
320
+ }
276
321
  }
277
322
  if (!oversize && pendingLen > PR_SUBSCRIPTION_LIMITS.maxRecordBytes) {
278
323
  oversize = true;
324
+ corruptLines += 1;
279
325
  pending = [];
280
326
  pendingLen = 0;
281
327
  }
@@ -286,22 +332,37 @@ function foldLegacyRegion(filePath, startByte, maxBytes) {
286
332
  nextByte: consumedTo,
287
333
  eof,
288
334
  aborted: false,
289
- corruptLines
335
+ corruptLines,
336
+ ioError: null,
337
+ discardingOversizeLine: false
338
+ };
339
+ }
340
+ if (oversize && pos - startByte >= maxBytes) {
341
+ return {
342
+ folded,
343
+ nextByte: pos,
344
+ eof: pos >= size,
345
+ aborted: false,
346
+ corruptLines,
347
+ ioError: null,
348
+ discardingOversizeLine: pos < size
290
349
  };
291
350
  }
292
351
  }
293
352
  } catch (err) {
294
353
  log(`[pr-monitor] foldLegacyRegion failed: ${err instanceof Error ? err.message : String(err)}`);
295
354
  return {
296
- folded,
297
- nextByte: consumedTo,
355
+ folded: new Map,
356
+ nextByte: startByte,
298
357
  eof: true,
299
358
  aborted: true,
300
- corruptLines
359
+ corruptLines: 0,
360
+ ioError: err instanceof Error ? err.message : String(err),
361
+ discardingOversizeLine
301
362
  };
302
363
  } finally {
303
364
  try {
304
- fs.closeSync(fd);
365
+ _internals.legacyCloseSync(fd);
305
366
  } catch {}
306
367
  }
307
368
  }
@@ -317,9 +378,11 @@ function mergeFoldedRecords(view, overlay) {
317
378
  return replaced;
318
379
  }
319
380
  function readCheckpoint(directory) {
381
+ const filePath = checkpointPath(directory);
382
+ let fd;
320
383
  let stat;
321
384
  try {
322
- stat = fs.statSync(checkpointPath(directory));
385
+ fd = fs.openSync(filePath, "r");
323
386
  } catch (err) {
324
387
  if (err.code === "ENOENT") {
325
388
  return { kind: "absent" };
@@ -329,20 +392,45 @@ function readCheckpoint(directory) {
329
392
  reason: `unreadable (${err.code ?? "unknown"})`
330
393
  };
331
394
  }
332
- if (stat.size > PR_SUBSCRIPTION_LIMITS.checkpointHardReadBytes) {
395
+ try {
396
+ stat = fs.fstatSync(fd);
397
+ } catch (err) {
398
+ try {
399
+ fs.closeSync(fd);
400
+ } catch {}
333
401
  return {
334
402
  kind: "invalid",
335
- reason: `checkpoint exceeds hard read ceiling (${stat.size} > ${PR_SUBSCRIPTION_LIMITS.checkpointHardReadBytes} bytes)`
403
+ reason: `unreadable (${err.code ?? "unknown"})`
336
404
  };
337
405
  }
338
406
  let raw;
339
407
  try {
340
- raw = fs.readFileSync(checkpointPath(directory), "utf-8");
408
+ if (stat.size > PR_SUBSCRIPTION_LIMITS.checkpointHardReadBytes) {
409
+ return {
410
+ kind: "invalid",
411
+ reason: `checkpoint exceeds hard read ceiling (${stat.size} > ${PR_SUBSCRIPTION_LIMITS.checkpointHardReadBytes} bytes)`
412
+ };
413
+ }
414
+ _internals.afterCheckpointFstat(filePath);
415
+ const buffer = Buffer.alloc(stat.size);
416
+ let bytesRead = 0;
417
+ while (bytesRead < stat.size) {
418
+ const read = _internals.readSync(fd, buffer, bytesRead, stat.size - bytesRead, bytesRead);
419
+ if (read <= 0) {
420
+ throw new Error(`premature checkpoint EOF (${bytesRead}/${stat.size} bytes)`);
421
+ }
422
+ bytesRead += read;
423
+ }
424
+ raw = buffer.subarray(0, bytesRead).toString("utf-8");
341
425
  } catch (err) {
342
426
  return {
343
427
  kind: "invalid",
344
428
  reason: `unreadable (${err.code ?? "unknown"})`
345
429
  };
430
+ } finally {
431
+ try {
432
+ fs.closeSync(fd);
433
+ } catch {}
346
434
  }
347
435
  let parsed;
348
436
  try {
@@ -373,6 +461,23 @@ function readCheckpoint(directory) {
373
461
  };
374
462
  }
375
463
  }
464
+ if (checkpoint.migration !== null) {
465
+ const baselineEntries = Object.entries(checkpoint.migration.baselineRecords);
466
+ if (baselineEntries.length > PR_SUBSCRIPTION_LIMITS.maxCheckpointRecords) {
467
+ return {
468
+ kind: "invalid",
469
+ reason: `migration baseline count ${baselineEntries.length} exceeds guard ${PR_SUBSCRIPTION_LIMITS.maxCheckpointRecords}`
470
+ };
471
+ }
472
+ for (const [key, rec] of baselineEntries) {
473
+ if (key !== rec.correlationId || rec.correlationId !== buildCorrelationId(rec.sessionID, rec.repoFullName, rec.prNumber)) {
474
+ return {
475
+ kind: "invalid",
476
+ reason: `migration baseline identity mismatch at key "${key}"`
477
+ };
478
+ }
479
+ }
480
+ }
376
481
  return { kind: "ok", value: checkpoint };
377
482
  }
378
483
  function freshCheckpoint(directory) {
@@ -426,14 +531,14 @@ function quarantineCheckpoint(directory, slot) {
426
531
  try {
427
532
  fs.renameSync(to, `${to}.prev`);
428
533
  } catch {}
429
- renameWithRetry(from, to);
534
+ _internals.renameWithRetry(from, to);
430
535
  return true;
431
536
  } catch (err) {
432
537
  log(`[pr-monitor] checkpoint quarantine (${slot}) failed: ${err instanceof Error ? err.message : String(err)} \u2014 the next checkpoint write replaces it`);
433
538
  return false;
434
539
  }
435
540
  }
436
- function flushAuditEvents(directory, events, sequence, maintenance) {
541
+ function flushAuditEvents(directory, events, sequence, _maintenance) {
437
542
  if (events.length === 0)
438
543
  return;
439
544
  ensureSwarmDir(directory);
@@ -451,42 +556,58 @@ function flushAuditEvents(directory, events, sequence, maintenance) {
451
556
  log(`[pr-monitor] audit append failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
452
557
  return;
453
558
  }
454
- compactAuditTail(directory, maintenance);
455
559
  }
456
- function compactAuditTail(directory, maintenance) {
560
+ function storageErrorCode(err) {
561
+ if (typeof err === "object" && err !== null && "code" in err) {
562
+ const code = err.code;
563
+ if (typeof code === "string" && code.length > 0)
564
+ return code;
565
+ }
566
+ return "unknown";
567
+ }
568
+ function planAuditCompaction(directory) {
457
569
  let size;
458
570
  try {
459
571
  size = fs.statSync(auditPath(directory)).size;
460
572
  } catch {
461
- return;
573
+ return null;
462
574
  }
463
575
  if (size <= PR_SUBSCRIPTION_LIMITS.auditMaxBytesLow)
464
- return;
465
- const windowBytes = 2 * PR_SUBSCRIPTION_LIMITS.auditMaxBytesHigh;
576
+ return null;
466
577
  let content;
578
+ let omittedPrefix = false;
467
579
  try {
468
- if (size > windowBytes) {
469
- const fd = fs.openSync(auditPath(directory), "r");
470
- try {
471
- const tail = Buffer.alloc(windowBytes);
472
- const n = fs.readSync(fd, tail, 0, windowBytes, size - windowBytes);
473
- const text = tail.subarray(0, n).toString("utf-8");
474
- const firstNl = text.indexOf(`
475
- `);
476
- content = firstNl === -1 ? "" : text.slice(firstNl + 1);
477
- } finally {
478
- fs.closeSync(fd);
580
+ const filePath = auditPath(directory);
581
+ const maxRead = PR_SUBSCRIPTION_LIMITS.auditMaxBytesHigh;
582
+ const start = Math.max(0, size - maxRead);
583
+ const length = Math.min(size, maxRead);
584
+ const buffer = Buffer.alloc(length);
585
+ const fd = fs.openSync(filePath, "r");
586
+ try {
587
+ let bytesRead = 0;
588
+ while (bytesRead < length) {
589
+ const read = _internals.readSync(fd, buffer, bytesRead, length - bytesRead, start + bytesRead);
590
+ if (read <= 0)
591
+ return null;
592
+ bytesRead += read;
479
593
  }
480
- } else {
481
- content = fs.readFileSync(auditPath(directory), "utf-8");
594
+ content = buffer.toString("utf-8");
595
+ } finally {
596
+ fs.closeSync(fd);
597
+ }
598
+ if (start > 0) {
599
+ omittedPrefix = true;
600
+ const firstNewline = content.indexOf(`
601
+ `);
602
+ content = firstNewline >= 0 ? content.slice(firstNewline + 1) : "";
482
603
  }
483
604
  } catch {
484
- return;
605
+ return null;
485
606
  }
486
607
  const all = content.split(`
487
608
  `).filter((line) => line.trim().length > 0);
488
609
  if (all.length <= PR_SUBSCRIPTION_LIMITS.auditMaxLinesHigh && size <= PR_SUBSCRIPTION_LIMITS.auditMaxBytesHigh) {
489
- return;
610
+ return null;
490
611
  }
491
612
  const kept = [];
492
613
  let bytes = 0;
@@ -498,14 +619,40 @@ function compactAuditTail(directory, maintenance) {
498
619
  kept.unshift(all[i]);
499
620
  bytes += lineBytes;
500
621
  }
501
- const dropped = all.length - kept.length;
502
- try {
503
- atomicWriteSwarmFileSync(auditPath(directory), kept.length > 0 ? `${kept.join(`
622
+ const dropped = all.length - kept.length + (omittedPrefix ? 1 : 0);
623
+ return {
624
+ content: kept.length > 0 ? `${kept.join(`
504
625
  `)}
505
- ` : "");
506
- maintenance.droppedAuditTransitions += dropped;
626
+ ` : "",
627
+ dropped
628
+ };
629
+ }
630
+ function applyAuditCompaction(directory, plan) {
631
+ if (!plan)
632
+ return false;
633
+ try {
634
+ _internals.auditCompactionWrite(auditPath(directory), plan.content);
635
+ return true;
636
+ } catch (err) {
637
+ log(`[pr-monitor] audit compaction failed (non-fatal): ${storageErrorCode(err)}`);
638
+ return false;
639
+ }
640
+ }
641
+ function prepareAuditCompaction(directory) {
642
+ const plan = planAuditCompaction(directory);
643
+ return plan;
644
+ }
645
+ function persistCheckpointWithAuditCompaction(directory, checkpoint, plan) {
646
+ _internals.writeCheckpointFile(directory, checkpoint);
647
+ if (!applyAuditCompaction(directory, plan) || !plan)
648
+ return;
649
+ const previousDropped = checkpoint.maintenance.droppedAuditTransitions;
650
+ checkpoint.maintenance.droppedAuditTransitions += plan.dropped;
651
+ try {
652
+ _internals.writeCheckpointFile(directory, checkpoint);
507
653
  } catch (err) {
508
- log(`[pr-monitor] audit compaction failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
654
+ checkpoint.maintenance.droppedAuditTransitions = previousDropped;
655
+ log(`[pr-monitor] audit compaction accounting failed (non-fatal): ${storageErrorCode(err)}`);
509
656
  }
510
657
  }
511
658
  function auditStats(directory) {
@@ -565,20 +712,74 @@ function maybeArchiveLegacy(directory, checkpoint) {
565
712
  if (!migration || !migration.done || migration.archived)
566
713
  return null;
567
714
  const legacy = storePath(directory);
568
- const size = fileSizeOrNull(legacy);
569
- if (size === null) {
570
- migration.archived = true;
715
+ let stat;
716
+ try {
717
+ stat = _internals.archiveStatSync(legacy);
718
+ } catch (err) {
719
+ if (err.code === "ENOENT") {
720
+ migration.archived = true;
721
+ } else {
722
+ log(`[pr-monitor] legacy archive inspection deferred: ${storageErrorCode(err)}`);
723
+ }
724
+ return null;
725
+ }
726
+ if (stat.size !== migration.sourceBytes || stat.mtimeMs !== migration.sourceMtimeMs)
727
+ return null;
728
+ _internals.beforeArchiveLegacy(directory);
729
+ try {
730
+ stat = _internals.archiveStatSync(legacy);
731
+ } catch {
571
732
  return null;
572
733
  }
573
- if (size !== migration.sourceBytes)
734
+ if (stat.size !== migration.sourceBytes || stat.mtimeMs !== migration.sourceMtimeMs)
574
735
  return null;
736
+ const archive = legacyArchivePath(directory);
737
+ const next = legacyArchiveNextPath(directory);
738
+ const previous = legacyArchivePreviousPath(directory);
575
739
  try {
740
+ _internals.beforeArchiveRename(directory);
576
741
  try {
577
- fs.unlinkSync(legacyArchivePath(directory));
742
+ fs.unlinkSync(next);
743
+ } catch {}
744
+ _internals.renameWithRetry(legacy, next);
745
+ const archivedStat = _internals.archiveStatSync(next);
746
+ if (archivedStat.size !== migration.sourceBytes || archivedStat.mtimeMs !== migration.sourceMtimeMs) {
747
+ _internals.renameWithRetry(next, legacy);
748
+ return null;
749
+ }
750
+ const archivedAt = new Date;
751
+ fs.utimesSync(next, archivedAt, archivedAt);
752
+ let movedPrevious = false;
753
+ try {
754
+ fs.unlinkSync(previous);
578
755
  } catch {}
579
- renameWithRetry(legacy, legacyArchivePath(directory));
756
+ try {
757
+ _internals.renameWithRetry(archive, previous);
758
+ movedPrevious = true;
759
+ } catch (err) {
760
+ if (err.code !== "ENOENT")
761
+ throw err;
762
+ }
763
+ try {
764
+ _internals.renameWithRetry(next, archive);
765
+ } catch (err) {
766
+ if (movedPrevious)
767
+ _internals.renameWithRetry(previous, archive);
768
+ _internals.renameWithRetry(next, legacy);
769
+ throw err;
770
+ }
771
+ if (movedPrevious) {
772
+ try {
773
+ fs.unlinkSync(previous);
774
+ } catch {}
775
+ }
580
776
  } catch (err) {
581
- log(`[pr-monitor] legacy archive deferred: ${err instanceof Error ? err.message : String(err)}`);
777
+ try {
778
+ if (fs.existsSync(next) && !fs.existsSync(legacy)) {
779
+ _internals.renameWithRetry(next, legacy);
780
+ }
781
+ } catch {}
782
+ log(`[pr-monitor] legacy archive deferred: ${storageErrorCode(err)}`);
582
783
  return null;
583
784
  }
584
785
  try {
@@ -588,6 +789,70 @@ function maybeArchiveLegacy(directory, checkpoint) {
588
789
  migration.archived = true;
589
790
  return { kind: "archive" };
590
791
  }
792
+ function reconcileLegacyArchiveStaging(directory, migration) {
793
+ const legacy = storePath(directory);
794
+ const archive = legacyArchivePath(directory);
795
+ const next = legacyArchiveNextPath(directory);
796
+ const previous = legacyArchivePreviousPath(directory);
797
+ let legacyExists = fileExistsStrict(legacy);
798
+ let archiveExists = fileExistsStrict(archive);
799
+ let nextExists = fileExistsStrict(next);
800
+ let previousExists = fileExistsStrict(previous);
801
+ if (!nextExists && !previousExists)
802
+ return;
803
+ if (legacyExists) {
804
+ if (!archiveExists && previousExists) {
805
+ _internals.renameWithRetry(previous, archive);
806
+ archiveExists = true;
807
+ previousExists = false;
808
+ }
809
+ if (!archiveExists && nextExists) {
810
+ const candidate = fs.statSync(next);
811
+ if (migration.done && candidate.size === migration.sourceBytes && candidate.mtimeMs === migration.sourceMtimeMs) {
812
+ _internals.renameWithRetry(next, archive);
813
+ archiveExists = true;
814
+ nextExists = false;
815
+ }
816
+ }
817
+ if (archiveExists && previousExists)
818
+ fs.unlinkSync(previous);
819
+ if (nextExists)
820
+ fs.unlinkSync(next);
821
+ return;
822
+ }
823
+ if (archiveExists) {
824
+ if (nextExists) {
825
+ _internals.renameWithRetry(next, legacy);
826
+ migration.archived = false;
827
+ legacyExists = true;
828
+ nextExists = false;
829
+ }
830
+ if (previousExists)
831
+ fs.unlinkSync(previous);
832
+ return;
833
+ }
834
+ if (previousExists) {
835
+ _internals.renameWithRetry(previous, archive);
836
+ archiveExists = true;
837
+ previousExists = false;
838
+ if (nextExists) {
839
+ _internals.renameWithRetry(next, legacy);
840
+ migration.archived = false;
841
+ legacyExists = true;
842
+ nextExists = false;
843
+ }
844
+ return;
845
+ }
846
+ if (nextExists) {
847
+ const candidate = fs.statSync(next);
848
+ if (migration.done && candidate.size === migration.sourceBytes && candidate.mtimeMs === migration.sourceMtimeMs) {
849
+ _internals.renameWithRetry(next, archive);
850
+ } else {
851
+ _internals.renameWithRetry(next, legacy);
852
+ migration.archived = false;
853
+ }
854
+ }
855
+ }
591
856
  function cleanupStaleLegacyArchive(directory) {
592
857
  try {
593
858
  const stat = fs.statSync(legacyArchivePath(directory));
@@ -605,7 +870,8 @@ function emitHealthTelemetry(trigger, checkpoint) {
605
870
  compactions: checkpoint.maintenance.compactions,
606
871
  corrupt_count: checkpoint.maintenance.corruptLegacyRecords,
607
872
  dropped_audit_count: checkpoint.maintenance.droppedAuditTransitions,
608
- checkpoint_bytes: Buffer.byteLength(JSON.stringify(checkpoint), "utf-8"),
873
+ checkpoint_bytes: Buffer.byteLength(`${JSON.stringify(checkpoint)}
874
+ `, "utf-8"),
609
875
  limit_bytes: PR_SUBSCRIPTION_LIMITS.maxCheckpointBytes,
610
876
  recovery_resets: checkpoint.maintenance.resets
611
877
  });
@@ -631,7 +897,7 @@ function warnMigrationCapacity(directory, records) {
631
897
  log(`[pr-monitor] legacy subscriptions.jsonl folds to ${records} records (>checkpoint capacity ${PR_SUBSCRIPTION_LIMITS.maxCheckpointRecords}); migration refused \u2014 archive or split the file so its subscriptions can be re-subscribed, then remove it`);
632
898
  }
633
899
  function overlayLegacy(directory, checkpoint) {
634
- const view = { ...checkpoint.records };
900
+ let view = { ...checkpoint.records };
635
901
  const legacy = storePath(directory);
636
902
  let stat = null;
637
903
  try {
@@ -660,10 +926,25 @@ function overlayLegacy(directory, checkpoint) {
660
926
  }
661
927
  const migration = checkpoint.migration;
662
928
  if (migration === null || !migration.done) {
663
- let cursor = migration?.scannedBytes ?? 0;
664
- if (cursor > stat.size)
665
- cursor = 0;
666
- const fold2 = foldLegacyRegion(legacy, cursor, Number.MAX_SAFE_INTEGER);
929
+ const baselineRecords = migration?.baselineRecords ?? {
930
+ ...checkpoint.records
931
+ };
932
+ const sameGeneration = migration !== null && stat.size === migration.sourceBytes && stat.mtimeMs === migration.sourceMtimeMs;
933
+ const cursor = sameGeneration ? migration.scannedBytes : 0;
934
+ const discardingOversizeLine = sameGeneration ? migration.discardingOversizeLine : false;
935
+ if (!sameGeneration && migration !== null) {
936
+ view = { ...baselineRecords };
937
+ }
938
+ const fold2 = foldLegacyRegion(legacy, cursor, Number.MAX_SAFE_INTEGER, discardingOversizeLine);
939
+ if (fold2.ioError)
940
+ return {
941
+ view,
942
+ usedLegacy: false,
943
+ absorbed: 0,
944
+ corruptLines: 0,
945
+ overLimit: false,
946
+ aborted: true
947
+ };
667
948
  const absorbed2 = mergeFoldedRecords(view, fold2.folded);
668
949
  return {
669
950
  view,
@@ -685,6 +966,15 @@ function overlayLegacy(directory, checkpoint) {
685
966
  };
686
967
  }
687
968
  const fold = foldLegacyRegion(legacy, 0, Number.MAX_SAFE_INTEGER);
969
+ if (fold.ioError)
970
+ return {
971
+ view,
972
+ usedLegacy: false,
973
+ absorbed: 0,
974
+ corruptLines: 0,
975
+ overLimit: false,
976
+ aborted: true
977
+ };
688
978
  const absorbed = mergeFoldedRecords(view, fold.folded);
689
979
  return {
690
980
  view,
@@ -713,31 +1003,38 @@ async function loadViewForRead(directory) {
713
1003
  const size = fileSizeOrNull(legacy);
714
1004
  if (size !== null && size <= PR_SUBSCRIPTION_LIMITS.legacySourceMaxBytes) {
715
1005
  const fold2 = foldLegacyRegion(legacy, 0, Number.MAX_SAFE_INTEGER);
716
- mergeFoldedRecords(view2, fold2.folded);
1006
+ if (!fold2.ioError)
1007
+ mergeFoldedRecords(view2, fold2.folded);
717
1008
  } else if (size !== null) {
718
1009
  warnLegacyOverLimit(directory, size);
719
1010
  }
720
1011
  return { view: view2, recoverySource: "corrupt-recovered" };
721
1012
  }
722
1013
  const legacyPath = storePath(directory);
723
- const legacySize = fileSizeOrNull(legacyPath);
724
- if (legacySize === null) {
1014
+ let legacyStat;
1015
+ try {
1016
+ legacyStat = fs.statSync(legacyPath);
1017
+ } catch {
725
1018
  return { view: {}, recoverySource: "empty" };
726
1019
  }
1020
+ const legacySize = legacyStat.size;
727
1021
  if (legacySize > PR_SUBSCRIPTION_LIMITS.legacySourceMaxBytes) {
728
1022
  warnLegacyOverLimit(directory, legacySize);
729
1023
  return { view: {}, recoverySource: "legacy-log" };
730
1024
  }
731
1025
  const fold = foldLegacyRegion(legacyPath, 0, Number.MAX_SAFE_INTEGER);
732
1026
  const view = {};
1027
+ if (fold.ioError)
1028
+ return { view, recoverySource: "legacy-log" };
733
1029
  mergeFoldedRecords(view, fold.folded);
734
1030
  if (!fold.aborted) {
735
- await bootstrapCheckpointFromLegacy(directory, view, fold);
1031
+ _internals.beforeBootstrapLock(directory);
1032
+ await bootstrapCheckpointFromLegacy(directory);
736
1033
  }
737
1034
  return { view, recoverySource: "legacy-log" };
738
1035
  }
739
1036
  var bootstrapAttempted = new Map;
740
- async function bootstrapCheckpointFromLegacy(directory, foldedView, fold) {
1037
+ async function bootstrapCheckpointFromLegacy(directory) {
741
1038
  if (bootstrapAttempted.has(directory))
742
1039
  return;
743
1040
  if (bootstrapAttempted.size >= 32) {
@@ -748,49 +1045,108 @@ async function bootstrapCheckpointFromLegacy(directory, foldedView, fold) {
748
1045
  await withEvidenceLock(directory, PR_SUBSCRIPTIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
749
1046
  if (readCheckpoint(directory).kind !== "absent")
750
1047
  return;
1048
+ let beforeFold;
1049
+ try {
1050
+ beforeFold = fs.statSync(storePath(directory));
1051
+ } catch {
1052
+ return;
1053
+ }
1054
+ const lockedFold = foldLegacyRegion(storePath(directory), 0, PR_SUBSCRIPTION_LIMITS.legacySourceMaxBytes);
1055
+ if (lockedFold.ioError)
1056
+ return;
1057
+ let afterFold;
1058
+ try {
1059
+ afterFold = fs.statSync(storePath(directory));
1060
+ } catch {
1061
+ return;
1062
+ }
1063
+ if (afterFold.size !== beforeFold.size || afterFold.mtimeMs !== beforeFold.mtimeMs)
1064
+ return;
1065
+ const foldedView = {};
1066
+ mergeFoldedRecords(foldedView, lockedFold.folded);
751
1067
  const checkpoint = freshCheckpoint(directory);
752
1068
  checkpoint.records = { ...foldedView };
753
1069
  const terminals = Object.values(foldedView).filter((rec) => rec.status !== "active");
754
1070
  checkpoint.terminalSummary.lastTerminalAt = terminals.length ? Math.max(...terminals.map((rec) => rec.updatedAt)) : null;
755
- checkpoint.maintenance.corruptLegacyRecords = fold.corruptLines;
756
- let bootstrapMtime = 0;
757
- try {
758
- bootstrapMtime = fs.statSync(storePath(directory)).mtimeMs;
759
- } catch {}
1071
+ checkpoint.maintenance.corruptLegacyRecords = lockedFold.corruptLines;
760
1072
  checkpoint.migration = {
761
- scannedBytes: fold.nextByte,
762
- sourceBytes: fold.nextByte,
763
- sourceMtimeMs: bootstrapMtime,
764
- corruptLines: fold.corruptLines,
1073
+ scannedBytes: lockedFold.nextByte,
1074
+ sourceBytes: beforeFold.size,
1075
+ sourceMtimeMs: beforeFold.mtimeMs,
1076
+ corruptLines: lockedFold.corruptLines,
1077
+ discardingOversizeLine: false,
1078
+ baselineRecords: {},
1079
+ baselineTerminalSummary: {
1080
+ removed: 0,
1081
+ expired: 0,
1082
+ lastTerminalAt: null
1083
+ },
765
1084
  done: true,
766
1085
  archived: false,
767
1086
  startedAt: Date.now()
768
1087
  };
769
1088
  checkpoint.sequence = 1;
770
1089
  checkpoint.updatedAt = Date.now();
771
- writeCheckpointFile(directory, checkpoint);
772
- flushAuditEvents(directory, [{ kind: "migrate-complete" }], checkpoint.sequence, checkpoint.maintenance);
1090
+ const auditCompaction = prepareAuditCompaction(directory);
1091
+ persistCheckpointWithAuditCompaction(directory, checkpoint, auditCompaction);
1092
+ const archiveEvent = maybeArchiveLegacy(directory, checkpoint);
1093
+ if (archiveEvent) {
1094
+ checkpoint.sequence += 1;
1095
+ checkpoint.updatedAt = Date.now();
1096
+ _internals.writeCheckpointFile(directory, checkpoint);
1097
+ }
1098
+ flushAuditEvents(directory, [
1099
+ { kind: "migrate-complete" },
1100
+ ...archiveEvent ? [archiveEvent] : []
1101
+ ], checkpoint.sequence, checkpoint.maintenance);
773
1102
  emitHealthTelemetry("migrate-complete", checkpoint);
1103
+ if (archiveEvent)
1104
+ emitHealthTelemetry("archive", checkpoint);
774
1105
  }, PR_SUBSCRIPTION_LIMITS.bootstrapLockTimeoutMs);
775
1106
  } catch (err) {
776
- log(`[pr-monitor] read-bootstrap skipped: ${err instanceof Error ? err.message : String(err)}`);
1107
+ log(`[pr-monitor] read-bootstrap skipped: ${storageErrorCode(err)}`);
777
1108
  }
778
1109
  }
779
1110
  function loadViewForWrite(directory) {
780
1111
  const audit = [];
781
1112
  let dirty = false;
1113
+ let reboundForeign = false;
782
1114
  let checkpoint;
783
1115
  const read = readCheckpoint(directory);
784
1116
  if (read.kind === "ok" && sameProjectRoot(read.value.rootPath, directory)) {
785
1117
  checkpoint = cloneCheckpoint(read.value);
786
1118
  } else if (read.kind === "ok") {
787
1119
  const displaced = Object.keys(read.value.records).length;
788
- quarantineCheckpoint(directory, "foreign");
1120
+ const legacy2 = storePath(directory);
1121
+ let foreignLegacyExists = false;
1122
+ try {
1123
+ _internals.statSync(legacy2);
1124
+ foreignLegacyExists = true;
1125
+ } catch (err) {
1126
+ if (err.code !== "ENOENT") {
1127
+ throw new Error(`PR subscription foreign legacy log could not be inspected; refusing to rebind (${storageErrorCode(err)})`);
1128
+ }
1129
+ }
1130
+ if (foreignLegacyExists) {
1131
+ const foreignLegacy = foreignLegacySlotPath(directory);
1132
+ try {
1133
+ try {
1134
+ fs.unlinkSync(foreignLegacy);
1135
+ } catch {}
1136
+ _internals.renameWithRetry(legacy2, foreignLegacy);
1137
+ } catch (err) {
1138
+ throw new Error(`PR subscription foreign legacy log could not be quarantined; refusing to rebind (${storageErrorCode(err)})`);
1139
+ }
1140
+ }
1141
+ if (!quarantineCheckpoint(directory, "foreign")) {
1142
+ throw new Error("PR subscription foreign checkpoint could not be quarantined; refusing to rebind");
1143
+ }
789
1144
  checkpoint = freshCheckpoint(directory);
790
1145
  checkpoint.maintenance.resets += read.value.maintenance.resets + 1;
791
1146
  audit.push({ kind: "foreign-rebind" });
792
1147
  dirty = true;
793
1148
  log(`[pr-monitor] foreign checkpoint quarantined (${displaced} displaced records, recorded root ${read.value.rootPath}); store rebound to ${directory}`);
1149
+ reboundForeign = true;
794
1150
  } else if (read.kind === "invalid") {
795
1151
  quarantineCheckpoint(directory, "corrupt");
796
1152
  checkpoint = freshCheckpoint(directory);
@@ -801,12 +1157,25 @@ function loadViewForWrite(directory) {
801
1157
  } else {
802
1158
  checkpoint = freshCheckpoint(directory);
803
1159
  }
1160
+ if (!reboundForeign && checkpoint.migration !== null) {
1161
+ try {
1162
+ reconcileLegacyArchiveStaging(directory, checkpoint.migration);
1163
+ } catch (err) {
1164
+ throw new Error(`PR subscription legacy archive staging could not be reconciled; refusing mutation (${storageErrorCode(err)})`);
1165
+ }
1166
+ }
804
1167
  const legacy = storePath(directory);
805
1168
  let legacyStat = null;
806
1169
  try {
807
- legacyStat = fs.statSync(legacy);
808
- } catch {}
1170
+ legacyStat = _internals.statSync(legacy);
1171
+ } catch (err) {
1172
+ if (err.code !== "ENOENT") {
1173
+ throw new Error(`PR subscription legacy store could not be inspected; refusing mutation (${storageErrorCode(err)})`);
1174
+ }
1175
+ }
809
1176
  let view;
1177
+ if (reboundForeign)
1178
+ legacyStat = null;
810
1179
  if (legacyStat === null) {
811
1180
  view = { ...checkpoint.records };
812
1181
  if (checkpoint.migration?.done && !checkpoint.migration.archived) {
@@ -817,25 +1186,44 @@ function loadViewForWrite(directory) {
817
1186
  }
818
1187
  if (legacyStat.size > PR_SUBSCRIPTION_LIMITS.legacySourceMaxBytes) {
819
1188
  warnLegacyOverLimit(directory, legacyStat.size);
820
- return { checkpoint, view: { ...checkpoint.records }, audit, dirty };
1189
+ throw new Error(`PR subscription legacy store exceeds the ${PR_SUBSCRIPTION_LIMITS.legacySourceMaxBytes}-byte migration ceiling; refusing mutation until the file is archived or split`);
821
1190
  }
822
1191
  const legacySize = legacyStat.size;
823
1192
  const legacyMtime = legacyStat.mtimeMs;
824
1193
  const migration = checkpoint.migration;
825
1194
  if (migration === null || !migration.done) {
826
- let cursor = migration?.scannedBytes ?? 0;
827
- if (cursor > legacySize)
828
- cursor = 0;
829
- const startedAt = migration?.startedAt ?? Date.now();
830
- let corruptTotal = migration?.corruptLines ?? 0;
1195
+ const baselineRecords = migration?.baselineRecords ?? {
1196
+ ...checkpoint.records
1197
+ };
1198
+ const baselineTerminalSummary = migration?.baselineTerminalSummary ?? {
1199
+ ...checkpoint.terminalSummary
1200
+ };
1201
+ const sameGeneration = migration !== null && legacySize === migration.sourceBytes && legacyMtime === migration.sourceMtimeMs;
1202
+ let cursor = sameGeneration ? migration.scannedBytes : 0;
1203
+ const startedAt = sameGeneration ? migration.startedAt : Date.now();
1204
+ let corruptTotal = sameGeneration ? migration.corruptLines : 0;
1205
+ let discardingOversizeLine = sameGeneration ? migration.discardingOversizeLine : false;
1206
+ if (!sameGeneration && migration !== null) {
1207
+ checkpoint.records = { ...baselineRecords };
1208
+ checkpoint.terminalSummary = { ...baselineTerminalSummary };
1209
+ checkpoint.maintenance.corruptLegacyRecords = Math.max(0, checkpoint.maintenance.corruptLegacyRecords - migration.corruptLines);
1210
+ }
831
1211
  view = { ...checkpoint.records };
832
1212
  let capacityRefused = false;
1213
+ let foldedThisOperation = 0;
833
1214
  while (true) {
834
- const fold = foldLegacyRegion(legacy, cursor, PR_SUBSCRIPTION_LIMITS.migrationChunkBytes);
1215
+ const chunkStart = cursor;
1216
+ const remainingOperationBytes = Math.max(1, PR_SUBSCRIPTION_LIMITS.migrationMaxBytesPerOperation - foldedThisOperation);
1217
+ const fold = foldLegacyRegion(legacy, cursor, Math.min(PR_SUBSCRIPTION_LIMITS.migrationChunkBytes, remainingOperationBytes), discardingOversizeLine);
1218
+ if (fold.ioError) {
1219
+ throw new Error("PR subscription legacy migration read failed (I/O error)");
1220
+ }
835
1221
  mergeFoldedRecords(view, fold.folded);
836
1222
  checkpoint.maintenance.corruptLegacyRecords += fold.corruptLines;
837
1223
  corruptTotal += fold.corruptLines;
1224
+ discardingOversizeLine = fold.discardingOversizeLine;
838
1225
  cursor = fold.nextByte;
1226
+ foldedThisOperation += Math.max(0, cursor - chunkStart);
839
1227
  if (fold.aborted) {
840
1228
  const progress = cloneCheckpoint(checkpoint);
841
1229
  progress.records = { ...view };
@@ -844,6 +1232,9 @@ function loadViewForWrite(directory) {
844
1232
  sourceBytes: legacySize,
845
1233
  sourceMtimeMs: legacyMtime,
846
1234
  corruptLines: corruptTotal,
1235
+ discardingOversizeLine,
1236
+ baselineRecords: { ...baselineRecords },
1237
+ baselineTerminalSummary: { ...baselineTerminalSummary },
847
1238
  done: false,
848
1239
  archived: false,
849
1240
  startedAt
@@ -872,6 +1263,9 @@ function loadViewForWrite(directory) {
872
1263
  sourceBytes: legacySize,
873
1264
  sourceMtimeMs: legacyMtime,
874
1265
  corruptLines: corruptTotal,
1266
+ discardingOversizeLine,
1267
+ baselineRecords: { ...baselineRecords },
1268
+ baselineTerminalSummary: { ...baselineTerminalSummary },
875
1269
  done: false,
876
1270
  archived: false,
877
1271
  startedAt
@@ -881,6 +1275,9 @@ function loadViewForWrite(directory) {
881
1275
  writeCheckpointFile(directory, progress);
882
1276
  checkpoint.sequence = progress.sequence;
883
1277
  dirty = true;
1278
+ if (foldedThisOperation >= PR_SUBSCRIPTION_LIMITS.migrationMaxBytesPerOperation) {
1279
+ throw new Error(`PR subscription legacy migration is in progress (${cursor}/${legacySize} bytes); retry the operation to continue`);
1280
+ }
884
1281
  continue;
885
1282
  }
886
1283
  checkpoint.migration = {
@@ -888,6 +1285,13 @@ function loadViewForWrite(directory) {
888
1285
  sourceBytes: legacySize,
889
1286
  sourceMtimeMs: legacyMtime,
890
1287
  corruptLines: corruptTotal,
1288
+ discardingOversizeLine: false,
1289
+ baselineRecords: {},
1290
+ baselineTerminalSummary: {
1291
+ removed: 0,
1292
+ expired: 0,
1293
+ lastTerminalAt: null
1294
+ },
891
1295
  done: true,
892
1296
  archived: false,
893
1297
  startedAt
@@ -919,20 +1323,32 @@ function finalizeWrite(directory, loaded, opAudit) {
919
1323
  const compactEvent = compactTerminalRecords(loaded.view, checkpoint);
920
1324
  if (compactEvent)
921
1325
  events.push(compactEvent);
922
- if (!loaded.dirty && events.length === 0)
1326
+ if (!loaded.dirty && events.length === 0) {
1327
+ const archiveEvent2 = maybeArchiveLegacy(directory, checkpoint);
1328
+ if (!archiveEvent2)
1329
+ return;
1330
+ checkpoint.updatedAt = Date.now();
1331
+ checkpoint.sequence += 1;
1332
+ const auditCompaction2 = prepareAuditCompaction(directory);
1333
+ persistCheckpointWithAuditCompaction(directory, checkpoint, auditCompaction2);
1334
+ flushAuditEvents(directory, [archiveEvent2], checkpoint.sequence, checkpoint.maintenance);
1335
+ cleanupStaleLegacyArchive(directory);
1336
+ emitHealthTelemetry("archive", checkpoint);
923
1337
  return;
1338
+ }
924
1339
  checkpoint.records = loaded.view;
925
1340
  checkpoint.updatedAt = Date.now();
926
1341
  checkpoint.rootPath = path.resolve(directory);
927
1342
  checkpoint.sequence += 1;
1343
+ const auditCompaction = prepareAuditCompaction(directory);
1344
+ persistCheckpointWithAuditCompaction(directory, checkpoint, auditCompaction);
928
1345
  flushAuditEvents(directory, events, checkpoint.sequence, checkpoint.maintenance);
929
- writeCheckpointFile(directory, checkpoint);
930
1346
  const archiveEvent = maybeArchiveLegacy(directory, checkpoint);
931
1347
  if (archiveEvent) {
932
1348
  events.push(archiveEvent);
933
1349
  checkpoint.sequence += 1;
1350
+ _internals.writeCheckpointFile(directory, checkpoint);
934
1351
  flushAuditEvents(directory, [archiveEvent], checkpoint.sequence, checkpoint.maintenance);
935
- writeCheckpointFile(directory, checkpoint);
936
1352
  }
937
1353
  cleanupStaleLegacyArchive(directory);
938
1354
  for (const kind of [
@@ -1061,6 +1477,7 @@ async function updateSnapshot(directory, correlationId, updates) {
1061
1477
  createdAt: match.createdAt,
1062
1478
  updatedAt: Date.now()
1063
1479
  };
1480
+ validateRecord(updated);
1064
1481
  loaded.view[correlationId] = updated;
1065
1482
  loaded.dirty = true;
1066
1483
  finalizeWrite(directory, loaded, []);
@@ -1139,7 +1556,8 @@ async function getPrSubscriptionHealth(directory) {
1139
1556
  if (legacySize !== null && !legacyOverLimit) {
1140
1557
  const fold = foldLegacyRegion(storePath(directory), 0, Number.MAX_SAFE_INTEGER);
1141
1558
  const view = {};
1142
- mergeFoldedRecords(view, fold.folded);
1559
+ if (!fold.ioError)
1560
+ mergeFoldedRecords(view, fold.folded);
1143
1561
  health = healthFromView(view, freshCheckpoint(directory));
1144
1562
  health.corruptLegacyRecords = fold.corruptLines;
1145
1563
  } else {
@@ -1152,7 +1570,8 @@ async function getPrSubscriptionHealth(directory) {
1152
1570
  } else {
1153
1571
  const fold = foldLegacyRegion(storePath(directory), 0, Number.MAX_SAFE_INTEGER);
1154
1572
  const view = {};
1155
- mergeFoldedRecords(view, fold.folded);
1573
+ if (!fold.ioError)
1574
+ mergeFoldedRecords(view, fold.folded);
1156
1575
  health = healthFromView(view, freshCheckpoint(directory));
1157
1576
  health.corruptLegacyRecords = fold.corruptLines;
1158
1577
  }
@@ -1166,7 +1585,7 @@ async function getPrSubscriptionHealth(directory) {
1166
1585
  applyFileStats(health, checkpointBytes, audit, archiveBytes);
1167
1586
  return health;
1168
1587
  } catch (err) {
1169
- log(`[pr-monitor] getPrSubscriptionHealth failed: ${err instanceof Error ? err.message : String(err)}`);
1588
+ log(`[pr-monitor] getPrSubscriptionHealth failed: ${storageErrorCode(err)}`);
1170
1589
  return emptyHealth();
1171
1590
  }
1172
1591
  }
@@ -1223,9 +1642,21 @@ function healthFromView(view, checkpoint) {
1223
1642
  return health;
1224
1643
  }
1225
1644
  var _internals = {
1645
+ afterCheckpointFstat: (_filePath) => {},
1646
+ archiveStatSync: fs.statSync,
1647
+ auditCompactionWrite: atomicWriteSwarmFileSync,
1648
+ beforeBootstrapLock: (_directory) => {},
1649
+ beforeArchiveLegacy: (_directory) => {},
1650
+ beforeArchiveRename: (_directory) => {},
1226
1651
  foldLegacyRegion,
1652
+ legacyCloseSync: fs.closeSync,
1653
+ legacyFstatSync: fs.fstatSync,
1227
1654
  mergeFoldedRecords,
1228
- sameProjectRoot
1655
+ readSync: fs.readSync,
1656
+ renameWithRetry,
1657
+ sameProjectRoot,
1658
+ statSync: fs.statSync,
1659
+ writeCheckpointFile
1229
1660
  };
1230
1661
 
1231
1662
  export { PR_SUBSCRIPTIONS_FILE, PR_SUBSCRIPTIONS_CHECKPOINT_FILE, PR_SUBSCRIPTIONS_AUDIT_FILE, PR_SUBSCRIPTION_LIMITS, setOnSubscriptionCreated, buildCorrelationId, subscribe, unsubscribe, listActive, lookupByPr, updateSnapshot, sweepStale, getPrSubscriptionHealth, _internals };