@graphrefly/graphrefly 0.15.0 → 0.17.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 (75) hide show
  1. package/dist/{chunk-4APC3AFN.js → chunk-2PORF4RP.js} +22 -49
  2. package/dist/chunk-2PORF4RP.js.map +1 -0
  3. package/dist/{chunk-QVYZD65U.js → chunk-646OG3PO.js} +10 -38
  4. package/dist/chunk-646OG3PO.js.map +1 -0
  5. package/dist/{chunk-H243FWYP.js → chunk-BV3TPSBK.js} +1 -2
  6. package/dist/chunk-BV3TPSBK.js.map +1 -0
  7. package/dist/chunk-EBNKJULL.js +231 -0
  8. package/dist/chunk-EBNKJULL.js.map +1 -0
  9. package/dist/{chunk-XQ4UMAU7.js → chunk-F2ULI3Q3.js} +2 -2
  10. package/dist/{chunk-CRACCCJY.js → chunk-IHJHBADD.js} +29 -5
  11. package/dist/chunk-IHJHBADD.js.map +1 -0
  12. package/dist/{chunk-YW6LFCFS.js → chunk-R6OHUUYB.js} +3 -3
  13. package/dist/{chunk-2ZICUAUJ.js → chunk-XJ6EMQ22.js} +10 -12
  14. package/dist/chunk-XJ6EMQ22.js.map +1 -0
  15. package/dist/{chunk-GKRKDYNT.js → chunk-YXROQFXZ.js} +3 -3
  16. package/dist/compat/nestjs/index.cjs +38 -42
  17. package/dist/compat/nestjs/index.cjs.map +1 -1
  18. package/dist/compat/nestjs/index.d.cts +4 -4
  19. package/dist/compat/nestjs/index.d.ts +4 -4
  20. package/dist/compat/nestjs/index.js +7 -7
  21. package/dist/core/index.cjs +0 -1
  22. package/dist/core/index.cjs.map +1 -1
  23. package/dist/core/index.d.cts +2 -2
  24. package/dist/core/index.d.ts +2 -2
  25. package/dist/core/index.js +3 -3
  26. package/dist/extra/index.cjs +27 -79
  27. package/dist/extra/index.cjs.map +1 -1
  28. package/dist/extra/index.d.cts +4 -4
  29. package/dist/extra/index.d.ts +4 -4
  30. package/dist/extra/index.js +3 -3
  31. package/dist/graph/index.cjs +151 -5
  32. package/dist/graph/index.cjs.map +1 -1
  33. package/dist/graph/index.d.cts +3 -3
  34. package/dist/graph/index.d.ts +3 -3
  35. package/dist/graph/index.js +10 -6
  36. package/dist/{graph-BXIK5Dq5.d.ts → graph-Dc-P9BVm.d.ts} +15 -3
  37. package/dist/{graph-BhADtuFU.d.cts → graph-fCsaaVIa.d.cts} +15 -3
  38. package/dist/{index-BkToATim.d.ts → index-4OIX-q0C.d.cts} +88 -3
  39. package/dist/{index-DSp5R3Xq.d.ts → index-BBVBYPxr.d.cts} +4 -4
  40. package/dist/{index-BNB0KjKe.d.ts → index-BmoUvOGN.d.ts} +1 -1
  41. package/dist/{index-DBhLjWSV.d.cts → index-ClaKZFPl.d.cts} +100 -31
  42. package/dist/{index-Wa8jXne6.d.cts → index-D7y9Q8W4.d.ts} +88 -3
  43. package/dist/{index-Dqemj9q0.d.cts → index-DWq0P9T6.d.ts} +4 -4
  44. package/dist/{index-fYObbpUw.d.ts → index-DhXznWyH.d.ts} +2 -2
  45. package/dist/{index-DANO9Gg7.d.cts → index-DlGMf_Qe.d.cts} +2 -2
  46. package/dist/{index-CKyYg4IP.d.ts → index-N704txAA.d.ts} +100 -31
  47. package/dist/{index-DKIyo4Bq.d.cts → index-YlOH1Gw6.d.cts} +1 -1
  48. package/dist/index.cjs +302 -231
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +71 -41
  51. package/dist/index.d.ts +71 -41
  52. package/dist/index.js +131 -151
  53. package/dist/index.js.map +1 -1
  54. package/dist/{meta-CrZUQAJ6.d.cts → meta-BV4pj9ML.d.cts} +6 -0
  55. package/dist/{meta-CrZUQAJ6.d.ts → meta-BV4pj9ML.d.ts} +6 -0
  56. package/dist/observable-Cz-AWhwR.d.cts +42 -0
  57. package/dist/observable-DCqlwGyl.d.ts +42 -0
  58. package/dist/patterns/reactive-layout/index.cjs +26 -3
  59. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  60. package/dist/patterns/reactive-layout/index.d.cts +3 -3
  61. package/dist/patterns/reactive-layout/index.d.ts +3 -3
  62. package/dist/patterns/reactive-layout/index.js +4 -4
  63. package/package.json +1 -1
  64. package/dist/chunk-2ZICUAUJ.js.map +0 -1
  65. package/dist/chunk-4APC3AFN.js.map +0 -1
  66. package/dist/chunk-CRACCCJY.js.map +0 -1
  67. package/dist/chunk-H243FWYP.js.map +0 -1
  68. package/dist/chunk-QVYZD65U.js.map +0 -1
  69. package/dist/chunk-ZHTHUX5D.js +0 -107
  70. package/dist/chunk-ZHTHUX5D.js.map +0 -1
  71. package/dist/reactive-log-ChbpUrY2.d.cts +0 -137
  72. package/dist/reactive-log-DV--7BWd.d.ts +0 -137
  73. /package/dist/{chunk-XQ4UMAU7.js.map → chunk-F2ULI3Q3.js.map} +0 -0
  74. /package/dist/{chunk-YW6LFCFS.js.map → chunk-R6OHUUYB.js.map} +0 -0
  75. /package/dist/{chunk-GKRKDYNT.js.map → chunk-YXROQFXZ.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -184,6 +184,7 @@ __export(index_exports, {
184
184
  fromWebhook: () => fromWebhook,
185
185
  globToRegExp: () => globToRegExp,
186
186
  graph: () => graph_exports,
187
+ graphProfile: () => graphProfile,
187
188
  graphspec: () => graphspec_exports,
188
189
  harness: () => harness_exports,
189
190
  interval: () => interval,
@@ -262,6 +263,7 @@ __export(index_exports, {
262
263
  shareReplay: () => shareReplay,
263
264
  signalToName: () => signalToName,
264
265
  signals: () => signals_exports,
266
+ sizeof: () => sizeof,
265
267
  skip: () => skip,
266
268
  solid: () => solid_exports,
267
269
  startWith: () => startWith,
@@ -1184,7 +1186,6 @@ var NodeImpl = class {
1184
1186
  this._downInternal(wasDirty ? [[RESOLVED]] : [[DIRTY], [RESOLVED]]);
1185
1187
  return;
1186
1188
  }
1187
- this._cached = value;
1188
1189
  this._downInternal(wasDirty ? [[DATA, value]] : [[DIRTY], [DATA, value]]);
1189
1190
  }
1190
1191
  _runFn() {
@@ -2997,15 +2998,14 @@ var GraphReflyEventExplorer = class {
2997
2998
  if (!cqrsGraph) return;
2998
2999
  cqrsGraph.event(meta.eventName);
2999
3000
  const eventNode = cqrsGraph.resolve(meta.eventName);
3000
- const currentSnap = eventNode.get();
3001
- const existingEntries = currentSnap?.value?.entries;
3001
+ const existingEntries = eventNode.get();
3002
3002
  let lastSeq = existingEntries && existingEntries.length > 0 ? existingEntries[existingEntries.length - 1].seq : 0;
3003
3003
  const handle = this.observeNodeOn(cqrsGraph, meta.eventName);
3004
3004
  const unsub = handle.subscribe((msgs) => {
3005
3005
  for (const m of msgs) {
3006
3006
  if (m[0] === DATA) {
3007
- const snap = m[1];
3008
- for (const entry of snap.value.entries) {
3007
+ const entries = m[1];
3008
+ for (const entry of entries) {
3009
3009
  if (entry.seq > lastSeq) {
3010
3010
  bound(entry);
3011
3011
  lastSeq = entry.seq;
@@ -3919,6 +3919,7 @@ var Graph = class _Graph {
3919
3919
  /** @internal — exposed for {@link teardownMountedGraph}. */
3920
3920
  _mounts = /* @__PURE__ */ new Map();
3921
3921
  _autoCheckpointDisposers = /* @__PURE__ */ new Set();
3922
+ _disposers = /* @__PURE__ */ new Set();
3922
3923
  _defaultVersioningLevel;
3923
3924
  static registerFactory(pattern, factory) {
3924
3925
  if (!pattern) {
@@ -5054,10 +5055,33 @@ var Graph = class _Graph {
5054
5055
  // Lifecycle & persistence (§3.7–§3.8)
5055
5056
  // ——————————————————————————————————————————————————————————————
5056
5057
  /**
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}.
5058
+ * Register a cleanup function to be called on {@link Graph.destroy}.
5059
+ *
5060
+ * Factories use this to attach teardown logic for internal nodes, keepalive
5061
+ * subscriptions, or other resources that are not registered on the graph and
5062
+ * would otherwise leak on repeated create/destroy cycles.
5063
+ *
5064
+ * Returns a removal function — call it to unregister the disposer early.
5065
+ */
5066
+ addDisposer(fn) {
5067
+ this._disposers.add(fn);
5068
+ return () => {
5069
+ this._disposers.delete(fn);
5070
+ };
5071
+ }
5072
+ /**
5073
+ * Drains disposers (registered via {@link addDisposer}), then sends `[[TEARDOWN]]` to all
5074
+ * nodes and clears registries on this graph and every mounted subgraph (§3.7).
5075
+ * The instance is left empty and may be reused with {@link Graph.add}.
5059
5076
  */
5060
5077
  destroy() {
5078
+ for (const dispose of [...this._disposers]) {
5079
+ try {
5080
+ dispose();
5081
+ } catch {
5082
+ }
5083
+ }
5084
+ this._disposers.clear();
5061
5085
  this.signal([[TEARDOWN]], { internal: true });
5062
5086
  for (const dispose of [...this._autoCheckpointDisposers]) {
5063
5087
  try {
@@ -5666,25 +5690,7 @@ var ResettableTimer = class {
5666
5690
  }
5667
5691
  };
5668
5692
 
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
5693
  // src/extra/reactive-log.ts
5685
- function emptySnapshot() {
5686
- return { version: 0, value: { entries: [] } };
5687
- }
5688
5694
  function keepaliveDerived(n) {
5689
5695
  return n.subscribe(() => {
5690
5696
  });
@@ -5698,22 +5704,16 @@ function reactiveLog(initial, options = {}) {
5698
5704
  if (maxSize !== void 0 && buf.length > maxSize) {
5699
5705
  buf.splice(0, buf.length - maxSize);
5700
5706
  }
5701
- let current = buf.length > 0 ? { version: 1, value: { entries: [...buf] } } : emptySnapshot();
5702
- const entries = state(current, {
5707
+ const entries = state(buf.length > 0 ? [...buf] : [], {
5703
5708
  name,
5704
5709
  describeKind: "state",
5705
- equals: snapshotEqualsVersion
5710
+ equals: (a, b) => a === b
5706
5711
  });
5707
5712
  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
- );
5713
+ const snapshot = [...buf];
5714
5714
  batch(() => {
5715
5715
  entries.down([[DIRTY]]);
5716
- entries.down([[DATA, current]]);
5716
+ entries.down([[DATA, snapshot]]);
5717
5717
  });
5718
5718
  }
5719
5719
  function trimBuf() {
@@ -5756,13 +5756,12 @@ function reactiveLog(initial, options = {}) {
5756
5756
  if (n < 0) {
5757
5757
  throw new RangeError("n must be >= 0");
5758
5758
  }
5759
- const snap = entries.get();
5760
- const e = snap.value.entries;
5759
+ const e = entries.get();
5761
5760
  const init = n === 0 ? [] : e.slice(Math.max(0, e.length - n));
5762
5761
  const out = derived(
5763
5762
  [entries],
5764
5763
  ([s]) => {
5765
- const list = s.value.entries;
5764
+ const list = s;
5766
5765
  return n === 0 ? [] : list.slice(Math.max(0, list.length - n));
5767
5766
  },
5768
5767
  { initial: init, describeKind: "derived" }
@@ -5777,13 +5776,12 @@ function logSlice(log, start, stop) {
5777
5776
  if (start < 0) {
5778
5777
  throw new RangeError("start must be >= 0");
5779
5778
  }
5780
- const snap = log.entries.get();
5781
- const e = snap.value.entries;
5779
+ const e = log.entries.get();
5782
5780
  const init = stop === void 0 ? e.slice(start) : e.slice(start, stop);
5783
5781
  const out = derived(
5784
5782
  [log.entries],
5785
5783
  ([s]) => {
5786
- const list = s.value.entries;
5784
+ const list = s;
5787
5785
  return stop === void 0 ? list.slice(start) : list.slice(start, stop);
5788
5786
  },
5789
5787
  { initial: init, describeKind: "derived" }
@@ -5800,9 +5798,11 @@ __export(graph_exports, {
5800
5798
  JsonCodec: () => JsonCodec,
5801
5799
  createDagCborCodec: () => createDagCborCodec,
5802
5800
  createDagCborZstdCodec: () => createDagCborZstdCodec,
5801
+ graphProfile: () => graphProfile,
5803
5802
  negotiateCodec: () => negotiateCodec,
5804
5803
  reachable: () => reachable,
5805
- replayWAL: () => replayWAL
5804
+ replayWAL: () => replayWAL,
5805
+ sizeof: () => sizeof
5806
5806
  });
5807
5807
 
5808
5808
  // src/graph/codec.ts
@@ -5881,6 +5881,125 @@ function replayWAL(entries) {
5881
5881
  return result;
5882
5882
  }
5883
5883
 
5884
+ // src/graph/sizeof.ts
5885
+ var OVERHEAD = {
5886
+ object: 56,
5887
+ array: 64,
5888
+ string: 40,
5889
+ // header; content added separately
5890
+ number: 8,
5891
+ boolean: 4,
5892
+ null: 0,
5893
+ undefined: 0,
5894
+ symbol: 40,
5895
+ bigint: 16,
5896
+ function: 120,
5897
+ map: 72,
5898
+ set: 72,
5899
+ mapEntry: 40,
5900
+ setEntry: 24
5901
+ };
5902
+ function sizeof(value) {
5903
+ const seen = /* @__PURE__ */ new WeakSet();
5904
+ return _sizeof(value, seen);
5905
+ }
5906
+ function _sizeof(value, seen) {
5907
+ if (value == null) return 0;
5908
+ const t = typeof value;
5909
+ switch (t) {
5910
+ case "number":
5911
+ return OVERHEAD.number;
5912
+ case "boolean":
5913
+ return OVERHEAD.boolean;
5914
+ case "string":
5915
+ return OVERHEAD.string + value.length * 2;
5916
+ // UTF-16
5917
+ case "bigint":
5918
+ return OVERHEAD.bigint;
5919
+ case "symbol":
5920
+ return OVERHEAD.symbol;
5921
+ case "function":
5922
+ if (seen.has(value)) return 0;
5923
+ seen.add(value);
5924
+ return OVERHEAD.function;
5925
+ case "undefined":
5926
+ return 0;
5927
+ }
5928
+ const obj = value;
5929
+ if (seen.has(obj)) return 0;
5930
+ seen.add(obj);
5931
+ if (obj instanceof Map) {
5932
+ let size2 = OVERHEAD.map;
5933
+ for (const [k, v] of obj) {
5934
+ size2 += OVERHEAD.mapEntry + _sizeof(k, seen) + _sizeof(v, seen);
5935
+ }
5936
+ return size2;
5937
+ }
5938
+ if (obj instanceof Set) {
5939
+ let size2 = OVERHEAD.set;
5940
+ for (const v of obj) {
5941
+ size2 += OVERHEAD.setEntry + _sizeof(v, seen);
5942
+ }
5943
+ return size2;
5944
+ }
5945
+ if (Array.isArray(obj)) {
5946
+ let size2 = OVERHEAD.array + obj.length * 8;
5947
+ for (const item of obj) {
5948
+ size2 += _sizeof(item, seen);
5949
+ }
5950
+ return size2;
5951
+ }
5952
+ if (obj instanceof ArrayBuffer) return obj.byteLength;
5953
+ if (ArrayBuffer.isView(obj)) return obj.byteLength;
5954
+ let size = OVERHEAD.object;
5955
+ const keys = Object.keys(obj);
5956
+ for (const key of keys) {
5957
+ size += OVERHEAD.string + key.length * 2;
5958
+ size += _sizeof(obj[key], seen);
5959
+ }
5960
+ return size;
5961
+ }
5962
+
5963
+ // src/graph/profile.ts
5964
+ function graphProfile(graph, opts) {
5965
+ const topN = opts?.topN ?? 10;
5966
+ const desc = graph.describe({ detail: "standard" });
5967
+ const targets = [];
5968
+ if (typeof graph._collectObserveTargets === "function") {
5969
+ graph._collectObserveTargets("", targets);
5970
+ }
5971
+ const pathToNode = /* @__PURE__ */ new Map();
5972
+ for (const [p, n] of targets) {
5973
+ pathToNode.set(p, n);
5974
+ }
5975
+ const profiles = [];
5976
+ for (const [path, nodeDesc] of Object.entries(desc.nodes)) {
5977
+ const nd = pathToNode.get(path);
5978
+ const impl = nd instanceof NodeImpl ? nd : null;
5979
+ const valueSizeBytes = impl ? sizeof(impl.get()) : 0;
5980
+ const subscriberCount = impl ? impl._sinkCount : 0;
5981
+ const depCount = nodeDesc.deps?.length ?? 0;
5982
+ profiles.push({
5983
+ path,
5984
+ type: nodeDesc.type,
5985
+ status: nodeDesc.status ?? "unknown",
5986
+ valueSizeBytes,
5987
+ subscriberCount,
5988
+ depCount
5989
+ });
5990
+ }
5991
+ const totalValueSizeBytes = profiles.reduce((sum, p) => sum + p.valueSizeBytes, 0);
5992
+ const hotspots = [...profiles].sort((a, b) => b.valueSizeBytes - a.valueSizeBytes).slice(0, topN);
5993
+ return {
5994
+ nodeCount: profiles.length,
5995
+ edgeCount: desc.edges.length,
5996
+ subgraphCount: desc.subgraphs.length,
5997
+ nodes: profiles,
5998
+ totalValueSizeBytes,
5999
+ hotspots
6000
+ };
6001
+ }
6002
+
5884
6003
  // src/patterns/cqrs.ts
5885
6004
  var COMMAND_GUARD = policy((allow, deny) => {
5886
6005
  allow("write");
@@ -6063,8 +6182,8 @@ var CqrsGraph = class extends Graph {
6063
6182
  (snapshots) => {
6064
6183
  const allEvents = [];
6065
6184
  for (const snapshot of snapshots) {
6066
- const snap = snapshot;
6067
- allEvents.push(...snap.value.entries);
6185
+ const entries = snapshot;
6186
+ allEvents.push(...entries);
6068
6187
  }
6069
6188
  allEvents.sort((a, b) => a.timestampNs - b.timestampNs || a.seq - b.seq);
6070
6189
  return reducer(initial, allEvents);
@@ -6105,9 +6224,8 @@ var CqrsGraph = class extends Graph {
6105
6224
  (snapshots) => {
6106
6225
  const errNode = sagaRef.n.meta.error;
6107
6226
  for (let i = 0; i < snapshots.length; i++) {
6108
- const snap = snapshots[i];
6227
+ const entries = snapshots[i];
6109
6228
  const eName = eventNames[i];
6110
- const entries = snap.value.entries;
6111
6229
  const lastCount = lastCounts.get(eName) ?? 0;
6112
6230
  if (entries.length > lastCount) {
6113
6231
  const newEntries = entries.slice(lastCount);
@@ -12046,9 +12164,6 @@ var throttleTime = throttle;
12046
12164
  var catchError = rescue;
12047
12165
 
12048
12166
  // src/extra/reactive-map.ts
12049
- function emptySnapshot2() {
12050
- return { version: 0, value: { map: /* @__PURE__ */ new Map() } };
12051
- }
12052
12167
  function isExpired(e, now) {
12053
12168
  return e.expiresAt !== void 0 && now >= e.expiresAt;
12054
12169
  }
@@ -12062,12 +12177,12 @@ function buildMap(store, now) {
12062
12177
  function reactiveMap(options = {}) {
12063
12178
  const { name, maxSize, defaultTtl, ...nodeOpts } = options;
12064
12179
  const store = /* @__PURE__ */ new Map();
12065
- let current = emptySnapshot2();
12066
- const n = state(current, {
12180
+ const n = state(/* @__PURE__ */ new Map(), {
12067
12181
  ...nodeOpts,
12068
12182
  name,
12069
12183
  describeKind: "state",
12070
- equals: snapshotEqualsVersion
12184
+ equals: (a, b) => a === b
12185
+ // identity; pushSnapshot always creates a new Map
12071
12186
  });
12072
12187
  function pruneExpiredInternal() {
12073
12188
  const now = monotonicNs();
@@ -12092,11 +12207,9 @@ function reactiveMap(options = {}) {
12092
12207
  pruneExpiredInternal();
12093
12208
  const now = monotonicNs();
12094
12209
  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
12210
  batch(() => {
12098
12211
  n.down([[DIRTY]]);
12099
- n.down([[DATA, current]]);
12212
+ n.down([[DATA, map3]]);
12100
12213
  });
12101
12214
  }
12102
12215
  function touchLru(key) {
@@ -12106,7 +12219,7 @@ function reactiveMap(options = {}) {
12106
12219
  store.set(key, e);
12107
12220
  }
12108
12221
  const bundle = {
12109
- node: n,
12222
+ entries: n,
12110
12223
  get(key) {
12111
12224
  const now = monotonicNs();
12112
12225
  const e = store.get(key);
@@ -12203,13 +12316,11 @@ function keepalive2(node2) {
12203
12316
  node2.subscribe(() => void 0);
12204
12317
  }
12205
12318
  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
- }
12319
+ if (snapshot instanceof Map) return snapshot;
12209
12320
  return /* @__PURE__ */ new Map();
12210
12321
  }
12211
12322
  function asReadonlyMap(store) {
12212
- return mapFromSnapshot(store.node.get());
12323
+ return mapFromSnapshot(store.entries.get());
12213
12324
  }
12214
12325
  function applyExtraction(store, extraction) {
12215
12326
  if (!Array.isArray(extraction.upsert)) {
@@ -12237,7 +12348,7 @@ function distill(source, extractFn, opts) {
12237
12348
  if (opts.evict) {
12238
12349
  const evictionKeys = dynamicNode((get) => {
12239
12350
  const out = [];
12240
- const snapshot = mapFromSnapshot(get(store.node));
12351
+ const snapshot = mapFromSnapshot(get(store.entries));
12241
12352
  for (const [key, mem] of snapshot) {
12242
12353
  const verdict = opts.evict(key, mem);
12243
12354
  if (isNodeLike(verdict)) {
@@ -12267,7 +12378,7 @@ function distill(source, extractFn, opts) {
12267
12378
  applyExtraction(store, extraction);
12268
12379
  });
12269
12380
  }
12270
- const compact = derived([store.node, contextNode], ([snapshot, context]) => {
12381
+ const compact = derived([store.entries, contextNode], ([snapshot, context]) => {
12271
12382
  const entries = [...mapFromSnapshot(snapshot).entries()].map(([key, value]) => ({
12272
12383
  key,
12273
12384
  value,
@@ -12285,7 +12396,7 @@ function distill(source, extractFn, opts) {
12285
12396
  }
12286
12397
  return packed;
12287
12398
  });
12288
- const size = derived([store.node], ([snapshot]) => mapFromSnapshot(snapshot).size);
12399
+ const size = derived([store.entries], ([snapshot]) => mapFromSnapshot(snapshot).size);
12289
12400
  keepalive2(compact);
12290
12401
  keepalive2(size);
12291
12402
  return { store, compact, size };
@@ -12322,9 +12433,6 @@ function pubsub() {
12322
12433
  }
12323
12434
 
12324
12435
  // src/extra/reactive-index.ts
12325
- function emptySnapshot3() {
12326
- return { version: 0, value: { rows: [] } };
12327
- }
12328
12436
  function rowKey(row) {
12329
12437
  return [row.secondary, row.primary];
12330
12438
  }
@@ -12370,31 +12478,25 @@ function keepaliveDerived2(n) {
12370
12478
  function reactiveIndex(options = {}) {
12371
12479
  const { name } = options;
12372
12480
  const buf = [];
12373
- let current = emptySnapshot3();
12374
- const ordered = state(current, {
12481
+ const ordered = state([], {
12375
12482
  name,
12376
12483
  describeKind: "state",
12377
- equals: snapshotEqualsVersion
12484
+ equals: (a, b) => a === b
12378
12485
  });
12379
12486
  const byPrimary = derived(
12380
12487
  [ordered],
12381
12488
  ([s]) => {
12382
- const rows = s.value.rows;
12489
+ const rows = s;
12383
12490
  return byPrimaryMap(rows);
12384
12491
  },
12385
12492
  { initial: /* @__PURE__ */ new Map(), describeKind: "derived" }
12386
12493
  );
12387
12494
  keepaliveDerived2(byPrimary);
12388
12495
  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
- );
12496
+ const snapshot = [...buf];
12395
12497
  batch(() => {
12396
12498
  ordered.down([[DIRTY]]);
12397
- ordered.down([[DATA, current]]);
12499
+ ordered.down([[DATA, snapshot]]);
12398
12500
  });
12399
12501
  }
12400
12502
  return {
@@ -12425,28 +12527,19 @@ function reactiveIndex(options = {}) {
12425
12527
  }
12426
12528
 
12427
12529
  // src/extra/reactive-list.ts
12428
- function emptySnapshot4() {
12429
- return { version: 0, value: { items: [] } };
12430
- }
12431
12530
  function reactiveList(initial, options = {}) {
12432
12531
  const { name } = options;
12433
12532
  const buf = initial ? [...initial] : [];
12434
- let current = buf.length > 0 ? { version: 1, value: { items: [...buf] } } : emptySnapshot4();
12435
- const items = state(current, {
12533
+ const items = state(buf.length > 0 ? [...buf] : [], {
12436
12534
  name,
12437
12535
  describeKind: "state",
12438
- equals: snapshotEqualsVersion
12536
+ equals: (a, b) => a === b
12439
12537
  });
12440
12538
  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
- );
12539
+ const snapshot = [...buf];
12447
12540
  batch(() => {
12448
12541
  items.down([[DIRTY]]);
12449
- items.down([[DATA, current]]);
12542
+ items.down([[DATA, snapshot]]);
12450
12543
  });
12451
12544
  }
12452
12545
  return {
@@ -13405,36 +13498,33 @@ function firstDataFromNode(resolved, opts) {
13405
13498
  }
13406
13499
  const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
13407
13500
  return new Promise((resolve, reject) => {
13408
- let timer;
13409
- const cleanup = () => {
13410
- if (timer !== void 0) clearTimeout(timer);
13411
- };
13501
+ const timer = new ResettableTimer();
13412
13502
  const unsub = resolved.subscribe((messages) => {
13413
13503
  for (const msg of messages) {
13414
13504
  if (msg[0] === DATA) {
13415
- cleanup();
13505
+ timer.cancel();
13416
13506
  unsub();
13417
13507
  resolve(msg[1]);
13418
13508
  return;
13419
13509
  }
13420
13510
  if (msg[0] === ERROR) {
13421
- cleanup();
13511
+ timer.cancel();
13422
13512
  unsub();
13423
13513
  reject(msg[1]);
13424
13514
  return;
13425
13515
  }
13426
13516
  if (msg[0] === COMPLETE) {
13427
- cleanup();
13517
+ timer.cancel();
13428
13518
  unsub();
13429
13519
  reject(new Error("firstDataFromNode: completed without producing a value"));
13430
13520
  return;
13431
13521
  }
13432
13522
  }
13433
13523
  });
13434
- timer = setTimeout(() => {
13524
+ timer.start(timeoutMs, () => {
13435
13525
  unsub();
13436
13526
  reject(new Error(`firstDataFromNode: timed out after ${timeoutMs}ms`));
13437
- }, timeoutMs);
13527
+ });
13438
13528
  });
13439
13529
  }
13440
13530
  async function resolveToolHandlerResult(value) {
@@ -13581,7 +13671,6 @@ function promptNode(adapter, deps, prompt, opts) {
13581
13671
  }
13582
13672
  var ChatStreamGraph = class extends Graph {
13583
13673
  _log;
13584
- _keepaliveSubs = [];
13585
13674
  messages;
13586
13675
  latest;
13587
13676
  messageCount;
@@ -13596,7 +13685,7 @@ var ChatStreamGraph = class extends Graph {
13596
13685
  this.latest = derived(
13597
13686
  [this.messages],
13598
13687
  ([snapshot]) => {
13599
- const entries = snapshot.value.entries;
13688
+ const entries = snapshot;
13600
13689
  return entries.length === 0 ? void 0 : entries[entries.length - 1];
13601
13690
  },
13602
13691
  {
@@ -13608,10 +13697,10 @@ var ChatStreamGraph = class extends Graph {
13608
13697
  );
13609
13698
  this.add("latest", this.latest);
13610
13699
  this.connect("messages", "latest");
13611
- this._keepaliveSubs.push(keepalive3(this.latest));
13700
+ this.addDisposer(keepalive3(this.latest));
13612
13701
  this.messageCount = derived(
13613
13702
  [this.messages],
13614
- ([snapshot]) => snapshot.value.entries.length,
13703
+ ([snapshot]) => snapshot.length,
13615
13704
  {
13616
13705
  name: "messageCount",
13617
13706
  describeKind: "derived",
@@ -13621,7 +13710,7 @@ var ChatStreamGraph = class extends Graph {
13621
13710
  );
13622
13711
  this.add("messageCount", this.messageCount);
13623
13712
  this.connect("messages", "messageCount");
13624
- this._keepaliveSubs.push(keepalive3(this.messageCount));
13713
+ this.addDisposer(keepalive3(this.messageCount));
13625
13714
  }
13626
13715
  append(role, content, extra) {
13627
13716
  this._log.append({ role, content, ...extra });
@@ -13633,12 +13722,7 @@ var ChatStreamGraph = class extends Graph {
13633
13722
  this._log.clear();
13634
13723
  }
13635
13724
  allMessages() {
13636
- return this.messages.get().value.entries;
13637
- }
13638
- destroy() {
13639
- for (const unsub of this._keepaliveSubs) unsub();
13640
- this._keepaliveSubs.length = 0;
13641
- super.destroy();
13725
+ return this.messages.get();
13642
13726
  }
13643
13727
  };
13644
13728
  function chatStream(name, opts) {
@@ -13647,7 +13731,6 @@ function chatStream(name, opts) {
13647
13731
  var ToolRegistryGraph = class extends Graph {
13648
13732
  definitions;
13649
13733
  schemas;
13650
- _keepaliveSubs = [];
13651
13734
  constructor(name, opts = {}) {
13652
13735
  super(name, opts.graph);
13653
13736
  this.definitions = state(/* @__PURE__ */ new Map(), {
@@ -13668,7 +13751,7 @@ var ToolRegistryGraph = class extends Graph {
13668
13751
  );
13669
13752
  this.add("schemas", this.schemas);
13670
13753
  this.connect("definitions", "schemas");
13671
- this._keepaliveSubs.push(keepalive3(this.schemas));
13754
+ this.addDisposer(keepalive3(this.schemas));
13672
13755
  }
13673
13756
  register(tool) {
13674
13757
  const current = this.definitions.get();
@@ -13693,11 +13776,6 @@ var ToolRegistryGraph = class extends Graph {
13693
13776
  getDefinition(name) {
13694
13777
  return this.definitions.get().get(name);
13695
13778
  }
13696
- destroy() {
13697
- for (const unsub of this._keepaliveSubs) unsub();
13698
- this._keepaliveSubs.length = 0;
13699
- super.destroy();
13700
- }
13701
13779
  };
13702
13780
  function toolRegistry(name, opts) {
13703
13781
  return new ToolRegistryGraph(name, opts);
@@ -13842,9 +13920,7 @@ function admissionFilter3D(opts = {}) {
13842
13920
  }
13843
13921
  var DEFAULT_DECAY_RATE = Math.LN2 / (7 * 86400);
13844
13922
  function extractStoreMap(snapshot) {
13845
- if (snapshot && typeof snapshot === "object" && "value" in snapshot && typeof snapshot.value === "object" && snapshot.value !== null && "map" in snapshot.value) {
13846
- return snapshot.value.map ?? /* @__PURE__ */ new Map();
13847
- }
13923
+ if (snapshot instanceof Map) return snapshot;
13848
13924
  return /* @__PURE__ */ new Map();
13849
13925
  }
13850
13926
  function agentMemory(name, source, opts) {
@@ -13895,7 +13971,7 @@ function agentMemory(name, source, opts) {
13895
13971
  consolidateTrigger
13896
13972
  };
13897
13973
  const distillBundle = distill(filteredSource, extractFn, distillOpts);
13898
- graph.add("store", distillBundle.store.node);
13974
+ graph.add("store", distillBundle.store.entries);
13899
13975
  graph.add("compact", distillBundle.compact);
13900
13976
  graph.add("size", distillBundle.size);
13901
13977
  graph.connect("store", "compact");
@@ -13922,7 +13998,7 @@ function agentMemory(name, source, opts) {
13922
13998
  const permanentKeys = /* @__PURE__ */ new Set();
13923
13999
  const tierOf = (key) => {
13924
14000
  if (permanentKeys.has(key)) return "permanent";
13925
- const storeMap = extractStoreMap(distillBundle.store.node.get());
14001
+ const storeMap = extractStoreMap(distillBundle.store.entries.get());
13926
14002
  if (storeMap.has(key)) return "active";
13927
14003
  return "archived";
13928
14004
  };
@@ -13931,7 +14007,7 @@ function agentMemory(name, source, opts) {
13931
14007
  permanent.upsert(key, value);
13932
14008
  };
13933
14009
  const entryCreatedAtNs = /* @__PURE__ */ new Map();
13934
- const storeNode = distillBundle.store.node;
14010
+ const storeNode = distillBundle.store.entries;
13935
14011
  const contextNode = opts.context ? fromAny(opts.context) : state(null);
13936
14012
  const tierClassifier = effect([storeNode, contextNode], ([snapshot, ctx]) => {
13937
14013
  const storeMap = extractStoreMap(snapshot);
@@ -13998,7 +14074,7 @@ function agentMemory(name, source, opts) {
13998
14074
  if (vectors || kg) {
13999
14075
  const embedFn = opts.embedFn;
14000
14076
  const entityFn = opts.entityFn;
14001
- const storeNode = distillBundle.store.node;
14077
+ const storeNode = distillBundle.store.entries;
14002
14078
  const indexer = effect([storeNode], ([snapshot]) => {
14003
14079
  const storeMap = extractStoreMap(snapshot);
14004
14080
  for (const [key, mem] of storeMap) {
@@ -14043,7 +14119,7 @@ function agentMemory(name, source, opts) {
14043
14119
  });
14044
14120
  graph.add("retrievalTrace", traceState);
14045
14121
  retrievalTraceNode = traceState;
14046
- const storeNode = distillBundle.store.node;
14122
+ const storeNode = distillBundle.store.entries;
14047
14123
  let lastTrace = null;
14048
14124
  const retrievalDerived = derived(
14049
14125
  [queryInput, storeNode, contextNode],
@@ -14136,12 +14212,10 @@ function agentMemory(name, source, opts) {
14136
14212
  return result;
14137
14213
  };
14138
14214
  }
14139
- const origDestroy = graph.destroy.bind(graph);
14140
- graph.destroy = () => {
14215
+ graph.addDisposer(() => {
14141
14216
  for (const unsub of keepaliveSubs) unsub();
14142
14217
  keepaliveSubs.length = 0;
14143
- origDestroy();
14144
- };
14218
+ });
14145
14219
  return Object.assign(graph, {
14146
14220
  distillBundle,
14147
14221
  compact: distillBundle.compact,
@@ -15760,7 +15834,7 @@ function funnel(name, sources, stages, opts) {
15760
15834
  });
15761
15835
  g.add(bridgeName, br);
15762
15836
  g.connect(prevOutputPath, bridgeName);
15763
- keepalive4(br);
15837
+ g.addDisposer(keepalive4(br));
15764
15838
  prevOutputPath = `${stage.name}::output`;
15765
15839
  }
15766
15840
  return g;
@@ -15812,7 +15886,7 @@ function feedback(graph, condition, reentry, opts) {
15812
15886
  });
15813
15887
  graph.add(feedbackEffectName, feedbackEffect);
15814
15888
  graph.connect(condition, feedbackEffectName);
15815
- keepalive4(feedbackEffect);
15889
+ graph.addDisposer(keepalive4(feedbackEffect));
15816
15890
  return graph;
15817
15891
  }
15818
15892
  function budgetGate(source, constraints, opts) {
@@ -16192,7 +16266,7 @@ function contentModerationGraph(name, opts) {
16192
16266
  }
16193
16267
  });
16194
16268
  g.add("__review_accumulator", reviewAccumulator);
16195
- keepalive5(reviewAccumulator);
16269
+ g.addDisposer(keepalive5(reviewAccumulator));
16196
16270
  try {
16197
16271
  g.connect("stratify::branch/review", "__review_accumulator");
16198
16272
  } catch {
@@ -16240,8 +16314,7 @@ function contentModerationGraph(name, opts) {
16240
16314
  const fbCondition = derived(
16241
16315
  [reviewLog.entries, policy2],
16242
16316
  (vals) => {
16243
- const snap = vals[0];
16244
- const entries = snap?.value?.entries;
16317
+ const entries = vals[0];
16245
16318
  if (entries && entries.length > 0) {
16246
16319
  const latest = entries[entries.length - 1];
16247
16320
  if (latest && latest.falsePositive) {
@@ -17393,9 +17466,11 @@ __export(harness_exports, {
17393
17466
  DEFAULT_QUEUE_CONFIGS: () => DEFAULT_QUEUE_CONFIGS,
17394
17467
  DEFAULT_SEVERITY_WEIGHTS: () => DEFAULT_SEVERITY_WEIGHTS,
17395
17468
  HarnessGraph: () => HarnessGraph,
17469
+ QUEUE_NAMES: () => QUEUE_NAMES,
17396
17470
  defaultErrorClassifier: () => defaultErrorClassifier,
17397
17471
  evalIntakeBridge: () => evalIntakeBridge,
17398
17472
  harnessLoop: () => harnessLoop,
17473
+ harnessProfile: () => harnessProfile,
17399
17474
  priorityScore: () => priorityScore,
17400
17475
  strategyKey: () => strategyKey,
17401
17476
  strategyModel: () => strategyModel
@@ -17473,7 +17548,6 @@ function messagingMeta(kind, extra) {
17473
17548
  }
17474
17549
  var TopicGraph = class extends Graph {
17475
17550
  _log;
17476
- _keepaliveDisposers = [];
17477
17551
  events;
17478
17552
  latest;
17479
17553
  constructor(name, opts = {}) {
@@ -17484,7 +17558,7 @@ var TopicGraph = class extends Graph {
17484
17558
  this.latest = derived(
17485
17559
  [this.events],
17486
17560
  ([snapshot]) => {
17487
- const entries = snapshot.value.entries;
17561
+ const entries = snapshot;
17488
17562
  return entries.length === 0 ? void 0 : entries[entries.length - 1];
17489
17563
  },
17490
17564
  {
@@ -17496,23 +17570,16 @@ var TopicGraph = class extends Graph {
17496
17570
  );
17497
17571
  this.add("latest", this.latest);
17498
17572
  this.connect("events", "latest");
17499
- this._keepaliveDisposers.push(keepalive6(this.latest));
17500
- }
17501
- destroy() {
17502
- for (const dispose of this._keepaliveDisposers) dispose();
17503
- this._keepaliveDisposers.length = 0;
17504
- super.destroy();
17573
+ this.addDisposer(keepalive6(this.latest));
17505
17574
  }
17506
17575
  publish(value) {
17507
17576
  this._log.append(value);
17508
17577
  }
17509
17578
  retained() {
17510
- const snapshot = this.events.get();
17511
- return snapshot.value.entries;
17579
+ return this.events.get();
17512
17580
  }
17513
17581
  };
17514
17582
  var SubscriptionGraph = class extends Graph {
17515
- _keepaliveDisposers = [];
17516
17583
  source;
17517
17584
  cursor;
17518
17585
  available;
@@ -17537,7 +17604,7 @@ var SubscriptionGraph = class extends Graph {
17537
17604
  this.available = derived(
17538
17605
  [this.source, this.cursor],
17539
17606
  ([sourceSnapshot, cursor]) => {
17540
- const entries = sourceSnapshot.value.entries;
17607
+ const entries = sourceSnapshot;
17541
17608
  const start = Math.max(0, Math.trunc(cursor ?? 0));
17542
17609
  return entries.slice(start);
17543
17610
  },
@@ -17552,13 +17619,8 @@ var SubscriptionGraph = class extends Graph {
17552
17619
  this.connect("topic::events", "source");
17553
17620
  this.connect("source", "available");
17554
17621
  this.connect("cursor", "available");
17555
- this._keepaliveDisposers.push(keepalive6(this.source));
17556
- this._keepaliveDisposers.push(keepalive6(this.available));
17557
- }
17558
- destroy() {
17559
- for (const dispose of this._keepaliveDisposers) dispose();
17560
- this._keepaliveDisposers.length = 0;
17561
- super.destroy();
17622
+ this.addDisposer(keepalive6(this.source));
17623
+ this.addDisposer(keepalive6(this.available));
17562
17624
  }
17563
17625
  ack(count) {
17564
17626
  const available = this.available.get();
@@ -17580,7 +17642,6 @@ var SubscriptionGraph = class extends Graph {
17580
17642
  var JobQueueGraph = class extends Graph {
17581
17643
  _pending;
17582
17644
  _jobs;
17583
- _keepaliveDisposers = [];
17584
17645
  _seq = 0;
17585
17646
  pending;
17586
17647
  jobs;
@@ -17590,27 +17651,18 @@ var JobQueueGraph = class extends Graph {
17590
17651
  this._pending = reactiveList([], { name: "pending" });
17591
17652
  this._jobs = reactiveMap({ name: "jobs" });
17592
17653
  this.pending = this._pending.items;
17593
- this.jobs = this._jobs.node;
17654
+ this.jobs = this._jobs.entries;
17594
17655
  this.add("pending", this.pending);
17595
17656
  this.add("jobs", this.jobs);
17596
- this.depth = derived(
17597
- [this.pending],
17598
- ([snapshot]) => snapshot.value.items.length,
17599
- {
17600
- name: "depth",
17601
- describeKind: "derived",
17602
- meta: messagingMeta("queue_depth"),
17603
- initial: 0
17604
- }
17605
- );
17657
+ this.depth = derived([this.pending], ([snapshot]) => snapshot.length, {
17658
+ name: "depth",
17659
+ describeKind: "derived",
17660
+ meta: messagingMeta("queue_depth"),
17661
+ initial: 0
17662
+ });
17606
17663
  this.add("depth", this.depth);
17607
17664
  this.connect("pending", "depth");
17608
- this._keepaliveDisposers.push(keepalive6(this.depth));
17609
- }
17610
- destroy() {
17611
- for (const dispose of this._keepaliveDisposers) dispose();
17612
- this._keepaliveDisposers.length = 0;
17613
- super.destroy();
17665
+ this.addDisposer(keepalive6(this.depth));
17614
17666
  }
17615
17667
  enqueue(payload, opts = {}) {
17616
17668
  const id = opts.id ?? `${this.name}-${++this._seq}`;
@@ -17633,8 +17685,7 @@ var JobQueueGraph = class extends Graph {
17633
17685
  if (max === 0) return [];
17634
17686
  const out = [];
17635
17687
  while (out.length < max) {
17636
- const snapshot = this.pending.get();
17637
- const ids = snapshot.value.items;
17688
+ const ids = this.pending.get();
17638
17689
  if (ids.length === 0) break;
17639
17690
  const id = this._pending.pop(0);
17640
17691
  const job = this._jobs.get(id);
@@ -17670,7 +17721,6 @@ var JobQueueGraph = class extends Graph {
17670
17721
  var JobFlowGraph = class extends Graph {
17671
17722
  _stageNames;
17672
17723
  _queues = /* @__PURE__ */ new Map();
17673
- _keepaliveDisposers = [];
17674
17724
  _completed;
17675
17725
  completed;
17676
17726
  completedCount;
@@ -17695,7 +17745,7 @@ var JobFlowGraph = class extends Graph {
17695
17745
  this.add("completed", this.completed);
17696
17746
  this.completedCount = derived(
17697
17747
  [this.completed],
17698
- ([snapshot]) => snapshot.value.entries.length,
17748
+ ([snapshot]) => snapshot.length,
17699
17749
  {
17700
17750
  name: "completedCount",
17701
17751
  describeKind: "derived",
@@ -17705,7 +17755,7 @@ var JobFlowGraph = class extends Graph {
17705
17755
  );
17706
17756
  this.add("completedCount", this.completedCount);
17707
17757
  this.connect("completed", "completedCount");
17708
- this._keepaliveDisposers.push(keepalive6(this.completedCount));
17758
+ this.addDisposer(keepalive6(this.completedCount));
17709
17759
  const maxPerPump = Math.max(
17710
17760
  1,
17711
17761
  requireNonNegativeInt(opts.maxPerPump ?? DEFAULT_MAX_PER_PUMP, "job flow maxPerPump")
@@ -17745,14 +17795,9 @@ var JobFlowGraph = class extends Graph {
17745
17795
  );
17746
17796
  this.add(`pump_${stage}`, pump);
17747
17797
  this.connect(`${stage}::pending`, `pump_${stage}`);
17748
- this._keepaliveDisposers.push(keepalive6(pump));
17798
+ this.addDisposer(keepalive6(pump));
17749
17799
  }
17750
17800
  }
17751
- destroy() {
17752
- for (const dispose of this._keepaliveDisposers) dispose();
17753
- this._keepaliveDisposers.length = 0;
17754
- super.destroy();
17755
- }
17756
17801
  stages() {
17757
17802
  return this._stageNames;
17758
17803
  }
@@ -17765,14 +17810,12 @@ var JobFlowGraph = class extends Graph {
17765
17810
  return this.queue(this._stageNames[0]).enqueue(payload, opts);
17766
17811
  }
17767
17812
  retainedCompleted() {
17768
- const snapshot = this.completed.get();
17769
- return snapshot.value.entries;
17813
+ return this.completed.get();
17770
17814
  }
17771
17815
  };
17772
17816
  var TopicBridgeGraph = class extends Graph {
17773
17817
  _sourceSub;
17774
17818
  _target;
17775
- _keepaliveDisposers = [];
17776
17819
  bridgedCount;
17777
17820
  constructor(name, sourceTopic, targetTopic, opts = {}) {
17778
17821
  super(name, opts.graph);
@@ -17817,12 +17860,7 @@ var TopicBridgeGraph = class extends Graph {
17817
17860
  );
17818
17861
  this.add("pump", pump);
17819
17862
  this.connect("subscription::available", "pump");
17820
- this._keepaliveDisposers.push(keepalive6(pump));
17821
- }
17822
- destroy() {
17823
- for (const dispose of this._keepaliveDisposers) dispose();
17824
- this._keepaliveDisposers.length = 0;
17825
- super.destroy();
17863
+ this.addDisposer(keepalive6(pump));
17826
17864
  }
17827
17865
  };
17828
17866
  function topic(name, opts) {
@@ -18114,7 +18152,7 @@ function gate(graph, name, source, opts) {
18114
18152
  isOpenNode.down([[DATA, false]]);
18115
18153
  }
18116
18154
  };
18117
- countNode.subscribe(() => void 0);
18155
+ graph.addDisposer(countNode.subscribe(() => void 0));
18118
18156
  registerStep(graph, name, output, src.path ? [src.path] : []);
18119
18157
  const internal = new Graph(`${name}_state`);
18120
18158
  internal.add("pending", pendingNode);
@@ -18333,6 +18371,12 @@ function onFailure(graph, name, source, recover, opts) {
18333
18371
  }
18334
18372
 
18335
18373
  // src/patterns/harness/types.ts
18374
+ var QUEUE_NAMES = [
18375
+ "auto-fix",
18376
+ "needs-decision",
18377
+ "investigation",
18378
+ "backlog"
18379
+ ];
18336
18380
  function strategyKey(rootCause, intervention) {
18337
18381
  return `${rootCause}\u2192${intervention}`;
18338
18382
  }
@@ -18361,9 +18405,9 @@ var DEFAULT_QUEUE_CONFIGS = {
18361
18405
  function strategyModel() {
18362
18406
  const _map = reactiveMap({ name: "strategy-entries" });
18363
18407
  const snapshot = derived(
18364
- [_map.node],
18408
+ [_map.entries],
18365
18409
  ([mapSnap]) => {
18366
- const raw = mapSnap.value.map;
18410
+ const raw = mapSnap;
18367
18411
  return new Map(raw);
18368
18412
  },
18369
18413
  {
@@ -18398,7 +18442,10 @@ function strategyModel() {
18398
18442
  }
18399
18443
  const _unsub = snapshot.subscribe(() => {
18400
18444
  });
18401
- return { node: snapshot, record, lookup };
18445
+ function dispose() {
18446
+ _unsub();
18447
+ }
18448
+ return { node: snapshot, record, lookup, dispose };
18402
18449
  }
18403
18450
  function priorityScore(item, strategy, lastInteractionNs, urgency, signals) {
18404
18451
  const severityWeights = { ...DEFAULT_SEVERITY_WEIGHTS, ...signals?.severityWeights };
@@ -18430,8 +18477,8 @@ function priorityScore(item, strategy, lastInteractionNs, urgency, signals) {
18430
18477
  }
18431
18478
 
18432
18479
  // src/patterns/harness/loop.ts
18433
- function baseSummary(summary) {
18434
- return summary.replace(/^\[RETRY \d+\/\d+\]\s*/, "");
18480
+ function trackingKey(item) {
18481
+ return item.relatedTo?.[0] ?? item.summary;
18435
18482
  }
18436
18483
  var DEFAULT_TRIAGE_PROMPT = `You are a triage classifier for a reactive collaboration harness.
18437
18484
 
@@ -18477,12 +18524,6 @@ Output JSON:
18477
18524
  "findings": ["<finding1>", ...],
18478
18525
  "errorClass": "self-correctable" | "structural" // only if verified=false
18479
18526
  }`;
18480
- var QUEUE_NAMES = [
18481
- "auto-fix",
18482
- "needs-decision",
18483
- "investigation",
18484
- "backlog"
18485
- ];
18486
18527
  var HarnessGraph = class extends Graph {
18487
18528
  /** Intake topic — publish items here to enter the loop. */
18488
18529
  intake;
@@ -18494,19 +18535,19 @@ var HarnessGraph = class extends Graph {
18494
18535
  strategy;
18495
18536
  /** Verify results topic — subscribe to see verification outcomes. */
18496
18537
  verifyResults;
18497
- /** Per-item fast-retry counts (keyed by base summary). */
18498
- retryTracker;
18499
- /** Per-item reingestion counts (keyed by base summary). */
18500
- reingestionTracker;
18501
- constructor(name, intake, queues, gates, strategy, verifyResults, retryTracker, reingestionTracker) {
18538
+ /** Global retry count across all items (circuit breaker). Reactive — subscribable. */
18539
+ totalRetries;
18540
+ /** Global reingestion count across all items (circuit breaker). Reactive — subscribable. */
18541
+ totalReingestions;
18542
+ constructor(name, intake, queues, gates, strategy, verifyResults, totalRetries, totalReingestions) {
18502
18543
  super(name);
18503
18544
  this.intake = intake;
18504
18545
  this.queues = queues;
18505
18546
  this.gates = gates;
18506
18547
  this.strategy = strategy;
18507
18548
  this.verifyResults = verifyResults;
18508
- this.retryTracker = retryTracker;
18509
- this.reingestionTracker = reingestionTracker;
18549
+ this.totalRetries = totalRetries;
18550
+ this.totalReingestions = totalReingestions;
18510
18551
  }
18511
18552
  };
18512
18553
  function harnessLoop(name, opts) {
@@ -18548,13 +18589,16 @@ function harnessLoop(name, opts) {
18548
18589
  for (const route of QUEUE_NAMES) {
18549
18590
  queueTopics.set(route, new TopicGraph(`queue/${route}`, { retainedLimit }));
18550
18591
  }
18551
- const router = effect([triageNode], ([triaged]) => {
18552
- const item = triaged;
18553
- if (!item || !item.route) return;
18554
- const topic2 = queueTopics.get(item.route);
18555
- if (topic2) topic2.publish(item);
18592
+ const routerInput = withLatestFrom(triageNode, triageInput);
18593
+ const router = effect([routerInput], ([pair]) => {
18594
+ const [classification, triagePair] = pair;
18595
+ if (!classification || !classification.route) return;
18596
+ const intakeItem = triagePair?.[0];
18597
+ const merged = { ...intakeItem, ...classification };
18598
+ const topic2 = queueTopics.get(merged.route);
18599
+ if (topic2) topic2.publish(merged);
18556
18600
  });
18557
- router.subscribe(() => {
18601
+ const routerUnsub = router.subscribe(() => {
18558
18602
  });
18559
18603
  const gateGraph = new Graph("gates");
18560
18604
  const gateControllers = /* @__PURE__ */ new Map();
@@ -18612,8 +18656,10 @@ function harnessLoop(name, opts) {
18612
18656
  executeInput
18613
18657
  );
18614
18658
  const maxReingestions = opts.maxReingestions ?? 1;
18615
- const retryTracker = /* @__PURE__ */ new Map();
18616
- const reingestionTracker = /* @__PURE__ */ new Map();
18659
+ const maxTotalRetries = Math.min(opts.maxTotalRetries ?? maxRetries * 10, 100);
18660
+ const maxTotalReingestions = Math.min(opts.maxTotalReingestions ?? maxReingestions * 10, 100);
18661
+ const totalRetries = state(0);
18662
+ const totalReingestions = state(0);
18617
18663
  const fastRetry = effect([verifyContext], ([ctx]) => {
18618
18664
  const [[vo, execRaw], item] = ctx;
18619
18665
  if (!vo || !item) return;
@@ -18639,34 +18685,38 @@ function harnessLoop(name, opts) {
18639
18685
  outcome: "failure",
18640
18686
  detail: vr.findings.join("; ")
18641
18687
  });
18642
- const key = baseSummary(item.summary);
18643
- const retryCount = retryTracker.get(key) ?? 0;
18644
- if (errClass === "self-correctable" && retryCount < maxRetries) {
18645
- retryTracker.set(key, retryCount + 1);
18688
+ const itemRetries = item._retries ?? 0;
18689
+ if (errClass === "self-correctable" && itemRetries < maxRetries && (totalRetries.get() ?? 0) < maxTotalRetries) {
18690
+ totalRetries.down([[DATA, (totalRetries.get() ?? 0) + 1]]);
18691
+ const key = trackingKey(item);
18646
18692
  const retryItem = {
18647
18693
  ...item,
18648
- summary: `[RETRY ${retryCount + 1}/${maxRetries}] ${baseSummary(item.summary)} \u2014 Previous attempt failed: ${vr.findings.join("; ")}`
18694
+ _retries: itemRetries + 1,
18695
+ summary: `[RETRY ${itemRetries + 1}/${maxRetries}] ${key} \u2014 Previous attempt failed: ${vr.findings.join("; ")}`,
18696
+ relatedTo: [key]
18649
18697
  };
18650
18698
  retryTopic.publish(retryItem);
18651
18699
  } else {
18652
18700
  strategy.record(item.rootCause, item.intervention, false);
18653
18701
  verifyResults.publish(vr);
18654
- const itemReingestions = reingestionTracker.get(key) ?? 0;
18655
- if (itemReingestions < maxReingestions) {
18656
- reingestionTracker.set(key, itemReingestions + 1);
18702
+ const key = trackingKey(item);
18703
+ const itemReingestions = item._reingestions ?? 0;
18704
+ if (itemReingestions < maxReingestions && (totalReingestions.get() ?? 0) < maxTotalReingestions) {
18705
+ totalReingestions.down([[DATA, (totalReingestions.get() ?? 0) + 1]]);
18657
18706
  intake.publish({
18658
18707
  source: "eval",
18659
- summary: `Verification failed for: ${baseSummary(item.summary)}`,
18708
+ summary: `Verification failed for: ${key}`,
18660
18709
  evidence: vr.findings.join("\n"),
18661
18710
  affectsAreas: item.affectsAreas,
18662
18711
  affectsEvalTasks: item.affectsEvalTasks,
18663
18712
  severity: "high",
18664
- relatedTo: [baseSummary(item.summary)]
18713
+ relatedTo: [key],
18714
+ _reingestions: itemReingestions + 1
18665
18715
  });
18666
18716
  }
18667
18717
  }
18668
18718
  });
18669
- fastRetry.subscribe(() => {
18719
+ const fastRetryUnsub = fastRetry.subscribe(() => {
18670
18720
  });
18671
18721
  const harness = new HarnessGraph(
18672
18722
  name,
@@ -18675,9 +18725,12 @@ function harnessLoop(name, opts) {
18675
18725
  gateControllers,
18676
18726
  strategy,
18677
18727
  verifyResults,
18678
- retryTracker,
18679
- reingestionTracker
18728
+ totalRetries,
18729
+ totalReingestions
18680
18730
  );
18731
+ harness.addDisposer(routerUnsub);
18732
+ harness.addDisposer(fastRetryUnsub);
18733
+ harness.addDisposer(strategy.dispose);
18681
18734
  harness.mount("intake", intake);
18682
18735
  for (const [route, topic2] of queueTopics) {
18683
18736
  harness.mount(`queue/${route}`, topic2);
@@ -18688,6 +18741,22 @@ function harnessLoop(name, opts) {
18688
18741
  return harness;
18689
18742
  }
18690
18743
 
18744
+ // src/patterns/harness/profile.ts
18745
+ function harnessProfile(harness, opts) {
18746
+ const base = graphProfile(harness, opts);
18747
+ const queueDepths = {};
18748
+ for (const [route, topic2] of harness.queues) {
18749
+ queueDepths[route] = topic2.retained().length;
18750
+ }
18751
+ return {
18752
+ ...base,
18753
+ queueDepths,
18754
+ strategyEntries: harness.strategy.node.get()?.size ?? 0,
18755
+ totalRetries: harness.totalRetries.get() ?? 0,
18756
+ totalReingestions: harness.totalReingestions.get() ?? 0
18757
+ };
18758
+ }
18759
+
18691
18760
  // src/patterns/reactive-layout/index.ts
18692
18761
  var reactive_layout_exports = {};
18693
18762
  __export(reactive_layout_exports, {
@@ -19301,6 +19370,7 @@ var version = "0.0.0";
19301
19370
  fromWebhook,
19302
19371
  globToRegExp,
19303
19372
  graph,
19373
+ graphProfile,
19304
19374
  graphspec,
19305
19375
  harness,
19306
19376
  interval,
@@ -19379,6 +19449,7 @@ var version = "0.0.0";
19379
19449
  shareReplay,
19380
19450
  signalToName,
19381
19451
  signals,
19452
+ sizeof,
19382
19453
  skip,
19383
19454
  solid,
19384
19455
  startWith,