@agent-e/core 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -140,7 +140,7 @@ var Observer = class {
140
140
  if (!actorsBySystem[e.system]) actorsBySystem[e.system] = /* @__PURE__ */ new Set();
141
141
  actorsBySystem[e.system].add(e.actor);
142
142
  const amt = e.amount ?? 0;
143
- if (e.type === "mint" || e.type === "enter") {
143
+ if (e.type === "mint") {
144
144
  flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) + amt;
145
145
  } else if (e.type === "burn" || e.type === "consume") {
146
146
  flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) - amt;
@@ -148,7 +148,7 @@ var Observer = class {
148
148
  }
149
149
  if (e.sourceOrSink) {
150
150
  const amt = e.amount ?? 0;
151
- if (e.type === "mint" || e.type === "enter") {
151
+ if (e.type === "mint") {
152
152
  flowBySource[e.sourceOrSink] = (flowBySource[e.sourceOrSink] ?? 0) + amt;
153
153
  } else if (e.type === "burn" || e.type === "consume") {
154
154
  flowBySink[e.sourceOrSink] = (flowBySink[e.sourceOrSink] ?? 0) + amt;
@@ -456,6 +456,9 @@ var Observer = class {
456
456
  sharkToothValleys: this.previousMetrics?.sharkToothValleys ?? [],
457
457
  eventCompletionRate: NaN,
458
458
  contentDropAge,
459
+ systems: state.systems ?? [],
460
+ sources: state.sources ?? [],
461
+ sinks: state.sinks ?? [],
459
462
  flowBySystem,
460
463
  activityBySystem,
461
464
  participantsBySystem,
@@ -605,6 +608,9 @@ function emptyMetrics(tick = 0) {
605
608
  sharkToothValleys: [],
606
609
  eventCompletionRate: NaN,
607
610
  contentDropAge: 0,
611
+ systems: [],
612
+ sources: [],
613
+ sinks: [],
608
614
  flowBySystem: {},
609
615
  activityBySystem: {},
610
616
  participantsBySystem: {},
@@ -943,7 +949,7 @@ var P9_RoleSwitchingNeedsFriction = {
943
949
  id: "P9",
944
950
  name: "Role Switching Needs Friction",
945
951
  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.",
952
+ 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
953
  check(metrics, thresholds) {
948
954
  const { churnByRole, roleShares } = metrics;
949
955
  const totalChurn = Object.values(churnByRole).reduce((s, v) => s + v, 0);
@@ -966,7 +972,7 @@ var P9_RoleSwitchingNeedsFriction = {
966
972
  return { violated: false };
967
973
  }
968
974
  };
969
- var P10_SpawnWeightingUsesInversePopulation = {
975
+ var P10_EntryWeightingUsesInversePopulation = {
970
976
  id: "P10",
971
977
  name: "Entry Weighting Uses Inverse Population",
972
978
  category: "population",
@@ -1072,7 +1078,7 @@ var P46_PersonaDiversity = {
1072
1078
  };
1073
1079
  var POPULATION_PRINCIPLES = [
1074
1080
  P9_RoleSwitchingNeedsFriction,
1075
- P10_SpawnWeightingUsesInversePopulation,
1081
+ P10_EntryWeightingUsesInversePopulation,
1076
1082
  P11_TwoTierPressure,
1077
1083
  P46_PersonaDiversity
1078
1084
  ];
@@ -1163,7 +1169,7 @@ var P14_TrackActualInjection = {
1163
1169
  id: "P14",
1164
1170
  name: "Track Actual Currency Injection, Not Value Creation",
1165
1171
  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.',
1172
+ description: 'Counting resource extraction as "currency injected" is misleading. Currency enters through faucet mechanisms (entering, rewards). Fake metrics break every downstream decision.',
1167
1173
  check(metrics, _thresholds) {
1168
1174
  for (const curr of metrics.currencies) {
1169
1175
  const faucetVolume = metrics.faucetVolumeByCurrency[curr] ?? 0;
@@ -1751,7 +1757,7 @@ var REGULATOR_PRINCIPLES = [
1751
1757
  ];
1752
1758
 
1753
1759
  // src/principles/market-dynamics.ts
1754
- var P29_PinchPoint = {
1760
+ var P29_BottleneckDetection = {
1755
1761
  id: "P29",
1756
1762
  name: "Bottleneck Detection",
1757
1763
  category: "market_dynamics",
@@ -1796,7 +1802,7 @@ var P29_PinchPoint = {
1796
1802
  return { violated: false };
1797
1803
  }
1798
1804
  };
1799
- var P30_MovingPinchPoint = {
1805
+ var P30_DynamicBottleneckRotation = {
1800
1806
  id: "P30",
1801
1807
  name: "Dynamic Bottleneck Rotation",
1802
1808
  category: "market_dynamics",
@@ -1871,8 +1877,8 @@ var P57_CombinatorialPriceSpace = {
1871
1877
  }
1872
1878
  };
1873
1879
  var MARKET_DYNAMICS_PRINCIPLES = [
1874
- P29_PinchPoint,
1875
- P30_MovingPinchPoint,
1880
+ P29_BottleneckDetection,
1881
+ P30_DynamicBottleneckRotation,
1876
1882
  P57_CombinatorialPriceSpace
1877
1883
  ];
1878
1884
 
@@ -2180,7 +2186,7 @@ var P40_ReplacementRate = {
2180
2186
  id: "P40",
2181
2187
  name: "Replacement Rate \u2265 2\xD7 Consumption",
2182
2188
  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.",
2189
+ 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
2190
  check(metrics, thresholds) {
2185
2191
  const { productionIndex, sinkVolume } = metrics;
2186
2192
  if (sinkVolume > 0 && productionIndex > 0) {
@@ -2547,7 +2553,7 @@ var OPEN_ECONOMY_PRINCIPLES = [
2547
2553
  ];
2548
2554
 
2549
2555
  // src/principles/operations.ts
2550
- var P51_SharkTooth = {
2556
+ var P51_CyclicalEngagement = {
2551
2557
  id: "P51",
2552
2558
  name: "Cyclical Engagement Pattern",
2553
2559
  category: "operations",
@@ -2603,7 +2609,7 @@ var P52_EndowmentEffect = {
2603
2609
  id: "P52",
2604
2610
  name: "Endowment Effect",
2605
2611
  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).",
2612
+ 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
2613
  check(metrics, _thresholds) {
2608
2614
  const { avgSatisfaction, churnRate } = metrics;
2609
2615
  const { eventCompletionRate } = metrics;
@@ -2672,11 +2678,11 @@ var P53_EventCompletionRate = {
2672
2678
  return { violated: false };
2673
2679
  }
2674
2680
  };
2675
- var P54_LiveOpsCadence = {
2681
+ var P54_OperationalCadence = {
2676
2682
  id: "P54",
2677
2683
  name: "Operational Cadence",
2678
2684
  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.",
2685
+ 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
2686
  check(metrics, _thresholds) {
2681
2687
  const { velocity, avgSatisfaction } = metrics;
2682
2688
  if (velocity < 2 && avgSatisfaction < 55 && metrics.tick > 100) {
@@ -2688,7 +2694,7 @@ var P54_LiveOpsCadence = {
2688
2694
  parameterType: "reward",
2689
2695
  direction: "increase",
2690
2696
  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)."
2697
+ reasoning: "Low velocity and satisfaction after long runtime. Possible supply stagnation. Increase rewards as bridge while new supply is developed (developer action required)."
2692
2698
  },
2693
2699
  confidence: 0.4,
2694
2700
  estimatedLag: 30
@@ -2697,11 +2703,11 @@ var P54_LiveOpsCadence = {
2697
2703
  return { violated: false };
2698
2704
  }
2699
2705
  };
2700
- var P56_ContentDropShock = {
2706
+ var P56_SupplyShockAbsorption = {
2701
2707
  id: "P56",
2702
2708
  name: "Supply Shock Absorption",
2703
2709
  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.",
2710
+ 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
2711
  check(metrics, thresholds) {
2706
2712
  const { contentDropAge, arbitrageIndex } = metrics;
2707
2713
  if (contentDropAge > 0 && contentDropAge <= thresholds.contentDropCooldownTicks) {
@@ -2720,7 +2726,7 @@ var P56_ContentDropShock = {
2720
2726
  scope: { tags: ["transaction"] },
2721
2727
  direction: "decrease",
2722
2728
  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.`
2729
+ 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
2730
  },
2725
2731
  confidence: 0.6,
2726
2732
  estimatedLag: 5
@@ -2731,11 +2737,11 @@ var P56_ContentDropShock = {
2731
2737
  }
2732
2738
  };
2733
2739
  var OPERATIONS_PRINCIPLES = [
2734
- P51_SharkTooth,
2740
+ P51_CyclicalEngagement,
2735
2741
  P52_EndowmentEffect,
2736
2742
  P53_EventCompletionRate,
2737
- P54_LiveOpsCadence,
2738
- P56_ContentDropShock
2743
+ P54_OperationalCadence,
2744
+ P56_SupplyShockAbsorption
2739
2745
  ];
2740
2746
 
2741
2747
  // src/principles/index.ts
@@ -2894,10 +2900,12 @@ var Simulator = class {
2894
2900
  const sign = direction === "increase" ? -1 : 1;
2895
2901
  const roleEntries = Object.entries(metrics.populationByRole).sort((a, b) => b[1] - a[1]);
2896
2902
  const dominantRoleCount = roleEntries[0]?.[1] ?? 0;
2897
- const resolvedKey = action.resolvedParameter;
2898
2903
  let impact;
2899
- if (resolvedKey && this.registry) {
2900
- impact = this.registry.getFlowImpact(resolvedKey);
2904
+ if (this.registry) {
2905
+ const resolved = this.registry.resolve(action.parameterType, action.scope);
2906
+ if (resolved) {
2907
+ impact = resolved.flowImpact;
2908
+ }
2901
2909
  }
2902
2910
  if (!impact) {
2903
2911
  impact = this.inferFlowImpact(action.parameterType);
@@ -2911,6 +2919,10 @@ var Simulator = class {
2911
2919
  return sign * dominantRoleCount * 0.5;
2912
2920
  case "mixed":
2913
2921
  return sign * (metrics.faucetVolumeByCurrency[currency] ?? 0) * 0.15;
2922
+ case "friction":
2923
+ return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
2924
+ case "redistribution":
2925
+ return sign * dominantRoleCount * 0.05;
2914
2926
  default:
2915
2927
  return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
2916
2928
  }
@@ -2993,6 +3005,8 @@ var Planner = class {
2993
3005
  this.constraints = /* @__PURE__ */ new Map();
2994
3006
  this.cooldowns = /* @__PURE__ */ new Map();
2995
3007
  // param → last-applied-tick
3008
+ this.typeCooldowns = /* @__PURE__ */ new Map();
3009
+ // type+scope key → last-applied-tick
2996
3010
  this.activePlanCount = 0;
2997
3011
  }
2998
3012
  lock(param) {
@@ -3015,6 +3029,8 @@ var Planner = class {
3015
3029
  */
3016
3030
  plan(diagnosis, metrics, simulationResult, currentParams, thresholds, registry) {
3017
3031
  const action = diagnosis.violation.suggestedAction;
3032
+ const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
3033
+ if (this.isTypeCooldown(typeKey, metrics.tick, thresholds.cooldownTicks)) return null;
3018
3034
  let param;
3019
3035
  let resolvedBaseline;
3020
3036
  let scope;
@@ -3072,6 +3088,9 @@ var Planner = class {
3072
3088
  }
3073
3089
  recordApplied(plan, tick) {
3074
3090
  this.cooldowns.set(plan.parameter, tick);
3091
+ const action = plan.diagnosis.violation.suggestedAction;
3092
+ const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
3093
+ this.typeCooldowns.set(typeKey, tick);
3075
3094
  this.activePlanCount++;
3076
3095
  }
3077
3096
  recordRolledBack(_plan) {
@@ -3088,6 +3107,19 @@ var Planner = class {
3088
3107
  /** Reset all cooldowns (useful for testing) */
3089
3108
  resetCooldowns() {
3090
3109
  this.cooldowns.clear();
3110
+ this.typeCooldowns.clear();
3111
+ }
3112
+ typeCooldownKey(type, scope) {
3113
+ const parts = [type];
3114
+ if (scope?.system) parts.push(`sys:${scope.system}`);
3115
+ if (scope?.currency) parts.push(`cur:${scope.currency}`);
3116
+ if (scope?.tags?.length) parts.push(`tags:${scope.tags.sort().join(",")}`);
3117
+ return parts.join("|");
3118
+ }
3119
+ isTypeCooldown(typeKey, currentTick, cooldownTicks) {
3120
+ const lastApplied = this.typeCooldowns.get(typeKey);
3121
+ if (lastApplied === void 0) return false;
3122
+ return currentTick - lastApplied < cooldownTicks;
3091
3123
  }
3092
3124
  };
3093
3125
 
@@ -3525,25 +3557,30 @@ var ParameterRegistry = class {
3525
3557
  * Resolve a parameterType + scope to a concrete RegisteredParameter.
3526
3558
  * Returns the best match, or undefined if no match.
3527
3559
  *
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)
3560
+ * Matching rules:
3561
+ * 1. Filter candidates by type
3562
+ * 2. Score each by scope specificity (system +10, currency +5, tags +3 each)
3563
+ * 3. Mismatched scope fields disqualify (score = -Infinity)
3564
+ * 4. Ties broken by `priority` (higher wins), then registration order
3565
+ * 5. All disqualified → undefined
3533
3566
  */
3534
3567
  resolve(type, scope) {
3535
3568
  const candidates = this.findByType(type);
3536
3569
  if (candidates.length === 0) return void 0;
3537
3570
  if (candidates.length === 1) return candidates[0];
3538
- let bestScore = -1;
3571
+ let bestScore = -Infinity;
3572
+ let bestPriority = -Infinity;
3539
3573
  let best;
3540
3574
  for (const candidate of candidates) {
3541
- const score = this.scopeMatchScore(candidate.scope, scope);
3542
- if (score > bestScore) {
3575
+ const score = this.scopeSpecificity(candidate.scope, scope);
3576
+ const prio = candidate.priority ?? 0;
3577
+ if (score > bestScore || score === bestScore && prio > bestPriority) {
3543
3578
  bestScore = score;
3579
+ bestPriority = prio;
3544
3580
  best = candidate;
3545
3581
  }
3546
3582
  }
3583
+ if (bestScore === -Infinity) return void 0;
3547
3584
  return best;
3548
3585
  }
3549
3586
  /** Find all parameters of a given type. */
@@ -3585,28 +3622,60 @@ var ParameterRegistry = class {
3585
3622
  get size() {
3586
3623
  return this.parameters.size;
3587
3624
  }
3625
+ /**
3626
+ * Validate the registry for common misconfigurations.
3627
+ * Returns warnings (non-fatal) and errors (likely broken).
3628
+ */
3629
+ validate() {
3630
+ const warnings = [];
3631
+ const errors = [];
3632
+ const typeMap = /* @__PURE__ */ new Map();
3633
+ for (const param of this.parameters.values()) {
3634
+ const list = typeMap.get(param.type) ?? [];
3635
+ list.push(param);
3636
+ typeMap.set(param.type, list);
3637
+ }
3638
+ for (const [type, params] of typeMap) {
3639
+ if (params.length > 1) {
3640
+ const unscopedCount = params.filter((p) => !p.scope).length;
3641
+ if (unscopedCount > 1) {
3642
+ errors.push(
3643
+ `Type '${type}' has ${unscopedCount} unscoped parameters \u2014 resolve() cannot distinguish them`
3644
+ );
3645
+ }
3646
+ }
3647
+ }
3648
+ for (const param of this.parameters.values()) {
3649
+ if (!param.flowImpact) {
3650
+ warnings.push(`Parameter '${param.key}' has no flowImpact \u2014 Simulator will use inference`);
3651
+ }
3652
+ }
3653
+ return {
3654
+ valid: errors.length === 0,
3655
+ warnings,
3656
+ errors
3657
+ };
3658
+ }
3588
3659
  // ── Private ─────────────────────────────────────────────────────────────
3589
- scopeMatchScore(paramScope, queryScope) {
3660
+ scopeSpecificity(paramScope, queryScope) {
3590
3661
  if (!queryScope) return 0;
3591
3662
  if (!paramScope) return 0;
3592
3663
  let score = 0;
3593
3664
  if (queryScope.system && paramScope.system) {
3594
3665
  if (queryScope.system === paramScope.system) score += 10;
3595
- else return -1;
3666
+ else return -Infinity;
3596
3667
  }
3597
3668
  if (queryScope.currency && paramScope.currency) {
3598
3669
  if (queryScope.currency === paramScope.currency) score += 5;
3599
- else return -1;
3670
+ else return -Infinity;
3600
3671
  }
3601
3672
  if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
3602
3673
  const overlap = queryScope.tags.filter((t) => paramScope.tags.includes(t)).length;
3603
3674
  if (overlap > 0) {
3604
3675
  score += overlap * 3;
3605
3676
  } else {
3606
- return -1;
3677
+ return -Infinity;
3607
3678
  }
3608
- } else if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
3609
- return -1;
3610
3679
  }
3611
3680
  return score;
3612
3681
  }
@@ -3638,6 +3707,7 @@ var AgentE = class {
3638
3707
  mode: this.mode,
3639
3708
  dominantRoles: config.dominantRoles ?? [],
3640
3709
  idealDistribution: config.idealDistribution ?? {},
3710
+ validateRegistry: config.validateRegistry ?? true,
3641
3711
  tickConfig: config.tickConfig ?? { duration: 1, unit: "tick" },
3642
3712
  gracePeriod: config.gracePeriod ?? 50,
3643
3713
  checkInterval: config.checkInterval ?? 5,
@@ -3658,6 +3728,11 @@ var AgentE = class {
3658
3728
  if (config.parameters) {
3659
3729
  this.registry.registerAll(config.parameters);
3660
3730
  }
3731
+ if (config.validateRegistry !== false && this.registry.size > 0) {
3732
+ const validation = this.registry.validate();
3733
+ for (const w of validation.warnings) console.warn(`[AgentE] Registry warning: ${w}`);
3734
+ for (const e of validation.errors) console.error(`[AgentE] Registry error: ${e}`);
3735
+ }
3661
3736
  this.simulator = new Simulator(this.registry);
3662
3737
  if (config.onDecision) this.on("decision", config.onDecision);
3663
3738
  if (config.onAlert) this.on("alert", config.onAlert);
@@ -3854,6 +3929,31 @@ var AgentE = class {
3854
3929
  }
3855
3930
  };
3856
3931
 
3932
+ // src/utils.ts
3933
+ function findWorstSystem(metrics, check, tolerancePercent = 0) {
3934
+ const systems = metrics.systems;
3935
+ if (systems.length === 0) return void 0;
3936
+ let worstSystem;
3937
+ let worstScore = -Infinity;
3938
+ let totalScore = 0;
3939
+ for (const sys of systems) {
3940
+ const score = check(sys, metrics);
3941
+ totalScore += score;
3942
+ if (score > worstScore) {
3943
+ worstScore = score;
3944
+ worstSystem = sys;
3945
+ }
3946
+ }
3947
+ if (!worstSystem) return void 0;
3948
+ if (tolerancePercent > 0 && systems.length > 1) {
3949
+ const avg = totalScore / systems.length;
3950
+ if (avg === 0) return { system: worstSystem, score: worstScore };
3951
+ const excessPercent = (worstScore - avg) / Math.abs(avg) * 100;
3952
+ if (excessPercent < tolerancePercent) return void 0;
3953
+ }
3954
+ return { system: worstSystem, score: worstScore };
3955
+ }
3956
+
3857
3957
  // src/StateValidator.ts
3858
3958
  function validateEconomyState(state) {
3859
3959
  const errors = [];
@@ -4204,7 +4304,7 @@ export {
4204
4304
  OPEN_ECONOMY_PRINCIPLES,
4205
4305
  OPERATIONS_PRINCIPLES,
4206
4306
  Observer,
4207
- P10_SpawnWeightingUsesInversePopulation,
4307
+ P10_EntryWeightingUsesInversePopulation,
4208
4308
  P11_TwoTierPressure,
4209
4309
  P12_OnePrimaryFaucet,
4210
4310
  P13_PotsAreZeroSumAndSelfRegulate,
@@ -4224,9 +4324,9 @@ export {
4224
4324
  P26_ContinuousPressureBeatsThresholdCuts,
4225
4325
  P27_AdjustmentsNeedCooldowns,
4226
4326
  P28_StructuralDominanceIsNotPathological,
4227
- P29_PinchPoint,
4327
+ P29_BottleneckDetection,
4228
4328
  P2_ClosedLoopsNeedDirectHandoff,
4229
- P30_MovingPinchPoint,
4329
+ P30_DynamicBottleneckRotation,
4230
4330
  P31_AnchorValueTracking,
4231
4331
  P32_VelocityAboveSupply,
4232
4332
  P33_FairNotEqual,
@@ -4249,12 +4349,12 @@ export {
4249
4349
  P49_IdleAssetTax,
4250
4350
  P4_MaterialsFlowFasterThanCooldown,
4251
4351
  P50_PayPowerRatio,
4252
- P51_SharkTooth,
4352
+ P51_CyclicalEngagement,
4253
4353
  P52_EndowmentEffect,
4254
4354
  P53_EventCompletionRate,
4255
- P54_LiveOpsCadence,
4355
+ P54_OperationalCadence,
4256
4356
  P55_ArbitrageThermometer,
4257
- P56_ContentDropShock,
4357
+ P56_SupplyShockAbsorption,
4258
4358
  P57_CombinatorialPriceSpace,
4259
4359
  P58_NoNaturalNumeraire,
4260
4360
  P59_GiftEconomyNoise,
@@ -4277,6 +4377,7 @@ export {
4277
4377
  SYSTEM_DYNAMICS_PRINCIPLES,
4278
4378
  Simulator,
4279
4379
  emptyMetrics,
4380
+ findWorstSystem,
4280
4381
  validateEconomyState
4281
4382
  };
4282
4383
  //# sourceMappingURL=index.mjs.map