@agent-e/core 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -32,7 +32,7 @@ var DEFAULT_THRESHOLDS = {
32
32
  cooldownTicks: 15,
33
33
  // Currency (P13)
34
34
  poolWinRate: 0.65,
35
- poolHouseCut: 0.1,
35
+ poolOperatorShare: 0.1,
36
36
  // Population balance (P9)
37
37
  roleSwitchFrictionMax: 0.05,
38
38
  // >5% of population switching in one period = herd
@@ -93,6 +93,12 @@ var Observer = class {
93
93
  this.customMetricFns[name] = fn;
94
94
  }
95
95
  compute(state, recentEvents) {
96
+ if (!state.currencies || state.currencies.length === 0) {
97
+ console.warn("[AgentE] Warning: state.currencies is empty. Metrics will be zeroed.");
98
+ }
99
+ if (!state.agentBalances || Object.keys(state.agentBalances).length === 0) {
100
+ console.warn("[AgentE] Warning: state.agentBalances is empty.");
101
+ }
96
102
  const tick = state.tick;
97
103
  const roles = Object.values(state.agentRoles);
98
104
  const totalAgents = Object.keys(state.agentBalances).length;
@@ -140,7 +146,7 @@ var Observer = class {
140
146
  if (!actorsBySystem[e.system]) actorsBySystem[e.system] = /* @__PURE__ */ new Set();
141
147
  actorsBySystem[e.system].add(e.actor);
142
148
  const amt = e.amount ?? 0;
143
- if (e.type === "mint" || e.type === "enter") {
149
+ if (e.type === "mint") {
144
150
  flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) + amt;
145
151
  } else if (e.type === "burn" || e.type === "consume") {
146
152
  flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) - amt;
@@ -148,7 +154,7 @@ var Observer = class {
148
154
  }
149
155
  if (e.sourceOrSink) {
150
156
  const amt = e.amount ?? 0;
151
- if (e.type === "mint" || e.type === "enter") {
157
+ if (e.type === "mint") {
152
158
  flowBySource[e.sourceOrSink] = (flowBySource[e.sourceOrSink] ?? 0) + amt;
153
159
  } else if (e.type === "burn" || e.type === "consume") {
154
160
  flowBySink[e.sourceOrSink] = (flowBySink[e.sourceOrSink] ?? 0) + amt;
@@ -187,7 +193,7 @@ var Observer = class {
187
193
  const faucet = faucetVolumeByCurrency[curr] ?? 0;
188
194
  const sink = sinkVolumeByCurrency[curr] ?? 0;
189
195
  netFlowByCurrency[curr] = faucet - sink;
190
- tapSinkRatioByCurrency[curr] = sink > 0 ? faucet / sink : faucet > 0 ? Infinity : 1;
196
+ tapSinkRatioByCurrency[curr] = sink > 0 ? Math.min(faucet / sink, 100) : faucet > 0 ? 100 : 1;
191
197
  const prevSupply = this.previousMetrics?.totalSupplyByCurrency?.[curr] ?? totalSupplyByCurrency[curr] ?? 0;
192
198
  const currSupply = totalSupplyByCurrency[curr] ?? 0;
193
199
  inflationRateByCurrency[curr] = prevSupply > 0 ? (currSupply - prevSupply) / prevSupply : 0;
@@ -222,7 +228,7 @@ var Observer = class {
222
228
  const faucetVolume = Object.values(faucetVolumeByCurrency).reduce((s, v) => s + v, 0);
223
229
  const sinkVolume = Object.values(sinkVolumeByCurrency).reduce((s, v) => s + v, 0);
224
230
  const netFlow = faucetVolume - sinkVolume;
225
- const tapSinkRatio = sinkVolume > 0 ? faucetVolume / sinkVolume : faucetVolume > 0 ? Infinity : 1;
231
+ const tapSinkRatio = sinkVolume > 0 ? Math.min(faucetVolume / sinkVolume, 100) : faucetVolume > 0 ? 100 : 1;
226
232
  const velocity = totalSupply > 0 ? tradeEvents.length / totalSupply : 0;
227
233
  const prevTotalSupply = this.previousMetrics?.totalSupply ?? totalSupply;
228
234
  const inflationRate = prevTotalSupply > 0 ? (totalSupply - prevTotalSupply) / prevTotalSupply : 0;
@@ -260,7 +266,9 @@ var Observer = class {
260
266
  const pVals = Object.values(resourcePrices);
261
267
  priceIndexByCurrency[curr] = pVals.length > 0 ? pVals.reduce((s, p) => s + p, 0) / pVals.length : 0;
262
268
  }
263
- this.previousPricesByCurrency = JSON.parse(JSON.stringify(pricesByCurrency));
269
+ this.previousPricesByCurrency = Object.fromEntries(
270
+ Object.entries(pricesByCurrency).map(([c, p]) => [c, { ...p }])
271
+ );
264
272
  const prices = pricesByCurrency[defaultCurrency] ?? {};
265
273
  const priceVolatility = priceVolatilityByCurrency[defaultCurrency] ?? {};
266
274
  const priceIndex = priceIndexByCurrency[defaultCurrency] ?? 0;
@@ -280,9 +288,9 @@ var Observer = class {
280
288
  for (const resource of /* @__PURE__ */ new Set([...Object.keys(supplyByResource), ...Object.keys(demandSignals)])) {
281
289
  const s = supplyByResource[resource] ?? 0;
282
290
  const d = demandSignals[resource] ?? 0;
283
- if (d > 2 && s / d < 0.5) {
291
+ if (d > 0 && d > 2 && s / d < 0.5) {
284
292
  pinchPoints[resource] = "scarce";
285
- } else if (s > 3 && d > 0 && s / d > 3) {
293
+ } else if (d > 0 && s > 3 && s / d > 3) {
286
294
  pinchPoints[resource] = "oversupplied";
287
295
  } else {
288
296
  pinchPoints[resource] = "optimal";
@@ -328,21 +336,11 @@ var Observer = class {
328
336
  const arbitrageIndexByCurrency = {};
329
337
  for (const curr of currencies) {
330
338
  const cPrices = pricesByCurrency[curr] ?? {};
331
- const priceKeys = Object.keys(cPrices).filter((k) => cPrices[k] > 0);
332
- if (priceKeys.length >= 2) {
333
- let pairCount = 0;
334
- let totalDivergence = 0;
335
- for (let i = 0; i < priceKeys.length; i++) {
336
- for (let j = i + 1; j < priceKeys.length; j++) {
337
- const pA = cPrices[priceKeys[i]];
338
- const pB = cPrices[priceKeys[j]];
339
- let ratio = pA / pB;
340
- ratio = Math.max(1e-3, Math.min(1e3, ratio));
341
- totalDivergence += Math.abs(Math.log(ratio));
342
- pairCount++;
343
- }
344
- }
345
- arbitrageIndexByCurrency[curr] = pairCount > 0 ? Math.min(1, totalDivergence / pairCount) : 0;
339
+ const logPrices = Object.values(cPrices).filter((p) => p > 0).map((p) => Math.log(p));
340
+ if (logPrices.length >= 2) {
341
+ const mean = logPrices.reduce((s, v) => s + v, 0) / logPrices.length;
342
+ const variance = logPrices.reduce((s, v) => s + (v - mean) ** 2, 0) / logPrices.length;
343
+ arbitrageIndexByCurrency[curr] = Math.min(1, Math.sqrt(variance));
346
344
  } else {
347
345
  arbitrageIndexByCurrency[curr] = 0;
348
346
  }
@@ -429,10 +427,10 @@ var Observer = class {
429
427
  prices,
430
428
  priceVolatility,
431
429
  poolSizes: poolSizesAggregate,
432
- extractionRatio: NaN,
433
- newUserDependency: NaN,
434
- smokeTestRatio: NaN,
435
- currencyInsulation: NaN,
430
+ extractionRatio: 0,
431
+ newUserDependency: 0,
432
+ smokeTestRatio: 0,
433
+ currencyInsulation: 0,
436
434
  arbitrageIndex,
437
435
  giftTradeRatio,
438
436
  disposalTradeRatio,
@@ -454,8 +452,11 @@ var Observer = class {
454
452
  timeToValue,
455
453
  sharkToothPeaks: this.previousMetrics?.sharkToothPeaks ?? [],
456
454
  sharkToothValleys: this.previousMetrics?.sharkToothValleys ?? [],
457
- eventCompletionRate: NaN,
455
+ eventCompletionRate: 0,
458
456
  contentDropAge,
457
+ systems: state.systems ?? [],
458
+ sources: state.sources ?? [],
459
+ sinks: state.sinks ?? [],
459
460
  flowBySystem,
460
461
  activityBySystem,
461
462
  participantsBySystem,
@@ -483,7 +484,7 @@ function computeGini(sorted) {
483
484
  for (let i = 0; i < n; i++) {
484
485
  numerator += (2 * (i + 1) - n - 1) * (sorted[i] ?? 0);
485
486
  }
486
- return Math.abs(numerator) / (n * sum);
487
+ return Math.min(1, Math.abs(numerator) / (n * sum));
487
488
  }
488
489
 
489
490
  // src/Diagnoser.ts
@@ -579,10 +580,10 @@ function emptyMetrics(tick = 0) {
579
580
  prices: {},
580
581
  priceVolatility: {},
581
582
  poolSizes: {},
582
- extractionRatio: NaN,
583
- newUserDependency: NaN,
584
- smokeTestRatio: NaN,
585
- currencyInsulation: NaN,
583
+ extractionRatio: 0,
584
+ newUserDependency: 0,
585
+ smokeTestRatio: 0,
586
+ currencyInsulation: 0,
586
587
  arbitrageIndex: 0,
587
588
  giftTradeRatio: 0,
588
589
  disposalTradeRatio: 0,
@@ -603,8 +604,11 @@ function emptyMetrics(tick = 0) {
603
604
  timeToValue: 0,
604
605
  sharkToothPeaks: [],
605
606
  sharkToothValleys: [],
606
- eventCompletionRate: NaN,
607
+ eventCompletionRate: 0,
607
608
  contentDropAge: 0,
609
+ systems: [],
610
+ sources: [],
611
+ sinks: [],
608
612
  flowBySystem: {},
609
613
  activityBySystem: {},
610
614
  participantsBySystem: {},
@@ -805,9 +809,9 @@ var SUPPLY_CHAIN_PRINCIPLES = [
805
809
  ];
806
810
 
807
811
  // src/principles/incentives.ts
808
- var P5_ProfitabilityIsCompetitive = {
812
+ var P5_ProfitabilityIsRelative = {
809
813
  id: "P5",
810
- name: "Profitability Is Competitive, Not Absolute",
814
+ name: "Profitability Is Relative, Not Absolute",
811
815
  category: "incentive",
812
816
  description: "Any profitability formula that returns the same number regardless of how many agents are already in that role will cause stampedes. 97 intermediaries happened because profit = transactions \xD7 10 with no competition denominator.",
813
817
  check(metrics, thresholds) {
@@ -871,7 +875,7 @@ var P7_NonSpecialistsSubsidiseSpecialists = {
871
875
  id: "P7",
872
876
  name: "Non-Specialists Subsidise Specialists in Zero-Sum Games",
873
877
  category: "incentive",
874
- description: "In zero-sum pools (competitive pool, staking), the math only works if non-specialists overpay relative to specialists. If the pool is >70% specialists, there is no one left to subsidise and the pot drains.",
878
+ description: "In zero-sum pools (staking, prize pools, etc.), the math only works if non-specialists overpay relative to specialists. If the pool is >70% specialists, there is no one left to subsidise and the pot drains.",
875
879
  check(metrics, _thresholds) {
876
880
  const { poolSizes } = metrics;
877
881
  for (const [poolName, poolSize] of Object.entries(poolSizes)) {
@@ -907,7 +911,7 @@ var P8_RegulatorCannotFightDesign = {
907
911
  id: "P8",
908
912
  name: "Regulator Cannot Fight the Design",
909
913
  category: "incentive",
910
- description: "If the economy is designed to have a majority role (e.g. dominant role exceeds 55%), the regulator must know this and exempt that role from population suppression. AgentE at tick 1 seeing dominant role exceeds 55% and slashing competitive pool rewards is overreach.",
914
+ description: "If the economy is designed to have a majority role (e.g. dominant role exceeds 55%), the regulator must know this and exempt that role from population suppression. AgentE at tick 1 seeing dominant role exceeds 55% and slashing pool rewards is overreach.",
911
915
  check(metrics, _thresholds) {
912
916
  const { roleShares, avgSatisfaction } = metrics;
913
917
  if (avgSatisfaction < 45) {
@@ -932,7 +936,7 @@ var P8_RegulatorCannotFightDesign = {
932
936
  }
933
937
  };
934
938
  var INCENTIVE_PRINCIPLES = [
935
- P5_ProfitabilityIsCompetitive,
939
+ P5_ProfitabilityIsRelative,
936
940
  P6_CrowdingMultiplierOnAllRoles,
937
941
  P7_NonSpecialistsSubsidiseSpecialists,
938
942
  P8_RegulatorCannotFightDesign
@@ -943,7 +947,7 @@ var P9_RoleSwitchingNeedsFriction = {
943
947
  id: "P9",
944
948
  name: "Role Switching Needs Friction",
945
949
  category: "population",
946
- description: "If >5% of the population switches roles in a single evaluation period, it is a herd movement, not rational rebalancing. Without friction (satisfaction cost, cooldown), one good tick causes mass migration.",
950
+ description: "If >5% of the population switches roles in a single evaluation period, it is a herd movement, not rational rebalancing. Without friction (satisfaction cost, minimum interval), one good tick causes mass migration.",
947
951
  check(metrics, thresholds) {
948
952
  const { churnByRole, roleShares } = metrics;
949
953
  const totalChurn = Object.values(churnByRole).reduce((s, v) => s + v, 0);
@@ -966,7 +970,7 @@ var P9_RoleSwitchingNeedsFriction = {
966
970
  return { violated: false };
967
971
  }
968
972
  };
969
- var P10_SpawnWeightingUsesInversePopulation = {
973
+ var P10_EntryWeightingUsesInversePopulation = {
970
974
  id: "P10",
971
975
  name: "Entry Weighting Uses Inverse Population",
972
976
  category: "population",
@@ -1072,7 +1076,7 @@ var P46_PersonaDiversity = {
1072
1076
  };
1073
1077
  var POPULATION_PRINCIPLES = [
1074
1078
  P9_RoleSwitchingNeedsFriction,
1075
- P10_SpawnWeightingUsesInversePopulation,
1079
+ P10_EntryWeightingUsesInversePopulation,
1076
1080
  P11_TwoTierPressure,
1077
1081
  P46_PersonaDiversity
1078
1082
  ];
@@ -1128,7 +1132,7 @@ var P13_PotsAreZeroSumAndSelfRegulate = {
1128
1132
  id: "P13",
1129
1133
  name: "Pots Self-Regulate with Correct Multiplier",
1130
1134
  category: "currency",
1131
- description: "Competitive pot math: winRate \xD7 multiplier > (1 - houseCut) drains the pot. At 65% win rate, multiplier must be \u2264 1.38. We use 1.5 for slight surplus buffer.",
1135
+ description: "Pool math: winRate \xD7 multiplier > (1 - operatorShare) drains the pot. At 65% win rate, multiplier must be \u2264 1.38. We use 1.5 for slight surplus buffer.",
1132
1136
  check(metrics, thresholds) {
1133
1137
  const { populationByRole } = metrics;
1134
1138
  const roleEntries = Object.entries(populationByRole).sort((a, b) => b[1] - a[1]);
@@ -1137,8 +1141,8 @@ var P13_PotsAreZeroSumAndSelfRegulate = {
1137
1141
  for (const curr of metrics.currencies) {
1138
1142
  const poolSize = currencyAmounts[curr] ?? 0;
1139
1143
  if (dominantCount > 5 && poolSize < 50) {
1140
- const { poolWinRate, poolHouseCut } = thresholds;
1141
- const maxSustainableMultiplier = (1 - poolHouseCut) / poolWinRate;
1144
+ const { poolWinRate, poolOperatorShare } = thresholds;
1145
+ const maxSustainableMultiplier = (1 - poolOperatorShare) / poolWinRate;
1142
1146
  return {
1143
1147
  violated: true,
1144
1148
  severity: 7,
@@ -1163,7 +1167,7 @@ var P14_TrackActualInjection = {
1163
1167
  id: "P14",
1164
1168
  name: "Track Actual Currency Injection, Not Value Creation",
1165
1169
  category: "currency",
1166
- description: 'Counting resource gathering as "currency injected" is misleading. Currency enters through faucet mechanisms (entering, rewards). Fake metrics break every downstream decision.',
1170
+ description: 'Counting resource extraction as "currency injected" is misleading. Currency enters through faucet mechanisms (entering, rewards). Fake metrics break every downstream decision.',
1167
1171
  check(metrics, _thresholds) {
1168
1172
  for (const curr of metrics.currencies) {
1169
1173
  const faucetVolume = metrics.faucetVolumeByCurrency[curr] ?? 0;
@@ -1421,7 +1425,7 @@ var P19_StartingSupplyExceedsDemand = {
1421
1425
  parameterType: "reward",
1422
1426
  direction: "increase",
1423
1427
  magnitude: 0.2,
1424
- reasoning: `${mostPopulatedRole} (${population} agents) has insufficient resources (${resourcesPerAgent.toFixed(2)} per agent). Cold-start scarcity. Boost competitive pool reward to attract participation despite scarcity.`
1428
+ reasoning: `${mostPopulatedRole} (${population} agents) has insufficient resources (${resourcesPerAgent.toFixed(2)} per agent). Cold-start scarcity. Boost pool reward to attract participation despite scarcity.`
1425
1429
  },
1426
1430
  confidence: 0.75,
1427
1431
  estimatedLag: 5
@@ -1751,7 +1755,7 @@ var REGULATOR_PRINCIPLES = [
1751
1755
  ];
1752
1756
 
1753
1757
  // src/principles/market-dynamics.ts
1754
- var P29_PinchPoint = {
1758
+ var P29_BottleneckDetection = {
1755
1759
  id: "P29",
1756
1760
  name: "Bottleneck Detection",
1757
1761
  category: "market_dynamics",
@@ -1796,7 +1800,7 @@ var P29_PinchPoint = {
1796
1800
  return { violated: false };
1797
1801
  }
1798
1802
  };
1799
- var P30_MovingPinchPoint = {
1803
+ var P30_DynamicBottleneckRotation = {
1800
1804
  id: "P30",
1801
1805
  name: "Dynamic Bottleneck Rotation",
1802
1806
  category: "market_dynamics",
@@ -1871,8 +1875,8 @@ var P57_CombinatorialPriceSpace = {
1871
1875
  }
1872
1876
  };
1873
1877
  var MARKET_DYNAMICS_PRINCIPLES = [
1874
- P29_PinchPoint,
1875
- P30_MovingPinchPoint,
1878
+ P29_BottleneckDetection,
1879
+ P30_DynamicBottleneckRotation,
1876
1880
  P57_CombinatorialPriceSpace
1877
1881
  ];
1878
1882
 
@@ -2166,7 +2170,7 @@ var P35_DestructionCreatesValue = {
2166
2170
  scope: { tags: ["entry"] },
2167
2171
  direction: "decrease",
2168
2172
  magnitude: 0.1,
2169
- reasoning: `${resource} supply at ${supply} units with low destruction (sink ${sinkVolume}/t). Resources not being consumed. Lower competitive pool entry to increase resource usage.`
2173
+ reasoning: `${resource} supply at ${supply} units with low destruction (sink ${sinkVolume}/t). Resources not being consumed. Lower pool entry to increase resource usage.`
2170
2174
  },
2171
2175
  confidence: 0.7,
2172
2176
  estimatedLag: 5
@@ -2180,7 +2184,7 @@ var P40_ReplacementRate = {
2180
2184
  id: "P40",
2181
2185
  name: "Replacement Rate \u2265 2\xD7 Consumption",
2182
2186
  category: "resource",
2183
- description: "Respawn/production rate must be at least 2\xD7 consumption rate for equilibrium. At 1\xD7 you drift toward depletion. At 2\xD7 you have a buffer for demand spikes.",
2187
+ description: "Replacement/production rate must be at least 2\xD7 consumption rate for equilibrium. At 1\xD7 you drift toward depletion. At 2\xD7 you have a buffer for demand spikes.",
2184
2188
  check(metrics, thresholds) {
2185
2189
  const { productionIndex, sinkVolume } = metrics;
2186
2190
  if (sinkVolume > 0 && productionIndex > 0) {
@@ -2547,7 +2551,7 @@ var OPEN_ECONOMY_PRINCIPLES = [
2547
2551
  ];
2548
2552
 
2549
2553
  // src/principles/operations.ts
2550
- var P51_SharkTooth = {
2554
+ var P51_CyclicalEngagement = {
2551
2555
  id: "P51",
2552
2556
  name: "Cyclical Engagement Pattern",
2553
2557
  category: "operations",
@@ -2603,7 +2607,7 @@ var P52_EndowmentEffect = {
2603
2607
  id: "P52",
2604
2608
  name: "Endowment Effect",
2605
2609
  category: "operations",
2606
- description: "Participants who never owned premium items do not value them. Free trial activities that let participants experience premium items drive conversions because ownership creates perceived value (endowment effect).",
2610
+ description: "Participants who never owned premium assets do not value them. Free trial activities that let participants experience premium assets drive conversions because ownership creates perceived value (endowment effect).",
2607
2611
  check(metrics, _thresholds) {
2608
2612
  const { avgSatisfaction, churnRate } = metrics;
2609
2613
  const { eventCompletionRate } = metrics;
@@ -2672,11 +2676,11 @@ var P53_EventCompletionRate = {
2672
2676
  return { violated: false };
2673
2677
  }
2674
2678
  };
2675
- var P54_LiveOpsCadence = {
2679
+ var P54_OperationalCadence = {
2676
2680
  id: "P54",
2677
2681
  name: "Operational Cadence",
2678
2682
  category: "operations",
2679
- description: ">50% of activities that are re-wrapped existing content \u2192 staleness. The cadence must include genuinely new content at regular intervals. This is an advisory principle \u2014 AgentE can flag but cannot fix content.",
2683
+ description: ">50% of activities that are re-wrapped existing supply \u2192 stagnation. The cadence must include genuinely new supply at regular intervals. This is an advisory principle \u2014 AgentE can flag but cannot fix supply.",
2680
2684
  check(metrics, _thresholds) {
2681
2685
  const { velocity, avgSatisfaction } = metrics;
2682
2686
  if (velocity < 2 && avgSatisfaction < 55 && metrics.tick > 100) {
@@ -2688,7 +2692,7 @@ var P54_LiveOpsCadence = {
2688
2692
  parameterType: "reward",
2689
2693
  direction: "increase",
2690
2694
  magnitude: 0.1,
2691
- reasoning: "Low velocity and satisfaction after long runtime. Possible content staleness. Increase rewards as bridge while new content is developed (developer action required)."
2695
+ reasoning: "Low velocity and satisfaction after long runtime. Possible supply stagnation. Increase rewards as bridge while new supply is developed (developer action required)."
2692
2696
  },
2693
2697
  confidence: 0.4,
2694
2698
  estimatedLag: 30
@@ -2697,11 +2701,11 @@ var P54_LiveOpsCadence = {
2697
2701
  return { violated: false };
2698
2702
  }
2699
2703
  };
2700
- var P56_ContentDropShock = {
2704
+ var P56_SupplyShockAbsorption = {
2701
2705
  id: "P56",
2702
2706
  name: "Supply Shock Absorption",
2703
2707
  category: "operations",
2704
- description: "Every new-item injection shatters existing price equilibria \u2014 arbitrage spikes as participants re-price. Build cooldown windows for price discovery before measuring post-drop economic health.",
2708
+ description: "Every new-item injection shatters existing price equilibria \u2014 arbitrage spikes as participants re-price. Build stabilization windows for price discovery before measuring post-injection economic health.",
2705
2709
  check(metrics, thresholds) {
2706
2710
  const { contentDropAge, arbitrageIndex } = metrics;
2707
2711
  if (contentDropAge > 0 && contentDropAge <= thresholds.contentDropCooldownTicks) {
@@ -2720,7 +2724,7 @@ var P56_ContentDropShock = {
2720
2724
  scope: { tags: ["transaction"] },
2721
2725
  direction: "decrease",
2722
2726
  magnitude: 0.1,
2723
- reasoning: `Content drop ${contentDropAge} ticks ago \u2014 arbitrage at ${arbitrageIndex.toFixed(2)} exceeds post-drop max (${thresholds.postDropArbitrageMax}). Price discovery struggling. Lower trading friction temporarily.`
2727
+ reasoning: `Supply injection ${contentDropAge} ticks ago \u2014 arbitrage at ${arbitrageIndex.toFixed(2)} exceeds post-injection max (${thresholds.postDropArbitrageMax}). Price discovery struggling. Lower trading friction temporarily.`
2724
2728
  },
2725
2729
  confidence: 0.6,
2726
2730
  estimatedLag: 5
@@ -2731,11 +2735,11 @@ var P56_ContentDropShock = {
2731
2735
  }
2732
2736
  };
2733
2737
  var OPERATIONS_PRINCIPLES = [
2734
- P51_SharkTooth,
2738
+ P51_CyclicalEngagement,
2735
2739
  P52_EndowmentEffect,
2736
2740
  P53_EventCompletionRate,
2737
- P54_LiveOpsCadence,
2738
- P56_ContentDropShock
2741
+ P54_OperationalCadence,
2742
+ P56_SupplyShockAbsorption
2739
2743
  ];
2740
2744
 
2741
2745
  // src/principles/index.ts
@@ -2773,15 +2777,24 @@ var ALL_PRINCIPLES = [
2773
2777
  ];
2774
2778
 
2775
2779
  // src/Simulator.ts
2780
+ var DEFAULT_SIM_CONFIG = {
2781
+ sinkMultiplier: 0.2,
2782
+ faucetMultiplier: 0.15,
2783
+ frictionMultiplier: 0.1,
2784
+ frictionVelocityScale: 10,
2785
+ redistributionMultiplier: 0.3,
2786
+ neutralMultiplier: 0.05,
2787
+ minIterations: 100,
2788
+ maxProjectionTicks: 20
2789
+ };
2776
2790
  var Simulator = class {
2777
- constructor(registry) {
2791
+ constructor(registry, simConfig) {
2778
2792
  this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
2779
- // Cache beforeViolations for the *current* tick only (one entry max).
2780
- // Using a Map here is intentional but the cache must be bounded — we only
2781
- // care about the tick that is currently being evaluated, so we evict any
2782
- // entries whose key differs from the incoming tick.
2783
- this.beforeViolationsCache = /* @__PURE__ */ new Map();
2793
+ // Cache beforeViolations for the *current* tick only.
2794
+ this.cachedViolationsTick = -1;
2795
+ this.cachedViolations = /* @__PURE__ */ new Set();
2784
2796
  this.registry = registry;
2797
+ this.simConfig = { ...DEFAULT_SIM_CONFIG, ...simConfig };
2785
2798
  }
2786
2799
  /**
2787
2800
  * Simulate the effect of applying `action` to the current economy forward `forwardTicks`.
@@ -2805,16 +2818,13 @@ var Simulator = class {
2805
2818
  const mean = this.averageMetrics(outcomes);
2806
2819
  const netImprovement = this.checkImprovement(currentMetrics, p50, action);
2807
2820
  const tick = currentMetrics.tick;
2808
- if (this.beforeViolationsCache.size > 0 && !this.beforeViolationsCache.has(tick)) {
2809
- this.beforeViolationsCache.clear();
2810
- }
2811
- let beforeViolations = this.beforeViolationsCache.get(tick);
2812
- if (!beforeViolations) {
2813
- beforeViolations = new Set(
2821
+ if (this.cachedViolationsTick !== tick) {
2822
+ this.cachedViolations = new Set(
2814
2823
  this.diagnoser.diagnose(currentMetrics, thresholds).map((d) => d.principle.id)
2815
2824
  );
2816
- this.beforeViolationsCache.set(tick, beforeViolations);
2825
+ this.cachedViolationsTick = tick;
2817
2826
  }
2827
+ const beforeViolations = this.cachedViolations;
2818
2828
  const afterViolations = new Set(
2819
2829
  this.diagnoser.diagnose(p50, thresholds).map((d) => d.principle.id)
2820
2830
  );
@@ -2894,25 +2904,32 @@ var Simulator = class {
2894
2904
  const sign = direction === "increase" ? -1 : 1;
2895
2905
  const roleEntries = Object.entries(metrics.populationByRole).sort((a, b) => b[1] - a[1]);
2896
2906
  const dominantRoleCount = roleEntries[0]?.[1] ?? 0;
2897
- const resolvedKey = action.resolvedParameter;
2898
2907
  let impact;
2899
- if (resolvedKey && this.registry) {
2900
- impact = this.registry.getFlowImpact(resolvedKey);
2908
+ if (this.registry) {
2909
+ const resolved = this.registry.resolve(action.parameterType, action.scope);
2910
+ if (resolved) {
2911
+ impact = resolved.flowImpact;
2912
+ }
2901
2913
  }
2902
2914
  if (!impact) {
2903
2915
  impact = this.inferFlowImpact(action.parameterType);
2904
2916
  }
2917
+ const cfg = this.simConfig;
2905
2918
  switch (impact) {
2906
2919
  case "sink":
2907
- return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.2;
2920
+ return sign * (metrics.netFlowByCurrency[currency] ?? 0) * cfg.sinkMultiplier;
2908
2921
  case "faucet":
2909
- return -sign * dominantRoleCount * 0.3;
2922
+ return -sign * dominantRoleCount * cfg.redistributionMultiplier;
2910
2923
  case "neutral":
2911
- return sign * dominantRoleCount * 0.5;
2924
+ return sign * dominantRoleCount * cfg.neutralMultiplier;
2912
2925
  case "mixed":
2913
- return sign * (metrics.faucetVolumeByCurrency[currency] ?? 0) * 0.15;
2926
+ return sign * (metrics.faucetVolumeByCurrency[currency] ?? 0) * cfg.faucetMultiplier;
2927
+ case "friction":
2928
+ return sign * (metrics.netFlowByCurrency[currency] ?? 0) * cfg.frictionMultiplier;
2929
+ case "redistribution":
2930
+ return sign * dominantRoleCount * cfg.neutralMultiplier;
2914
2931
  default:
2915
- return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
2932
+ return sign * (metrics.netFlowByCurrency[currency] ?? 0) * cfg.frictionMultiplier;
2916
2933
  }
2917
2934
  }
2918
2935
  /** Infer flow impact from parameter type when registry is unavailable */
@@ -2933,7 +2950,7 @@ var Simulator = class {
2933
2950
  return "mixed";
2934
2951
  }
2935
2952
  }
2936
- checkImprovement(before, after, action) {
2953
+ checkImprovement(before, after, _action) {
2937
2954
  const satisfactionImproved = after.avgSatisfaction >= before.avgSatisfaction - 2;
2938
2955
  const flowMoreBalanced = before.currencies.every((curr) => {
2939
2956
  const afterFlow = Math.abs(after.netFlowByCurrency[curr] ?? 0);
@@ -2945,7 +2962,6 @@ var Simulator = class {
2945
2962
  const beforeGini = before.giniCoefficientByCurrency[curr] ?? 0;
2946
2963
  return afterGini <= beforeGini + 0.05;
2947
2964
  });
2948
- void action;
2949
2965
  return satisfactionImproved && flowMoreBalanced && notWorseGini;
2950
2966
  }
2951
2967
  averageMetrics(outcomes) {
@@ -2993,6 +3009,8 @@ var Planner = class {
2993
3009
  this.constraints = /* @__PURE__ */ new Map();
2994
3010
  this.cooldowns = /* @__PURE__ */ new Map();
2995
3011
  // param → last-applied-tick
3012
+ this.typeCooldowns = /* @__PURE__ */ new Map();
3013
+ // type+scope key → last-applied-tick
2996
3014
  this.activePlanCount = 0;
2997
3015
  }
2998
3016
  lock(param) {
@@ -3015,6 +3033,8 @@ var Planner = class {
3015
3033
  */
3016
3034
  plan(diagnosis, metrics, simulationResult, currentParams, thresholds, registry) {
3017
3035
  const action = diagnosis.violation.suggestedAction;
3036
+ const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
3037
+ if (this.isTypeCooldown(typeKey, metrics.tick, thresholds.cooldownTicks)) return null;
3018
3038
  let param;
3019
3039
  let resolvedBaseline;
3020
3040
  let scope;
@@ -3072,6 +3092,9 @@ var Planner = class {
3072
3092
  }
3073
3093
  recordApplied(plan, tick) {
3074
3094
  this.cooldowns.set(plan.parameter, tick);
3095
+ const action = plan.diagnosis.violation.suggestedAction;
3096
+ const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
3097
+ this.typeCooldowns.set(typeKey, tick);
3075
3098
  this.activePlanCount++;
3076
3099
  }
3077
3100
  recordRolledBack(_plan) {
@@ -3088,13 +3111,35 @@ var Planner = class {
3088
3111
  /** Reset all cooldowns (useful for testing) */
3089
3112
  resetCooldowns() {
3090
3113
  this.cooldowns.clear();
3114
+ this.typeCooldowns.clear();
3115
+ }
3116
+ /** V1.5.2: Reset active plan count (e.g., on system restart) */
3117
+ resetActivePlans() {
3118
+ this.activePlanCount = 0;
3119
+ }
3120
+ /** V1.5.2: Current active plan count (for diagnostics) */
3121
+ getActivePlanCount() {
3122
+ return this.activePlanCount;
3123
+ }
3124
+ typeCooldownKey(type, scope) {
3125
+ const parts = [type];
3126
+ if (scope?.system) parts.push(`sys:${scope.system}`);
3127
+ if (scope?.currency) parts.push(`cur:${scope.currency}`);
3128
+ if (scope?.tags?.length) parts.push(`tags:${scope.tags.sort().join(",")}`);
3129
+ return parts.join("|");
3130
+ }
3131
+ isTypeCooldown(typeKey, currentTick, cooldownTicks) {
3132
+ const lastApplied = this.typeCooldowns.get(typeKey);
3133
+ if (lastApplied === void 0) return false;
3134
+ return currentTick - lastApplied < cooldownTicks;
3091
3135
  }
3092
3136
  };
3093
3137
 
3094
3138
  // src/Executor.ts
3095
3139
  var Executor = class {
3096
- constructor() {
3140
+ constructor(settlementWindowTicks = 200) {
3097
3141
  this.activePlans = [];
3142
+ this.maxActiveTicks = settlementWindowTicks;
3098
3143
  }
3099
3144
  async apply(plan, adapter, currentParams) {
3100
3145
  const originalValue = currentParams[plan.parameter] ?? plan.currentValue;
@@ -3113,8 +3158,7 @@ var Executor = class {
3113
3158
  for (const active of this.activePlans) {
3114
3159
  const { plan, originalValue } = active;
3115
3160
  const rc = plan.rollbackCondition;
3116
- const maxActiveTicks = 200;
3117
- if (plan.appliedAt !== void 0 && metrics.tick - plan.appliedAt > maxActiveTicks) {
3161
+ if (plan.appliedAt !== void 0 && metrics.tick - plan.appliedAt > this.maxActiveTicks) {
3118
3162
  settled.push(plan);
3119
3163
  continue;
3120
3164
  }
@@ -3181,9 +3225,9 @@ var DecisionLog = class {
3181
3225
  reasoning: this.buildReasoning(diagnosis, plan, result),
3182
3226
  metricsSnapshot: metrics
3183
3227
  };
3184
- this.entries.unshift(entry);
3185
- if (this.entries.length > this.maxEntries) {
3186
- this.entries.pop();
3228
+ this.entries.push(entry);
3229
+ if (this.entries.length > this.maxEntries * 1.5) {
3230
+ this.entries = this.entries.slice(-this.maxEntries);
3187
3231
  }
3188
3232
  return entry;
3189
3233
  }
@@ -3198,8 +3242,10 @@ var DecisionLog = class {
3198
3242
  reasoning: reason,
3199
3243
  metricsSnapshot: metrics
3200
3244
  };
3201
- this.entries.unshift(entry);
3202
- if (this.entries.length > this.maxEntries) this.entries.pop();
3245
+ this.entries.push(entry);
3246
+ if (this.entries.length > this.maxEntries * 1.5) {
3247
+ this.entries = this.entries.slice(-this.maxEntries);
3248
+ }
3203
3249
  }
3204
3250
  query(filter) {
3205
3251
  return this.entries.filter((e) => {
@@ -3212,7 +3258,7 @@ var DecisionLog = class {
3212
3258
  });
3213
3259
  }
3214
3260
  latest(n = 30) {
3215
- return this.entries.slice(0, n);
3261
+ return this.entries.slice(-n).reverse();
3216
3262
  }
3217
3263
  export(format = "json") {
3218
3264
  if (format === "text") {
@@ -3441,10 +3487,13 @@ var MetricStore = class {
3441
3487
  var PersonaTracker = class {
3442
3488
  constructor() {
3443
3489
  this.agentHistory = /* @__PURE__ */ new Map();
3490
+ this.lastSeen = /* @__PURE__ */ new Map();
3444
3491
  }
3445
3492
  /** Ingest a state snapshot and update agent signal history */
3446
3493
  update(state) {
3494
+ const tick = state.tick;
3447
3495
  for (const agentId of Object.keys(state.agentBalances)) {
3496
+ this.lastSeen.set(agentId, tick);
3448
3497
  const history = this.agentHistory.get(agentId) ?? [];
3449
3498
  const inv = state.agentInventories[agentId] ?? {};
3450
3499
  const uniqueItems = Object.values(inv).filter((q) => q > 0).length;
@@ -3462,6 +3511,14 @@ var PersonaTracker = class {
3462
3511
  if (history.length > 50) history.shift();
3463
3512
  this.agentHistory.set(agentId, history);
3464
3513
  }
3514
+ if (tick % 50 === 0) {
3515
+ for (const [id, lastTick] of this.lastSeen) {
3516
+ if (tick - lastTick > 100) {
3517
+ this.agentHistory.delete(id);
3518
+ this.lastSeen.delete(id);
3519
+ }
3520
+ }
3521
+ }
3465
3522
  }
3466
3523
  /** Classify all agents and return persona distribution */
3467
3524
  getDistribution() {
@@ -3525,25 +3582,30 @@ var ParameterRegistry = class {
3525
3582
  * Resolve a parameterType + scope to a concrete RegisteredParameter.
3526
3583
  * Returns the best match, or undefined if no match.
3527
3584
  *
3528
- * Matching rules (in priority order):
3529
- * 1. Exact type match + all scope fields match
3530
- * 2. Exact type match + partial scope match (tags overlap)
3531
- * 3. Exact type match + no scope constraints
3532
- * 4. undefined (no match)
3585
+ * Matching rules:
3586
+ * 1. Filter candidates by type
3587
+ * 2. Score each by scope specificity (system +10, currency +5, tags +3 each)
3588
+ * 3. Mismatched scope fields disqualify (score = -Infinity)
3589
+ * 4. Ties broken by `priority` (higher wins), then registration order
3590
+ * 5. All disqualified → undefined
3533
3591
  */
3534
3592
  resolve(type, scope) {
3535
3593
  const candidates = this.findByType(type);
3536
3594
  if (candidates.length === 0) return void 0;
3537
3595
  if (candidates.length === 1) return candidates[0];
3538
- let bestScore = -1;
3596
+ let bestScore = -Infinity;
3597
+ let bestPriority = -Infinity;
3539
3598
  let best;
3540
3599
  for (const candidate of candidates) {
3541
- const score = this.scopeMatchScore(candidate.scope, scope);
3542
- if (score > bestScore) {
3600
+ const score = this.scopeSpecificity(candidate.scope, scope);
3601
+ const prio = candidate.priority ?? 0;
3602
+ if (score > bestScore || score === bestScore && prio > bestPriority) {
3543
3603
  bestScore = score;
3604
+ bestPriority = prio;
3544
3605
  best = candidate;
3545
3606
  }
3546
3607
  }
3608
+ if (bestScore === -Infinity) return void 0;
3547
3609
  return best;
3548
3610
  }
3549
3611
  /** Find all parameters of a given type. */
@@ -3585,28 +3647,60 @@ var ParameterRegistry = class {
3585
3647
  get size() {
3586
3648
  return this.parameters.size;
3587
3649
  }
3650
+ /**
3651
+ * Validate the registry for common misconfigurations.
3652
+ * Returns warnings (non-fatal) and errors (likely broken).
3653
+ */
3654
+ validate() {
3655
+ const warnings = [];
3656
+ const errors = [];
3657
+ const typeMap = /* @__PURE__ */ new Map();
3658
+ for (const param of this.parameters.values()) {
3659
+ const list = typeMap.get(param.type) ?? [];
3660
+ list.push(param);
3661
+ typeMap.set(param.type, list);
3662
+ }
3663
+ for (const [type, params] of typeMap) {
3664
+ if (params.length > 1) {
3665
+ const unscopedCount = params.filter((p) => !p.scope).length;
3666
+ if (unscopedCount > 1) {
3667
+ errors.push(
3668
+ `Type '${type}' has ${unscopedCount} unscoped parameters \u2014 resolve() cannot distinguish them`
3669
+ );
3670
+ }
3671
+ }
3672
+ }
3673
+ for (const param of this.parameters.values()) {
3674
+ if (!param.flowImpact) {
3675
+ warnings.push(`Parameter '${param.key}' has no flowImpact \u2014 Simulator will use inference`);
3676
+ }
3677
+ }
3678
+ return {
3679
+ valid: errors.length === 0,
3680
+ warnings,
3681
+ errors
3682
+ };
3683
+ }
3588
3684
  // ── Private ─────────────────────────────────────────────────────────────
3589
- scopeMatchScore(paramScope, queryScope) {
3685
+ scopeSpecificity(paramScope, queryScope) {
3590
3686
  if (!queryScope) return 0;
3591
3687
  if (!paramScope) return 0;
3592
3688
  let score = 0;
3593
3689
  if (queryScope.system && paramScope.system) {
3594
3690
  if (queryScope.system === paramScope.system) score += 10;
3595
- else return -1;
3691
+ else return -Infinity;
3596
3692
  }
3597
3693
  if (queryScope.currency && paramScope.currency) {
3598
3694
  if (queryScope.currency === paramScope.currency) score += 5;
3599
- else return -1;
3695
+ else return -Infinity;
3600
3696
  }
3601
3697
  if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
3602
3698
  const overlap = queryScope.tags.filter((t) => paramScope.tags.includes(t)).length;
3603
3699
  if (overlap > 0) {
3604
3700
  score += overlap * 3;
3605
3701
  } else {
3606
- return -1;
3702
+ return -Infinity;
3607
3703
  }
3608
- } else if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
3609
- return -1;
3610
3704
  }
3611
3705
  return score;
3612
3706
  }
@@ -3616,7 +3710,6 @@ var ParameterRegistry = class {
3616
3710
  var AgentE = class {
3617
3711
  constructor(config) {
3618
3712
  this.planner = new Planner();
3619
- this.executor = new Executor();
3620
3713
  this.registry = new ParameterRegistry();
3621
3714
  // ── State ──
3622
3715
  this.log = new DecisionLog();
@@ -3638,6 +3731,9 @@ var AgentE = class {
3638
3731
  mode: this.mode,
3639
3732
  dominantRoles: config.dominantRoles ?? [],
3640
3733
  idealDistribution: config.idealDistribution ?? {},
3734
+ validateRegistry: config.validateRegistry ?? true,
3735
+ simulation: config.simulation ?? {},
3736
+ settlementWindowTicks: config.settlementWindowTicks ?? 200,
3641
3737
  tickConfig: config.tickConfig ?? { duration: 1, unit: "tick" },
3642
3738
  gracePeriod: config.gracePeriod ?? 50,
3643
3739
  checkInterval: config.checkInterval ?? 5,
@@ -3658,7 +3754,13 @@ var AgentE = class {
3658
3754
  if (config.parameters) {
3659
3755
  this.registry.registerAll(config.parameters);
3660
3756
  }
3661
- this.simulator = new Simulator(this.registry);
3757
+ if (config.validateRegistry !== false && this.registry.size > 0) {
3758
+ const validation = this.registry.validate();
3759
+ for (const w of validation.warnings) console.warn(`[AgentE] Registry warning: ${w}`);
3760
+ for (const e of validation.errors) console.error(`[AgentE] Registry error: ${e}`);
3761
+ }
3762
+ this.executor = new Executor(config.settlementWindowTicks);
3763
+ this.simulator = new Simulator(this.registry, config.simulation);
3662
3764
  if (config.onDecision) this.on("decision", config.onDecision);
3663
3765
  if (config.onAlert) this.on("alert", config.onAlert);
3664
3766
  if (config.onRollback) this.on("rollback", config.onRollback);
@@ -3694,7 +3796,7 @@ var AgentE = class {
3694
3796
  if (!this.isRunning || this.isPaused) return;
3695
3797
  const currentState = state ?? await Promise.resolve(this.adapter.getState());
3696
3798
  this.currentTick = currentState.tick;
3697
- const events = [...this.eventBuffer];
3799
+ const events = this.eventBuffer;
3698
3800
  this.eventBuffer = [];
3699
3801
  let metrics;
3700
3802
  try {
@@ -3812,7 +3914,9 @@ var AgentE = class {
3812
3914
  // ── Events ──────────────────────────────────────────────────────────────────
3813
3915
  on(event, handler) {
3814
3916
  const list = this.handlers.get(event) ?? [];
3815
- list.push(handler);
3917
+ if (!list.includes(handler)) {
3918
+ list.push(handler);
3919
+ }
3816
3920
  this.handlers.set(event, list);
3817
3921
  return this;
3818
3922
  }
@@ -3825,8 +3929,12 @@ var AgentE = class {
3825
3929
  const list = this.handlers.get(event) ?? [];
3826
3930
  let result;
3827
3931
  for (const handler of list) {
3828
- result = handler(...args);
3829
- if (result === false) return false;
3932
+ try {
3933
+ result = handler(...args);
3934
+ if (result === false) return false;
3935
+ } catch (err) {
3936
+ console.error(`[AgentE] Handler error on '${event}':`, err);
3937
+ }
3830
3938
  }
3831
3939
  return result;
3832
3940
  }
@@ -3854,6 +3962,31 @@ var AgentE = class {
3854
3962
  }
3855
3963
  };
3856
3964
 
3965
+ // src/utils.ts
3966
+ function findWorstSystem(metrics, check, tolerancePercent = 0) {
3967
+ const systems = metrics.systems;
3968
+ if (systems.length === 0) return void 0;
3969
+ let worstSystem;
3970
+ let worstScore = -Infinity;
3971
+ let totalScore = 0;
3972
+ for (const sys of systems) {
3973
+ const score = check(sys, metrics);
3974
+ totalScore += score;
3975
+ if (score > worstScore) {
3976
+ worstScore = score;
3977
+ worstSystem = sys;
3978
+ }
3979
+ }
3980
+ if (!worstSystem) return void 0;
3981
+ if (tolerancePercent > 0 && systems.length > 1) {
3982
+ const avg = totalScore / systems.length;
3983
+ if (avg === 0) return { system: worstSystem, score: worstScore };
3984
+ const excessPercent = (worstScore - avg) / Math.abs(avg) * 100;
3985
+ if (excessPercent < tolerancePercent) return void 0;
3986
+ }
3987
+ return { system: worstSystem, score: worstScore };
3988
+ }
3989
+
3857
3990
  // src/StateValidator.ts
3858
3991
  function validateEconomyState(state) {
3859
3992
  const errors = [];
@@ -4204,7 +4337,7 @@ export {
4204
4337
  OPEN_ECONOMY_PRINCIPLES,
4205
4338
  OPERATIONS_PRINCIPLES,
4206
4339
  Observer,
4207
- P10_SpawnWeightingUsesInversePopulation,
4340
+ P10_EntryWeightingUsesInversePopulation,
4208
4341
  P11_TwoTierPressure,
4209
4342
  P12_OnePrimaryFaucet,
4210
4343
  P13_PotsAreZeroSumAndSelfRegulate,
@@ -4224,9 +4357,9 @@ export {
4224
4357
  P26_ContinuousPressureBeatsThresholdCuts,
4225
4358
  P27_AdjustmentsNeedCooldowns,
4226
4359
  P28_StructuralDominanceIsNotPathological,
4227
- P29_PinchPoint,
4360
+ P29_BottleneckDetection,
4228
4361
  P2_ClosedLoopsNeedDirectHandoff,
4229
- P30_MovingPinchPoint,
4362
+ P30_DynamicBottleneckRotation,
4230
4363
  P31_AnchorValueTracking,
4231
4364
  P32_VelocityAboveSupply,
4232
4365
  P33_FairNotEqual,
@@ -4249,16 +4382,16 @@ export {
4249
4382
  P49_IdleAssetTax,
4250
4383
  P4_MaterialsFlowFasterThanCooldown,
4251
4384
  P50_PayPowerRatio,
4252
- P51_SharkTooth,
4385
+ P51_CyclicalEngagement,
4253
4386
  P52_EndowmentEffect,
4254
4387
  P53_EventCompletionRate,
4255
- P54_LiveOpsCadence,
4388
+ P54_OperationalCadence,
4256
4389
  P55_ArbitrageThermometer,
4257
- P56_ContentDropShock,
4390
+ P56_SupplyShockAbsorption,
4258
4391
  P57_CombinatorialPriceSpace,
4259
4392
  P58_NoNaturalNumeraire,
4260
4393
  P59_GiftEconomyNoise,
4261
- P5_ProfitabilityIsCompetitive,
4394
+ P5_ProfitabilityIsRelative,
4262
4395
  P60_SurplusDisposalAsymmetry,
4263
4396
  P6_CrowdingMultiplierOnAllRoles,
4264
4397
  P7_NonSpecialistsSubsidiseSpecialists,
@@ -4277,6 +4410,7 @@ export {
4277
4410
  SYSTEM_DYNAMICS_PRINCIPLES,
4278
4411
  Simulator,
4279
4412
  emptyMetrics,
4413
+ findWorstSystem,
4280
4414
  validateEconomyState
4281
4415
  };
4282
4416
  //# sourceMappingURL=index.mjs.map