@agent-e/core 1.4.4 → 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
@@ -30,13 +30,13 @@ __export(index_exports, {
30
30
  Executor: () => Executor,
31
31
  FEEDBACK_LOOP_PRINCIPLES: () => FEEDBACK_LOOP_PRINCIPLES,
32
32
  INCENTIVE_PRINCIPLES: () => INCENTIVE_PRINCIPLES,
33
- LIVEOPS_PRINCIPLES: () => LIVEOPS_PRINCIPLES,
34
33
  MARKET_DYNAMICS_PRINCIPLES: () => MARKET_DYNAMICS_PRINCIPLES,
35
34
  MEASUREMENT_PRINCIPLES: () => MEASUREMENT_PRINCIPLES,
36
35
  MetricStore: () => MetricStore,
37
36
  OPEN_ECONOMY_PRINCIPLES: () => OPEN_ECONOMY_PRINCIPLES,
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,
@@ -96,9 +96,10 @@ __export(index_exports, {
96
96
  P7_NonSpecialistsSubsidiseSpecialists: () => P7_NonSpecialistsSubsidiseSpecialists,
97
97
  P8_RegulatorCannotFightDesign: () => P8_RegulatorCannotFightDesign,
98
98
  P9_RoleSwitchingNeedsFriction: () => P9_RoleSwitchingNeedsFriction,
99
+ PARTICIPANT_EXPERIENCE_PRINCIPLES: () => PARTICIPANT_EXPERIENCE_PRINCIPLES,
99
100
  PERSONA_HEALTHY_RANGES: () => PERSONA_HEALTHY_RANGES,
100
- PLAYER_EXPERIENCE_PRINCIPLES: () => PLAYER_EXPERIENCE_PRINCIPLES,
101
101
  POPULATION_PRINCIPLES: () => POPULATION_PRINCIPLES,
102
+ ParameterRegistry: () => ParameterRegistry,
102
103
  PersonaTracker: () => PersonaTracker,
103
104
  Planner: () => Planner,
104
105
  REGULATOR_PRINCIPLES: () => REGULATOR_PRINCIPLES,
@@ -108,6 +109,7 @@ __export(index_exports, {
108
109
  SYSTEM_DYNAMICS_PRINCIPLES: () => SYSTEM_DYNAMICS_PRINCIPLES,
109
110
  Simulator: () => Simulator,
110
111
  emptyMetrics: () => emptyMetrics,
112
+ findWorstSystem: () => findWorstSystem,
111
113
  validateEconomyState: () => validateEconomyState
112
114
  });
113
115
  module.exports = __toCommonJS(index_exports);
@@ -126,11 +128,11 @@ var DEFAULT_THRESHOLDS = {
126
128
  smokeTestWarning: 0.3,
127
129
  smokeTestCritical: 0.1,
128
130
  currencyInsulationMax: 0.5,
129
- // Player Experience (P45, P50)
131
+ // Participant Experience (P45, P50)
130
132
  timeBudgetRatio: 0.8,
131
133
  payPowerRatioMax: 2,
132
134
  payPowerRatioTarget: 1.5,
133
- // LiveOps (P51, P53)
135
+ // Operations (P51, P53)
134
136
  sharkToothPeakDecay: 0.95,
135
137
  sharkToothValleyDecay: 0.9,
136
138
  eventCompletionMin: 0.4,
@@ -184,7 +186,7 @@ var PERSONA_HEALTHY_RANGES = {
184
186
  Earner: { min: 0, max: 0.15 },
185
187
  Builder: { min: 0.05, max: 0.15 },
186
188
  Social: { min: 0.1, max: 0.2 },
187
- Whale: { min: 0, max: 0.05 },
189
+ HighValue: { min: 0, max: 0.05 },
188
190
  Influencer: { min: 0, max: 0.05 }
189
191
  };
190
192
  var DEFAULT_TICK_CONFIG = {
@@ -221,7 +223,7 @@ var Observer = class {
221
223
  const curr = e.currency ?? defaultCurrency;
222
224
  switch (e.type) {
223
225
  case "mint":
224
- case "spawn":
226
+ case "enter":
225
227
  faucetVolumeByCurrency[curr] = (faucetVolumeByCurrency[curr] ?? 0) + (e.amount ?? 0);
226
228
  break;
227
229
  case "burn":
@@ -243,6 +245,46 @@ var Observer = class {
243
245
  break;
244
246
  }
245
247
  }
248
+ const flowBySystem = {};
249
+ const activityBySystem = {};
250
+ const actorsBySystem = {};
251
+ const flowBySource = {};
252
+ const flowBySink = {};
253
+ for (const e of recentEvents) {
254
+ if (e.system) {
255
+ activityBySystem[e.system] = (activityBySystem[e.system] ?? 0) + 1;
256
+ if (!actorsBySystem[e.system]) actorsBySystem[e.system] = /* @__PURE__ */ new Set();
257
+ actorsBySystem[e.system].add(e.actor);
258
+ const amt = e.amount ?? 0;
259
+ if (e.type === "mint") {
260
+ flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) + amt;
261
+ } else if (e.type === "burn" || e.type === "consume") {
262
+ flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) - amt;
263
+ }
264
+ }
265
+ if (e.sourceOrSink) {
266
+ const amt = e.amount ?? 0;
267
+ if (e.type === "mint") {
268
+ flowBySource[e.sourceOrSink] = (flowBySource[e.sourceOrSink] ?? 0) + amt;
269
+ } else if (e.type === "burn" || e.type === "consume") {
270
+ flowBySink[e.sourceOrSink] = (flowBySink[e.sourceOrSink] ?? 0) + amt;
271
+ }
272
+ }
273
+ }
274
+ const participantsBySystem = {};
275
+ for (const [sys, actors] of Object.entries(actorsBySystem)) {
276
+ participantsBySystem[sys] = actors.size;
277
+ }
278
+ const totalSourceFlow = Object.values(flowBySource).reduce((s, v) => s + v, 0);
279
+ const sourceShare = {};
280
+ for (const [src, vol] of Object.entries(flowBySource)) {
281
+ sourceShare[src] = totalSourceFlow > 0 ? vol / totalSourceFlow : 0;
282
+ }
283
+ const totalSinkFlow = Object.values(flowBySink).reduce((s, v) => s + v, 0);
284
+ const sinkShare = {};
285
+ for (const [snk, vol] of Object.entries(flowBySink)) {
286
+ sinkShare[snk] = totalSinkFlow > 0 ? vol / totalSinkFlow : 0;
287
+ }
246
288
  const currencies = state.currencies;
247
289
  const totalSupplyByCurrency = {};
248
290
  const balancesByCurrency = {};
@@ -452,7 +494,8 @@ var Observer = class {
452
494
  for (const [name, fn] of Object.entries(this.customMetricFns)) {
453
495
  try {
454
496
  custom[name] = fn(state);
455
- } catch {
497
+ } catch (err) {
498
+ console.warn(`[AgentE] Custom metric '${name}' threw an error:`, err);
456
499
  custom[name] = NaN;
457
500
  }
458
501
  }
@@ -529,6 +572,16 @@ var Observer = class {
529
572
  sharkToothValleys: this.previousMetrics?.sharkToothValleys ?? [],
530
573
  eventCompletionRate: NaN,
531
574
  contentDropAge,
575
+ systems: state.systems ?? [],
576
+ sources: state.sources ?? [],
577
+ sinks: state.sinks ?? [],
578
+ flowBySystem,
579
+ activityBySystem,
580
+ participantsBySystem,
581
+ flowBySource,
582
+ flowBySink,
583
+ sourceShare,
584
+ sinkShare,
532
585
  custom
533
586
  };
534
587
  this.previousMetrics = metrics;
@@ -671,6 +724,16 @@ function emptyMetrics(tick = 0) {
671
724
  sharkToothValleys: [],
672
725
  eventCompletionRate: NaN,
673
726
  contentDropAge: 0,
727
+ systems: [],
728
+ sources: [],
729
+ sinks: [],
730
+ flowBySystem: {},
731
+ activityBySystem: {},
732
+ participantsBySystem: {},
733
+ flowBySource: {},
734
+ flowBySink: {},
735
+ sourceShare: {},
736
+ sinkShare: {},
674
737
  custom: {}
675
738
  };
676
739
  }
@@ -703,7 +766,7 @@ var P1_ProductionMatchesConsumption = {
703
766
  severity: 7,
704
767
  evidence: { scarceResources: violations, dominantRole: dominantRole?.[0], dominantShare },
705
768
  suggestedAction: {
706
- parameter: "productionCost",
769
+ parameterType: "cost",
707
770
  direction: "decrease",
708
771
  magnitude: 0.15,
709
772
  reasoning: "Lower production cost to incentivise more production."
@@ -737,7 +800,8 @@ var P2_ClosedLoopsNeedDirectHandoff = {
737
800
  severity: 5,
738
801
  evidence: { backlogResources, velocity },
739
802
  suggestedAction: {
740
- parameter: "transactionFee",
803
+ parameterType: "fee",
804
+ scope: { tags: ["transaction"] },
741
805
  direction: "increase",
742
806
  magnitude: 0.2,
743
807
  reasoning: "Raise market fees to discourage raw material listings. Direct hand-off at production zones is the correct channel."
@@ -767,7 +831,7 @@ var P3_BootstrapCapitalCoversFirstTransaction = {
767
831
  severity: 8,
768
832
  evidence: { resource, totalProducers, supply },
769
833
  suggestedAction: {
770
- parameter: "productionCost",
834
+ parameterType: "cost",
771
835
  direction: "decrease",
772
836
  magnitude: 0.3,
773
837
  reasoning: "Producers cannot complete first transaction. Lower production cost to unblock bootstrap."
@@ -786,7 +850,7 @@ var P4_MaterialsFlowFasterThanCooldown = {
786
850
  id: "P4",
787
851
  name: "Materials Flow Faster Than Cooldown",
788
852
  category: "supply_chain",
789
- description: "Input delivery rate must exceed or match production cooldown rate. If producers craft every 5 ticks but only receive raw materials every 10 ticks, they starve regardless of supply levels.",
853
+ description: "Input delivery rate must exceed or match production cooldown rate. If producers produce every 5 ticks but only receive raw materials every 10 ticks, they starve regardless of supply levels.",
790
854
  check(metrics, _thresholds) {
791
855
  const { supplyByResource, populationByRole, velocity, totalAgents } = metrics;
792
856
  const totalSupply = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
@@ -799,7 +863,7 @@ var P4_MaterialsFlowFasterThanCooldown = {
799
863
  severity: 5,
800
864
  evidence: { avgSupplyPerAgent, velocity, totalRoles },
801
865
  suggestedAction: {
802
- parameter: "yieldRate",
866
+ parameterType: "yield",
803
867
  direction: "increase",
804
868
  magnitude: 0.15,
805
869
  reasoning: "Low supply per agent with stagnant velocity. Increase yield to compensate."
@@ -814,7 +878,7 @@ var P4_MaterialsFlowFasterThanCooldown = {
814
878
  severity: 4,
815
879
  evidence: { avgSupplyPerAgent, totalSupply, totalAgents },
816
880
  suggestedAction: {
817
- parameter: "yieldRate",
881
+ parameterType: "yield",
818
882
  direction: "decrease",
819
883
  magnitude: 0.2,
820
884
  reasoning: "Raw materials piling up. Extractors outpacing producers."
@@ -842,7 +906,7 @@ var P60_SurplusDisposalAsymmetry = {
842
906
  discount: thresholds.disposalTradeWeightDiscount
843
907
  },
844
908
  suggestedAction: {
845
- parameter: "productionCost",
909
+ parameterType: "cost",
846
910
  direction: "decrease",
847
911
  magnitude: 0.1,
848
912
  reasoning: `${(disposalTradeRatio * 100).toFixed(0)}% of trades are surplus disposal. Price signals unreliable as demand indicators. Lower production costs to shift balance toward deliberate production-for-sale. ADVISORY: Weight disposal-trade prices at ${thresholds.disposalTradeWeightDiscount}\xD7 in index calculations.`
@@ -885,7 +949,8 @@ var P5_ProfitabilityIsCompetitive = {
885
949
  population: populationByRole[dominantRole]
886
950
  },
887
951
  suggestedAction: {
888
- parameter: "transactionFee",
952
+ parameterType: "fee",
953
+ scope: { tags: ["transaction"] },
889
954
  direction: "increase",
890
955
  magnitude: thresholds.maxAdjustmentPercent,
891
956
  reasoning: `${dominantRole} share at ${((roleShares[dominantRole] ?? 0) * 100).toFixed(0)}%. Likely stampede from non-competitive profitability formula. Raise market friction to slow role accumulation.`
@@ -911,7 +976,7 @@ var P6_CrowdingMultiplierOnAllRoles = {
911
976
  severity: 5,
912
977
  evidence: { role, share },
913
978
  suggestedAction: {
914
- parameter: "productionCost",
979
+ parameterType: "cost",
915
980
  direction: "increase",
916
981
  magnitude: 0.1,
917
982
  reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 no crowding pressure detected. Apply role-specific cost increase to simulate saturation.`
@@ -946,7 +1011,8 @@ var P7_NonSpecialistsSubsidiseSpecialists = {
946
1011
  severity: 6,
947
1012
  evidence: { poolName, poolSize, dominantRole, dominantShare },
948
1013
  suggestedAction: {
949
- parameter: "entryFee",
1014
+ parameterType: "fee",
1015
+ scope: { tags: ["entry"] },
950
1016
  direction: "decrease",
951
1017
  magnitude: 0.1,
952
1018
  reasoning: `Pool "${poolName}" draining (${poolSize}) \u2014 ${dominantRole} at ${(dominantShare * 100).toFixed(0)}%. Too many specialists, not enough subsidising non-specialists. Lower entry fee to attract diverse participants.`
@@ -974,7 +1040,7 @@ var P8_RegulatorCannotFightDesign = {
974
1040
  severity: 4,
975
1041
  evidence: { dominantRole: dominantRole[0], share: dominantRole[1], avgSatisfaction },
976
1042
  suggestedAction: {
977
- parameter: "rewardRate",
1043
+ parameterType: "reward",
978
1044
  direction: "increase",
979
1045
  magnitude: 0.1,
980
1046
  reasoning: `Low satisfaction with ${dominantRole[0]} dominant. Regulator may be suppressing a structurally necessary role. Ease pressure on dominant role rewards.`
@@ -999,7 +1065,7 @@ var P9_RoleSwitchingNeedsFriction = {
999
1065
  id: "P9",
1000
1066
  name: "Role Switching Needs Friction",
1001
1067
  category: "population",
1002
- 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.",
1003
1069
  check(metrics, thresholds) {
1004
1070
  const { churnByRole, roleShares } = metrics;
1005
1071
  const totalChurn = Object.values(churnByRole).reduce((s, v) => s + v, 0);
@@ -1009,7 +1075,7 @@ var P9_RoleSwitchingNeedsFriction = {
1009
1075
  severity: 5,
1010
1076
  evidence: { totalChurnRate: totalChurn, churnByRole },
1011
1077
  suggestedAction: {
1012
- parameter: "productionCost",
1078
+ parameterType: "cost",
1013
1079
  direction: "increase",
1014
1080
  magnitude: 0.05,
1015
1081
  reasoning: `Role switch rate ${(totalChurn * 100).toFixed(1)}% exceeds friction threshold. Increase production costs to slow herd movement.`
@@ -1022,11 +1088,11 @@ var P9_RoleSwitchingNeedsFriction = {
1022
1088
  return { violated: false };
1023
1089
  }
1024
1090
  };
1025
- var P10_SpawnWeightingUsesInversePopulation = {
1091
+ var P10_EntryWeightingUsesInversePopulation = {
1026
1092
  id: "P10",
1027
- name: "Spawn Weighting Uses Inverse Population",
1093
+ name: "Entry Weighting Uses Inverse Population",
1028
1094
  category: "population",
1029
- description: "New agents should preferentially fill the least-populated roles. Flat entry probability causes initial imbalances to compound.",
1095
+ description: "New entrants should preferentially fill the least-populated roles. Flat entry probability causes initial imbalances to compound.",
1030
1096
  check(metrics, _thresholds) {
1031
1097
  const { roleShares } = metrics;
1032
1098
  if (Object.keys(roleShares).length === 0) return { violated: false };
@@ -1041,7 +1107,7 @@ var P10_SpawnWeightingUsesInversePopulation = {
1041
1107
  severity: 4,
1042
1108
  evidence: { roleShares, stdDev, leastPopulatedRole: minRole?.[0] },
1043
1109
  suggestedAction: {
1044
- parameter: "yieldRate",
1110
+ parameterType: "yield",
1045
1111
  direction: "increase",
1046
1112
  magnitude: 0.05,
1047
1113
  reasoning: `High role share variance (\u03C3=${stdDev.toFixed(2)}). Entry weighting may not be filling under-populated roles. Increasing yield makes under-populated producer roles more attractive.`
@@ -1067,7 +1133,8 @@ var P11_TwoTierPressure = {
1067
1133
  severity: 6,
1068
1134
  evidence: { role, share },
1069
1135
  suggestedAction: {
1070
- parameter: "transactionFee",
1136
+ parameterType: "fee",
1137
+ scope: { tags: ["transaction"] },
1071
1138
  direction: "increase",
1072
1139
  magnitude: 0.15,
1073
1140
  reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 continuous pressure was insufficient. Hard intervention needed alongside resumed continuous pressure.`
@@ -1095,7 +1162,7 @@ var P46_PersonaDiversity = {
1095
1162
  severity: 5,
1096
1163
  evidence: { dominantPersona: persona, share, personaDistribution },
1097
1164
  suggestedAction: {
1098
- parameter: "rewardRate",
1165
+ parameterType: "reward",
1099
1166
  direction: "increase",
1100
1167
  magnitude: 0.1,
1101
1168
  reasoning: `${persona} persona at ${(share * 100).toFixed(0)}% \u2014 behavioral monoculture. Diversify reward structures to attract other persona types.`
@@ -1112,7 +1179,8 @@ var P46_PersonaDiversity = {
1112
1179
  severity: 3,
1113
1180
  evidence: { significantClusters, required: thresholds.personaMinClusters },
1114
1181
  suggestedAction: {
1115
- parameter: "transactionFee",
1182
+ parameterType: "fee",
1183
+ scope: { tags: ["transaction"] },
1116
1184
  direction: "decrease",
1117
1185
  magnitude: 0.05,
1118
1186
  reasoning: `Only ${significantClusters} significant persona clusters (need ${thresholds.personaMinClusters}). Lower trade barriers to attract non-dominant persona types.`
@@ -1126,7 +1194,7 @@ var P46_PersonaDiversity = {
1126
1194
  };
1127
1195
  var POPULATION_PRINCIPLES = [
1128
1196
  P9_RoleSwitchingNeedsFriction,
1129
- P10_SpawnWeightingUsesInversePopulation,
1197
+ P10_EntryWeightingUsesInversePopulation,
1130
1198
  P11_TwoTierPressure,
1131
1199
  P46_PersonaDiversity
1132
1200
  ];
@@ -1136,7 +1204,7 @@ var P12_OnePrimaryFaucet = {
1136
1204
  id: "P12",
1137
1205
  name: "One Primary Faucet",
1138
1206
  category: "currency",
1139
- description: "Multiple independent currency sources (gathering + production + quests) each creating currency causes uncontrolled inflation. One clear primary faucet makes the economy predictable and auditable.",
1207
+ description: "Multiple independent currency sources (gathering + production + activities) each creating currency causes uncontrolled inflation. One clear primary faucet makes the economy predictable and auditable.",
1140
1208
  check(metrics, thresholds) {
1141
1209
  for (const curr of metrics.currencies) {
1142
1210
  const netFlow = metrics.netFlowByCurrency[curr] ?? 0;
@@ -1148,9 +1216,9 @@ var P12_OnePrimaryFaucet = {
1148
1216
  severity: 5,
1149
1217
  evidence: { currency: curr, netFlow, faucetVolume, sinkVolume },
1150
1218
  suggestedAction: {
1151
- parameter: "productionCost",
1219
+ parameterType: "cost",
1152
1220
  direction: "increase",
1153
- currency: curr,
1221
+ scope: { currency: curr },
1154
1222
  magnitude: 0.15,
1155
1223
  reasoning: `[${curr}] Net flow +${netFlow.toFixed(1)}/tick. Inflationary. Increase production cost (primary sink) to balance faucet output.`
1156
1224
  },
@@ -1164,9 +1232,9 @@ var P12_OnePrimaryFaucet = {
1164
1232
  severity: 4,
1165
1233
  evidence: { currency: curr, netFlow, faucetVolume, sinkVolume },
1166
1234
  suggestedAction: {
1167
- parameter: "productionCost",
1235
+ parameterType: "cost",
1168
1236
  direction: "decrease",
1169
- currency: curr,
1237
+ scope: { currency: curr },
1170
1238
  magnitude: 0.15,
1171
1239
  reasoning: `[${curr}] Net flow ${netFlow.toFixed(1)}/tick. Deflationary. Decrease production cost to ease sink pressure.`
1172
1240
  },
@@ -1198,9 +1266,9 @@ var P13_PotsAreZeroSumAndSelfRegulate = {
1198
1266
  severity: 7,
1199
1267
  evidence: { currency: curr, pool: poolName, poolSize, participants: dominantCount, maxSustainableMultiplier },
1200
1268
  suggestedAction: {
1201
- parameter: "rewardRate",
1269
+ parameterType: "reward",
1202
1270
  direction: "decrease",
1203
- currency: curr,
1271
+ scope: { currency: curr },
1204
1272
  magnitude: 0.15,
1205
1273
  reasoning: `[${curr}] ${poolName} pool at ${poolSize.toFixed(0)} currency with ${dominantCount} active participants. Sustainable multiplier \u2264 ${maxSustainableMultiplier.toFixed(2)}. Reduce reward multiplier to prevent pool drain.`
1206
1274
  },
@@ -1217,7 +1285,7 @@ var P14_TrackActualInjection = {
1217
1285
  id: "P14",
1218
1286
  name: "Track Actual Currency Injection, Not Value Creation",
1219
1287
  category: "currency",
1220
- description: 'Counting resource gathering as "currency injected" is misleading. Currency enters through faucet mechanisms (spawning, 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.',
1221
1289
  check(metrics, _thresholds) {
1222
1290
  for (const curr of metrics.currencies) {
1223
1291
  const faucetVolume = metrics.faucetVolumeByCurrency[curr] ?? 0;
@@ -1230,9 +1298,9 @@ var P14_TrackActualInjection = {
1230
1298
  severity: 4,
1231
1299
  evidence: { currency: curr, faucetVolume, netFlow, supplyGrowthRate },
1232
1300
  suggestedAction: {
1233
- parameter: "yieldRate",
1301
+ parameterType: "yield",
1234
1302
  direction: "decrease",
1235
- currency: curr,
1303
+ scope: { currency: curr },
1236
1304
  magnitude: 0.1,
1237
1305
  reasoning: `[${curr}] Supply growing at ${(supplyGrowthRate * 100).toFixed(1)}%/tick. Verify currency injection tracking. Resources should not create currency directly.`
1238
1306
  },
@@ -1262,9 +1330,9 @@ var P15_PoolsNeedCapAndDecay = {
1262
1330
  severity: 6,
1263
1331
  evidence: { currency: curr, pool, size, shareOfSupply, cap: poolCapPercent },
1264
1332
  suggestedAction: {
1265
- parameter: "transactionFee",
1333
+ parameterType: "fee",
1266
1334
  direction: "decrease",
1267
- currency: curr,
1335
+ scope: { tags: ["transaction"], currency: curr },
1268
1336
  magnitude: 0.1,
1269
1337
  reasoning: `[${curr}] ${pool} pool at ${(shareOfSupply * 100).toFixed(1)}% of supply (cap: ${(poolCapPercent * 100).toFixed(0)}%). Currency frozen. Lower fees to encourage circulation over accumulation.`
1270
1338
  },
@@ -1294,9 +1362,9 @@ var P16_WithdrawalPenaltyScales = {
1294
1362
  severity: 3,
1295
1363
  evidence: { currency: curr, pool: poolName, poolSize, estimatedStaked: stakedEstimate },
1296
1364
  suggestedAction: {
1297
- parameter: "transactionFee",
1365
+ parameterType: "fee",
1298
1366
  direction: "increase",
1299
- currency: curr,
1367
+ scope: { tags: ["transaction"], currency: curr },
1300
1368
  magnitude: 0.05,
1301
1369
  reasoning: `[${curr}] ${poolName} pool depleted while significant currency should be locked. Early withdrawals may be draining the pool. Ensure withdrawal penalty scales with lock duration.`
1302
1370
  },
@@ -1326,9 +1394,9 @@ var P32_VelocityAboveSupply = {
1326
1394
  severity: 4,
1327
1395
  evidence: { currency: curr, velocity, totalSupply, totalResources },
1328
1396
  suggestedAction: {
1329
- parameter: "transactionFee",
1397
+ parameterType: "fee",
1330
1398
  direction: "decrease",
1331
- currency: curr,
1399
+ scope: { tags: ["transaction"], currency: curr },
1332
1400
  magnitude: 0.2,
1333
1401
  reasoning: `[${curr}] Velocity ${velocity}/t with ${totalResources} resources in system. Economy stagnant despite available supply. Lower trading friction.`
1334
1402
  },
@@ -1368,9 +1436,9 @@ var P58_NoNaturalNumeraire = {
1368
1436
  meanPrice: mean
1369
1437
  },
1370
1438
  suggestedAction: {
1371
- parameter: "productionCost",
1439
+ parameterType: "cost",
1372
1440
  direction: "increase",
1373
- currency: curr,
1441
+ scope: { currency: curr },
1374
1442
  magnitude: 0.1,
1375
1443
  reasoning: `[${curr}] Price coefficient of variation ${coeffOfVariation.toFixed(2)} with velocity ${velocity.toFixed(1)}. All items priced similarly in an active economy \u2014 no natural num\xE9raire emerging. If a designated currency exists, increase its sink demand to differentiate it.`
1376
1444
  },
@@ -1405,7 +1473,8 @@ var P17_GracePeriodBeforeIntervention = {
1405
1473
  severity: 7,
1406
1474
  evidence: { tick: metrics.tick, avgSatisfaction: metrics.avgSatisfaction },
1407
1475
  suggestedAction: {
1408
- parameter: "entryFee",
1476
+ parameterType: "fee",
1477
+ scope: { tags: ["entry"] },
1409
1478
  direction: "decrease",
1410
1479
  magnitude: 0.2,
1411
1480
  reasoning: `Very low satisfaction at tick ${metrics.tick}. Intervention may have fired during grace period. Ease all costs to let economy bootstrap.`
@@ -1432,7 +1501,7 @@ var P18_FirstProducerNeedsStartingInventory = {
1432
1501
  severity: 8,
1433
1502
  evidence: { tick: metrics.tick, resource, supply, totalAgents: metrics.totalAgents },
1434
1503
  suggestedAction: {
1435
- parameter: "productionCost",
1504
+ parameterType: "cost",
1436
1505
  direction: "decrease",
1437
1506
  magnitude: 0.5,
1438
1507
  reasoning: `Bootstrap failure: ${resource} supply is 0 at tick ${metrics.tick} with ${metrics.totalAgents} agents. Drastically reduce production cost to allow immediate output.`
@@ -1471,7 +1540,7 @@ var P19_StartingSupplyExceedsDemand = {
1471
1540
  resourcesPerAgent
1472
1541
  },
1473
1542
  suggestedAction: {
1474
- parameter: "rewardRate",
1543
+ parameterType: "reward",
1475
1544
  direction: "increase",
1476
1545
  magnitude: 0.2,
1477
1546
  reasoning: `${mostPopulatedRole} (${population} agents) has insufficient resources (${resourcesPerAgent.toFixed(2)} per agent). Cold-start scarcity. Boost competitive pool reward to attract participation despite scarcity.`
@@ -1505,7 +1574,7 @@ var P20_DecayPreventsAccumulation = {
1505
1574
  severity: 4,
1506
1575
  evidence: { totalResources, resourcesPerAgent, velocity },
1507
1576
  suggestedAction: {
1508
- parameter: "yieldRate",
1577
+ parameterType: "yield",
1509
1578
  direction: "decrease",
1510
1579
  magnitude: 0.1,
1511
1580
  reasoning: `${totalResources.toFixed(0)} resources with velocity ${velocity}/t. Likely hoarding. Reduce yield to increase scarcity and force circulation.`
@@ -1533,7 +1602,8 @@ var P21_PriceFromGlobalSupply = {
1533
1602
  severity: 3,
1534
1603
  evidence: { resource, volatility, supply, price: prices[resource] },
1535
1604
  suggestedAction: {
1536
- parameter: "transactionFee",
1605
+ parameterType: "fee",
1606
+ scope: { tags: ["transaction"] },
1537
1607
  direction: "increase",
1538
1608
  magnitude: 0.05,
1539
1609
  reasoning: `${resource} price volatile (${(volatility * 100).toFixed(0)}%) despite supply ${supply}. Price may not reflect global inventory. Increase trading friction to stabilise.`
@@ -1550,7 +1620,7 @@ var P22_MarketAwarenessPreventsSurplus = {
1550
1620
  id: "P22",
1551
1621
  name: "Market Awareness Prevents Overproduction",
1552
1622
  category: "feedback",
1553
- description: "Producers who craft without checking market prices will create surpluses that crash prices. Agents need to see prices before deciding to produce.",
1623
+ description: "Producers who produce without checking market prices will create surpluses that crash prices. Agents need to see prices before deciding to produce.",
1554
1624
  check(metrics, _thresholds) {
1555
1625
  const { supplyByResource, prices, productionIndex } = metrics;
1556
1626
  const priceValues = Object.values(prices).filter((p) => p > 0);
@@ -1574,7 +1644,7 @@ var P22_MarketAwarenessPreventsSurplus = {
1574
1644
  productionIndex
1575
1645
  },
1576
1646
  suggestedAction: {
1577
- parameter: "productionCost",
1647
+ parameterType: "cost",
1578
1648
  direction: "increase",
1579
1649
  magnitude: 0.1,
1580
1650
  reasoning: `${resource} price ${price.toFixed(0)} is ${(priceDeviation * 100).toFixed(0)}% of median (${medianPrice.toFixed(0)}). Supply ${supply} units but still producing. Producers appear unaware of market. Raise production cost to slow output.`
@@ -1601,7 +1671,7 @@ var P23_ProfitabilityFactorsFeasibility = {
1601
1671
  severity: 5,
1602
1672
  evidence: { blockedFraction, blockedAgentCount, avgSatisfaction },
1603
1673
  suggestedAction: {
1604
- parameter: "productionCost",
1674
+ parameterType: "cost",
1605
1675
  direction: "decrease",
1606
1676
  magnitude: 0.15,
1607
1677
  reasoning: `${(blockedFraction * 100).toFixed(0)}% of agents blocked with low satisfaction. Agents may have roles they cannot afford to execute. Lower production costs to restore feasibility.`
@@ -1627,7 +1697,8 @@ var P24_BlockedAgentsDecayFaster = {
1627
1697
  severity: 5,
1628
1698
  evidence: { blockedFraction, blockedAgentCount, churnRate },
1629
1699
  suggestedAction: {
1630
- parameter: "transactionFee",
1700
+ parameterType: "fee",
1701
+ scope: { tags: ["transaction"] },
1631
1702
  direction: "decrease",
1632
1703
  magnitude: 0.15,
1633
1704
  reasoning: `${(blockedFraction * 100).toFixed(0)}% of agents blocked. Blocked agents churn silently, skewing metrics. Lower fees to unblock market participation.`
@@ -1672,7 +1743,7 @@ var P25_CorrectLeversForCorrectProblems = {
1672
1743
  netFlow
1673
1744
  },
1674
1745
  suggestedAction: {
1675
- parameter: "yieldRate",
1746
+ parameterType: "yield",
1676
1747
  direction: "decrease",
1677
1748
  magnitude: 0.15,
1678
1749
  reasoning: `Inflation with ${resource} backlog (${supply} units, ${(supply / Math.max(1, avgSupply)).toFixed(1)}\xD7 average). Root cause is gathering. Correct lever: yieldRate, not fees.`
@@ -1698,7 +1769,7 @@ var P26_ContinuousPressureBeatsThresholdCuts = {
1698
1769
  severity: 4,
1699
1770
  evidence: { inflationRate },
1700
1771
  suggestedAction: {
1701
- parameter: "productionCost",
1772
+ parameterType: "cost",
1702
1773
  direction: inflationRate > 0 ? "increase" : "decrease",
1703
1774
  magnitude: Math.min(thresholds.maxAdjustmentPercent, 0.05),
1704
1775
  // force smaller step
@@ -1724,7 +1795,8 @@ var P27_AdjustmentsNeedCooldowns = {
1724
1795
  severity: 4,
1725
1796
  evidence: { churnRate, avgSatisfaction },
1726
1797
  suggestedAction: {
1727
- parameter: "entryFee",
1798
+ parameterType: "fee",
1799
+ scope: { tags: ["entry"] },
1728
1800
  direction: "decrease",
1729
1801
  magnitude: 0.05,
1730
1802
  reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) with low satisfaction. Possible oscillation from rapid adjustments. Apply small correction only.`
@@ -1755,7 +1827,7 @@ var P28_StructuralDominanceIsNotPathological = {
1755
1827
  severity: 5,
1756
1828
  evidence: { dominantRole, dominantShare, avgSatisfaction },
1757
1829
  suggestedAction: {
1758
- parameter: "productionCost",
1830
+ parameterType: "cost",
1759
1831
  direction: "decrease",
1760
1832
  magnitude: 0.1,
1761
1833
  reasoning: `${dominantRole} dominant (${(dominantShare * 100).toFixed(0)}%) with low satisfaction. Pathological dominance \u2014 agents trapped, not thriving. Ease costs to allow role switching.`
@@ -1771,7 +1843,7 @@ var P38_CommunicationPreventsRevolt = {
1771
1843
  id: "P38",
1772
1844
  name: "Communication Prevents Revolt",
1773
1845
  category: "regulator",
1774
- description: "Every adjustment must be logged with reasoning. An adjustment made without explanation to players causes revolt. AgentE logs every decision \u2014 this principle checks that logging is active.",
1846
+ description: "Every adjustment must be logged with reasoning. An adjustment made without explanation to participants causes revolt. AgentE logs every decision \u2014 this principle checks that logging is active.",
1775
1847
  check(metrics, _thresholds) {
1776
1848
  const { churnRate } = metrics;
1777
1849
  if (churnRate > 0.1) {
@@ -1780,7 +1852,7 @@ var P38_CommunicationPreventsRevolt = {
1780
1852
  severity: 3,
1781
1853
  evidence: { churnRate },
1782
1854
  suggestedAction: {
1783
- parameter: "rewardRate",
1855
+ parameterType: "reward",
1784
1856
  direction: "increase",
1785
1857
  magnitude: 0.1,
1786
1858
  reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) \u2014 agents leaving. Ensure all recent adjustments are logged with reasoning to diagnose cause.`
@@ -1801,9 +1873,9 @@ var REGULATOR_PRINCIPLES = [
1801
1873
  ];
1802
1874
 
1803
1875
  // src/principles/market-dynamics.ts
1804
- var P29_PinchPoint = {
1876
+ var P29_BottleneckDetection = {
1805
1877
  id: "P29",
1806
- name: "Pinch Point",
1878
+ name: "Bottleneck Detection",
1807
1879
  category: "market_dynamics",
1808
1880
  description: "Every economy has a resource that constrains all downstream activity. Identify which resource is the pinch point (consumers need them, producers make them). If demand drops \u2192 oversupply. If frustration rises \u2192 undersupply.",
1809
1881
  check(metrics, _thresholds) {
@@ -1817,7 +1889,7 @@ var P29_PinchPoint = {
1817
1889
  severity: 7,
1818
1890
  evidence: { resource, supply, demand, status },
1819
1891
  suggestedAction: {
1820
- parameter: "productionCost",
1892
+ parameterType: "cost",
1821
1893
  direction: "decrease",
1822
1894
  magnitude: 0.15,
1823
1895
  reasoning: `${resource} is a pinch point and currently SCARCE (supply ${supply}, demand ${demand}). Reduce production cost to increase throughput.`
@@ -1833,7 +1905,7 @@ var P29_PinchPoint = {
1833
1905
  severity: 4,
1834
1906
  evidence: { resource, supply, status },
1835
1907
  suggestedAction: {
1836
- parameter: "productionCost",
1908
+ parameterType: "cost",
1837
1909
  direction: "increase",
1838
1910
  magnitude: 0.1,
1839
1911
  reasoning: `${resource} is a pinch point and OVERSUPPLIED (supply ${supply}). Raise production cost to reduce surplus.`
@@ -1846,11 +1918,11 @@ var P29_PinchPoint = {
1846
1918
  return { violated: false };
1847
1919
  }
1848
1920
  };
1849
- var P30_MovingPinchPoint = {
1921
+ var P30_DynamicBottleneckRotation = {
1850
1922
  id: "P30",
1851
- name: "Moving Pinch Point",
1923
+ name: "Dynamic Bottleneck Rotation",
1852
1924
  category: "market_dynamics",
1853
- description: "Agent progression shifts the demand curve. A static pinch point that works early will be cleared later. The pinch point must move with agent progression to maintain ongoing scarcity and engagement.",
1925
+ description: "Participant progression shifts the demand curve. A static pinch point that works early will be cleared later. The pinch point must move with participant progression to maintain ongoing scarcity and engagement.",
1854
1926
  check(metrics, _thresholds) {
1855
1927
  const { capacityUsage, supplyByResource, avgSatisfaction } = metrics;
1856
1928
  const totalResources = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
@@ -1861,7 +1933,7 @@ var P30_MovingPinchPoint = {
1861
1933
  severity: 3,
1862
1934
  evidence: { capacityUsage, resourcesPerAgent, avgSatisfaction },
1863
1935
  suggestedAction: {
1864
- parameter: "productionCost",
1936
+ parameterType: "cost",
1865
1937
  direction: "increase",
1866
1938
  magnitude: 0.1,
1867
1939
  reasoning: "Economy operating at full capacity with abundant resources and high satisfaction. Pinch point may have been cleared. Increase production cost to restore scarcity."
@@ -1877,7 +1949,7 @@ var P57_CombinatorialPriceSpace = {
1877
1949
  id: "P57",
1878
1950
  name: "Combinatorial Price Space",
1879
1951
  category: "market_dynamics",
1880
- description: "N tradeable items generate (N\u22121)N/2 relative prices. With thousands of items no single agent can track them all. Design for distributed self-organization, not centralized pricing.",
1952
+ description: "N tradeable items generate (N\u22121)N/2 relative prices. With thousands of items no single participant can track them all. Design for distributed self-organization, not centralized pricing.",
1881
1953
  check(metrics, thresholds) {
1882
1954
  const { prices, priceVolatility } = metrics;
1883
1955
  const priceKeys = Object.keys(prices);
@@ -1907,7 +1979,8 @@ var P57_CombinatorialPriceSpace = {
1907
1979
  target: thresholds.relativePriceConvergenceTarget
1908
1980
  },
1909
1981
  suggestedAction: {
1910
- parameter: "transactionFee",
1982
+ parameterType: "fee",
1983
+ scope: { tags: ["transaction"] },
1911
1984
  direction: "decrease",
1912
1985
  magnitude: 0.1,
1913
1986
  reasoning: `Only ${(convergenceRate * 100).toFixed(0)}% of ${relativePriceCount} relative prices have converged (target: ${(thresholds.relativePriceConvergenceTarget * 100).toFixed(0)}%). Price space too complex for distributed discovery. Lower friction to help.`
@@ -1920,8 +1993,8 @@ var P57_CombinatorialPriceSpace = {
1920
1993
  }
1921
1994
  };
1922
1995
  var MARKET_DYNAMICS_PRINCIPLES = [
1923
- P29_PinchPoint,
1924
- P30_MovingPinchPoint,
1996
+ P29_BottleneckDetection,
1997
+ P30_DynamicBottleneckRotation,
1925
1998
  P57_CombinatorialPriceSpace
1926
1999
  ];
1927
2000
 
@@ -1939,7 +2012,7 @@ var P31_AnchorValueTracking = {
1939
2012
  severity: 5,
1940
2013
  evidence: { anchorRatioDrift, inflationRate },
1941
2014
  suggestedAction: {
1942
- parameter: "productionCost",
2015
+ parameterType: "cost",
1943
2016
  direction: anchorRatioDrift > 0 ? "increase" : "decrease",
1944
2017
  magnitude: 0.1,
1945
2018
  reasoning: `Anchor ratio has drifted ${(anchorRatioDrift * 100).toFixed(0)}% from baseline. Time-to-value for participants is changing. Adjust production costs to restore.`
@@ -1964,7 +2037,8 @@ var P41_MultiResolutionMonitoring = {
1964
2037
  severity: 4,
1965
2038
  evidence: { giniCoefficient, avgSatisfaction },
1966
2039
  suggestedAction: {
1967
- parameter: "transactionFee",
2040
+ parameterType: "fee",
2041
+ scope: { tags: ["transaction"] },
1968
2042
  direction: "increase",
1969
2043
  magnitude: 0.1,
1970
2044
  reasoning: `Gini ${giniCoefficient.toFixed(2)} rising despite okay satisfaction. Early warning from fine-resolution monitoring. Raise trading fees to slow wealth concentration before it hurts satisfaction.`
@@ -1993,7 +2067,8 @@ var P55_ArbitrageThermometer = {
1993
2067
  critical: thresholds.arbitrageIndexCritical
1994
2068
  },
1995
2069
  suggestedAction: {
1996
- parameter: "transactionFee",
2070
+ parameterType: "fee",
2071
+ scope: { tags: ["transaction"] },
1997
2072
  direction: "decrease",
1998
2073
  magnitude: 0.15,
1999
2074
  reasoning: `Arbitrage index ${arbitrageIndex.toFixed(2)} exceeds critical threshold (${thresholds.arbitrageIndexCritical}). Relative prices are diverging \u2014 economy destabilizing. Lower trading friction to accelerate price convergence.`
@@ -2011,7 +2086,8 @@ var P55_ArbitrageThermometer = {
2011
2086
  warning: thresholds.arbitrageIndexWarning
2012
2087
  },
2013
2088
  suggestedAction: {
2014
- parameter: "transactionFee",
2089
+ parameterType: "fee",
2090
+ scope: { tags: ["transaction"] },
2015
2091
  direction: "decrease",
2016
2092
  magnitude: 0.08,
2017
2093
  reasoning: `Arbitrage index ${arbitrageIndex.toFixed(2)} above warning threshold (${thresholds.arbitrageIndexWarning}). Early sign of price divergence. Gently reduce friction to support self-correction.`
@@ -2039,7 +2115,8 @@ var P59_GiftEconomyNoise = {
2039
2115
  threshold: thresholds.giftTradeFilterRatio
2040
2116
  },
2041
2117
  suggestedAction: {
2042
- parameter: "transactionFee",
2118
+ parameterType: "fee",
2119
+ scope: { tags: ["transaction"] },
2043
2120
  direction: "increase",
2044
2121
  magnitude: 0.05,
2045
2122
  reasoning: `${(giftTradeRatio * 100).toFixed(0)}% of trades are gift-like (price = 0 or <30% market). Exceeds filter threshold (${(thresholds.giftTradeFilterRatio * 100).toFixed(0)}%). Price signals contaminated. Slightly raise trading fees to discourage zero-value listings. ADVISORY: Consider filtering sub-market trades from price index computation.`
@@ -2082,9 +2159,9 @@ var P42_TheMedianPrinciple = {
2082
2159
  medianBalance
2083
2160
  },
2084
2161
  suggestedAction: {
2085
- parameter: "transactionFee",
2162
+ parameterType: "fee",
2163
+ scope: { tags: ["transaction"], currency: curr },
2086
2164
  direction: "increase",
2087
- currency: curr,
2088
2165
  magnitude: 0.15,
2089
2166
  reasoning: `[${curr}] Mean/median divergence ${(meanMedianDivergence * 100).toFixed(0)}% (threshold: ${(thresholds.meanMedianDivergenceMax * 100).toFixed(0)}%). Economy has outliers skewing metrics. Use median for decisions. Raise transaction fees to redistribute wealth.`
2090
2167
  },
@@ -2109,7 +2186,7 @@ var P43_SimulationMinimum = {
2109
2186
  severity: 3,
2110
2187
  evidence: { inflationRate, minIterations: thresholds.simulationMinIterations },
2111
2188
  suggestedAction: {
2112
- parameter: "productionCost",
2189
+ parameterType: "cost",
2113
2190
  direction: inflationRate > 0 ? "increase" : "decrease",
2114
2191
  magnitude: 0.05,
2115
2192
  reasoning: `Large inflation rate swing (${(inflationRate * 100).toFixed(0)}%). Ensure all decisions use \u2265${thresholds.simulationMinIterations} simulation iterations. Apply conservative correction.`
@@ -2147,7 +2224,7 @@ var P39_TheLagPrinciple = {
2147
2224
  severity: 5,
2148
2225
  evidence: { inflationRate, netFlow, lagRange: [lagMin, lagMax] },
2149
2226
  suggestedAction: {
2150
- parameter: "productionCost",
2227
+ parameterType: "cost",
2151
2228
  direction: "increase",
2152
2229
  magnitude: 0.03,
2153
2230
  // very small — oscillation means over-adjusting
@@ -2174,7 +2251,8 @@ var P44_ComplexityBudget = {
2174
2251
  severity: 3,
2175
2252
  evidence: { customMetricCount, budgetMax: thresholds.complexityBudgetMax },
2176
2253
  suggestedAction: {
2177
- parameter: "transactionFee",
2254
+ parameterType: "fee",
2255
+ scope: { tags: ["transaction"] },
2178
2256
  direction: "decrease",
2179
2257
  magnitude: 0.01,
2180
2258
  reasoning: `${customMetricCount} custom metrics tracked (budget: ${thresholds.complexityBudgetMax}). Consider pruning low-impact parameters. Applying minimal correction to avoid adding complexity.`
@@ -2206,7 +2284,8 @@ var P35_DestructionCreatesValue = {
2206
2284
  severity: 6,
2207
2285
  evidence: { resource, supply, sinkVolume, netFlow },
2208
2286
  suggestedAction: {
2209
- parameter: "entryFee",
2287
+ parameterType: "fee",
2288
+ scope: { tags: ["entry"] },
2210
2289
  direction: "decrease",
2211
2290
  magnitude: 0.1,
2212
2291
  reasoning: `${resource} supply at ${supply} units with low destruction (sink ${sinkVolume}/t). Resources not being consumed. Lower competitive pool entry to increase resource usage.`
@@ -2223,7 +2302,7 @@ var P40_ReplacementRate = {
2223
2302
  id: "P40",
2224
2303
  name: "Replacement Rate \u2265 2\xD7 Consumption",
2225
2304
  category: "resource",
2226
- 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.",
2227
2306
  check(metrics, thresholds) {
2228
2307
  const { productionIndex, sinkVolume } = metrics;
2229
2308
  if (sinkVolume > 0 && productionIndex > 0) {
@@ -2234,7 +2313,7 @@ var P40_ReplacementRate = {
2234
2313
  severity: 6,
2235
2314
  evidence: { productionIndex, sinkVolume, replacementRatio },
2236
2315
  suggestedAction: {
2237
- parameter: "yieldRate",
2316
+ parameterType: "yield",
2238
2317
  direction: "increase",
2239
2318
  magnitude: 0.15,
2240
2319
  reasoning: `Replacement rate ${replacementRatio.toFixed(2)} (need \u2265${thresholds.replacementRateMultiplier}). Production below consumption. Resources will deplete. Increase yield.`
@@ -2248,7 +2327,7 @@ var P40_ReplacementRate = {
2248
2327
  severity: 3,
2249
2328
  evidence: { productionIndex, sinkVolume, replacementRatio },
2250
2329
  suggestedAction: {
2251
- parameter: "yieldRate",
2330
+ parameterType: "yield",
2252
2331
  direction: "decrease",
2253
2332
  magnitude: 0.1,
2254
2333
  reasoning: `Replacement rate ${replacementRatio.toFixed(2)} \u2014 overproducing. Production far exceeds consumption. Reduce yield to prevent glut.`
@@ -2274,7 +2353,8 @@ var P49_IdleAssetTax = {
2274
2353
  severity: 5,
2275
2354
  evidence: { giniCoefficient, top10PctShare, velocity },
2276
2355
  suggestedAction: {
2277
- parameter: "transactionFee",
2356
+ parameterType: "fee",
2357
+ scope: { tags: ["transaction"] },
2278
2358
  direction: "increase",
2279
2359
  magnitude: 0.15,
2280
2360
  reasoning: `Gini ${giniCoefficient.toFixed(2)}, top 10% hold ${(top10PctShare * 100).toFixed(0)}%, velocity ${velocity}. Wealth concentrated in idle assets. Raise trading costs to simulate holding tax.`
@@ -2292,11 +2372,11 @@ var RESOURCE_MGMT_PRINCIPLES = [
2292
2372
  P49_IdleAssetTax
2293
2373
  ];
2294
2374
 
2295
- // src/principles/player-experience.ts
2375
+ // src/principles/participant-experience.ts
2296
2376
  var P33_FairNotEqual = {
2297
2377
  id: "P33",
2298
2378
  name: "Fair \u2260 Equal",
2299
- category: "player_experience",
2379
+ category: "participant_experience",
2300
2380
  description: "Gini = 0 is boring \u2014 everyone has the same and there is nothing to strive for. Healthy inequality from skill/effort is fine. Inequality from money (pay-to-win) is toxic. Target Gini 0.3-0.45: meaningful spread, not oligarchy.",
2301
2381
  check(metrics, thresholds) {
2302
2382
  for (const curr of metrics.currencies) {
@@ -2307,9 +2387,9 @@ var P33_FairNotEqual = {
2307
2387
  severity: 3,
2308
2388
  evidence: { currency: curr, giniCoefficient },
2309
2389
  suggestedAction: {
2310
- parameter: "rewardRate",
2390
+ parameterType: "reward",
2311
2391
  direction: "increase",
2312
- currency: curr,
2392
+ scope: { currency: curr },
2313
2393
  magnitude: 0.1,
2314
2394
  reasoning: `[${curr}] Gini ${giniCoefficient.toFixed(2)} \u2014 near-perfect equality. Economy lacks stakes. Increase winner rewards to create meaningful spread.`
2315
2395
  },
@@ -2323,9 +2403,9 @@ var P33_FairNotEqual = {
2323
2403
  severity: 7,
2324
2404
  evidence: { currency: curr, giniCoefficient },
2325
2405
  suggestedAction: {
2326
- parameter: "transactionFee",
2406
+ parameterType: "fee",
2327
2407
  direction: "increase",
2328
- currency: curr,
2408
+ scope: { tags: ["transaction"], currency: curr },
2329
2409
  magnitude: 0.2,
2330
2410
  reasoning: `[${curr}] Gini ${giniCoefficient.toFixed(2)} \u2014 oligarchy level. Toxic inequality. Raise transaction fees to redistribute wealth from rich to pool.`
2331
2411
  },
@@ -2339,9 +2419,9 @@ var P33_FairNotEqual = {
2339
2419
  severity: 4,
2340
2420
  evidence: { currency: curr, giniCoefficient },
2341
2421
  suggestedAction: {
2342
- parameter: "transactionFee",
2422
+ parameterType: "fee",
2343
2423
  direction: "increase",
2344
- currency: curr,
2424
+ scope: { tags: ["transaction"], currency: curr },
2345
2425
  magnitude: 0.1,
2346
2426
  reasoning: `[${curr}] Gini ${giniCoefficient.toFixed(2)} \u2014 high inequality warning. Gently raise fees to slow wealth concentration.`
2347
2427
  },
@@ -2355,9 +2435,9 @@ var P33_FairNotEqual = {
2355
2435
  };
2356
2436
  var P36_MechanicFrictionDetector = {
2357
2437
  id: "P36",
2358
- name: "Mechanic Friction Detector",
2359
- category: "player_experience",
2360
- description: "Deterministic + probabilistic systems \u2192 expectation mismatch. When crafting is guaranteed but combat is random, players feel betrayed by the random side. Mix mechanics carefully or segregate them entirely.",
2438
+ name: "Mechanism Friction Detector",
2439
+ category: "participant_experience",
2440
+ description: "Deterministic + probabilistic systems \u2192 expectation mismatch. When production is guaranteed but competition is random, participants feel betrayed by the random side. Mix mechanisms carefully or segregate them entirely.",
2361
2441
  check(metrics, _thresholds) {
2362
2442
  const { avgSatisfaction, churnRate, velocity } = metrics;
2363
2443
  if (churnRate > 0.1 && avgSatisfaction < 50 && velocity > 3) {
@@ -2366,10 +2446,10 @@ var P36_MechanicFrictionDetector = {
2366
2446
  severity: 5,
2367
2447
  evidence: { churnRate, avgSatisfaction, velocity },
2368
2448
  suggestedAction: {
2369
- parameter: "rewardRate",
2449
+ parameterType: "reward",
2370
2450
  direction: "increase",
2371
2451
  magnitude: 0.15,
2372
- reasoning: `Churn ${(churnRate * 100).toFixed(1)}% with satisfaction ${avgSatisfaction.toFixed(0)} despite active economy (velocity ` + velocity.toFixed(1) + "). Suggests mechanic friction (deterministic vs random systems). Increase rewards to compensate for perceived unfairness. ADVISORY: Review if mixing guaranteed and probabilistic mechanics."
2452
+ reasoning: `Churn ${(churnRate * 100).toFixed(1)}% with satisfaction ${avgSatisfaction.toFixed(0)} despite active economy (velocity ` + velocity.toFixed(1) + "). Suggests mechanism friction (deterministic vs random systems). Increase rewards to compensate for perceived unfairness. ADVISORY: Review if mixing guaranteed and probabilistic mechanisms."
2373
2453
  },
2374
2454
  confidence: 0.55,
2375
2455
  estimatedLag: 15
@@ -2380,8 +2460,8 @@ var P36_MechanicFrictionDetector = {
2380
2460
  };
2381
2461
  var P37_LatecommerProblem = {
2382
2462
  id: "P37",
2383
- name: "Latecomer Problem",
2384
- category: "player_experience",
2463
+ name: "Late Entrant Problem",
2464
+ category: "participant_experience",
2385
2465
  description: "A new participant must reach viability in reasonable time. If all the good roles are saturated and prices are high, new agents cannot contribute and churn immediately.",
2386
2466
  check(metrics, _thresholds) {
2387
2467
  const { timeToValue, avgSatisfaction, churnRate } = metrics;
@@ -2391,7 +2471,7 @@ var P37_LatecommerProblem = {
2391
2471
  severity: 6,
2392
2472
  evidence: { timeToValue, avgSatisfaction, churnRate },
2393
2473
  suggestedAction: {
2394
- parameter: "productionCost",
2474
+ parameterType: "cost",
2395
2475
  direction: "decrease",
2396
2476
  magnitude: 0.15,
2397
2477
  reasoning: `New agents taking ${timeToValue} ticks to reach viability. Churn ${(churnRate * 100).toFixed(1)}%, satisfaction ${avgSatisfaction.toFixed(0)}. Lower production costs to help new participants contribute faster.`
@@ -2406,7 +2486,7 @@ var P37_LatecommerProblem = {
2406
2486
  var P45_TimeBudget = {
2407
2487
  id: "P45",
2408
2488
  name: "Time Budget",
2409
- category: "player_experience",
2489
+ category: "participant_experience",
2410
2490
  description: "required_time \u2264 available_time \xD7 0.8. If the economy requires more engagement than participants can realistically give, it is a disguised paywall. The 0.8 buffer accounts for real life.",
2411
2491
  check(metrics, thresholds) {
2412
2492
  const { timeToValue, avgSatisfaction } = metrics;
@@ -2418,8 +2498,9 @@ var P45_TimeBudget = {
2418
2498
  severity: 5,
2419
2499
  evidence: { timeToValue, avgSatisfaction, timeBudgetRatio: thresholds.timeBudgetRatio },
2420
2500
  suggestedAction: {
2421
- parameter: "entryFee",
2501
+ parameterType: "fee",
2422
2502
  direction: "decrease",
2503
+ scope: { tags: ["entry"] },
2423
2504
  magnitude: 0.15,
2424
2505
  reasoning: `Time-to-value ${timeToValue} ticks with ${avgSatisfaction.toFixed(0)} satisfaction. Economy requires too much time investment. Lower barriers to participation.`
2425
2506
  },
@@ -2433,7 +2514,7 @@ var P45_TimeBudget = {
2433
2514
  var P50_PayPowerRatio = {
2434
2515
  id: "P50",
2435
2516
  name: "Pay-Power Ratio",
2436
- category: "player_experience",
2517
+ category: "participant_experience",
2437
2518
  description: "spender / non-spender power ratio > 2.0 = pay-to-win territory. Target 1.5 (meaningful advantage without shutting out non-payers). Above 2.0, non-paying participants start leaving.",
2438
2519
  check(metrics, thresholds) {
2439
2520
  const { top10PctShare, giniCoefficient } = metrics;
@@ -2448,8 +2529,9 @@ var P50_PayPowerRatio = {
2448
2529
  threshold: thresholds.payPowerRatioMax
2449
2530
  },
2450
2531
  suggestedAction: {
2451
- parameter: "transactionFee",
2532
+ parameterType: "fee",
2452
2533
  direction: "increase",
2534
+ scope: { tags: ["transaction"] },
2453
2535
  magnitude: 0.2,
2454
2536
  reasoning: `Top 10% hold ${(top10PctShare * 100).toFixed(0)}% of wealth (Gini ${giniCoefficient.toFixed(2)}). Wealth advantage may exceed pay-power ratio threshold. Redistribute via higher trading fees.`
2455
2537
  },
@@ -2460,7 +2542,7 @@ var P50_PayPowerRatio = {
2460
2542
  return { violated: false };
2461
2543
  }
2462
2544
  };
2463
- var PLAYER_EXPERIENCE_PRINCIPLES = [
2545
+ var PARTICIPANT_EXPERIENCE_PRINCIPLES = [
2464
2546
  P33_FairNotEqual,
2465
2547
  P36_MechanicFrictionDetector,
2466
2548
  P37_LatecommerProblem,
@@ -2483,7 +2565,8 @@ var P34_ExtractionRatio = {
2483
2565
  severity: 8,
2484
2566
  evidence: { extractionRatio, threshold: thresholds.extractionRatioRed },
2485
2567
  suggestedAction: {
2486
- parameter: "transactionFee",
2568
+ parameterType: "fee",
2569
+ scope: { tags: ["transaction"] },
2487
2570
  direction: "increase",
2488
2571
  magnitude: 0.25,
2489
2572
  reasoning: `Extraction ratio ${(extractionRatio * 100).toFixed(0)}% (critical: ${(thresholds.extractionRatioRed * 100).toFixed(0)}%). Economy is extraction-heavy and subsidy-dependent. Raise fees to increase the cost of extraction.`
@@ -2498,7 +2581,8 @@ var P34_ExtractionRatio = {
2498
2581
  severity: 5,
2499
2582
  evidence: { extractionRatio, threshold: thresholds.extractionRatioYellow },
2500
2583
  suggestedAction: {
2501
- parameter: "transactionFee",
2584
+ parameterType: "fee",
2585
+ scope: { tags: ["transaction"] },
2502
2586
  direction: "increase",
2503
2587
  magnitude: 0.1,
2504
2588
  reasoning: `Extraction ratio ${(extractionRatio * 100).toFixed(0)}% (warning: ${(thresholds.extractionRatioYellow * 100).toFixed(0)}%). Economy trending toward extraction-heavy. Apply early pressure.`
@@ -2524,7 +2608,7 @@ var P47_SmokeTest = {
2524
2608
  severity: 9,
2525
2609
  evidence: { smokeTestRatio, threshold: thresholds.smokeTestCritical },
2526
2610
  suggestedAction: {
2527
- parameter: "rewardRate",
2611
+ parameterType: "reward",
2528
2612
  direction: "increase",
2529
2613
  magnitude: 0.2,
2530
2614
  reasoning: `Utility/market ratio ${(smokeTestRatio * 100).toFixed(0)}% (critical). Economy is >90% speculative. Collapse risk is extreme. Increase utility rewards to anchor real value.`
@@ -2539,7 +2623,7 @@ var P47_SmokeTest = {
2539
2623
  severity: 6,
2540
2624
  evidence: { smokeTestRatio, threshold: thresholds.smokeTestWarning },
2541
2625
  suggestedAction: {
2542
- parameter: "rewardRate",
2626
+ parameterType: "reward",
2543
2627
  direction: "increase",
2544
2628
  magnitude: 0.1,
2545
2629
  reasoning: `Utility/market ratio ${(smokeTestRatio * 100).toFixed(0)}% (warning). Economy is >70% speculative. Boost utility rewards to restore intrinsic value anchor.`
@@ -2565,7 +2649,8 @@ var P48_CurrencyInsulation = {
2565
2649
  severity: 6,
2566
2650
  evidence: { currencyInsulation, threshold: thresholds.currencyInsulationMax },
2567
2651
  suggestedAction: {
2568
- parameter: "transactionFee",
2652
+ parameterType: "fee",
2653
+ scope: { tags: ["transaction"] },
2569
2654
  direction: "increase",
2570
2655
  magnitude: 0.1,
2571
2656
  reasoning: `Currency correlation with external market: ${(currencyInsulation * 100).toFixed(0)}% (max: ${(thresholds.currencyInsulationMax * 100).toFixed(0)}%). Economy is exposed to external market shocks. Increase internal friction to reduce external correlation.`
@@ -2583,12 +2668,12 @@ var OPEN_ECONOMY_PRINCIPLES = [
2583
2668
  P48_CurrencyInsulation
2584
2669
  ];
2585
2670
 
2586
- // src/principles/liveops.ts
2587
- var P51_SharkTooth = {
2671
+ // src/principles/operations.ts
2672
+ var P51_CyclicalEngagement = {
2588
2673
  id: "P51",
2589
- name: "Shark Tooth Pattern",
2590
- category: "liveops",
2591
- description: "Each event peak should be \u226595% of the previous peak. If peaks are shrinking (shark tooth becoming flat), event fatigue is setting in. If valleys are deepening, the off-event economy is failing to sustain engagement.",
2674
+ name: "Cyclical Engagement Pattern",
2675
+ category: "operations",
2676
+ description: "Each activity peak should be >=95% of the previous peak. If peaks are shrinking (cyclical engagement becoming flat), activity fatigue is setting in. If valleys are deepening, the off-activity economy is failing to sustain engagement.",
2592
2677
  check(metrics, thresholds) {
2593
2678
  const { sharkToothPeaks, sharkToothValleys } = metrics;
2594
2679
  if (sharkToothPeaks.length < 2) return { violated: false };
@@ -2605,10 +2690,10 @@ var P51_SharkTooth = {
2605
2690
  threshold: thresholds.sharkToothPeakDecay
2606
2691
  },
2607
2692
  suggestedAction: {
2608
- parameter: "rewardRate",
2693
+ parameterType: "reward",
2609
2694
  direction: "increase",
2610
2695
  magnitude: 0.1,
2611
- reasoning: `Peak engagement dropped to ${(lastPeak / prevPeak * 100).toFixed(0)}% of previous peak (threshold: ${(thresholds.sharkToothPeakDecay * 100).toFixed(0)}%). Event fatigue detected. Boost event rewards to restore peak engagement.`
2696
+ reasoning: `Peak engagement dropped to ${(lastPeak / prevPeak * 100).toFixed(0)}% of previous peak (threshold: ${(thresholds.sharkToothPeakDecay * 100).toFixed(0)}%). Activity fatigue detected. Boost activity rewards to restore peak engagement.`
2612
2697
  },
2613
2698
  confidence: 0.75,
2614
2699
  estimatedLag: 30
@@ -2623,10 +2708,10 @@ var P51_SharkTooth = {
2623
2708
  severity: 4,
2624
2709
  evidence: { lastValley, prevValley, ratio: lastValley / prevValley },
2625
2710
  suggestedAction: {
2626
- parameter: "productionCost",
2711
+ parameterType: "cost",
2627
2712
  direction: "decrease",
2628
2713
  magnitude: 0.1,
2629
- reasoning: "Between-event engagement declining (deepening valleys). Base economy not sustaining participants between events. Lower production costs to improve off-event value."
2714
+ reasoning: "Between-activity engagement declining (deepening valleys). Base economy not sustaining participants between activities. Lower production costs to improve off-activity value."
2630
2715
  },
2631
2716
  confidence: 0.65,
2632
2717
  estimatedLag: 20
@@ -2639,8 +2724,8 @@ var P51_SharkTooth = {
2639
2724
  var P52_EndowmentEffect = {
2640
2725
  id: "P52",
2641
2726
  name: "Endowment Effect",
2642
- category: "liveops",
2643
- description: "Participants who never owned premium items do not value them. Free trial events that let participants experience premium items drive conversions because ownership creates perceived value (endowment effect).",
2727
+ category: "operations",
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).",
2644
2729
  check(metrics, _thresholds) {
2645
2730
  const { avgSatisfaction, churnRate } = metrics;
2646
2731
  const { eventCompletionRate } = metrics;
@@ -2651,10 +2736,10 @@ var P52_EndowmentEffect = {
2651
2736
  severity: 4,
2652
2737
  evidence: { eventCompletionRate, avgSatisfaction, churnRate },
2653
2738
  suggestedAction: {
2654
- parameter: "rewardRate",
2739
+ parameterType: "reward",
2655
2740
  direction: "increase",
2656
2741
  magnitude: 0.15,
2657
- reasoning: `${(eventCompletionRate * 100).toFixed(0)}% event completion but satisfaction only ${avgSatisfaction.toFixed(0)}. Events not creating perceived value. Increase reward quality/quantity.`
2742
+ reasoning: `${(eventCompletionRate * 100).toFixed(0)}% activity completion but satisfaction only ${avgSatisfaction.toFixed(0)}. Activities not creating perceived value. Increase reward quality/quantity.`
2658
2743
  },
2659
2744
  confidence: 0.6,
2660
2745
  estimatedLag: 20
@@ -2665,8 +2750,8 @@ var P52_EndowmentEffect = {
2665
2750
  };
2666
2751
  var P53_EventCompletionRate = {
2667
2752
  id: "P53",
2668
- name: "Event Completion Rate Sweet Spot",
2669
- category: "liveops",
2753
+ name: "Activity Completion Rate Sweet Spot",
2754
+ category: "operations",
2670
2755
  description: "Free completion at 60-80% is the sweet spot. <40% = predatory design. >80% = no monetization pressure. 100% free = zero reason to ever spend.",
2671
2756
  check(metrics, thresholds) {
2672
2757
  const { eventCompletionRate } = metrics;
@@ -2681,10 +2766,10 @@ var P53_EventCompletionRate = {
2681
2766
  max: thresholds.eventCompletionMax
2682
2767
  },
2683
2768
  suggestedAction: {
2684
- parameter: "productionCost",
2769
+ parameterType: "cost",
2685
2770
  direction: "decrease",
2686
2771
  magnitude: 0.15,
2687
- reasoning: `Event completion rate ${(eventCompletionRate * 100).toFixed(0)}% \u2014 predatory territory (min: ${(thresholds.eventCompletionMin * 100).toFixed(0)}%). Too hard for free participants. Lower barriers to participation.`
2772
+ reasoning: `Activity completion rate ${(eventCompletionRate * 100).toFixed(0)}% \u2014 predatory territory (min: ${(thresholds.eventCompletionMin * 100).toFixed(0)}%). Too hard for free participants. Lower barriers to participation.`
2688
2773
  },
2689
2774
  confidence: 0.8,
2690
2775
  estimatedLag: 10
@@ -2696,10 +2781,11 @@ var P53_EventCompletionRate = {
2696
2781
  severity: 3,
2697
2782
  evidence: { eventCompletionRate, max: thresholds.eventCompletionMax },
2698
2783
  suggestedAction: {
2699
- parameter: "entryFee",
2784
+ parameterType: "fee",
2785
+ scope: { tags: ["entry"] },
2700
2786
  direction: "increase",
2701
2787
  magnitude: 0.05,
2702
- reasoning: `Event completion rate ${(eventCompletionRate * 100).toFixed(0)}% \u2014 no monetization pressure (max: ${(thresholds.eventCompletionMax * 100).toFixed(0)}%). Slightly raise costs to create meaningful premium differentiation.`
2788
+ reasoning: `Activity completion rate ${(eventCompletionRate * 100).toFixed(0)}% \u2014 no monetization pressure (max: ${(thresholds.eventCompletionMax * 100).toFixed(0)}%). Slightly raise costs to create meaningful premium differentiation.`
2703
2789
  },
2704
2790
  confidence: 0.55,
2705
2791
  estimatedLag: 10
@@ -2708,11 +2794,11 @@ var P53_EventCompletionRate = {
2708
2794
  return { violated: false };
2709
2795
  }
2710
2796
  };
2711
- var P54_LiveOpsCadence = {
2797
+ var P54_OperationalCadence = {
2712
2798
  id: "P54",
2713
- name: "LiveOps Cadence",
2714
- category: "liveops",
2715
- description: ">50% of events 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.",
2799
+ name: "Operational Cadence",
2800
+ category: "operations",
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.",
2716
2802
  check(metrics, _thresholds) {
2717
2803
  const { velocity, avgSatisfaction } = metrics;
2718
2804
  if (velocity < 2 && avgSatisfaction < 55 && metrics.tick > 100) {
@@ -2721,10 +2807,10 @@ var P54_LiveOpsCadence = {
2721
2807
  severity: 3,
2722
2808
  evidence: { velocity, avgSatisfaction, tick: metrics.tick },
2723
2809
  suggestedAction: {
2724
- parameter: "rewardRate",
2810
+ parameterType: "reward",
2725
2811
  direction: "increase",
2726
2812
  magnitude: 0.1,
2727
- 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)."
2728
2814
  },
2729
2815
  confidence: 0.4,
2730
2816
  estimatedLag: 30
@@ -2733,11 +2819,11 @@ var P54_LiveOpsCadence = {
2733
2819
  return { violated: false };
2734
2820
  }
2735
2821
  };
2736
- var P56_ContentDropShock = {
2822
+ var P56_SupplyShockAbsorption = {
2737
2823
  id: "P56",
2738
- name: "Content-Drop Shock",
2739
- category: "liveops",
2740
- 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.",
2824
+ name: "Supply Shock Absorption",
2825
+ category: "operations",
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.",
2741
2827
  check(metrics, thresholds) {
2742
2828
  const { contentDropAge, arbitrageIndex } = metrics;
2743
2829
  if (contentDropAge > 0 && contentDropAge <= thresholds.contentDropCooldownTicks) {
@@ -2752,10 +2838,11 @@ var P56_ContentDropShock = {
2752
2838
  postDropMax: thresholds.postDropArbitrageMax
2753
2839
  },
2754
2840
  suggestedAction: {
2755
- parameter: "transactionFee",
2841
+ parameterType: "fee",
2842
+ scope: { tags: ["transaction"] },
2756
2843
  direction: "decrease",
2757
2844
  magnitude: 0.1,
2758
- 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.`
2759
2846
  },
2760
2847
  confidence: 0.6,
2761
2848
  estimatedLag: 5
@@ -2765,12 +2852,12 @@ var P56_ContentDropShock = {
2765
2852
  return { violated: false };
2766
2853
  }
2767
2854
  };
2768
- var LIVEOPS_PRINCIPLES = [
2769
- P51_SharkTooth,
2855
+ var OPERATIONS_PRINCIPLES = [
2856
+ P51_CyclicalEngagement,
2770
2857
  P52_EndowmentEffect,
2771
2858
  P53_EventCompletionRate,
2772
- P54_LiveOpsCadence,
2773
- P56_ContentDropShock
2859
+ P54_OperationalCadence,
2860
+ P56_SupplyShockAbsorption
2774
2861
  ];
2775
2862
 
2776
2863
  // src/principles/index.ts
@@ -2799,23 +2886,24 @@ var ALL_PRINCIPLES = [
2799
2886
  // P39, P44
2800
2887
  ...RESOURCE_MGMT_PRINCIPLES,
2801
2888
  // P35, P40, P49
2802
- ...PLAYER_EXPERIENCE_PRINCIPLES,
2889
+ ...PARTICIPANT_EXPERIENCE_PRINCIPLES,
2803
2890
  // P33, P36, P37, P45, P50
2804
2891
  ...OPEN_ECONOMY_PRINCIPLES,
2805
2892
  // P34, P47-P48
2806
- ...LIVEOPS_PRINCIPLES
2893
+ ...OPERATIONS_PRINCIPLES
2807
2894
  // P51-P54, P56
2808
2895
  ];
2809
2896
 
2810
2897
  // src/Simulator.ts
2811
2898
  var Simulator = class {
2812
- constructor() {
2899
+ constructor(registry) {
2813
2900
  this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
2814
2901
  // Cache beforeViolations for the *current* tick only (one entry max).
2815
2902
  // Using a Map here is intentional but the cache must be bounded — we only
2816
2903
  // care about the tick that is currently being evaluated, so we evict any
2817
2904
  // entries whose key differs from the incoming tick.
2818
2905
  this.beforeViolationsCache = /* @__PURE__ */ new Map();
2906
+ this.registry = registry;
2819
2907
  }
2820
2908
  /**
2821
2909
  * Simulate the effect of applying `action` to the current economy forward `forwardTicks`.
@@ -2882,7 +2970,7 @@ var Simulator = class {
2882
2970
  const multiplier = this.actionMultiplier(action);
2883
2971
  const noise = () => 1 + (Math.random() - 0.5) * 0.1;
2884
2972
  const currencies = metrics.currencies;
2885
- const targetCurrency = action.currency;
2973
+ const targetCurrency = action.scope?.currency;
2886
2974
  const supplies = { ...metrics.totalSupplyByCurrency };
2887
2975
  const netFlows = { ...metrics.netFlowByCurrency };
2888
2976
  const ginis = { ...metrics.giniCoefficientByCurrency };
@@ -2924,26 +3012,54 @@ var Simulator = class {
2924
3012
  return action.direction === "increase" ? 1 + base : 1 - base;
2925
3013
  }
2926
3014
  flowEffect(action, metrics, currency) {
2927
- const { parameter, direction } = action;
3015
+ const { direction } = action;
2928
3016
  const sign = direction === "increase" ? -1 : 1;
2929
3017
  const roleEntries = Object.entries(metrics.populationByRole).sort((a, b) => b[1] - a[1]);
2930
3018
  const dominantRoleCount = roleEntries[0]?.[1] ?? 0;
2931
- if (parameter === "productionCost") {
2932
- return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.2;
2933
- }
2934
- if (parameter === "transactionFee") {
2935
- return sign * (metrics.velocityByCurrency[currency] ?? 0) * 10 * 0.1;
2936
- }
2937
- if (parameter === "entryFee") {
2938
- return sign * dominantRoleCount * 0.5;
2939
- }
2940
- if (parameter === "rewardRate") {
2941
- return -sign * dominantRoleCount * 0.3;
3019
+ let impact;
3020
+ if (this.registry) {
3021
+ const resolved = this.registry.resolve(action.parameterType, action.scope);
3022
+ if (resolved) {
3023
+ impact = resolved.flowImpact;
3024
+ }
2942
3025
  }
2943
- if (parameter === "yieldRate") {
2944
- return sign * (metrics.faucetVolumeByCurrency[currency] ?? 0) * 0.15;
3026
+ if (!impact) {
3027
+ impact = this.inferFlowImpact(action.parameterType);
3028
+ }
3029
+ switch (impact) {
3030
+ case "sink":
3031
+ return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.2;
3032
+ case "faucet":
3033
+ return -sign * dominantRoleCount * 0.3;
3034
+ case "neutral":
3035
+ return sign * dominantRoleCount * 0.5;
3036
+ case "mixed":
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;
3042
+ default:
3043
+ return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
3044
+ }
3045
+ }
3046
+ /** Infer flow impact from parameter type when registry is unavailable */
3047
+ inferFlowImpact(parameterType) {
3048
+ switch (parameterType) {
3049
+ case "cost":
3050
+ case "fee":
3051
+ case "penalty":
3052
+ return "sink";
3053
+ case "reward":
3054
+ return "faucet";
3055
+ case "yield":
3056
+ return "mixed";
3057
+ case "cap":
3058
+ case "multiplier":
3059
+ return "neutral";
3060
+ default:
3061
+ return "mixed";
2945
3062
  }
2946
- return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
2947
3063
  }
2948
3064
  checkImprovement(before, after, action) {
2949
3065
  const satisfactionImproved = after.avgSatisfaction >= before.avgSatisfaction - 2;
@@ -3005,6 +3121,8 @@ var Planner = class {
3005
3121
  this.constraints = /* @__PURE__ */ new Map();
3006
3122
  this.cooldowns = /* @__PURE__ */ new Map();
3007
3123
  // param → last-applied-tick
3124
+ this.typeCooldowns = /* @__PURE__ */ new Map();
3125
+ // type+scope key → last-applied-tick
3008
3126
  this.activePlanCount = 0;
3009
3127
  }
3010
3128
  lock(param) {
@@ -3023,16 +3141,32 @@ var Planner = class {
3023
3141
  * - parameter is still in cooldown
3024
3142
  * - simulation result failed
3025
3143
  * - complexity budget exceeded
3144
+ * - no matching parameter in registry
3026
3145
  */
3027
- plan(diagnosis, metrics, simulationResult, currentParams, thresholds) {
3146
+ plan(diagnosis, metrics, simulationResult, currentParams, thresholds, registry) {
3028
3147
  const action = diagnosis.violation.suggestedAction;
3029
- const param = action.parameter;
3148
+ const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
3149
+ if (this.isTypeCooldown(typeKey, metrics.tick, thresholds.cooldownTicks)) return null;
3150
+ let param;
3151
+ let resolvedBaseline;
3152
+ let scope;
3153
+ if (registry) {
3154
+ const resolved = registry.resolve(action.parameterType, action.scope);
3155
+ if (!resolved) return null;
3156
+ param = resolved.key;
3157
+ resolvedBaseline = resolved.currentValue;
3158
+ scope = resolved.scope;
3159
+ action.resolvedParameter = param;
3160
+ } else {
3161
+ param = action.resolvedParameter ?? action.parameterType;
3162
+ scope = action.scope;
3163
+ }
3030
3164
  if (this.lockedParams.has(param)) return null;
3031
3165
  if (this.isOnCooldown(param, metrics.tick, thresholds.cooldownTicks)) return null;
3032
3166
  if (!simulationResult.netImprovement) return null;
3033
3167
  if (!simulationResult.noNewProblems) return null;
3034
3168
  if (this.activePlanCount >= thresholds.complexityBudgetMax) return null;
3035
- const currentValue = currentParams[param] ?? 1;
3169
+ const currentValue = resolvedBaseline ?? currentParams[param] ?? action.absoluteValue ?? 1;
3036
3170
  const magnitude = Math.min(action.magnitude ?? 0.1, thresholds.maxAdjustmentPercent);
3037
3171
  let targetValue;
3038
3172
  if (action.direction === "set" && action.absoluteValue !== void 0) {
@@ -3052,7 +3186,7 @@ var Planner = class {
3052
3186
  id: `plan_${metrics.tick}_${param}`,
3053
3187
  diagnosis,
3054
3188
  parameter: param,
3055
- ...action.currency !== void 0 ? { currency: action.currency } : {},
3189
+ ...scope !== void 0 ? { scope } : {},
3056
3190
  currentValue,
3057
3191
  targetValue,
3058
3192
  maxChangePercent: thresholds.maxAdjustmentPercent,
@@ -3061,7 +3195,6 @@ var Planner = class {
3061
3195
  metric: "avgSatisfaction",
3062
3196
  direction: "below",
3063
3197
  threshold: Math.max(20, metrics.avgSatisfaction - 10),
3064
- // rollback if sat drops >10 pts
3065
3198
  checkAfterTick: metrics.tick + estimatedLag + 3
3066
3199
  },
3067
3200
  simulationResult,
@@ -3071,11 +3204,17 @@ var Planner = class {
3071
3204
  }
3072
3205
  recordApplied(plan, tick) {
3073
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);
3074
3210
  this.activePlanCount++;
3075
3211
  }
3076
3212
  recordRolledBack(_plan) {
3077
3213
  this.activePlanCount = Math.max(0, this.activePlanCount - 1);
3078
3214
  }
3215
+ recordSettled(_plan) {
3216
+ this.activePlanCount = Math.max(0, this.activePlanCount - 1);
3217
+ }
3079
3218
  isOnCooldown(param, currentTick, cooldownTicks) {
3080
3219
  const lastApplied = this.cooldowns.get(param);
3081
3220
  if (lastApplied === void 0) return false;
@@ -3084,6 +3223,19 @@ var Planner = class {
3084
3223
  /** Reset all cooldowns (useful for testing) */
3085
3224
  resetCooldowns() {
3086
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;
3087
3239
  }
3088
3240
  };
3089
3241
 
@@ -3094,40 +3246,54 @@ var Executor = class {
3094
3246
  }
3095
3247
  async apply(plan, adapter, currentParams) {
3096
3248
  const originalValue = currentParams[plan.parameter] ?? plan.currentValue;
3097
- await adapter.setParam(plan.parameter, plan.targetValue, plan.currency);
3249
+ await adapter.setParam(plan.parameter, plan.targetValue, plan.scope);
3098
3250
  plan.appliedAt = plan.diagnosis.tick;
3099
3251
  this.activePlans.push({ plan, originalValue });
3100
3252
  }
3101
3253
  /**
3102
3254
  * Check all active plans for rollback conditions.
3103
- * Called every tick after metrics are computed.
3104
- * Returns list of plans that were rolled back.
3255
+ * Returns { rolledBack, settled } plans that were undone and plans that passed their window.
3105
3256
  */
3106
3257
  async checkRollbacks(metrics, adapter) {
3107
3258
  const rolledBack = [];
3259
+ const settled = [];
3108
3260
  const remaining = [];
3109
3261
  for (const active of this.activePlans) {
3110
3262
  const { plan, originalValue } = active;
3111
3263
  const rc = plan.rollbackCondition;
3264
+ const maxActiveTicks = 200;
3265
+ if (plan.appliedAt !== void 0 && metrics.tick - plan.appliedAt > maxActiveTicks) {
3266
+ settled.push(plan);
3267
+ continue;
3268
+ }
3112
3269
  if (metrics.tick < rc.checkAfterTick) {
3113
3270
  remaining.push(active);
3114
3271
  continue;
3115
3272
  }
3116
3273
  const metricValue = this.getMetricValue(metrics, rc.metric);
3274
+ if (Number.isNaN(metricValue)) {
3275
+ console.warn(
3276
+ `[AgentE] Rollback check: metric path '${rc.metric}' resolved to NaN for plan '${plan.id}'. Triggering rollback as fail-safe.`
3277
+ );
3278
+ await adapter.setParam(plan.parameter, originalValue, plan.scope);
3279
+ rolledBack.push(plan);
3280
+ continue;
3281
+ }
3117
3282
  const shouldRollback = rc.direction === "below" ? metricValue < rc.threshold : metricValue > rc.threshold;
3118
3283
  if (shouldRollback) {
3119
- await adapter.setParam(plan.parameter, originalValue, plan.currency);
3284
+ await adapter.setParam(plan.parameter, originalValue, plan.scope);
3120
3285
  rolledBack.push(plan);
3121
3286
  } else {
3122
3287
  const settledTick = rc.checkAfterTick + 10;
3123
3288
  if (metrics.tick > settledTick) {
3289
+ settled.push(plan);
3124
3290
  } else {
3125
3291
  remaining.push(active);
3126
3292
  }
3127
3293
  }
3128
3294
  }
3129
3295
  this.activePlans = remaining;
3130
- return rolledBack;
3296
+ return { rolledBack, settled };
3131
3297
  }
3132
3298
  getMetricValue(metrics, metricPath) {
3133
3299
  const parts = metricPath.split(".");
@@ -3216,7 +3382,8 @@ var DecisionLog = class {
3216
3382
  return {
3217
3383
  id: `stub_${metrics.tick}`,
3218
3384
  diagnosis,
3219
- parameter: action.parameter,
3385
+ parameter: action.resolvedParameter ?? action.parameterType,
3386
+ ...action.scope !== void 0 ? { scope: action.scope } : {},
3220
3387
  currentValue: 1,
3221
3388
  targetValue: 1,
3222
3389
  maxChangePercent: 0,
@@ -3454,13 +3621,13 @@ var PersonaTracker = class {
3454
3621
  Earner: 0,
3455
3622
  Builder: 0,
3456
3623
  Social: 0,
3457
- Whale: 0,
3624
+ HighValue: 0,
3458
3625
  Influencer: 0
3459
3626
  };
3460
3627
  let total = 0;
3461
3628
  for (const [, history] of this.agentHistory) {
3462
3629
  const persona = this.classify(history);
3463
- counts[persona]++;
3630
+ counts[persona] = (counts[persona] ?? 0) + 1;
3464
3631
  total++;
3465
3632
  }
3466
3633
  if (total === 0) return {};
@@ -3480,7 +3647,7 @@ var PersonaTracker = class {
3480
3647
  const extraction = avg("netExtraction");
3481
3648
  const uniqueItems = avg("uniqueItemsHeld");
3482
3649
  const spend = avg("spendAmount");
3483
- if (spend > 1e3) return "Whale";
3650
+ if (spend > 1e3) return "HighValue";
3484
3651
  if (txRate > 10) return "Trader";
3485
3652
  if (uniqueItems > 5 && extraction < 0) return "Collector";
3486
3653
  if (extraction > 100) return "Earner";
@@ -3489,12 +3656,153 @@ var PersonaTracker = class {
3489
3656
  }
3490
3657
  };
3491
3658
 
3659
+ // src/ParameterRegistry.ts
3660
+ var ParameterRegistry = class {
3661
+ constructor() {
3662
+ this.parameters = /* @__PURE__ */ new Map();
3663
+ }
3664
+ /** Register a parameter. Overwrites if key already exists. */
3665
+ register(param) {
3666
+ this.parameters.set(param.key, { ...param });
3667
+ }
3668
+ /** Register multiple parameters at once. */
3669
+ registerAll(params) {
3670
+ for (const p of params) this.register(p);
3671
+ }
3672
+ /**
3673
+ * Resolve a parameterType + scope to a concrete RegisteredParameter.
3674
+ * Returns the best match, or undefined if no match.
3675
+ *
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
3682
+ */
3683
+ resolve(type, scope) {
3684
+ const candidates = this.findByType(type);
3685
+ if (candidates.length === 0) return void 0;
3686
+ if (candidates.length === 1) return candidates[0];
3687
+ let bestScore = -Infinity;
3688
+ let bestPriority = -Infinity;
3689
+ let best;
3690
+ for (const candidate of candidates) {
3691
+ const score = this.scopeSpecificity(candidate.scope, scope);
3692
+ const prio = candidate.priority ?? 0;
3693
+ if (score > bestScore || score === bestScore && prio > bestPriority) {
3694
+ bestScore = score;
3695
+ bestPriority = prio;
3696
+ best = candidate;
3697
+ }
3698
+ }
3699
+ if (bestScore === -Infinity) return void 0;
3700
+ return best;
3701
+ }
3702
+ /** Find all parameters of a given type. */
3703
+ findByType(type) {
3704
+ const results = [];
3705
+ for (const param of this.parameters.values()) {
3706
+ if (param.type === type) results.push(param);
3707
+ }
3708
+ return results;
3709
+ }
3710
+ /** Find all parameters belonging to a given system. */
3711
+ findBySystem(system) {
3712
+ const results = [];
3713
+ for (const param of this.parameters.values()) {
3714
+ if (param.scope?.system === system) results.push(param);
3715
+ }
3716
+ return results;
3717
+ }
3718
+ /** Get a parameter by its concrete key. */
3719
+ get(key) {
3720
+ return this.parameters.get(key);
3721
+ }
3722
+ /** Get the flow impact of a parameter by its concrete key. */
3723
+ getFlowImpact(key) {
3724
+ return this.parameters.get(key)?.flowImpact;
3725
+ }
3726
+ /** Update the current value of a registered parameter. */
3727
+ updateValue(key, value) {
3728
+ const param = this.parameters.get(key);
3729
+ if (param) {
3730
+ param.currentValue = value;
3731
+ }
3732
+ }
3733
+ /** Get all registered parameters. */
3734
+ getAll() {
3735
+ return [...this.parameters.values()];
3736
+ }
3737
+ /** Number of registered parameters. */
3738
+ get size() {
3739
+ return this.parameters.size;
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
+ }
3775
+ // ── Private ─────────────────────────────────────────────────────────────
3776
+ scopeSpecificity(paramScope, queryScope) {
3777
+ if (!queryScope) return 0;
3778
+ if (!paramScope) return 0;
3779
+ let score = 0;
3780
+ if (queryScope.system && paramScope.system) {
3781
+ if (queryScope.system === paramScope.system) score += 10;
3782
+ else return -Infinity;
3783
+ }
3784
+ if (queryScope.currency && paramScope.currency) {
3785
+ if (queryScope.currency === paramScope.currency) score += 5;
3786
+ else return -Infinity;
3787
+ }
3788
+ if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
3789
+ const overlap = queryScope.tags.filter((t) => paramScope.tags.includes(t)).length;
3790
+ if (overlap > 0) {
3791
+ score += overlap * 3;
3792
+ } else {
3793
+ return -Infinity;
3794
+ }
3795
+ }
3796
+ return score;
3797
+ }
3798
+ };
3799
+
3492
3800
  // src/AgentE.ts
3493
3801
  var AgentE = class {
3494
3802
  constructor(config) {
3495
- this.simulator = new Simulator();
3496
3803
  this.planner = new Planner();
3497
3804
  this.executor = new Executor();
3805
+ this.registry = new ParameterRegistry();
3498
3806
  // ── State ──
3499
3807
  this.log = new DecisionLog();
3500
3808
  this.personaTracker = new PersonaTracker();
@@ -3515,11 +3823,13 @@ var AgentE = class {
3515
3823
  mode: this.mode,
3516
3824
  dominantRoles: config.dominantRoles ?? [],
3517
3825
  idealDistribution: config.idealDistribution ?? {},
3826
+ validateRegistry: config.validateRegistry ?? true,
3518
3827
  tickConfig: config.tickConfig ?? { duration: 1, unit: "tick" },
3519
3828
  gracePeriod: config.gracePeriod ?? 50,
3520
3829
  checkInterval: config.checkInterval ?? 5,
3521
3830
  maxAdjustmentPercent: config.maxAdjustmentPercent ?? 0.15,
3522
- cooldownTicks: config.cooldownTicks ?? 15
3831
+ cooldownTicks: config.cooldownTicks ?? 15,
3832
+ parameters: config.parameters ?? []
3523
3833
  };
3524
3834
  this.thresholds = {
3525
3835
  ...DEFAULT_THRESHOLDS,
@@ -3531,6 +3841,15 @@ var AgentE = class {
3531
3841
  this.observer = new Observer(tickConfig);
3532
3842
  this.store = new MetricStore(tickConfig);
3533
3843
  this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
3844
+ if (config.parameters) {
3845
+ this.registry.registerAll(config.parameters);
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
+ }
3852
+ this.simulator = new Simulator(this.registry);
3534
3853
  if (config.onDecision) this.on("decision", config.onDecision);
3535
3854
  if (config.onAlert) this.on("alert", config.onAlert);
3536
3855
  if (config.onRollback) this.on("rollback", config.onRollback);
@@ -3568,15 +3887,24 @@ var AgentE = class {
3568
3887
  this.currentTick = currentState.tick;
3569
3888
  const events = [...this.eventBuffer];
3570
3889
  this.eventBuffer = [];
3571
- const metrics = this.observer.compute(currentState, events);
3890
+ let metrics;
3891
+ try {
3892
+ metrics = this.observer.compute(currentState, events);
3893
+ } catch (err) {
3894
+ console.error(`[AgentE] Observer.compute() failed at tick ${currentState.tick}:`, err);
3895
+ return;
3896
+ }
3572
3897
  this.store.record(metrics);
3573
3898
  this.personaTracker.update(currentState);
3574
3899
  metrics.personaDistribution = this.personaTracker.getDistribution();
3575
- const rolledBack = await this.executor.checkRollbacks(metrics, this.adapter);
3900
+ const { rolledBack, settled } = await this.executor.checkRollbacks(metrics, this.adapter);
3576
3901
  for (const plan2 of rolledBack) {
3577
3902
  this.planner.recordRolledBack(plan2);
3578
3903
  this.emit("rollback", plan2, "rollback condition triggered");
3579
3904
  }
3905
+ for (const plan2 of settled) {
3906
+ this.planner.recordSettled(plan2);
3907
+ }
3580
3908
  if (metrics.tick < this.config.gracePeriod) return;
3581
3909
  if (metrics.tick % this.config.checkInterval !== 0) return;
3582
3910
  const diagnoses = this.diagnoser.diagnose(metrics, this.thresholds);
@@ -3598,7 +3926,8 @@ var AgentE = class {
3598
3926
  metrics,
3599
3927
  simulationResult,
3600
3928
  this.params,
3601
- this.thresholds
3929
+ this.thresholds,
3930
+ this.registry
3602
3931
  );
3603
3932
  if (!plan) {
3604
3933
  let reason = "skipped_cooldown";
@@ -3618,6 +3947,7 @@ var AgentE = class {
3618
3947
  }
3619
3948
  await this.executor.apply(plan, this.adapter, this.params);
3620
3949
  this.params[plan.parameter] = plan.targetValue;
3950
+ this.registry.updateValue(plan.parameter, plan.targetValue);
3621
3951
  this.planner.recordApplied(plan, metrics.tick);
3622
3952
  const entry = this.log.record(topDiagnosis, plan, "applied", metrics);
3623
3953
  this.emit("decision", entry);
@@ -3627,6 +3957,7 @@ var AgentE = class {
3627
3957
  async apply(plan) {
3628
3958
  await this.executor.apply(plan, this.adapter, this.params);
3629
3959
  this.params[plan.parameter] = plan.targetValue;
3960
+ this.registry.updateValue(plan.parameter, plan.targetValue);
3630
3961
  this.planner.recordApplied(plan, this.currentTick);
3631
3962
  }
3632
3963
  // ── Developer API ───────────────────────────────────────────────────────────
@@ -3651,6 +3982,12 @@ var AgentE = class {
3651
3982
  removePrinciple(id) {
3652
3983
  this.diagnoser.removePrinciple(id);
3653
3984
  }
3985
+ registerParameter(param) {
3986
+ this.registry.register(param);
3987
+ }
3988
+ getRegistry() {
3989
+ return this.registry;
3990
+ }
3654
3991
  registerCustomMetric(name, fn) {
3655
3992
  this.observer.registerCustomMetric(name, fn);
3656
3993
  }
@@ -3708,6 +4045,31 @@ var AgentE = class {
3708
4045
  }
3709
4046
  };
3710
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
+
3711
4073
  // src/StateValidator.ts
3712
4074
  function validateEconomyState(state) {
3713
4075
  const errors = [];
@@ -4053,13 +4415,13 @@ function describeValue(value) {
4053
4415
  Executor,
4054
4416
  FEEDBACK_LOOP_PRINCIPLES,
4055
4417
  INCENTIVE_PRINCIPLES,
4056
- LIVEOPS_PRINCIPLES,
4057
4418
  MARKET_DYNAMICS_PRINCIPLES,
4058
4419
  MEASUREMENT_PRINCIPLES,
4059
4420
  MetricStore,
4060
4421
  OPEN_ECONOMY_PRINCIPLES,
4422
+ OPERATIONS_PRINCIPLES,
4061
4423
  Observer,
4062
- P10_SpawnWeightingUsesInversePopulation,
4424
+ P10_EntryWeightingUsesInversePopulation,
4063
4425
  P11_TwoTierPressure,
4064
4426
  P12_OnePrimaryFaucet,
4065
4427
  P13_PotsAreZeroSumAndSelfRegulate,
@@ -4079,9 +4441,9 @@ function describeValue(value) {
4079
4441
  P26_ContinuousPressureBeatsThresholdCuts,
4080
4442
  P27_AdjustmentsNeedCooldowns,
4081
4443
  P28_StructuralDominanceIsNotPathological,
4082
- P29_PinchPoint,
4444
+ P29_BottleneckDetection,
4083
4445
  P2_ClosedLoopsNeedDirectHandoff,
4084
- P30_MovingPinchPoint,
4446
+ P30_DynamicBottleneckRotation,
4085
4447
  P31_AnchorValueTracking,
4086
4448
  P32_VelocityAboveSupply,
4087
4449
  P33_FairNotEqual,
@@ -4104,12 +4466,12 @@ function describeValue(value) {
4104
4466
  P49_IdleAssetTax,
4105
4467
  P4_MaterialsFlowFasterThanCooldown,
4106
4468
  P50_PayPowerRatio,
4107
- P51_SharkTooth,
4469
+ P51_CyclicalEngagement,
4108
4470
  P52_EndowmentEffect,
4109
4471
  P53_EventCompletionRate,
4110
- P54_LiveOpsCadence,
4472
+ P54_OperationalCadence,
4111
4473
  P55_ArbitrageThermometer,
4112
- P56_ContentDropShock,
4474
+ P56_SupplyShockAbsorption,
4113
4475
  P57_CombinatorialPriceSpace,
4114
4476
  P58_NoNaturalNumeraire,
4115
4477
  P59_GiftEconomyNoise,
@@ -4119,9 +4481,10 @@ function describeValue(value) {
4119
4481
  P7_NonSpecialistsSubsidiseSpecialists,
4120
4482
  P8_RegulatorCannotFightDesign,
4121
4483
  P9_RoleSwitchingNeedsFriction,
4484
+ PARTICIPANT_EXPERIENCE_PRINCIPLES,
4122
4485
  PERSONA_HEALTHY_RANGES,
4123
- PLAYER_EXPERIENCE_PRINCIPLES,
4124
4486
  POPULATION_PRINCIPLES,
4487
+ ParameterRegistry,
4125
4488
  PersonaTracker,
4126
4489
  Planner,
4127
4490
  REGULATOR_PRINCIPLES,
@@ -4131,6 +4494,7 @@ function describeValue(value) {
4131
4494
  SYSTEM_DYNAMICS_PRINCIPLES,
4132
4495
  Simulator,
4133
4496
  emptyMetrics,
4497
+ findWorstSystem,
4134
4498
  validateEconomyState
4135
4499
  });
4136
4500
  //# sourceMappingURL=index.js.map