@graphrefly/graphrefly 0.14.0 → 0.16.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 (71) hide show
  1. package/dist/{chunk-2ZICUAUJ.js → chunk-26A4E7J7.js} +10 -12
  2. package/dist/chunk-26A4E7J7.js.map +1 -0
  3. package/dist/{chunk-CRACCCJY.js → chunk-3BLRREFM.js} +29 -5
  4. package/dist/chunk-3BLRREFM.js.map +1 -0
  5. package/dist/{chunk-XQ4UMAU7.js → chunk-ITDVOCFO.js} +2 -2
  6. package/dist/{chunk-YW6LFCFS.js → chunk-LKP7IWRV.js} +3 -3
  7. package/dist/{chunk-4APC3AFN.js → chunk-RLVFZDCE.js} +22 -49
  8. package/dist/chunk-RLVFZDCE.js.map +1 -0
  9. package/dist/{chunk-GKRKDYNT.js → chunk-RZSQ7P2C.js} +3 -3
  10. package/dist/{chunk-ZHTHUX5D.js → chunk-SHRJH2DN.js} +3 -3
  11. package/dist/{chunk-H243FWYP.js → chunk-VZY2B2LU.js} +1 -1
  12. package/dist/{chunk-H243FWYP.js.map → chunk-VZY2B2LU.js.map} +1 -1
  13. package/dist/{chunk-QVYZD65U.js → chunk-YX263TXI.js} +10 -38
  14. package/dist/chunk-YX263TXI.js.map +1 -0
  15. package/dist/compat/nestjs/index.cjs +38 -41
  16. package/dist/compat/nestjs/index.cjs.map +1 -1
  17. package/dist/compat/nestjs/index.d.cts +4 -4
  18. package/dist/compat/nestjs/index.d.ts +4 -4
  19. package/dist/compat/nestjs/index.js +7 -7
  20. package/dist/core/index.cjs.map +1 -1
  21. package/dist/core/index.d.cts +2 -2
  22. package/dist/core/index.d.ts +2 -2
  23. package/dist/core/index.js +3 -3
  24. package/dist/extra/index.cjs +27 -78
  25. package/dist/extra/index.cjs.map +1 -1
  26. package/dist/extra/index.d.cts +4 -4
  27. package/dist/extra/index.d.ts +4 -4
  28. package/dist/extra/index.js +3 -3
  29. package/dist/graph/index.cjs +26 -2
  30. package/dist/graph/index.cjs.map +1 -1
  31. package/dist/graph/index.d.cts +3 -3
  32. package/dist/graph/index.d.ts +3 -3
  33. package/dist/graph/index.js +4 -4
  34. package/dist/{graph-BXIK5Dq5.d.ts → graph-Dc-P9BVm.d.ts} +15 -3
  35. package/dist/{graph-BhADtuFU.d.cts → graph-fCsaaVIa.d.cts} +15 -3
  36. package/dist/{index-DSp5R3Xq.d.ts → index-BBVBYPxr.d.cts} +4 -4
  37. package/dist/{index-BkToATim.d.ts → index-BR19vQME.d.ts} +1 -1
  38. package/dist/{index-BNB0KjKe.d.ts → index-BmoUvOGN.d.ts} +1 -1
  39. package/dist/{index-DBhLjWSV.d.cts → index-ClaKZFPl.d.cts} +100 -31
  40. package/dist/{index-Dqemj9q0.d.cts → index-DWq0P9T6.d.ts} +4 -4
  41. package/dist/{index-Wa8jXne6.d.cts → index-Db27z6Ki.d.cts} +1 -1
  42. package/dist/{index-fYObbpUw.d.ts → index-DhXznWyH.d.ts} +2 -2
  43. package/dist/{index-DANO9Gg7.d.cts → index-DlGMf_Qe.d.cts} +2 -2
  44. package/dist/{index-CKyYg4IP.d.ts → index-N704txAA.d.ts} +100 -31
  45. package/dist/{index-DKIyo4Bq.d.cts → index-YlOH1Gw6.d.cts} +1 -1
  46. package/dist/index.cjs +185 -224
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.cts +35 -39
  49. package/dist/index.d.ts +35 -39
  50. package/dist/index.js +143 -153
  51. package/dist/index.js.map +1 -1
  52. package/dist/{meta-CrZUQAJ6.d.cts → meta-BV4pj9ML.d.cts} +6 -0
  53. package/dist/{meta-CrZUQAJ6.d.ts → meta-BV4pj9ML.d.ts} +6 -0
  54. package/dist/observable-Cz-AWhwR.d.cts +42 -0
  55. package/dist/observable-DCqlwGyl.d.ts +42 -0
  56. package/dist/patterns/reactive-layout/index.cjs +26 -2
  57. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  58. package/dist/patterns/reactive-layout/index.d.cts +3 -3
  59. package/dist/patterns/reactive-layout/index.d.ts +3 -3
  60. package/dist/patterns/reactive-layout/index.js +4 -4
  61. package/package.json +3 -2
  62. package/dist/chunk-2ZICUAUJ.js.map +0 -1
  63. package/dist/chunk-4APC3AFN.js.map +0 -1
  64. package/dist/chunk-CRACCCJY.js.map +0 -1
  65. package/dist/chunk-QVYZD65U.js.map +0 -1
  66. package/dist/reactive-log-ChbpUrY2.d.cts +0 -137
  67. package/dist/reactive-log-DV--7BWd.d.ts +0 -137
  68. /package/dist/{chunk-XQ4UMAU7.js.map → chunk-ITDVOCFO.js.map} +0 -0
  69. /package/dist/{chunk-YW6LFCFS.js.map → chunk-LKP7IWRV.js.map} +0 -0
  70. /package/dist/{chunk-GKRKDYNT.js.map → chunk-RZSQ7P2C.js.map} +0 -0
  71. /package/dist/{chunk-ZHTHUX5D.js.map → chunk-SHRJH2DN.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -2997,15 +2997,14 @@ var GraphReflyEventExplorer = class {
2997
2997
  if (!cqrsGraph) return;
2998
2998
  cqrsGraph.event(meta.eventName);
2999
2999
  const eventNode = cqrsGraph.resolve(meta.eventName);
3000
- const currentSnap = eventNode.get();
3001
- const existingEntries = currentSnap?.value?.entries;
3000
+ const existingEntries = eventNode.get();
3002
3001
  let lastSeq = existingEntries && existingEntries.length > 0 ? existingEntries[existingEntries.length - 1].seq : 0;
3003
3002
  const handle = this.observeNodeOn(cqrsGraph, meta.eventName);
3004
3003
  const unsub = handle.subscribe((msgs) => {
3005
3004
  for (const m of msgs) {
3006
3005
  if (m[0] === DATA) {
3007
- const snap = m[1];
3008
- for (const entry of snap.value.entries) {
3006
+ const entries = m[1];
3007
+ for (const entry of entries) {
3009
3008
  if (entry.seq > lastSeq) {
3010
3009
  bound(entry);
3011
3010
  lastSeq = entry.seq;
@@ -3919,6 +3918,7 @@ var Graph = class _Graph {
3919
3918
  /** @internal — exposed for {@link teardownMountedGraph}. */
3920
3919
  _mounts = /* @__PURE__ */ new Map();
3921
3920
  _autoCheckpointDisposers = /* @__PURE__ */ new Set();
3921
+ _disposers = /* @__PURE__ */ new Set();
3922
3922
  _defaultVersioningLevel;
3923
3923
  static registerFactory(pattern, factory) {
3924
3924
  if (!pattern) {
@@ -4645,7 +4645,7 @@ var Graph = class _Graph {
4645
4645
  _createObserveResult(path, target, options) {
4646
4646
  const timeline = options.timeline === true;
4647
4647
  const causal = options.causal === true;
4648
- const derived3 = options.derived === true;
4648
+ const derived2 = options.derived === true;
4649
4649
  const minimal = options.detail === "minimal";
4650
4650
  const result = {
4651
4651
  values: {},
@@ -4658,14 +4658,14 @@ var Graph = class _Graph {
4658
4658
  let lastTriggerDepIndex;
4659
4659
  let lastRunDepValues;
4660
4660
  let detachInspectorHook;
4661
- if ((causal || derived3) && target instanceof NodeImpl) {
4661
+ if ((causal || derived2) && target instanceof NodeImpl) {
4662
4662
  detachInspectorHook = target._setInspectorHook((event) => {
4663
4663
  if (event.kind === "dep_message") {
4664
4664
  lastTriggerDepIndex = event.depIndex;
4665
4665
  return;
4666
4666
  }
4667
4667
  lastRunDepValues = [...event.depValues];
4668
- if (derived3) {
4668
+ if (derived2) {
4669
4669
  result.events.push({
4670
4670
  type: "derived",
4671
4671
  path,
@@ -5054,10 +5054,33 @@ var Graph = class _Graph {
5054
5054
  // Lifecycle & persistence (§3.7–§3.8)
5055
5055
  // ——————————————————————————————————————————————————————————————
5056
5056
  /**
5057
- * Sends `[[TEARDOWN]]` to all nodes, then clears registries on this graph and every
5058
- * mounted subgraph (§3.7). The instance is left empty and may be reused with {@link Graph.add}.
5057
+ * Register a cleanup function to be called on {@link Graph.destroy}.
5058
+ *
5059
+ * Factories use this to attach teardown logic for internal nodes, keepalive
5060
+ * subscriptions, or other resources that are not registered on the graph and
5061
+ * would otherwise leak on repeated create/destroy cycles.
5062
+ *
5063
+ * Returns a removal function — call it to unregister the disposer early.
5064
+ */
5065
+ addDisposer(fn) {
5066
+ this._disposers.add(fn);
5067
+ return () => {
5068
+ this._disposers.delete(fn);
5069
+ };
5070
+ }
5071
+ /**
5072
+ * Drains disposers (registered via {@link addDisposer}), then sends `[[TEARDOWN]]` to all
5073
+ * nodes and clears registries on this graph and every mounted subgraph (§3.7).
5074
+ * The instance is left empty and may be reused with {@link Graph.add}.
5059
5075
  */
5060
5076
  destroy() {
5077
+ for (const dispose of [...this._disposers]) {
5078
+ try {
5079
+ dispose();
5080
+ } catch {
5081
+ }
5082
+ }
5083
+ this._disposers.clear();
5061
5084
  this.signal([[TEARDOWN]], { internal: true });
5062
5085
  for (const dispose of [...this._autoCheckpointDisposers]) {
5063
5086
  try {
@@ -5666,25 +5689,7 @@ var ResettableTimer = class {
5666
5689
  }
5667
5690
  };
5668
5691
 
5669
- // src/extra/reactive-base.ts
5670
- function snapshotEqualsVersion(a, b) {
5671
- if (typeof a !== "object" || a == null || typeof b !== "object" || b == null) {
5672
- return Object.is(a, b);
5673
- }
5674
- if (!("version" in a) || !("version" in b)) return Object.is(a, b);
5675
- return a.version === b.version;
5676
- }
5677
- function bumpVersion(current, nextValue, v0) {
5678
- if (v0 != null) {
5679
- return { version: current.version + 1, value: nextValue, v0 };
5680
- }
5681
- return { version: current.version + 1, value: nextValue };
5682
- }
5683
-
5684
5692
  // src/extra/reactive-log.ts
5685
- function emptySnapshot() {
5686
- return { version: 0, value: { entries: [] } };
5687
- }
5688
5693
  function keepaliveDerived(n) {
5689
5694
  return n.subscribe(() => {
5690
5695
  });
@@ -5698,22 +5703,16 @@ function reactiveLog(initial, options = {}) {
5698
5703
  if (maxSize !== void 0 && buf.length > maxSize) {
5699
5704
  buf.splice(0, buf.length - maxSize);
5700
5705
  }
5701
- let current = buf.length > 0 ? { version: 1, value: { entries: [...buf] } } : emptySnapshot();
5702
- const entries = state(current, {
5706
+ const entries = state(buf.length > 0 ? [...buf] : [], {
5703
5707
  name,
5704
5708
  describeKind: "state",
5705
- equals: snapshotEqualsVersion
5709
+ equals: (a, b) => a === b
5706
5710
  });
5707
5711
  function pushSnapshot() {
5708
- const ev = entries.v;
5709
- current = bumpVersion(
5710
- current,
5711
- { entries: [...buf] },
5712
- ev ? { id: ev.id, version: ev.version } : void 0
5713
- );
5712
+ const snapshot = [...buf];
5714
5713
  batch(() => {
5715
5714
  entries.down([[DIRTY]]);
5716
- entries.down([[DATA, current]]);
5715
+ entries.down([[DATA, snapshot]]);
5717
5716
  });
5718
5717
  }
5719
5718
  function trimBuf() {
@@ -5756,13 +5755,12 @@ function reactiveLog(initial, options = {}) {
5756
5755
  if (n < 0) {
5757
5756
  throw new RangeError("n must be >= 0");
5758
5757
  }
5759
- const snap = entries.get();
5760
- const e = snap.value.entries;
5758
+ const e = entries.get();
5761
5759
  const init = n === 0 ? [] : e.slice(Math.max(0, e.length - n));
5762
5760
  const out = derived(
5763
5761
  [entries],
5764
5762
  ([s]) => {
5765
- const list = s.value.entries;
5763
+ const list = s;
5766
5764
  return n === 0 ? [] : list.slice(Math.max(0, list.length - n));
5767
5765
  },
5768
5766
  { initial: init, describeKind: "derived" }
@@ -5777,13 +5775,12 @@ function logSlice(log, start, stop) {
5777
5775
  if (start < 0) {
5778
5776
  throw new RangeError("start must be >= 0");
5779
5777
  }
5780
- const snap = log.entries.get();
5781
- const e = snap.value.entries;
5778
+ const e = log.entries.get();
5782
5779
  const init = stop === void 0 ? e.slice(start) : e.slice(start, stop);
5783
5780
  const out = derived(
5784
5781
  [log.entries],
5785
5782
  ([s]) => {
5786
- const list = s.value.entries;
5783
+ const list = s;
5787
5784
  return stop === void 0 ? list.slice(start) : list.slice(start, stop);
5788
5785
  },
5789
5786
  { initial: init, describeKind: "derived" }
@@ -6063,8 +6060,8 @@ var CqrsGraph = class extends Graph {
6063
6060
  (snapshots) => {
6064
6061
  const allEvents = [];
6065
6062
  for (const snapshot of snapshots) {
6066
- const snap = snapshot;
6067
- allEvents.push(...snap.value.entries);
6063
+ const entries = snapshot;
6064
+ allEvents.push(...entries);
6068
6065
  }
6069
6066
  allEvents.sort((a, b) => a.timestampNs - b.timestampNs || a.seq - b.seq);
6070
6067
  return reducer(initial, allEvents);
@@ -6105,9 +6102,8 @@ var CqrsGraph = class extends Graph {
6105
6102
  (snapshots) => {
6106
6103
  const errNode = sagaRef.n.meta.error;
6107
6104
  for (let i = 0; i < snapshots.length; i++) {
6108
- const snap = snapshots[i];
6105
+ const entries = snapshots[i];
6109
6106
  const eName = eventNames[i];
6110
- const entries = snap.value.entries;
6111
6107
  const lastCount = lastCounts.get(eName) ?? 0;
6112
6108
  if (entries.length > lastCount) {
6113
6109
  const newEntries = entries.slice(lastCount);
@@ -12046,9 +12042,6 @@ var throttleTime = throttle;
12046
12042
  var catchError = rescue;
12047
12043
 
12048
12044
  // src/extra/reactive-map.ts
12049
- function emptySnapshot2() {
12050
- return { version: 0, value: { map: /* @__PURE__ */ new Map() } };
12051
- }
12052
12045
  function isExpired(e, now) {
12053
12046
  return e.expiresAt !== void 0 && now >= e.expiresAt;
12054
12047
  }
@@ -12062,12 +12055,12 @@ function buildMap(store, now) {
12062
12055
  function reactiveMap(options = {}) {
12063
12056
  const { name, maxSize, defaultTtl, ...nodeOpts } = options;
12064
12057
  const store = /* @__PURE__ */ new Map();
12065
- let current = emptySnapshot2();
12066
- const n = state(current, {
12058
+ const n = state(/* @__PURE__ */ new Map(), {
12067
12059
  ...nodeOpts,
12068
12060
  name,
12069
12061
  describeKind: "state",
12070
- equals: snapshotEqualsVersion
12062
+ equals: (a, b) => a === b
12063
+ // identity; pushSnapshot always creates a new Map
12071
12064
  });
12072
12065
  function pruneExpiredInternal() {
12073
12066
  const now = monotonicNs();
@@ -12092,11 +12085,9 @@ function reactiveMap(options = {}) {
12092
12085
  pruneExpiredInternal();
12093
12086
  const now = monotonicNs();
12094
12087
  const map3 = buildMap(store, now);
12095
- const nv = n.v;
12096
- current = bumpVersion(current, { map: map3 }, nv ? { id: nv.id, version: nv.version } : void 0);
12097
12088
  batch(() => {
12098
12089
  n.down([[DIRTY]]);
12099
- n.down([[DATA, current]]);
12090
+ n.down([[DATA, map3]]);
12100
12091
  });
12101
12092
  }
12102
12093
  function touchLru(key) {
@@ -12106,7 +12097,7 @@ function reactiveMap(options = {}) {
12106
12097
  store.set(key, e);
12107
12098
  }
12108
12099
  const bundle = {
12109
- node: n,
12100
+ entries: n,
12110
12101
  get(key) {
12111
12102
  const now = monotonicNs();
12112
12103
  const e = store.get(key);
@@ -12203,13 +12194,11 @@ function keepalive2(node2) {
12203
12194
  node2.subscribe(() => void 0);
12204
12195
  }
12205
12196
  function mapFromSnapshot(snapshot) {
12206
- if (typeof snapshot === "object" && snapshot !== null && "value" in snapshot && typeof snapshot.value === "object" && snapshot.value !== null && "map" in snapshot.value) {
12207
- return snapshot.value.map ?? /* @__PURE__ */ new Map();
12208
- }
12197
+ if (snapshot instanceof Map) return snapshot;
12209
12198
  return /* @__PURE__ */ new Map();
12210
12199
  }
12211
12200
  function asReadonlyMap(store) {
12212
- return mapFromSnapshot(store.node.get());
12201
+ return mapFromSnapshot(store.entries.get());
12213
12202
  }
12214
12203
  function applyExtraction(store, extraction) {
12215
12204
  if (!Array.isArray(extraction.upsert)) {
@@ -12237,7 +12226,7 @@ function distill(source, extractFn, opts) {
12237
12226
  if (opts.evict) {
12238
12227
  const evictionKeys = dynamicNode((get) => {
12239
12228
  const out = [];
12240
- const snapshot = mapFromSnapshot(get(store.node));
12229
+ const snapshot = mapFromSnapshot(get(store.entries));
12241
12230
  for (const [key, mem] of snapshot) {
12242
12231
  const verdict = opts.evict(key, mem);
12243
12232
  if (isNodeLike(verdict)) {
@@ -12267,7 +12256,7 @@ function distill(source, extractFn, opts) {
12267
12256
  applyExtraction(store, extraction);
12268
12257
  });
12269
12258
  }
12270
- const compact = derived([store.node, contextNode], ([snapshot, context]) => {
12259
+ const compact = derived([store.entries, contextNode], ([snapshot, context]) => {
12271
12260
  const entries = [...mapFromSnapshot(snapshot).entries()].map(([key, value]) => ({
12272
12261
  key,
12273
12262
  value,
@@ -12285,7 +12274,7 @@ function distill(source, extractFn, opts) {
12285
12274
  }
12286
12275
  return packed;
12287
12276
  });
12288
- const size = derived([store.node], ([snapshot]) => mapFromSnapshot(snapshot).size);
12277
+ const size = derived([store.entries], ([snapshot]) => mapFromSnapshot(snapshot).size);
12289
12278
  keepalive2(compact);
12290
12279
  keepalive2(size);
12291
12280
  return { store, compact, size };
@@ -12322,9 +12311,6 @@ function pubsub() {
12322
12311
  }
12323
12312
 
12324
12313
  // src/extra/reactive-index.ts
12325
- function emptySnapshot3() {
12326
- return { version: 0, value: { rows: [] } };
12327
- }
12328
12314
  function rowKey(row) {
12329
12315
  return [row.secondary, row.primary];
12330
12316
  }
@@ -12370,31 +12356,25 @@ function keepaliveDerived2(n) {
12370
12356
  function reactiveIndex(options = {}) {
12371
12357
  const { name } = options;
12372
12358
  const buf = [];
12373
- let current = emptySnapshot3();
12374
- const ordered = state(current, {
12359
+ const ordered = state([], {
12375
12360
  name,
12376
12361
  describeKind: "state",
12377
- equals: snapshotEqualsVersion
12362
+ equals: (a, b) => a === b
12378
12363
  });
12379
12364
  const byPrimary = derived(
12380
12365
  [ordered],
12381
12366
  ([s]) => {
12382
- const rows = s.value.rows;
12367
+ const rows = s;
12383
12368
  return byPrimaryMap(rows);
12384
12369
  },
12385
12370
  { initial: /* @__PURE__ */ new Map(), describeKind: "derived" }
12386
12371
  );
12387
12372
  keepaliveDerived2(byPrimary);
12388
12373
  function pushSnapshot() {
12389
- const ov = ordered.v;
12390
- current = bumpVersion(
12391
- current,
12392
- { rows: [...buf] },
12393
- ov ? { id: ov.id, version: ov.version } : void 0
12394
- );
12374
+ const snapshot = [...buf];
12395
12375
  batch(() => {
12396
12376
  ordered.down([[DIRTY]]);
12397
- ordered.down([[DATA, current]]);
12377
+ ordered.down([[DATA, snapshot]]);
12398
12378
  });
12399
12379
  }
12400
12380
  return {
@@ -12425,28 +12405,19 @@ function reactiveIndex(options = {}) {
12425
12405
  }
12426
12406
 
12427
12407
  // src/extra/reactive-list.ts
12428
- function emptySnapshot4() {
12429
- return { version: 0, value: { items: [] } };
12430
- }
12431
12408
  function reactiveList(initial, options = {}) {
12432
12409
  const { name } = options;
12433
12410
  const buf = initial ? [...initial] : [];
12434
- let current = buf.length > 0 ? { version: 1, value: { items: [...buf] } } : emptySnapshot4();
12435
- const items = state(current, {
12411
+ const items = state(buf.length > 0 ? [...buf] : [], {
12436
12412
  name,
12437
12413
  describeKind: "state",
12438
- equals: snapshotEqualsVersion
12414
+ equals: (a, b) => a === b
12439
12415
  });
12440
12416
  function pushSnapshot() {
12441
- const iv = items.v;
12442
- current = bumpVersion(
12443
- current,
12444
- { items: [...buf] },
12445
- iv ? { id: iv.id, version: iv.version } : void 0
12446
- );
12417
+ const snapshot = [...buf];
12447
12418
  batch(() => {
12448
12419
  items.down([[DIRTY]]);
12449
- items.down([[DATA, current]]);
12420
+ items.down([[DATA, snapshot]]);
12450
12421
  });
12451
12422
  }
12452
12423
  return {
@@ -13523,7 +13494,9 @@ function promptNode(adapter, deps, prompt, opts) {
13523
13494
  const messagesNode = derived(
13524
13495
  deps,
13525
13496
  (values) => {
13497
+ if (values.some((v) => v == null)) return [];
13526
13498
  const text = typeof prompt === "string" ? prompt : prompt(...values);
13499
+ if (!text) return [];
13527
13500
  const msgs = [];
13528
13501
  if (opts?.systemPrompt) msgs.push({ role: "system", content: opts.systemPrompt });
13529
13502
  msgs.push({ role: "user", content: text });
@@ -13579,7 +13552,6 @@ function promptNode(adapter, deps, prompt, opts) {
13579
13552
  }
13580
13553
  var ChatStreamGraph = class extends Graph {
13581
13554
  _log;
13582
- _keepaliveSubs = [];
13583
13555
  messages;
13584
13556
  latest;
13585
13557
  messageCount;
@@ -13594,7 +13566,7 @@ var ChatStreamGraph = class extends Graph {
13594
13566
  this.latest = derived(
13595
13567
  [this.messages],
13596
13568
  ([snapshot]) => {
13597
- const entries = snapshot.value.entries;
13569
+ const entries = snapshot;
13598
13570
  return entries.length === 0 ? void 0 : entries[entries.length - 1];
13599
13571
  },
13600
13572
  {
@@ -13606,10 +13578,10 @@ var ChatStreamGraph = class extends Graph {
13606
13578
  );
13607
13579
  this.add("latest", this.latest);
13608
13580
  this.connect("messages", "latest");
13609
- this._keepaliveSubs.push(keepalive3(this.latest));
13581
+ this.addDisposer(keepalive3(this.latest));
13610
13582
  this.messageCount = derived(
13611
13583
  [this.messages],
13612
- ([snapshot]) => snapshot.value.entries.length,
13584
+ ([snapshot]) => snapshot.length,
13613
13585
  {
13614
13586
  name: "messageCount",
13615
13587
  describeKind: "derived",
@@ -13619,7 +13591,7 @@ var ChatStreamGraph = class extends Graph {
13619
13591
  );
13620
13592
  this.add("messageCount", this.messageCount);
13621
13593
  this.connect("messages", "messageCount");
13622
- this._keepaliveSubs.push(keepalive3(this.messageCount));
13594
+ this.addDisposer(keepalive3(this.messageCount));
13623
13595
  }
13624
13596
  append(role, content, extra) {
13625
13597
  this._log.append({ role, content, ...extra });
@@ -13631,12 +13603,7 @@ var ChatStreamGraph = class extends Graph {
13631
13603
  this._log.clear();
13632
13604
  }
13633
13605
  allMessages() {
13634
- return this.messages.get().value.entries;
13635
- }
13636
- destroy() {
13637
- for (const unsub of this._keepaliveSubs) unsub();
13638
- this._keepaliveSubs.length = 0;
13639
- super.destroy();
13606
+ return this.messages.get();
13640
13607
  }
13641
13608
  };
13642
13609
  function chatStream(name, opts) {
@@ -13645,7 +13612,6 @@ function chatStream(name, opts) {
13645
13612
  var ToolRegistryGraph = class extends Graph {
13646
13613
  definitions;
13647
13614
  schemas;
13648
- _keepaliveSubs = [];
13649
13615
  constructor(name, opts = {}) {
13650
13616
  super(name, opts.graph);
13651
13617
  this.definitions = state(/* @__PURE__ */ new Map(), {
@@ -13666,7 +13632,7 @@ var ToolRegistryGraph = class extends Graph {
13666
13632
  );
13667
13633
  this.add("schemas", this.schemas);
13668
13634
  this.connect("definitions", "schemas");
13669
- this._keepaliveSubs.push(keepalive3(this.schemas));
13635
+ this.addDisposer(keepalive3(this.schemas));
13670
13636
  }
13671
13637
  register(tool) {
13672
13638
  const current = this.definitions.get();
@@ -13691,11 +13657,6 @@ var ToolRegistryGraph = class extends Graph {
13691
13657
  getDefinition(name) {
13692
13658
  return this.definitions.get().get(name);
13693
13659
  }
13694
- destroy() {
13695
- for (const unsub of this._keepaliveSubs) unsub();
13696
- this._keepaliveSubs.length = 0;
13697
- super.destroy();
13698
- }
13699
13660
  };
13700
13661
  function toolRegistry(name, opts) {
13701
13662
  return new ToolRegistryGraph(name, opts);
@@ -13840,9 +13801,7 @@ function admissionFilter3D(opts = {}) {
13840
13801
  }
13841
13802
  var DEFAULT_DECAY_RATE = Math.LN2 / (7 * 86400);
13842
13803
  function extractStoreMap(snapshot) {
13843
- if (snapshot && typeof snapshot === "object" && "value" in snapshot && typeof snapshot.value === "object" && snapshot.value !== null && "map" in snapshot.value) {
13844
- return snapshot.value.map ?? /* @__PURE__ */ new Map();
13845
- }
13804
+ if (snapshot instanceof Map) return snapshot;
13846
13805
  return /* @__PURE__ */ new Map();
13847
13806
  }
13848
13807
  function agentMemory(name, source, opts) {
@@ -13893,7 +13852,7 @@ function agentMemory(name, source, opts) {
13893
13852
  consolidateTrigger
13894
13853
  };
13895
13854
  const distillBundle = distill(filteredSource, extractFn, distillOpts);
13896
- graph.add("store", distillBundle.store.node);
13855
+ graph.add("store", distillBundle.store.entries);
13897
13856
  graph.add("compact", distillBundle.compact);
13898
13857
  graph.add("size", distillBundle.size);
13899
13858
  graph.connect("store", "compact");
@@ -13920,7 +13879,7 @@ function agentMemory(name, source, opts) {
13920
13879
  const permanentKeys = /* @__PURE__ */ new Set();
13921
13880
  const tierOf = (key) => {
13922
13881
  if (permanentKeys.has(key)) return "permanent";
13923
- const storeMap = extractStoreMap(distillBundle.store.node.get());
13882
+ const storeMap = extractStoreMap(distillBundle.store.entries.get());
13924
13883
  if (storeMap.has(key)) return "active";
13925
13884
  return "archived";
13926
13885
  };
@@ -13929,7 +13888,7 @@ function agentMemory(name, source, opts) {
13929
13888
  permanent.upsert(key, value);
13930
13889
  };
13931
13890
  const entryCreatedAtNs = /* @__PURE__ */ new Map();
13932
- const storeNode = distillBundle.store.node;
13891
+ const storeNode = distillBundle.store.entries;
13933
13892
  const contextNode = opts.context ? fromAny(opts.context) : state(null);
13934
13893
  const tierClassifier = effect([storeNode, contextNode], ([snapshot, ctx]) => {
13935
13894
  const storeMap = extractStoreMap(snapshot);
@@ -13996,7 +13955,7 @@ function agentMemory(name, source, opts) {
13996
13955
  if (vectors || kg) {
13997
13956
  const embedFn = opts.embedFn;
13998
13957
  const entityFn = opts.entityFn;
13999
- const storeNode = distillBundle.store.node;
13958
+ const storeNode = distillBundle.store.entries;
14000
13959
  const indexer = effect([storeNode], ([snapshot]) => {
14001
13960
  const storeMap = extractStoreMap(snapshot);
14002
13961
  for (const [key, mem] of storeMap) {
@@ -14041,7 +14000,7 @@ function agentMemory(name, source, opts) {
14041
14000
  });
14042
14001
  graph.add("retrievalTrace", traceState);
14043
14002
  retrievalTraceNode = traceState;
14044
- const storeNode = distillBundle.store.node;
14003
+ const storeNode = distillBundle.store.entries;
14045
14004
  let lastTrace = null;
14046
14005
  const retrievalDerived = derived(
14047
14006
  [queryInput, storeNode, contextNode],
@@ -14134,12 +14093,10 @@ function agentMemory(name, source, opts) {
14134
14093
  return result;
14135
14094
  };
14136
14095
  }
14137
- const origDestroy = graph.destroy.bind(graph);
14138
- graph.destroy = () => {
14096
+ graph.addDisposer(() => {
14139
14097
  for (const unsub of keepaliveSubs) unsub();
14140
14098
  keepaliveSubs.length = 0;
14141
- origDestroy();
14142
- };
14099
+ });
14143
14100
  return Object.assign(graph, {
14144
14101
  distillBundle,
14145
14102
  compact: distillBundle.compact,
@@ -15758,7 +15715,7 @@ function funnel(name, sources, stages, opts) {
15758
15715
  });
15759
15716
  g.add(bridgeName, br);
15760
15717
  g.connect(prevOutputPath, bridgeName);
15761
- keepalive4(br);
15718
+ g.addDisposer(keepalive4(br));
15762
15719
  prevOutputPath = `${stage.name}::output`;
15763
15720
  }
15764
15721
  return g;
@@ -15810,7 +15767,7 @@ function feedback(graph, condition, reentry, opts) {
15810
15767
  });
15811
15768
  graph.add(feedbackEffectName, feedbackEffect);
15812
15769
  graph.connect(condition, feedbackEffectName);
15813
- keepalive4(feedbackEffect);
15770
+ graph.addDisposer(keepalive4(feedbackEffect));
15814
15771
  return graph;
15815
15772
  }
15816
15773
  function budgetGate(source, constraints, opts) {
@@ -16190,7 +16147,7 @@ function contentModerationGraph(name, opts) {
16190
16147
  }
16191
16148
  });
16192
16149
  g.add("__review_accumulator", reviewAccumulator);
16193
- keepalive5(reviewAccumulator);
16150
+ g.addDisposer(keepalive5(reviewAccumulator));
16194
16151
  try {
16195
16152
  g.connect("stratify::branch/review", "__review_accumulator");
16196
16153
  } catch {
@@ -16238,8 +16195,7 @@ function contentModerationGraph(name, opts) {
16238
16195
  const fbCondition = derived(
16239
16196
  [reviewLog.entries, policy2],
16240
16197
  (vals) => {
16241
- const snap = vals[0];
16242
- const entries = snap?.value?.entries;
16198
+ const entries = vals[0];
16243
16199
  if (entries && entries.length > 0) {
16244
16200
  const latest = entries[entries.length - 1];
16245
16201
  if (latest && latest.falsePositive) {
@@ -17471,7 +17427,6 @@ function messagingMeta(kind, extra) {
17471
17427
  }
17472
17428
  var TopicGraph = class extends Graph {
17473
17429
  _log;
17474
- _keepaliveDisposers = [];
17475
17430
  events;
17476
17431
  latest;
17477
17432
  constructor(name, opts = {}) {
@@ -17482,7 +17437,7 @@ var TopicGraph = class extends Graph {
17482
17437
  this.latest = derived(
17483
17438
  [this.events],
17484
17439
  ([snapshot]) => {
17485
- const entries = snapshot.value.entries;
17440
+ const entries = snapshot;
17486
17441
  return entries.length === 0 ? void 0 : entries[entries.length - 1];
17487
17442
  },
17488
17443
  {
@@ -17494,23 +17449,16 @@ var TopicGraph = class extends Graph {
17494
17449
  );
17495
17450
  this.add("latest", this.latest);
17496
17451
  this.connect("events", "latest");
17497
- this._keepaliveDisposers.push(keepalive6(this.latest));
17498
- }
17499
- destroy() {
17500
- for (const dispose of this._keepaliveDisposers) dispose();
17501
- this._keepaliveDisposers.length = 0;
17502
- super.destroy();
17452
+ this.addDisposer(keepalive6(this.latest));
17503
17453
  }
17504
17454
  publish(value) {
17505
17455
  this._log.append(value);
17506
17456
  }
17507
17457
  retained() {
17508
- const snapshot = this.events.get();
17509
- return snapshot.value.entries;
17458
+ return this.events.get();
17510
17459
  }
17511
17460
  };
17512
17461
  var SubscriptionGraph = class extends Graph {
17513
- _keepaliveDisposers = [];
17514
17462
  source;
17515
17463
  cursor;
17516
17464
  available;
@@ -17535,7 +17483,7 @@ var SubscriptionGraph = class extends Graph {
17535
17483
  this.available = derived(
17536
17484
  [this.source, this.cursor],
17537
17485
  ([sourceSnapshot, cursor]) => {
17538
- const entries = sourceSnapshot.value.entries;
17486
+ const entries = sourceSnapshot;
17539
17487
  const start = Math.max(0, Math.trunc(cursor ?? 0));
17540
17488
  return entries.slice(start);
17541
17489
  },
@@ -17550,13 +17498,8 @@ var SubscriptionGraph = class extends Graph {
17550
17498
  this.connect("topic::events", "source");
17551
17499
  this.connect("source", "available");
17552
17500
  this.connect("cursor", "available");
17553
- this._keepaliveDisposers.push(keepalive6(this.source));
17554
- this._keepaliveDisposers.push(keepalive6(this.available));
17555
- }
17556
- destroy() {
17557
- for (const dispose of this._keepaliveDisposers) dispose();
17558
- this._keepaliveDisposers.length = 0;
17559
- super.destroy();
17501
+ this.addDisposer(keepalive6(this.source));
17502
+ this.addDisposer(keepalive6(this.available));
17560
17503
  }
17561
17504
  ack(count) {
17562
17505
  const available = this.available.get();
@@ -17578,7 +17521,6 @@ var SubscriptionGraph = class extends Graph {
17578
17521
  var JobQueueGraph = class extends Graph {
17579
17522
  _pending;
17580
17523
  _jobs;
17581
- _keepaliveDisposers = [];
17582
17524
  _seq = 0;
17583
17525
  pending;
17584
17526
  jobs;
@@ -17588,27 +17530,18 @@ var JobQueueGraph = class extends Graph {
17588
17530
  this._pending = reactiveList([], { name: "pending" });
17589
17531
  this._jobs = reactiveMap({ name: "jobs" });
17590
17532
  this.pending = this._pending.items;
17591
- this.jobs = this._jobs.node;
17533
+ this.jobs = this._jobs.entries;
17592
17534
  this.add("pending", this.pending);
17593
17535
  this.add("jobs", this.jobs);
17594
- this.depth = derived(
17595
- [this.pending],
17596
- ([snapshot]) => snapshot.value.items.length,
17597
- {
17598
- name: "depth",
17599
- describeKind: "derived",
17600
- meta: messagingMeta("queue_depth"),
17601
- initial: 0
17602
- }
17603
- );
17536
+ this.depth = derived([this.pending], ([snapshot]) => snapshot.length, {
17537
+ name: "depth",
17538
+ describeKind: "derived",
17539
+ meta: messagingMeta("queue_depth"),
17540
+ initial: 0
17541
+ });
17604
17542
  this.add("depth", this.depth);
17605
17543
  this.connect("pending", "depth");
17606
- this._keepaliveDisposers.push(keepalive6(this.depth));
17607
- }
17608
- destroy() {
17609
- for (const dispose of this._keepaliveDisposers) dispose();
17610
- this._keepaliveDisposers.length = 0;
17611
- super.destroy();
17544
+ this.addDisposer(keepalive6(this.depth));
17612
17545
  }
17613
17546
  enqueue(payload, opts = {}) {
17614
17547
  const id = opts.id ?? `${this.name}-${++this._seq}`;
@@ -17631,8 +17564,7 @@ var JobQueueGraph = class extends Graph {
17631
17564
  if (max === 0) return [];
17632
17565
  const out = [];
17633
17566
  while (out.length < max) {
17634
- const snapshot = this.pending.get();
17635
- const ids = snapshot.value.items;
17567
+ const ids = this.pending.get();
17636
17568
  if (ids.length === 0) break;
17637
17569
  const id = this._pending.pop(0);
17638
17570
  const job = this._jobs.get(id);
@@ -17668,7 +17600,6 @@ var JobQueueGraph = class extends Graph {
17668
17600
  var JobFlowGraph = class extends Graph {
17669
17601
  _stageNames;
17670
17602
  _queues = /* @__PURE__ */ new Map();
17671
- _keepaliveDisposers = [];
17672
17603
  _completed;
17673
17604
  completed;
17674
17605
  completedCount;
@@ -17693,7 +17624,7 @@ var JobFlowGraph = class extends Graph {
17693
17624
  this.add("completed", this.completed);
17694
17625
  this.completedCount = derived(
17695
17626
  [this.completed],
17696
- ([snapshot]) => snapshot.value.entries.length,
17627
+ ([snapshot]) => snapshot.length,
17697
17628
  {
17698
17629
  name: "completedCount",
17699
17630
  describeKind: "derived",
@@ -17703,7 +17634,7 @@ var JobFlowGraph = class extends Graph {
17703
17634
  );
17704
17635
  this.add("completedCount", this.completedCount);
17705
17636
  this.connect("completed", "completedCount");
17706
- this._keepaliveDisposers.push(keepalive6(this.completedCount));
17637
+ this.addDisposer(keepalive6(this.completedCount));
17707
17638
  const maxPerPump = Math.max(
17708
17639
  1,
17709
17640
  requireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, "job flow maxPerPump")
@@ -17743,14 +17674,9 @@ var JobFlowGraph = class extends Graph {
17743
17674
  );
17744
17675
  this.add(`pump_${stage}`, pump);
17745
17676
  this.connect(`${stage}::pending`, `pump_${stage}`);
17746
- this._keepaliveDisposers.push(keepalive6(pump));
17677
+ this.addDisposer(keepalive6(pump));
17747
17678
  }
17748
17679
  }
17749
- destroy() {
17750
- for (const dispose of this._keepaliveDisposers) dispose();
17751
- this._keepaliveDisposers.length = 0;
17752
- super.destroy();
17753
- }
17754
17680
  stages() {
17755
17681
  return this._stageNames;
17756
17682
  }
@@ -17763,14 +17689,12 @@ var JobFlowGraph = class extends Graph {
17763
17689
  return this.queue(this._stageNames[0]).enqueue(payload, opts);
17764
17690
  }
17765
17691
  retainedCompleted() {
17766
- const snapshot = this.completed.get();
17767
- return snapshot.value.entries;
17692
+ return this.completed.get();
17768
17693
  }
17769
17694
  };
17770
17695
  var TopicBridgeGraph = class extends Graph {
17771
17696
  _sourceSub;
17772
17697
  _target;
17773
- _keepaliveDisposers = [];
17774
17698
  bridgedCount;
17775
17699
  constructor(name, sourceTopic, targetTopic, opts = {}) {
17776
17700
  super(name, opts.graph);
@@ -17815,12 +17739,7 @@ var TopicBridgeGraph = class extends Graph {
17815
17739
  );
17816
17740
  this.add("pump", pump);
17817
17741
  this.connect("subscription::available", "pump");
17818
- this._keepaliveDisposers.push(keepalive6(pump));
17819
- }
17820
- destroy() {
17821
- for (const dispose of this._keepaliveDisposers) dispose();
17822
- this._keepaliveDisposers.length = 0;
17823
- super.destroy();
17742
+ this.addDisposer(keepalive6(pump));
17824
17743
  }
17825
17744
  };
17826
17745
  function topic(name, opts) {
@@ -18112,7 +18031,7 @@ function gate(graph, name, source, opts) {
18112
18031
  isOpenNode.down([[DATA, false]]);
18113
18032
  }
18114
18033
  };
18115
- countNode.subscribe(() => void 0);
18034
+ graph.addDisposer(countNode.subscribe(() => void 0));
18116
18035
  registerStep(graph, name, output, src.path ? [src.path] : []);
18117
18036
  const internal = new Graph(`${name}_state`);
18118
18037
  internal.add("pending", pendingNode);
@@ -18359,9 +18278,9 @@ var DEFAULT_QUEUE_CONFIGS = {
18359
18278
  function strategyModel() {
18360
18279
  const _map = reactiveMap({ name: "strategy-entries" });
18361
18280
  const snapshot = derived(
18362
- [_map.node],
18281
+ [_map.entries],
18363
18282
  ([mapSnap]) => {
18364
- const raw = mapSnap.value.map;
18283
+ const raw = mapSnap;
18365
18284
  return new Map(raw);
18366
18285
  },
18367
18286
  {
@@ -18396,7 +18315,10 @@ function strategyModel() {
18396
18315
  }
18397
18316
  const _unsub = snapshot.subscribe(() => {
18398
18317
  });
18399
- return { node: snapshot, record, lookup };
18318
+ function dispose() {
18319
+ _unsub();
18320
+ }
18321
+ return { node: snapshot, record, lookup, dispose };
18400
18322
  }
18401
18323
  function priorityScore(item, strategy, lastInteractionNs, urgency, signals) {
18402
18324
  const severityWeights = { ...DEFAULT_SEVERITY_WEIGHTS, ...signals?.severityWeights };
@@ -18428,6 +18350,9 @@ function priorityScore(item, strategy, lastInteractionNs, urgency, signals) {
18428
18350
  }
18429
18351
 
18430
18352
  // src/patterns/harness/loop.ts
18353
+ function baseSummary(summary) {
18354
+ return summary.replace(/^\[RETRY \d+\/\d+\]\s*/, "");
18355
+ }
18431
18356
  var DEFAULT_TRIAGE_PROMPT = `You are a triage classifier for a reactive collaboration harness.
18432
18357
 
18433
18358
  Given an intake item, classify it and output JSON:
@@ -18489,13 +18414,19 @@ var HarnessGraph = class extends Graph {
18489
18414
  strategy;
18490
18415
  /** Verify results topic — subscribe to see verification outcomes. */
18491
18416
  verifyResults;
18492
- constructor(name, intake, queues, gates, strategy, verifyResults) {
18417
+ /** Per-item fast-retry counts (keyed by base summary). */
18418
+ retryTracker;
18419
+ /** Per-item reingestion counts (keyed by base summary). */
18420
+ reingestionTracker;
18421
+ constructor(name, intake, queues, gates, strategy, verifyResults, retryTracker, reingestionTracker) {
18493
18422
  super(name);
18494
18423
  this.intake = intake;
18495
18424
  this.queues = queues;
18496
18425
  this.gates = gates;
18497
18426
  this.strategy = strategy;
18498
18427
  this.verifyResults = verifyResults;
18428
+ this.retryTracker = retryTracker;
18429
+ this.reingestionTracker = reingestionTracker;
18499
18430
  }
18500
18431
  };
18501
18432
  function harnessLoop(name, opts) {
@@ -18512,14 +18443,20 @@ function harnessLoop(name, opts) {
18512
18443
  }
18513
18444
  const intake = new TopicGraph("intake", { retainedLimit });
18514
18445
  const strategy = strategyModel();
18446
+ const triageInput = withLatestFrom(
18447
+ intake.latest,
18448
+ strategy.node
18449
+ );
18515
18450
  const triageNode = promptNode(
18516
18451
  adapter,
18517
- [intake.latest, strategy.node],
18518
- opts.triagePrompt ?? ((item, strat) => {
18519
- return DEFAULT_TRIAGE_PROMPT.replace("{{strategy}}", JSON.stringify(strat)).replace(
18520
- "{{item}}",
18521
- JSON.stringify(item)
18522
- );
18452
+ [triageInput],
18453
+ opts.triagePrompt ?? ((pair) => {
18454
+ const [item, strat] = pair;
18455
+ if (!item) return "";
18456
+ return DEFAULT_TRIAGE_PROMPT.replace(
18457
+ "{{strategy}}",
18458
+ JSON.stringify(Array.from(strat.entries()))
18459
+ ).replace("{{item}}", JSON.stringify(item));
18523
18460
  }),
18524
18461
  {
18525
18462
  name: "triage",
@@ -18531,12 +18468,14 @@ function harnessLoop(name, opts) {
18531
18468
  for (const route of QUEUE_NAMES) {
18532
18469
  queueTopics.set(route, new TopicGraph(`queue/${route}`, { retainedLimit }));
18533
18470
  }
18534
- const _router = effect([triageNode], ([triaged]) => {
18471
+ const router = effect([triageNode], ([triaged]) => {
18535
18472
  const item = triaged;
18536
18473
  if (!item || !item.route) return;
18537
18474
  const topic2 = queueTopics.get(item.route);
18538
18475
  if (topic2) topic2.publish(item);
18539
18476
  });
18477
+ const routerUnsub = router.subscribe(() => {
18478
+ });
18540
18479
  const gateGraph = new Graph("gates");
18541
18480
  const gateControllers = /* @__PURE__ */ new Map();
18542
18481
  for (const route of QUEUE_NAMES) {
@@ -18566,9 +18505,7 @@ function harnessLoop(name, opts) {
18566
18505
  const executeNode = promptNode(
18567
18506
  adapter,
18568
18507
  [executeInput],
18569
- opts.executePrompt ?? ((item) => {
18570
- return DEFAULT_EXECUTE_PROMPT.replace("{{item}}", JSON.stringify(item));
18571
- }),
18508
+ opts.executePrompt ?? ((item) => DEFAULT_EXECUTE_PROMPT.replace("{{item}}", JSON.stringify(item))),
18572
18509
  {
18573
18510
  name: "execute",
18574
18511
  format: "json",
@@ -18579,67 +18516,91 @@ function harnessLoop(name, opts) {
18579
18516
  const verifyNode = promptNode(
18580
18517
  adapter,
18581
18518
  [executeNode, executeInput],
18582
- opts.verifyPrompt ?? ((execution, item) => {
18583
- return DEFAULT_VERIFY_PROMPT.replace("{{execution}}", JSON.stringify(execution)).replace(
18584
- "{{item}}",
18585
- JSON.stringify(item)
18586
- );
18587
- }),
18519
+ opts.verifyPrompt ?? ((execution, item) => DEFAULT_VERIFY_PROMPT.replace("{{execution}}", JSON.stringify(execution)).replace(
18520
+ "{{item}}",
18521
+ JSON.stringify(item)
18522
+ )),
18588
18523
  {
18589
18524
  name: "verify",
18590
18525
  format: "json",
18591
18526
  retries: 1
18592
18527
  }
18593
18528
  );
18529
+ const verifyWithExec = withLatestFrom(verifyNode, executeNode);
18530
+ const verifyContext = withLatestFrom(
18531
+ verifyWithExec,
18532
+ executeInput
18533
+ );
18594
18534
  const maxReingestions = opts.maxReingestions ?? 1;
18595
- let reingestionCount = 0;
18596
- const _fastRetry = effect([verifyNode], ([result]) => {
18597
- const vr = result;
18598
- if (!vr) return;
18535
+ const retryTracker = /* @__PURE__ */ new Map();
18536
+ const reingestionTracker = /* @__PURE__ */ new Map();
18537
+ const fastRetry = effect([verifyContext], ([ctx]) => {
18538
+ const [[vo, execRaw], item] = ctx;
18539
+ if (!vo || !item) return;
18540
+ const exec = {
18541
+ item,
18542
+ outcome: execRaw?.outcome ?? "failure",
18543
+ detail: execRaw?.detail ?? "unknown"
18544
+ };
18545
+ const vr = {
18546
+ item,
18547
+ execution: exec,
18548
+ verified: vo.verified,
18549
+ findings: vo.findings ?? [],
18550
+ errorClass: vo.errorClass
18551
+ };
18599
18552
  if (vr.verified) {
18600
- strategy.record(vr.item.rootCause, vr.item.intervention, true);
18553
+ strategy.record(item.rootCause, item.intervention, true);
18601
18554
  verifyResults.publish(vr);
18602
18555
  return;
18603
18556
  }
18604
18557
  const errClass = vr.errorClass ?? errorClassifier({
18605
- item: vr.item,
18558
+ item,
18606
18559
  outcome: "failure",
18607
- detail: vr.findings.join("; "),
18608
- retryCount: 0
18560
+ detail: vr.findings.join("; ")
18609
18561
  });
18610
- const exec = vr.execution;
18611
- const retryCount = exec?.retryCount ?? 0;
18562
+ const key = baseSummary(item.summary);
18563
+ const retryCount = retryTracker.get(key) ?? 0;
18612
18564
  if (errClass === "self-correctable" && retryCount < maxRetries) {
18565
+ retryTracker.set(key, retryCount + 1);
18613
18566
  const retryItem = {
18614
- ...vr.item,
18615
- summary: `[RETRY ${retryCount + 1}/${maxRetries}] ${vr.item.summary} \u2014 Previous attempt failed: ${vr.findings.join("; ")}`
18567
+ ...item,
18568
+ summary: `[RETRY ${retryCount + 1}/${maxRetries}] ${baseSummary(item.summary)} \u2014 Previous attempt failed: ${vr.findings.join("; ")}`
18616
18569
  };
18617
18570
  retryTopic.publish(retryItem);
18618
18571
  } else {
18619
- strategy.record(vr.item.rootCause, vr.item.intervention, false);
18572
+ strategy.record(item.rootCause, item.intervention, false);
18620
18573
  verifyResults.publish(vr);
18621
- if (reingestionCount < maxReingestions) {
18622
- reingestionCount++;
18574
+ const itemReingestions = reingestionTracker.get(key) ?? 0;
18575
+ if (itemReingestions < maxReingestions) {
18576
+ reingestionTracker.set(key, itemReingestions + 1);
18623
18577
  intake.publish({
18624
18578
  source: "eval",
18625
- summary: `Verification failed for: ${vr.item.summary}`,
18579
+ summary: `Verification failed for: ${baseSummary(item.summary)}`,
18626
18580
  evidence: vr.findings.join("\n"),
18627
- affectsAreas: vr.item.affectsAreas,
18628
- affectsEvalTasks: vr.item.affectsEvalTasks,
18581
+ affectsAreas: item.affectsAreas,
18582
+ affectsEvalTasks: item.affectsEvalTasks,
18629
18583
  severity: "high",
18630
- relatedTo: [vr.item.summary]
18584
+ relatedTo: [baseSummary(item.summary)]
18631
18585
  });
18632
18586
  }
18633
18587
  }
18634
18588
  });
18589
+ const fastRetryUnsub = fastRetry.subscribe(() => {
18590
+ });
18635
18591
  const harness = new HarnessGraph(
18636
18592
  name,
18637
18593
  intake,
18638
18594
  queueTopics,
18639
18595
  gateControllers,
18640
18596
  strategy,
18641
- verifyResults
18597
+ verifyResults,
18598
+ retryTracker,
18599
+ reingestionTracker
18642
18600
  );
18601
+ harness.addDisposer(routerUnsub);
18602
+ harness.addDisposer(fastRetryUnsub);
18603
+ harness.addDisposer(strategy.dispose);
18643
18604
  harness.mount("intake", intake);
18644
18605
  for (const [route, topic2] of queueTopics) {
18645
18606
  harness.mount(`queue/${route}`, topic2);