@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.js CHANGED
@@ -36,7 +36,7 @@ __export(index_exports, {
36
36
  OPEN_ECONOMY_PRINCIPLES: () => OPEN_ECONOMY_PRINCIPLES,
37
37
  OPERATIONS_PRINCIPLES: () => OPERATIONS_PRINCIPLES,
38
38
  Observer: () => Observer,
39
- P10_SpawnWeightingUsesInversePopulation: () => P10_SpawnWeightingUsesInversePopulation,
39
+ P10_EntryWeightingUsesInversePopulation: () => P10_EntryWeightingUsesInversePopulation,
40
40
  P11_TwoTierPressure: () => P11_TwoTierPressure,
41
41
  P12_OnePrimaryFaucet: () => P12_OnePrimaryFaucet,
42
42
  P13_PotsAreZeroSumAndSelfRegulate: () => P13_PotsAreZeroSumAndSelfRegulate,
@@ -56,9 +56,9 @@ __export(index_exports, {
56
56
  P26_ContinuousPressureBeatsThresholdCuts: () => P26_ContinuousPressureBeatsThresholdCuts,
57
57
  P27_AdjustmentsNeedCooldowns: () => P27_AdjustmentsNeedCooldowns,
58
58
  P28_StructuralDominanceIsNotPathological: () => P28_StructuralDominanceIsNotPathological,
59
- P29_PinchPoint: () => P29_PinchPoint,
59
+ P29_BottleneckDetection: () => P29_BottleneckDetection,
60
60
  P2_ClosedLoopsNeedDirectHandoff: () => P2_ClosedLoopsNeedDirectHandoff,
61
- P30_MovingPinchPoint: () => P30_MovingPinchPoint,
61
+ P30_DynamicBottleneckRotation: () => P30_DynamicBottleneckRotation,
62
62
  P31_AnchorValueTracking: () => P31_AnchorValueTracking,
63
63
  P32_VelocityAboveSupply: () => P32_VelocityAboveSupply,
64
64
  P33_FairNotEqual: () => P33_FairNotEqual,
@@ -81,12 +81,12 @@ __export(index_exports, {
81
81
  P49_IdleAssetTax: () => P49_IdleAssetTax,
82
82
  P4_MaterialsFlowFasterThanCooldown: () => P4_MaterialsFlowFasterThanCooldown,
83
83
  P50_PayPowerRatio: () => P50_PayPowerRatio,
84
- P51_SharkTooth: () => P51_SharkTooth,
84
+ P51_CyclicalEngagement: () => P51_CyclicalEngagement,
85
85
  P52_EndowmentEffect: () => P52_EndowmentEffect,
86
86
  P53_EventCompletionRate: () => P53_EventCompletionRate,
87
- P54_LiveOpsCadence: () => P54_LiveOpsCadence,
87
+ P54_OperationalCadence: () => P54_OperationalCadence,
88
88
  P55_ArbitrageThermometer: () => P55_ArbitrageThermometer,
89
- P56_ContentDropShock: () => P56_ContentDropShock,
89
+ P56_SupplyShockAbsorption: () => P56_SupplyShockAbsorption,
90
90
  P57_CombinatorialPriceSpace: () => P57_CombinatorialPriceSpace,
91
91
  P58_NoNaturalNumeraire: () => P58_NoNaturalNumeraire,
92
92
  P59_GiftEconomyNoise: () => P59_GiftEconomyNoise,
@@ -109,6 +109,7 @@ __export(index_exports, {
109
109
  SYSTEM_DYNAMICS_PRINCIPLES: () => SYSTEM_DYNAMICS_PRINCIPLES,
110
110
  Simulator: () => Simulator,
111
111
  emptyMetrics: () => emptyMetrics,
112
+ findWorstSystem: () => findWorstSystem,
112
113
  validateEconomyState: () => validateEconomyState
113
114
  });
114
115
  module.exports = __toCommonJS(index_exports);
@@ -255,7 +256,7 @@ var Observer = class {
255
256
  if (!actorsBySystem[e.system]) actorsBySystem[e.system] = /* @__PURE__ */ new Set();
256
257
  actorsBySystem[e.system].add(e.actor);
257
258
  const amt = e.amount ?? 0;
258
- if (e.type === "mint" || e.type === "enter") {
259
+ if (e.type === "mint") {
259
260
  flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) + amt;
260
261
  } else if (e.type === "burn" || e.type === "consume") {
261
262
  flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) - amt;
@@ -263,7 +264,7 @@ var Observer = class {
263
264
  }
264
265
  if (e.sourceOrSink) {
265
266
  const amt = e.amount ?? 0;
266
- if (e.type === "mint" || e.type === "enter") {
267
+ if (e.type === "mint") {
267
268
  flowBySource[e.sourceOrSink] = (flowBySource[e.sourceOrSink] ?? 0) + amt;
268
269
  } else if (e.type === "burn" || e.type === "consume") {
269
270
  flowBySink[e.sourceOrSink] = (flowBySink[e.sourceOrSink] ?? 0) + amt;
@@ -571,6 +572,9 @@ var Observer = class {
571
572
  sharkToothValleys: this.previousMetrics?.sharkToothValleys ?? [],
572
573
  eventCompletionRate: NaN,
573
574
  contentDropAge,
575
+ systems: state.systems ?? [],
576
+ sources: state.sources ?? [],
577
+ sinks: state.sinks ?? [],
574
578
  flowBySystem,
575
579
  activityBySystem,
576
580
  participantsBySystem,
@@ -720,6 +724,9 @@ function emptyMetrics(tick = 0) {
720
724
  sharkToothValleys: [],
721
725
  eventCompletionRate: NaN,
722
726
  contentDropAge: 0,
727
+ systems: [],
728
+ sources: [],
729
+ sinks: [],
723
730
  flowBySystem: {},
724
731
  activityBySystem: {},
725
732
  participantsBySystem: {},
@@ -1058,7 +1065,7 @@ var P9_RoleSwitchingNeedsFriction = {
1058
1065
  id: "P9",
1059
1066
  name: "Role Switching Needs Friction",
1060
1067
  category: "population",
1061
- 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.",
1068
+ 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.",
1062
1069
  check(metrics, thresholds) {
1063
1070
  const { churnByRole, roleShares } = metrics;
1064
1071
  const totalChurn = Object.values(churnByRole).reduce((s, v) => s + v, 0);
@@ -1081,7 +1088,7 @@ var P9_RoleSwitchingNeedsFriction = {
1081
1088
  return { violated: false };
1082
1089
  }
1083
1090
  };
1084
- var P10_SpawnWeightingUsesInversePopulation = {
1091
+ var P10_EntryWeightingUsesInversePopulation = {
1085
1092
  id: "P10",
1086
1093
  name: "Entry Weighting Uses Inverse Population",
1087
1094
  category: "population",
@@ -1187,7 +1194,7 @@ var P46_PersonaDiversity = {
1187
1194
  };
1188
1195
  var POPULATION_PRINCIPLES = [
1189
1196
  P9_RoleSwitchingNeedsFriction,
1190
- P10_SpawnWeightingUsesInversePopulation,
1197
+ P10_EntryWeightingUsesInversePopulation,
1191
1198
  P11_TwoTierPressure,
1192
1199
  P46_PersonaDiversity
1193
1200
  ];
@@ -1278,7 +1285,7 @@ var P14_TrackActualInjection = {
1278
1285
  id: "P14",
1279
1286
  name: "Track Actual Currency Injection, Not Value Creation",
1280
1287
  category: "currency",
1281
- description: 'Counting resource gathering as "currency injected" is misleading. Currency enters through faucet mechanisms (entering, rewards). Fake metrics break every downstream decision.',
1288
+ description: 'Counting resource extraction as "currency injected" is misleading. Currency enters through faucet mechanisms (entering, rewards). Fake metrics break every downstream decision.',
1282
1289
  check(metrics, _thresholds) {
1283
1290
  for (const curr of metrics.currencies) {
1284
1291
  const faucetVolume = metrics.faucetVolumeByCurrency[curr] ?? 0;
@@ -1866,7 +1873,7 @@ var REGULATOR_PRINCIPLES = [
1866
1873
  ];
1867
1874
 
1868
1875
  // src/principles/market-dynamics.ts
1869
- var P29_PinchPoint = {
1876
+ var P29_BottleneckDetection = {
1870
1877
  id: "P29",
1871
1878
  name: "Bottleneck Detection",
1872
1879
  category: "market_dynamics",
@@ -1911,7 +1918,7 @@ var P29_PinchPoint = {
1911
1918
  return { violated: false };
1912
1919
  }
1913
1920
  };
1914
- var P30_MovingPinchPoint = {
1921
+ var P30_DynamicBottleneckRotation = {
1915
1922
  id: "P30",
1916
1923
  name: "Dynamic Bottleneck Rotation",
1917
1924
  category: "market_dynamics",
@@ -1986,8 +1993,8 @@ var P57_CombinatorialPriceSpace = {
1986
1993
  }
1987
1994
  };
1988
1995
  var MARKET_DYNAMICS_PRINCIPLES = [
1989
- P29_PinchPoint,
1990
- P30_MovingPinchPoint,
1996
+ P29_BottleneckDetection,
1997
+ P30_DynamicBottleneckRotation,
1991
1998
  P57_CombinatorialPriceSpace
1992
1999
  ];
1993
2000
 
@@ -2295,7 +2302,7 @@ var P40_ReplacementRate = {
2295
2302
  id: "P40",
2296
2303
  name: "Replacement Rate \u2265 2\xD7 Consumption",
2297
2304
  category: "resource",
2298
- 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.",
2305
+ 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.",
2299
2306
  check(metrics, thresholds) {
2300
2307
  const { productionIndex, sinkVolume } = metrics;
2301
2308
  if (sinkVolume > 0 && productionIndex > 0) {
@@ -2662,7 +2669,7 @@ var OPEN_ECONOMY_PRINCIPLES = [
2662
2669
  ];
2663
2670
 
2664
2671
  // src/principles/operations.ts
2665
- var P51_SharkTooth = {
2672
+ var P51_CyclicalEngagement = {
2666
2673
  id: "P51",
2667
2674
  name: "Cyclical Engagement Pattern",
2668
2675
  category: "operations",
@@ -2718,7 +2725,7 @@ var P52_EndowmentEffect = {
2718
2725
  id: "P52",
2719
2726
  name: "Endowment Effect",
2720
2727
  category: "operations",
2721
- 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).",
2728
+ 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).",
2722
2729
  check(metrics, _thresholds) {
2723
2730
  const { avgSatisfaction, churnRate } = metrics;
2724
2731
  const { eventCompletionRate } = metrics;
@@ -2787,11 +2794,11 @@ var P53_EventCompletionRate = {
2787
2794
  return { violated: false };
2788
2795
  }
2789
2796
  };
2790
- var P54_LiveOpsCadence = {
2797
+ var P54_OperationalCadence = {
2791
2798
  id: "P54",
2792
2799
  name: "Operational Cadence",
2793
2800
  category: "operations",
2794
- 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.",
2801
+ 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.",
2795
2802
  check(metrics, _thresholds) {
2796
2803
  const { velocity, avgSatisfaction } = metrics;
2797
2804
  if (velocity < 2 && avgSatisfaction < 55 && metrics.tick > 100) {
@@ -2803,7 +2810,7 @@ var P54_LiveOpsCadence = {
2803
2810
  parameterType: "reward",
2804
2811
  direction: "increase",
2805
2812
  magnitude: 0.1,
2806
- reasoning: "Low velocity and satisfaction after long runtime. Possible content staleness. Increase rewards as bridge while new content is developed (developer action required)."
2813
+ reasoning: "Low velocity and satisfaction after long runtime. Possible supply stagnation. Increase rewards as bridge while new supply is developed (developer action required)."
2807
2814
  },
2808
2815
  confidence: 0.4,
2809
2816
  estimatedLag: 30
@@ -2812,11 +2819,11 @@ var P54_LiveOpsCadence = {
2812
2819
  return { violated: false };
2813
2820
  }
2814
2821
  };
2815
- var P56_ContentDropShock = {
2822
+ var P56_SupplyShockAbsorption = {
2816
2823
  id: "P56",
2817
2824
  name: "Supply Shock Absorption",
2818
2825
  category: "operations",
2819
- 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.",
2826
+ 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.",
2820
2827
  check(metrics, thresholds) {
2821
2828
  const { contentDropAge, arbitrageIndex } = metrics;
2822
2829
  if (contentDropAge > 0 && contentDropAge <= thresholds.contentDropCooldownTicks) {
@@ -2835,7 +2842,7 @@ var P56_ContentDropShock = {
2835
2842
  scope: { tags: ["transaction"] },
2836
2843
  direction: "decrease",
2837
2844
  magnitude: 0.1,
2838
- 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.`
2845
+ 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.`
2839
2846
  },
2840
2847
  confidence: 0.6,
2841
2848
  estimatedLag: 5
@@ -2846,11 +2853,11 @@ var P56_ContentDropShock = {
2846
2853
  }
2847
2854
  };
2848
2855
  var OPERATIONS_PRINCIPLES = [
2849
- P51_SharkTooth,
2856
+ P51_CyclicalEngagement,
2850
2857
  P52_EndowmentEffect,
2851
2858
  P53_EventCompletionRate,
2852
- P54_LiveOpsCadence,
2853
- P56_ContentDropShock
2859
+ P54_OperationalCadence,
2860
+ P56_SupplyShockAbsorption
2854
2861
  ];
2855
2862
 
2856
2863
  // src/principles/index.ts
@@ -3009,10 +3016,12 @@ var Simulator = class {
3009
3016
  const sign = direction === "increase" ? -1 : 1;
3010
3017
  const roleEntries = Object.entries(metrics.populationByRole).sort((a, b) => b[1] - a[1]);
3011
3018
  const dominantRoleCount = roleEntries[0]?.[1] ?? 0;
3012
- const resolvedKey = action.resolvedParameter;
3013
3019
  let impact;
3014
- if (resolvedKey && this.registry) {
3015
- impact = this.registry.getFlowImpact(resolvedKey);
3020
+ if (this.registry) {
3021
+ const resolved = this.registry.resolve(action.parameterType, action.scope);
3022
+ if (resolved) {
3023
+ impact = resolved.flowImpact;
3024
+ }
3016
3025
  }
3017
3026
  if (!impact) {
3018
3027
  impact = this.inferFlowImpact(action.parameterType);
@@ -3026,6 +3035,10 @@ var Simulator = class {
3026
3035
  return sign * dominantRoleCount * 0.5;
3027
3036
  case "mixed":
3028
3037
  return sign * (metrics.faucetVolumeByCurrency[currency] ?? 0) * 0.15;
3038
+ case "friction":
3039
+ return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
3040
+ case "redistribution":
3041
+ return sign * dominantRoleCount * 0.05;
3029
3042
  default:
3030
3043
  return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
3031
3044
  }
@@ -3108,6 +3121,8 @@ var Planner = class {
3108
3121
  this.constraints = /* @__PURE__ */ new Map();
3109
3122
  this.cooldowns = /* @__PURE__ */ new Map();
3110
3123
  // param → last-applied-tick
3124
+ this.typeCooldowns = /* @__PURE__ */ new Map();
3125
+ // type+scope key → last-applied-tick
3111
3126
  this.activePlanCount = 0;
3112
3127
  }
3113
3128
  lock(param) {
@@ -3130,6 +3145,8 @@ var Planner = class {
3130
3145
  */
3131
3146
  plan(diagnosis, metrics, simulationResult, currentParams, thresholds, registry) {
3132
3147
  const action = diagnosis.violation.suggestedAction;
3148
+ const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
3149
+ if (this.isTypeCooldown(typeKey, metrics.tick, thresholds.cooldownTicks)) return null;
3133
3150
  let param;
3134
3151
  let resolvedBaseline;
3135
3152
  let scope;
@@ -3187,6 +3204,9 @@ var Planner = class {
3187
3204
  }
3188
3205
  recordApplied(plan, tick) {
3189
3206
  this.cooldowns.set(plan.parameter, tick);
3207
+ const action = plan.diagnosis.violation.suggestedAction;
3208
+ const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
3209
+ this.typeCooldowns.set(typeKey, tick);
3190
3210
  this.activePlanCount++;
3191
3211
  }
3192
3212
  recordRolledBack(_plan) {
@@ -3203,6 +3223,19 @@ var Planner = class {
3203
3223
  /** Reset all cooldowns (useful for testing) */
3204
3224
  resetCooldowns() {
3205
3225
  this.cooldowns.clear();
3226
+ this.typeCooldowns.clear();
3227
+ }
3228
+ typeCooldownKey(type, scope) {
3229
+ const parts = [type];
3230
+ if (scope?.system) parts.push(`sys:${scope.system}`);
3231
+ if (scope?.currency) parts.push(`cur:${scope.currency}`);
3232
+ if (scope?.tags?.length) parts.push(`tags:${scope.tags.sort().join(",")}`);
3233
+ return parts.join("|");
3234
+ }
3235
+ isTypeCooldown(typeKey, currentTick, cooldownTicks) {
3236
+ const lastApplied = this.typeCooldowns.get(typeKey);
3237
+ if (lastApplied === void 0) return false;
3238
+ return currentTick - lastApplied < cooldownTicks;
3206
3239
  }
3207
3240
  };
3208
3241
 
@@ -3640,25 +3673,30 @@ var ParameterRegistry = class {
3640
3673
  * Resolve a parameterType + scope to a concrete RegisteredParameter.
3641
3674
  * Returns the best match, or undefined if no match.
3642
3675
  *
3643
- * Matching rules (in priority order):
3644
- * 1. Exact type match + all scope fields match
3645
- * 2. Exact type match + partial scope match (tags overlap)
3646
- * 3. Exact type match + no scope constraints
3647
- * 4. undefined (no match)
3676
+ * Matching rules:
3677
+ * 1. Filter candidates by type
3678
+ * 2. Score each by scope specificity (system +10, currency +5, tags +3 each)
3679
+ * 3. Mismatched scope fields disqualify (score = -Infinity)
3680
+ * 4. Ties broken by `priority` (higher wins), then registration order
3681
+ * 5. All disqualified → undefined
3648
3682
  */
3649
3683
  resolve(type, scope) {
3650
3684
  const candidates = this.findByType(type);
3651
3685
  if (candidates.length === 0) return void 0;
3652
3686
  if (candidates.length === 1) return candidates[0];
3653
- let bestScore = -1;
3687
+ let bestScore = -Infinity;
3688
+ let bestPriority = -Infinity;
3654
3689
  let best;
3655
3690
  for (const candidate of candidates) {
3656
- const score = this.scopeMatchScore(candidate.scope, scope);
3657
- if (score > bestScore) {
3691
+ const score = this.scopeSpecificity(candidate.scope, scope);
3692
+ const prio = candidate.priority ?? 0;
3693
+ if (score > bestScore || score === bestScore && prio > bestPriority) {
3658
3694
  bestScore = score;
3695
+ bestPriority = prio;
3659
3696
  best = candidate;
3660
3697
  }
3661
3698
  }
3699
+ if (bestScore === -Infinity) return void 0;
3662
3700
  return best;
3663
3701
  }
3664
3702
  /** Find all parameters of a given type. */
@@ -3700,28 +3738,60 @@ var ParameterRegistry = class {
3700
3738
  get size() {
3701
3739
  return this.parameters.size;
3702
3740
  }
3741
+ /**
3742
+ * Validate the registry for common misconfigurations.
3743
+ * Returns warnings (non-fatal) and errors (likely broken).
3744
+ */
3745
+ validate() {
3746
+ const warnings = [];
3747
+ const errors = [];
3748
+ const typeMap = /* @__PURE__ */ new Map();
3749
+ for (const param of this.parameters.values()) {
3750
+ const list = typeMap.get(param.type) ?? [];
3751
+ list.push(param);
3752
+ typeMap.set(param.type, list);
3753
+ }
3754
+ for (const [type, params] of typeMap) {
3755
+ if (params.length > 1) {
3756
+ const unscopedCount = params.filter((p) => !p.scope).length;
3757
+ if (unscopedCount > 1) {
3758
+ errors.push(
3759
+ `Type '${type}' has ${unscopedCount} unscoped parameters \u2014 resolve() cannot distinguish them`
3760
+ );
3761
+ }
3762
+ }
3763
+ }
3764
+ for (const param of this.parameters.values()) {
3765
+ if (!param.flowImpact) {
3766
+ warnings.push(`Parameter '${param.key}' has no flowImpact \u2014 Simulator will use inference`);
3767
+ }
3768
+ }
3769
+ return {
3770
+ valid: errors.length === 0,
3771
+ warnings,
3772
+ errors
3773
+ };
3774
+ }
3703
3775
  // ── Private ─────────────────────────────────────────────────────────────
3704
- scopeMatchScore(paramScope, queryScope) {
3776
+ scopeSpecificity(paramScope, queryScope) {
3705
3777
  if (!queryScope) return 0;
3706
3778
  if (!paramScope) return 0;
3707
3779
  let score = 0;
3708
3780
  if (queryScope.system && paramScope.system) {
3709
3781
  if (queryScope.system === paramScope.system) score += 10;
3710
- else return -1;
3782
+ else return -Infinity;
3711
3783
  }
3712
3784
  if (queryScope.currency && paramScope.currency) {
3713
3785
  if (queryScope.currency === paramScope.currency) score += 5;
3714
- else return -1;
3786
+ else return -Infinity;
3715
3787
  }
3716
3788
  if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
3717
3789
  const overlap = queryScope.tags.filter((t) => paramScope.tags.includes(t)).length;
3718
3790
  if (overlap > 0) {
3719
3791
  score += overlap * 3;
3720
3792
  } else {
3721
- return -1;
3793
+ return -Infinity;
3722
3794
  }
3723
- } else if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
3724
- return -1;
3725
3795
  }
3726
3796
  return score;
3727
3797
  }
@@ -3753,6 +3823,7 @@ var AgentE = class {
3753
3823
  mode: this.mode,
3754
3824
  dominantRoles: config.dominantRoles ?? [],
3755
3825
  idealDistribution: config.idealDistribution ?? {},
3826
+ validateRegistry: config.validateRegistry ?? true,
3756
3827
  tickConfig: config.tickConfig ?? { duration: 1, unit: "tick" },
3757
3828
  gracePeriod: config.gracePeriod ?? 50,
3758
3829
  checkInterval: config.checkInterval ?? 5,
@@ -3773,6 +3844,11 @@ var AgentE = class {
3773
3844
  if (config.parameters) {
3774
3845
  this.registry.registerAll(config.parameters);
3775
3846
  }
3847
+ if (config.validateRegistry !== false && this.registry.size > 0) {
3848
+ const validation = this.registry.validate();
3849
+ for (const w of validation.warnings) console.warn(`[AgentE] Registry warning: ${w}`);
3850
+ for (const e of validation.errors) console.error(`[AgentE] Registry error: ${e}`);
3851
+ }
3776
3852
  this.simulator = new Simulator(this.registry);
3777
3853
  if (config.onDecision) this.on("decision", config.onDecision);
3778
3854
  if (config.onAlert) this.on("alert", config.onAlert);
@@ -3969,6 +4045,31 @@ var AgentE = class {
3969
4045
  }
3970
4046
  };
3971
4047
 
4048
+ // src/utils.ts
4049
+ function findWorstSystem(metrics, check, tolerancePercent = 0) {
4050
+ const systems = metrics.systems;
4051
+ if (systems.length === 0) return void 0;
4052
+ let worstSystem;
4053
+ let worstScore = -Infinity;
4054
+ let totalScore = 0;
4055
+ for (const sys of systems) {
4056
+ const score = check(sys, metrics);
4057
+ totalScore += score;
4058
+ if (score > worstScore) {
4059
+ worstScore = score;
4060
+ worstSystem = sys;
4061
+ }
4062
+ }
4063
+ if (!worstSystem) return void 0;
4064
+ if (tolerancePercent > 0 && systems.length > 1) {
4065
+ const avg = totalScore / systems.length;
4066
+ if (avg === 0) return { system: worstSystem, score: worstScore };
4067
+ const excessPercent = (worstScore - avg) / Math.abs(avg) * 100;
4068
+ if (excessPercent < tolerancePercent) return void 0;
4069
+ }
4070
+ return { system: worstSystem, score: worstScore };
4071
+ }
4072
+
3972
4073
  // src/StateValidator.ts
3973
4074
  function validateEconomyState(state) {
3974
4075
  const errors = [];
@@ -4320,7 +4421,7 @@ function describeValue(value) {
4320
4421
  OPEN_ECONOMY_PRINCIPLES,
4321
4422
  OPERATIONS_PRINCIPLES,
4322
4423
  Observer,
4323
- P10_SpawnWeightingUsesInversePopulation,
4424
+ P10_EntryWeightingUsesInversePopulation,
4324
4425
  P11_TwoTierPressure,
4325
4426
  P12_OnePrimaryFaucet,
4326
4427
  P13_PotsAreZeroSumAndSelfRegulate,
@@ -4340,9 +4441,9 @@ function describeValue(value) {
4340
4441
  P26_ContinuousPressureBeatsThresholdCuts,
4341
4442
  P27_AdjustmentsNeedCooldowns,
4342
4443
  P28_StructuralDominanceIsNotPathological,
4343
- P29_PinchPoint,
4444
+ P29_BottleneckDetection,
4344
4445
  P2_ClosedLoopsNeedDirectHandoff,
4345
- P30_MovingPinchPoint,
4446
+ P30_DynamicBottleneckRotation,
4346
4447
  P31_AnchorValueTracking,
4347
4448
  P32_VelocityAboveSupply,
4348
4449
  P33_FairNotEqual,
@@ -4365,12 +4466,12 @@ function describeValue(value) {
4365
4466
  P49_IdleAssetTax,
4366
4467
  P4_MaterialsFlowFasterThanCooldown,
4367
4468
  P50_PayPowerRatio,
4368
- P51_SharkTooth,
4469
+ P51_CyclicalEngagement,
4369
4470
  P52_EndowmentEffect,
4370
4471
  P53_EventCompletionRate,
4371
- P54_LiveOpsCadence,
4472
+ P54_OperationalCadence,
4372
4473
  P55_ArbitrageThermometer,
4373
- P56_ContentDropShock,
4474
+ P56_SupplyShockAbsorption,
4374
4475
  P57_CombinatorialPriceSpace,
4375
4476
  P58_NoNaturalNumeraire,
4376
4477
  P59_GiftEconomyNoise,
@@ -4393,6 +4494,7 @@ function describeValue(value) {
4393
4494
  SYSTEM_DYNAMICS_PRINCIPLES,
4394
4495
  Simulator,
4395
4496
  emptyMetrics,
4497
+ findWorstSystem,
4396
4498
  validateEconomyState
4397
4499
  });
4398
4500
  //# sourceMappingURL=index.js.map