@agent-e/core 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -70
- package/dist/index.d.mts +78 -18
- package/dist/index.d.ts +78 -18
- package/dist/index.js +265 -130
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +257 -123
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -4
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
OPEN_ECONOMY_PRINCIPLES: () => OPEN_ECONOMY_PRINCIPLES,
|
|
37
37
|
OPERATIONS_PRINCIPLES: () => OPERATIONS_PRINCIPLES,
|
|
38
38
|
Observer: () => Observer,
|
|
39
|
-
|
|
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
|
-
|
|
59
|
+
P29_BottleneckDetection: () => P29_BottleneckDetection,
|
|
60
60
|
P2_ClosedLoopsNeedDirectHandoff: () => P2_ClosedLoopsNeedDirectHandoff,
|
|
61
|
-
|
|
61
|
+
P30_DynamicBottleneckRotation: () => P30_DynamicBottleneckRotation,
|
|
62
62
|
P31_AnchorValueTracking: () => P31_AnchorValueTracking,
|
|
63
63
|
P32_VelocityAboveSupply: () => P32_VelocityAboveSupply,
|
|
64
64
|
P33_FairNotEqual: () => P33_FairNotEqual,
|
|
@@ -81,16 +81,16 @@ __export(index_exports, {
|
|
|
81
81
|
P49_IdleAssetTax: () => P49_IdleAssetTax,
|
|
82
82
|
P4_MaterialsFlowFasterThanCooldown: () => P4_MaterialsFlowFasterThanCooldown,
|
|
83
83
|
P50_PayPowerRatio: () => P50_PayPowerRatio,
|
|
84
|
-
|
|
84
|
+
P51_CyclicalEngagement: () => P51_CyclicalEngagement,
|
|
85
85
|
P52_EndowmentEffect: () => P52_EndowmentEffect,
|
|
86
86
|
P53_EventCompletionRate: () => P53_EventCompletionRate,
|
|
87
|
-
|
|
87
|
+
P54_OperationalCadence: () => P54_OperationalCadence,
|
|
88
88
|
P55_ArbitrageThermometer: () => P55_ArbitrageThermometer,
|
|
89
|
-
|
|
89
|
+
P56_SupplyShockAbsorption: () => P56_SupplyShockAbsorption,
|
|
90
90
|
P57_CombinatorialPriceSpace: () => P57_CombinatorialPriceSpace,
|
|
91
91
|
P58_NoNaturalNumeraire: () => P58_NoNaturalNumeraire,
|
|
92
92
|
P59_GiftEconomyNoise: () => P59_GiftEconomyNoise,
|
|
93
|
-
|
|
93
|
+
P5_ProfitabilityIsRelative: () => P5_ProfitabilityIsRelative,
|
|
94
94
|
P60_SurplusDisposalAsymmetry: () => P60_SurplusDisposalAsymmetry,
|
|
95
95
|
P6_CrowdingMultiplierOnAllRoles: () => P6_CrowdingMultiplierOnAllRoles,
|
|
96
96
|
P7_NonSpecialistsSubsidiseSpecialists: () => P7_NonSpecialistsSubsidiseSpecialists,
|
|
@@ -109,6 +109,7 @@ __export(index_exports, {
|
|
|
109
109
|
SYSTEM_DYNAMICS_PRINCIPLES: () => SYSTEM_DYNAMICS_PRINCIPLES,
|
|
110
110
|
Simulator: () => Simulator,
|
|
111
111
|
emptyMetrics: () => emptyMetrics,
|
|
112
|
+
findWorstSystem: () => findWorstSystem,
|
|
112
113
|
validateEconomyState: () => validateEconomyState
|
|
113
114
|
});
|
|
114
115
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -147,7 +148,7 @@ var DEFAULT_THRESHOLDS = {
|
|
|
147
148
|
cooldownTicks: 15,
|
|
148
149
|
// Currency (P13)
|
|
149
150
|
poolWinRate: 0.65,
|
|
150
|
-
|
|
151
|
+
poolOperatorShare: 0.1,
|
|
151
152
|
// Population balance (P9)
|
|
152
153
|
roleSwitchFrictionMax: 0.05,
|
|
153
154
|
// >5% of population switching in one period = herd
|
|
@@ -208,6 +209,12 @@ var Observer = class {
|
|
|
208
209
|
this.customMetricFns[name] = fn;
|
|
209
210
|
}
|
|
210
211
|
compute(state, recentEvents) {
|
|
212
|
+
if (!state.currencies || state.currencies.length === 0) {
|
|
213
|
+
console.warn("[AgentE] Warning: state.currencies is empty. Metrics will be zeroed.");
|
|
214
|
+
}
|
|
215
|
+
if (!state.agentBalances || Object.keys(state.agentBalances).length === 0) {
|
|
216
|
+
console.warn("[AgentE] Warning: state.agentBalances is empty.");
|
|
217
|
+
}
|
|
211
218
|
const tick = state.tick;
|
|
212
219
|
const roles = Object.values(state.agentRoles);
|
|
213
220
|
const totalAgents = Object.keys(state.agentBalances).length;
|
|
@@ -255,7 +262,7 @@ var Observer = class {
|
|
|
255
262
|
if (!actorsBySystem[e.system]) actorsBySystem[e.system] = /* @__PURE__ */ new Set();
|
|
256
263
|
actorsBySystem[e.system].add(e.actor);
|
|
257
264
|
const amt = e.amount ?? 0;
|
|
258
|
-
if (e.type === "mint"
|
|
265
|
+
if (e.type === "mint") {
|
|
259
266
|
flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) + amt;
|
|
260
267
|
} else if (e.type === "burn" || e.type === "consume") {
|
|
261
268
|
flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) - amt;
|
|
@@ -263,7 +270,7 @@ var Observer = class {
|
|
|
263
270
|
}
|
|
264
271
|
if (e.sourceOrSink) {
|
|
265
272
|
const amt = e.amount ?? 0;
|
|
266
|
-
if (e.type === "mint"
|
|
273
|
+
if (e.type === "mint") {
|
|
267
274
|
flowBySource[e.sourceOrSink] = (flowBySource[e.sourceOrSink] ?? 0) + amt;
|
|
268
275
|
} else if (e.type === "burn" || e.type === "consume") {
|
|
269
276
|
flowBySink[e.sourceOrSink] = (flowBySink[e.sourceOrSink] ?? 0) + amt;
|
|
@@ -302,7 +309,7 @@ var Observer = class {
|
|
|
302
309
|
const faucet = faucetVolumeByCurrency[curr] ?? 0;
|
|
303
310
|
const sink = sinkVolumeByCurrency[curr] ?? 0;
|
|
304
311
|
netFlowByCurrency[curr] = faucet - sink;
|
|
305
|
-
tapSinkRatioByCurrency[curr] = sink > 0 ? faucet / sink : faucet > 0 ?
|
|
312
|
+
tapSinkRatioByCurrency[curr] = sink > 0 ? Math.min(faucet / sink, 100) : faucet > 0 ? 100 : 1;
|
|
306
313
|
const prevSupply = this.previousMetrics?.totalSupplyByCurrency?.[curr] ?? totalSupplyByCurrency[curr] ?? 0;
|
|
307
314
|
const currSupply = totalSupplyByCurrency[curr] ?? 0;
|
|
308
315
|
inflationRateByCurrency[curr] = prevSupply > 0 ? (currSupply - prevSupply) / prevSupply : 0;
|
|
@@ -337,7 +344,7 @@ var Observer = class {
|
|
|
337
344
|
const faucetVolume = Object.values(faucetVolumeByCurrency).reduce((s, v) => s + v, 0);
|
|
338
345
|
const sinkVolume = Object.values(sinkVolumeByCurrency).reduce((s, v) => s + v, 0);
|
|
339
346
|
const netFlow = faucetVolume - sinkVolume;
|
|
340
|
-
const tapSinkRatio = sinkVolume > 0 ? faucetVolume / sinkVolume : faucetVolume > 0 ?
|
|
347
|
+
const tapSinkRatio = sinkVolume > 0 ? Math.min(faucetVolume / sinkVolume, 100) : faucetVolume > 0 ? 100 : 1;
|
|
341
348
|
const velocity = totalSupply > 0 ? tradeEvents.length / totalSupply : 0;
|
|
342
349
|
const prevTotalSupply = this.previousMetrics?.totalSupply ?? totalSupply;
|
|
343
350
|
const inflationRate = prevTotalSupply > 0 ? (totalSupply - prevTotalSupply) / prevTotalSupply : 0;
|
|
@@ -375,7 +382,9 @@ var Observer = class {
|
|
|
375
382
|
const pVals = Object.values(resourcePrices);
|
|
376
383
|
priceIndexByCurrency[curr] = pVals.length > 0 ? pVals.reduce((s, p) => s + p, 0) / pVals.length : 0;
|
|
377
384
|
}
|
|
378
|
-
this.previousPricesByCurrency =
|
|
385
|
+
this.previousPricesByCurrency = Object.fromEntries(
|
|
386
|
+
Object.entries(pricesByCurrency).map(([c, p]) => [c, { ...p }])
|
|
387
|
+
);
|
|
379
388
|
const prices = pricesByCurrency[defaultCurrency] ?? {};
|
|
380
389
|
const priceVolatility = priceVolatilityByCurrency[defaultCurrency] ?? {};
|
|
381
390
|
const priceIndex = priceIndexByCurrency[defaultCurrency] ?? 0;
|
|
@@ -395,9 +404,9 @@ var Observer = class {
|
|
|
395
404
|
for (const resource of /* @__PURE__ */ new Set([...Object.keys(supplyByResource), ...Object.keys(demandSignals)])) {
|
|
396
405
|
const s = supplyByResource[resource] ?? 0;
|
|
397
406
|
const d = demandSignals[resource] ?? 0;
|
|
398
|
-
if (d > 2 && s / d < 0.5) {
|
|
407
|
+
if (d > 0 && d > 2 && s / d < 0.5) {
|
|
399
408
|
pinchPoints[resource] = "scarce";
|
|
400
|
-
} else if (
|
|
409
|
+
} else if (d > 0 && s > 3 && s / d > 3) {
|
|
401
410
|
pinchPoints[resource] = "oversupplied";
|
|
402
411
|
} else {
|
|
403
412
|
pinchPoints[resource] = "optimal";
|
|
@@ -443,21 +452,11 @@ var Observer = class {
|
|
|
443
452
|
const arbitrageIndexByCurrency = {};
|
|
444
453
|
for (const curr of currencies) {
|
|
445
454
|
const cPrices = pricesByCurrency[curr] ?? {};
|
|
446
|
-
const
|
|
447
|
-
if (
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
for (let j = i + 1; j < priceKeys.length; j++) {
|
|
452
|
-
const pA = cPrices[priceKeys[i]];
|
|
453
|
-
const pB = cPrices[priceKeys[j]];
|
|
454
|
-
let ratio = pA / pB;
|
|
455
|
-
ratio = Math.max(1e-3, Math.min(1e3, ratio));
|
|
456
|
-
totalDivergence += Math.abs(Math.log(ratio));
|
|
457
|
-
pairCount++;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
arbitrageIndexByCurrency[curr] = pairCount > 0 ? Math.min(1, totalDivergence / pairCount) : 0;
|
|
455
|
+
const logPrices = Object.values(cPrices).filter((p) => p > 0).map((p) => Math.log(p));
|
|
456
|
+
if (logPrices.length >= 2) {
|
|
457
|
+
const mean = logPrices.reduce((s, v) => s + v, 0) / logPrices.length;
|
|
458
|
+
const variance = logPrices.reduce((s, v) => s + (v - mean) ** 2, 0) / logPrices.length;
|
|
459
|
+
arbitrageIndexByCurrency[curr] = Math.min(1, Math.sqrt(variance));
|
|
461
460
|
} else {
|
|
462
461
|
arbitrageIndexByCurrency[curr] = 0;
|
|
463
462
|
}
|
|
@@ -544,10 +543,10 @@ var Observer = class {
|
|
|
544
543
|
prices,
|
|
545
544
|
priceVolatility,
|
|
546
545
|
poolSizes: poolSizesAggregate,
|
|
547
|
-
extractionRatio:
|
|
548
|
-
newUserDependency:
|
|
549
|
-
smokeTestRatio:
|
|
550
|
-
currencyInsulation:
|
|
546
|
+
extractionRatio: 0,
|
|
547
|
+
newUserDependency: 0,
|
|
548
|
+
smokeTestRatio: 0,
|
|
549
|
+
currencyInsulation: 0,
|
|
551
550
|
arbitrageIndex,
|
|
552
551
|
giftTradeRatio,
|
|
553
552
|
disposalTradeRatio,
|
|
@@ -569,8 +568,11 @@ var Observer = class {
|
|
|
569
568
|
timeToValue,
|
|
570
569
|
sharkToothPeaks: this.previousMetrics?.sharkToothPeaks ?? [],
|
|
571
570
|
sharkToothValleys: this.previousMetrics?.sharkToothValleys ?? [],
|
|
572
|
-
eventCompletionRate:
|
|
571
|
+
eventCompletionRate: 0,
|
|
573
572
|
contentDropAge,
|
|
573
|
+
systems: state.systems ?? [],
|
|
574
|
+
sources: state.sources ?? [],
|
|
575
|
+
sinks: state.sinks ?? [],
|
|
574
576
|
flowBySystem,
|
|
575
577
|
activityBySystem,
|
|
576
578
|
participantsBySystem,
|
|
@@ -598,7 +600,7 @@ function computeGini(sorted) {
|
|
|
598
600
|
for (let i = 0; i < n; i++) {
|
|
599
601
|
numerator += (2 * (i + 1) - n - 1) * (sorted[i] ?? 0);
|
|
600
602
|
}
|
|
601
|
-
return Math.abs(numerator) / (n * sum);
|
|
603
|
+
return Math.min(1, Math.abs(numerator) / (n * sum));
|
|
602
604
|
}
|
|
603
605
|
|
|
604
606
|
// src/Diagnoser.ts
|
|
@@ -694,10 +696,10 @@ function emptyMetrics(tick = 0) {
|
|
|
694
696
|
prices: {},
|
|
695
697
|
priceVolatility: {},
|
|
696
698
|
poolSizes: {},
|
|
697
|
-
extractionRatio:
|
|
698
|
-
newUserDependency:
|
|
699
|
-
smokeTestRatio:
|
|
700
|
-
currencyInsulation:
|
|
699
|
+
extractionRatio: 0,
|
|
700
|
+
newUserDependency: 0,
|
|
701
|
+
smokeTestRatio: 0,
|
|
702
|
+
currencyInsulation: 0,
|
|
701
703
|
arbitrageIndex: 0,
|
|
702
704
|
giftTradeRatio: 0,
|
|
703
705
|
disposalTradeRatio: 0,
|
|
@@ -718,8 +720,11 @@ function emptyMetrics(tick = 0) {
|
|
|
718
720
|
timeToValue: 0,
|
|
719
721
|
sharkToothPeaks: [],
|
|
720
722
|
sharkToothValleys: [],
|
|
721
|
-
eventCompletionRate:
|
|
723
|
+
eventCompletionRate: 0,
|
|
722
724
|
contentDropAge: 0,
|
|
725
|
+
systems: [],
|
|
726
|
+
sources: [],
|
|
727
|
+
sinks: [],
|
|
723
728
|
flowBySystem: {},
|
|
724
729
|
activityBySystem: {},
|
|
725
730
|
participantsBySystem: {},
|
|
@@ -920,9 +925,9 @@ var SUPPLY_CHAIN_PRINCIPLES = [
|
|
|
920
925
|
];
|
|
921
926
|
|
|
922
927
|
// src/principles/incentives.ts
|
|
923
|
-
var
|
|
928
|
+
var P5_ProfitabilityIsRelative = {
|
|
924
929
|
id: "P5",
|
|
925
|
-
name: "Profitability Is
|
|
930
|
+
name: "Profitability Is Relative, Not Absolute",
|
|
926
931
|
category: "incentive",
|
|
927
932
|
description: "Any profitability formula that returns the same number regardless of how many agents are already in that role will cause stampedes. 97 intermediaries happened because profit = transactions \xD7 10 with no competition denominator.",
|
|
928
933
|
check(metrics, thresholds) {
|
|
@@ -986,7 +991,7 @@ var P7_NonSpecialistsSubsidiseSpecialists = {
|
|
|
986
991
|
id: "P7",
|
|
987
992
|
name: "Non-Specialists Subsidise Specialists in Zero-Sum Games",
|
|
988
993
|
category: "incentive",
|
|
989
|
-
description: "In zero-sum pools (
|
|
994
|
+
description: "In zero-sum pools (staking, prize pools, etc.), the math only works if non-specialists overpay relative to specialists. If the pool is >70% specialists, there is no one left to subsidise and the pot drains.",
|
|
990
995
|
check(metrics, _thresholds) {
|
|
991
996
|
const { poolSizes } = metrics;
|
|
992
997
|
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
@@ -1022,7 +1027,7 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
1022
1027
|
id: "P8",
|
|
1023
1028
|
name: "Regulator Cannot Fight the Design",
|
|
1024
1029
|
category: "incentive",
|
|
1025
|
-
description: "If the economy is designed to have a majority role (e.g. dominant role exceeds 55%), the regulator must know this and exempt that role from population suppression. AgentE at tick 1 seeing dominant role exceeds 55% and slashing
|
|
1030
|
+
description: "If the economy is designed to have a majority role (e.g. dominant role exceeds 55%), the regulator must know this and exempt that role from population suppression. AgentE at tick 1 seeing dominant role exceeds 55% and slashing pool rewards is overreach.",
|
|
1026
1031
|
check(metrics, _thresholds) {
|
|
1027
1032
|
const { roleShares, avgSatisfaction } = metrics;
|
|
1028
1033
|
if (avgSatisfaction < 45) {
|
|
@@ -1047,7 +1052,7 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
1047
1052
|
}
|
|
1048
1053
|
};
|
|
1049
1054
|
var INCENTIVE_PRINCIPLES = [
|
|
1050
|
-
|
|
1055
|
+
P5_ProfitabilityIsRelative,
|
|
1051
1056
|
P6_CrowdingMultiplierOnAllRoles,
|
|
1052
1057
|
P7_NonSpecialistsSubsidiseSpecialists,
|
|
1053
1058
|
P8_RegulatorCannotFightDesign
|
|
@@ -1058,7 +1063,7 @@ var P9_RoleSwitchingNeedsFriction = {
|
|
|
1058
1063
|
id: "P9",
|
|
1059
1064
|
name: "Role Switching Needs Friction",
|
|
1060
1065
|
category: "population",
|
|
1061
|
-
description: "If >5% of the population switches roles in a single evaluation period, it is a herd movement, not rational rebalancing. Without friction (satisfaction cost,
|
|
1066
|
+
description: "If >5% of the population switches roles in a single evaluation period, it is a herd movement, not rational rebalancing. Without friction (satisfaction cost, minimum interval), one good tick causes mass migration.",
|
|
1062
1067
|
check(metrics, thresholds) {
|
|
1063
1068
|
const { churnByRole, roleShares } = metrics;
|
|
1064
1069
|
const totalChurn = Object.values(churnByRole).reduce((s, v) => s + v, 0);
|
|
@@ -1081,7 +1086,7 @@ var P9_RoleSwitchingNeedsFriction = {
|
|
|
1081
1086
|
return { violated: false };
|
|
1082
1087
|
}
|
|
1083
1088
|
};
|
|
1084
|
-
var
|
|
1089
|
+
var P10_EntryWeightingUsesInversePopulation = {
|
|
1085
1090
|
id: "P10",
|
|
1086
1091
|
name: "Entry Weighting Uses Inverse Population",
|
|
1087
1092
|
category: "population",
|
|
@@ -1187,7 +1192,7 @@ var P46_PersonaDiversity = {
|
|
|
1187
1192
|
};
|
|
1188
1193
|
var POPULATION_PRINCIPLES = [
|
|
1189
1194
|
P9_RoleSwitchingNeedsFriction,
|
|
1190
|
-
|
|
1195
|
+
P10_EntryWeightingUsesInversePopulation,
|
|
1191
1196
|
P11_TwoTierPressure,
|
|
1192
1197
|
P46_PersonaDiversity
|
|
1193
1198
|
];
|
|
@@ -1243,7 +1248,7 @@ var P13_PotsAreZeroSumAndSelfRegulate = {
|
|
|
1243
1248
|
id: "P13",
|
|
1244
1249
|
name: "Pots Self-Regulate with Correct Multiplier",
|
|
1245
1250
|
category: "currency",
|
|
1246
|
-
description: "
|
|
1251
|
+
description: "Pool math: winRate \xD7 multiplier > (1 - operatorShare) drains the pot. At 65% win rate, multiplier must be \u2264 1.38. We use 1.5 for slight surplus buffer.",
|
|
1247
1252
|
check(metrics, thresholds) {
|
|
1248
1253
|
const { populationByRole } = metrics;
|
|
1249
1254
|
const roleEntries = Object.entries(populationByRole).sort((a, b) => b[1] - a[1]);
|
|
@@ -1252,8 +1257,8 @@ var P13_PotsAreZeroSumAndSelfRegulate = {
|
|
|
1252
1257
|
for (const curr of metrics.currencies) {
|
|
1253
1258
|
const poolSize = currencyAmounts[curr] ?? 0;
|
|
1254
1259
|
if (dominantCount > 5 && poolSize < 50) {
|
|
1255
|
-
const { poolWinRate,
|
|
1256
|
-
const maxSustainableMultiplier = (1 -
|
|
1260
|
+
const { poolWinRate, poolOperatorShare } = thresholds;
|
|
1261
|
+
const maxSustainableMultiplier = (1 - poolOperatorShare) / poolWinRate;
|
|
1257
1262
|
return {
|
|
1258
1263
|
violated: true,
|
|
1259
1264
|
severity: 7,
|
|
@@ -1278,7 +1283,7 @@ var P14_TrackActualInjection = {
|
|
|
1278
1283
|
id: "P14",
|
|
1279
1284
|
name: "Track Actual Currency Injection, Not Value Creation",
|
|
1280
1285
|
category: "currency",
|
|
1281
|
-
description: 'Counting resource
|
|
1286
|
+
description: 'Counting resource extraction as "currency injected" is misleading. Currency enters through faucet mechanisms (entering, rewards). Fake metrics break every downstream decision.',
|
|
1282
1287
|
check(metrics, _thresholds) {
|
|
1283
1288
|
for (const curr of metrics.currencies) {
|
|
1284
1289
|
const faucetVolume = metrics.faucetVolumeByCurrency[curr] ?? 0;
|
|
@@ -1536,7 +1541,7 @@ var P19_StartingSupplyExceedsDemand = {
|
|
|
1536
1541
|
parameterType: "reward",
|
|
1537
1542
|
direction: "increase",
|
|
1538
1543
|
magnitude: 0.2,
|
|
1539
|
-
reasoning: `${mostPopulatedRole} (${population} agents) has insufficient resources (${resourcesPerAgent.toFixed(2)} per agent). Cold-start scarcity. Boost
|
|
1544
|
+
reasoning: `${mostPopulatedRole} (${population} agents) has insufficient resources (${resourcesPerAgent.toFixed(2)} per agent). Cold-start scarcity. Boost pool reward to attract participation despite scarcity.`
|
|
1540
1545
|
},
|
|
1541
1546
|
confidence: 0.75,
|
|
1542
1547
|
estimatedLag: 5
|
|
@@ -1866,7 +1871,7 @@ var REGULATOR_PRINCIPLES = [
|
|
|
1866
1871
|
];
|
|
1867
1872
|
|
|
1868
1873
|
// src/principles/market-dynamics.ts
|
|
1869
|
-
var
|
|
1874
|
+
var P29_BottleneckDetection = {
|
|
1870
1875
|
id: "P29",
|
|
1871
1876
|
name: "Bottleneck Detection",
|
|
1872
1877
|
category: "market_dynamics",
|
|
@@ -1911,7 +1916,7 @@ var P29_PinchPoint = {
|
|
|
1911
1916
|
return { violated: false };
|
|
1912
1917
|
}
|
|
1913
1918
|
};
|
|
1914
|
-
var
|
|
1919
|
+
var P30_DynamicBottleneckRotation = {
|
|
1915
1920
|
id: "P30",
|
|
1916
1921
|
name: "Dynamic Bottleneck Rotation",
|
|
1917
1922
|
category: "market_dynamics",
|
|
@@ -1986,8 +1991,8 @@ var P57_CombinatorialPriceSpace = {
|
|
|
1986
1991
|
}
|
|
1987
1992
|
};
|
|
1988
1993
|
var MARKET_DYNAMICS_PRINCIPLES = [
|
|
1989
|
-
|
|
1990
|
-
|
|
1994
|
+
P29_BottleneckDetection,
|
|
1995
|
+
P30_DynamicBottleneckRotation,
|
|
1991
1996
|
P57_CombinatorialPriceSpace
|
|
1992
1997
|
];
|
|
1993
1998
|
|
|
@@ -2281,7 +2286,7 @@ var P35_DestructionCreatesValue = {
|
|
|
2281
2286
|
scope: { tags: ["entry"] },
|
|
2282
2287
|
direction: "decrease",
|
|
2283
2288
|
magnitude: 0.1,
|
|
2284
|
-
reasoning: `${resource} supply at ${supply} units with low destruction (sink ${sinkVolume}/t). Resources not being consumed. Lower
|
|
2289
|
+
reasoning: `${resource} supply at ${supply} units with low destruction (sink ${sinkVolume}/t). Resources not being consumed. Lower pool entry to increase resource usage.`
|
|
2285
2290
|
},
|
|
2286
2291
|
confidence: 0.7,
|
|
2287
2292
|
estimatedLag: 5
|
|
@@ -2295,7 +2300,7 @@ var P40_ReplacementRate = {
|
|
|
2295
2300
|
id: "P40",
|
|
2296
2301
|
name: "Replacement Rate \u2265 2\xD7 Consumption",
|
|
2297
2302
|
category: "resource",
|
|
2298
|
-
description: "
|
|
2303
|
+
description: "Replacement/production rate must be at least 2\xD7 consumption rate for equilibrium. At 1\xD7 you drift toward depletion. At 2\xD7 you have a buffer for demand spikes.",
|
|
2299
2304
|
check(metrics, thresholds) {
|
|
2300
2305
|
const { productionIndex, sinkVolume } = metrics;
|
|
2301
2306
|
if (sinkVolume > 0 && productionIndex > 0) {
|
|
@@ -2662,7 +2667,7 @@ var OPEN_ECONOMY_PRINCIPLES = [
|
|
|
2662
2667
|
];
|
|
2663
2668
|
|
|
2664
2669
|
// src/principles/operations.ts
|
|
2665
|
-
var
|
|
2670
|
+
var P51_CyclicalEngagement = {
|
|
2666
2671
|
id: "P51",
|
|
2667
2672
|
name: "Cyclical Engagement Pattern",
|
|
2668
2673
|
category: "operations",
|
|
@@ -2718,7 +2723,7 @@ var P52_EndowmentEffect = {
|
|
|
2718
2723
|
id: "P52",
|
|
2719
2724
|
name: "Endowment Effect",
|
|
2720
2725
|
category: "operations",
|
|
2721
|
-
description: "Participants who never owned premium
|
|
2726
|
+
description: "Participants who never owned premium assets do not value them. Free trial activities that let participants experience premium assets drive conversions because ownership creates perceived value (endowment effect).",
|
|
2722
2727
|
check(metrics, _thresholds) {
|
|
2723
2728
|
const { avgSatisfaction, churnRate } = metrics;
|
|
2724
2729
|
const { eventCompletionRate } = metrics;
|
|
@@ -2787,11 +2792,11 @@ var P53_EventCompletionRate = {
|
|
|
2787
2792
|
return { violated: false };
|
|
2788
2793
|
}
|
|
2789
2794
|
};
|
|
2790
|
-
var
|
|
2795
|
+
var P54_OperationalCadence = {
|
|
2791
2796
|
id: "P54",
|
|
2792
2797
|
name: "Operational Cadence",
|
|
2793
2798
|
category: "operations",
|
|
2794
|
-
description: ">50% of activities that are re-wrapped existing
|
|
2799
|
+
description: ">50% of activities that are re-wrapped existing supply \u2192 stagnation. The cadence must include genuinely new supply at regular intervals. This is an advisory principle \u2014 AgentE can flag but cannot fix supply.",
|
|
2795
2800
|
check(metrics, _thresholds) {
|
|
2796
2801
|
const { velocity, avgSatisfaction } = metrics;
|
|
2797
2802
|
if (velocity < 2 && avgSatisfaction < 55 && metrics.tick > 100) {
|
|
@@ -2803,7 +2808,7 @@ var P54_LiveOpsCadence = {
|
|
|
2803
2808
|
parameterType: "reward",
|
|
2804
2809
|
direction: "increase",
|
|
2805
2810
|
magnitude: 0.1,
|
|
2806
|
-
reasoning: "Low velocity and satisfaction after long runtime. Possible
|
|
2811
|
+
reasoning: "Low velocity and satisfaction after long runtime. Possible supply stagnation. Increase rewards as bridge while new supply is developed (developer action required)."
|
|
2807
2812
|
},
|
|
2808
2813
|
confidence: 0.4,
|
|
2809
2814
|
estimatedLag: 30
|
|
@@ -2812,11 +2817,11 @@ var P54_LiveOpsCadence = {
|
|
|
2812
2817
|
return { violated: false };
|
|
2813
2818
|
}
|
|
2814
2819
|
};
|
|
2815
|
-
var
|
|
2820
|
+
var P56_SupplyShockAbsorption = {
|
|
2816
2821
|
id: "P56",
|
|
2817
2822
|
name: "Supply Shock Absorption",
|
|
2818
2823
|
category: "operations",
|
|
2819
|
-
description: "Every new-item injection shatters existing price equilibria \u2014 arbitrage spikes as participants re-price. Build
|
|
2824
|
+
description: "Every new-item injection shatters existing price equilibria \u2014 arbitrage spikes as participants re-price. Build stabilization windows for price discovery before measuring post-injection economic health.",
|
|
2820
2825
|
check(metrics, thresholds) {
|
|
2821
2826
|
const { contentDropAge, arbitrageIndex } = metrics;
|
|
2822
2827
|
if (contentDropAge > 0 && contentDropAge <= thresholds.contentDropCooldownTicks) {
|
|
@@ -2835,7 +2840,7 @@ var P56_ContentDropShock = {
|
|
|
2835
2840
|
scope: { tags: ["transaction"] },
|
|
2836
2841
|
direction: "decrease",
|
|
2837
2842
|
magnitude: 0.1,
|
|
2838
|
-
reasoning: `
|
|
2843
|
+
reasoning: `Supply injection ${contentDropAge} ticks ago \u2014 arbitrage at ${arbitrageIndex.toFixed(2)} exceeds post-injection max (${thresholds.postDropArbitrageMax}). Price discovery struggling. Lower trading friction temporarily.`
|
|
2839
2844
|
},
|
|
2840
2845
|
confidence: 0.6,
|
|
2841
2846
|
estimatedLag: 5
|
|
@@ -2846,11 +2851,11 @@ var P56_ContentDropShock = {
|
|
|
2846
2851
|
}
|
|
2847
2852
|
};
|
|
2848
2853
|
var OPERATIONS_PRINCIPLES = [
|
|
2849
|
-
|
|
2854
|
+
P51_CyclicalEngagement,
|
|
2850
2855
|
P52_EndowmentEffect,
|
|
2851
2856
|
P53_EventCompletionRate,
|
|
2852
|
-
|
|
2853
|
-
|
|
2857
|
+
P54_OperationalCadence,
|
|
2858
|
+
P56_SupplyShockAbsorption
|
|
2854
2859
|
];
|
|
2855
2860
|
|
|
2856
2861
|
// src/principles/index.ts
|
|
@@ -2888,15 +2893,24 @@ var ALL_PRINCIPLES = [
|
|
|
2888
2893
|
];
|
|
2889
2894
|
|
|
2890
2895
|
// src/Simulator.ts
|
|
2896
|
+
var DEFAULT_SIM_CONFIG = {
|
|
2897
|
+
sinkMultiplier: 0.2,
|
|
2898
|
+
faucetMultiplier: 0.15,
|
|
2899
|
+
frictionMultiplier: 0.1,
|
|
2900
|
+
frictionVelocityScale: 10,
|
|
2901
|
+
redistributionMultiplier: 0.3,
|
|
2902
|
+
neutralMultiplier: 0.05,
|
|
2903
|
+
minIterations: 100,
|
|
2904
|
+
maxProjectionTicks: 20
|
|
2905
|
+
};
|
|
2891
2906
|
var Simulator = class {
|
|
2892
|
-
constructor(registry) {
|
|
2907
|
+
constructor(registry, simConfig) {
|
|
2893
2908
|
this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
|
|
2894
|
-
// Cache beforeViolations for the *current* tick only
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
// entries whose key differs from the incoming tick.
|
|
2898
|
-
this.beforeViolationsCache = /* @__PURE__ */ new Map();
|
|
2909
|
+
// Cache beforeViolations for the *current* tick only.
|
|
2910
|
+
this.cachedViolationsTick = -1;
|
|
2911
|
+
this.cachedViolations = /* @__PURE__ */ new Set();
|
|
2899
2912
|
this.registry = registry;
|
|
2913
|
+
this.simConfig = { ...DEFAULT_SIM_CONFIG, ...simConfig };
|
|
2900
2914
|
}
|
|
2901
2915
|
/**
|
|
2902
2916
|
* Simulate the effect of applying `action` to the current economy forward `forwardTicks`.
|
|
@@ -2920,16 +2934,13 @@ var Simulator = class {
|
|
|
2920
2934
|
const mean = this.averageMetrics(outcomes);
|
|
2921
2935
|
const netImprovement = this.checkImprovement(currentMetrics, p50, action);
|
|
2922
2936
|
const tick = currentMetrics.tick;
|
|
2923
|
-
if (this.
|
|
2924
|
-
this.
|
|
2925
|
-
}
|
|
2926
|
-
let beforeViolations = this.beforeViolationsCache.get(tick);
|
|
2927
|
-
if (!beforeViolations) {
|
|
2928
|
-
beforeViolations = new Set(
|
|
2937
|
+
if (this.cachedViolationsTick !== tick) {
|
|
2938
|
+
this.cachedViolations = new Set(
|
|
2929
2939
|
this.diagnoser.diagnose(currentMetrics, thresholds).map((d) => d.principle.id)
|
|
2930
2940
|
);
|
|
2931
|
-
this.
|
|
2941
|
+
this.cachedViolationsTick = tick;
|
|
2932
2942
|
}
|
|
2943
|
+
const beforeViolations = this.cachedViolations;
|
|
2933
2944
|
const afterViolations = new Set(
|
|
2934
2945
|
this.diagnoser.diagnose(p50, thresholds).map((d) => d.principle.id)
|
|
2935
2946
|
);
|
|
@@ -3009,25 +3020,32 @@ var Simulator = class {
|
|
|
3009
3020
|
const sign = direction === "increase" ? -1 : 1;
|
|
3010
3021
|
const roleEntries = Object.entries(metrics.populationByRole).sort((a, b) => b[1] - a[1]);
|
|
3011
3022
|
const dominantRoleCount = roleEntries[0]?.[1] ?? 0;
|
|
3012
|
-
const resolvedKey = action.resolvedParameter;
|
|
3013
3023
|
let impact;
|
|
3014
|
-
if (
|
|
3015
|
-
|
|
3024
|
+
if (this.registry) {
|
|
3025
|
+
const resolved = this.registry.resolve(action.parameterType, action.scope);
|
|
3026
|
+
if (resolved) {
|
|
3027
|
+
impact = resolved.flowImpact;
|
|
3028
|
+
}
|
|
3016
3029
|
}
|
|
3017
3030
|
if (!impact) {
|
|
3018
3031
|
impact = this.inferFlowImpact(action.parameterType);
|
|
3019
3032
|
}
|
|
3033
|
+
const cfg = this.simConfig;
|
|
3020
3034
|
switch (impact) {
|
|
3021
3035
|
case "sink":
|
|
3022
|
-
return sign * (metrics.netFlowByCurrency[currency] ?? 0) *
|
|
3036
|
+
return sign * (metrics.netFlowByCurrency[currency] ?? 0) * cfg.sinkMultiplier;
|
|
3023
3037
|
case "faucet":
|
|
3024
|
-
return -sign * dominantRoleCount *
|
|
3038
|
+
return -sign * dominantRoleCount * cfg.redistributionMultiplier;
|
|
3025
3039
|
case "neutral":
|
|
3026
|
-
return sign * dominantRoleCount *
|
|
3040
|
+
return sign * dominantRoleCount * cfg.neutralMultiplier;
|
|
3027
3041
|
case "mixed":
|
|
3028
|
-
return sign * (metrics.faucetVolumeByCurrency[currency] ?? 0) *
|
|
3042
|
+
return sign * (metrics.faucetVolumeByCurrency[currency] ?? 0) * cfg.faucetMultiplier;
|
|
3043
|
+
case "friction":
|
|
3044
|
+
return sign * (metrics.netFlowByCurrency[currency] ?? 0) * cfg.frictionMultiplier;
|
|
3045
|
+
case "redistribution":
|
|
3046
|
+
return sign * dominantRoleCount * cfg.neutralMultiplier;
|
|
3029
3047
|
default:
|
|
3030
|
-
return sign * (metrics.netFlowByCurrency[currency] ?? 0) *
|
|
3048
|
+
return sign * (metrics.netFlowByCurrency[currency] ?? 0) * cfg.frictionMultiplier;
|
|
3031
3049
|
}
|
|
3032
3050
|
}
|
|
3033
3051
|
/** Infer flow impact from parameter type when registry is unavailable */
|
|
@@ -3048,7 +3066,7 @@ var Simulator = class {
|
|
|
3048
3066
|
return "mixed";
|
|
3049
3067
|
}
|
|
3050
3068
|
}
|
|
3051
|
-
checkImprovement(before, after,
|
|
3069
|
+
checkImprovement(before, after, _action) {
|
|
3052
3070
|
const satisfactionImproved = after.avgSatisfaction >= before.avgSatisfaction - 2;
|
|
3053
3071
|
const flowMoreBalanced = before.currencies.every((curr) => {
|
|
3054
3072
|
const afterFlow = Math.abs(after.netFlowByCurrency[curr] ?? 0);
|
|
@@ -3060,7 +3078,6 @@ var Simulator = class {
|
|
|
3060
3078
|
const beforeGini = before.giniCoefficientByCurrency[curr] ?? 0;
|
|
3061
3079
|
return afterGini <= beforeGini + 0.05;
|
|
3062
3080
|
});
|
|
3063
|
-
void action;
|
|
3064
3081
|
return satisfactionImproved && flowMoreBalanced && notWorseGini;
|
|
3065
3082
|
}
|
|
3066
3083
|
averageMetrics(outcomes) {
|
|
@@ -3108,6 +3125,8 @@ var Planner = class {
|
|
|
3108
3125
|
this.constraints = /* @__PURE__ */ new Map();
|
|
3109
3126
|
this.cooldowns = /* @__PURE__ */ new Map();
|
|
3110
3127
|
// param → last-applied-tick
|
|
3128
|
+
this.typeCooldowns = /* @__PURE__ */ new Map();
|
|
3129
|
+
// type+scope key → last-applied-tick
|
|
3111
3130
|
this.activePlanCount = 0;
|
|
3112
3131
|
}
|
|
3113
3132
|
lock(param) {
|
|
@@ -3130,6 +3149,8 @@ var Planner = class {
|
|
|
3130
3149
|
*/
|
|
3131
3150
|
plan(diagnosis, metrics, simulationResult, currentParams, thresholds, registry) {
|
|
3132
3151
|
const action = diagnosis.violation.suggestedAction;
|
|
3152
|
+
const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
|
|
3153
|
+
if (this.isTypeCooldown(typeKey, metrics.tick, thresholds.cooldownTicks)) return null;
|
|
3133
3154
|
let param;
|
|
3134
3155
|
let resolvedBaseline;
|
|
3135
3156
|
let scope;
|
|
@@ -3187,6 +3208,9 @@ var Planner = class {
|
|
|
3187
3208
|
}
|
|
3188
3209
|
recordApplied(plan, tick) {
|
|
3189
3210
|
this.cooldowns.set(plan.parameter, tick);
|
|
3211
|
+
const action = plan.diagnosis.violation.suggestedAction;
|
|
3212
|
+
const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
|
|
3213
|
+
this.typeCooldowns.set(typeKey, tick);
|
|
3190
3214
|
this.activePlanCount++;
|
|
3191
3215
|
}
|
|
3192
3216
|
recordRolledBack(_plan) {
|
|
@@ -3203,13 +3227,35 @@ var Planner = class {
|
|
|
3203
3227
|
/** Reset all cooldowns (useful for testing) */
|
|
3204
3228
|
resetCooldowns() {
|
|
3205
3229
|
this.cooldowns.clear();
|
|
3230
|
+
this.typeCooldowns.clear();
|
|
3231
|
+
}
|
|
3232
|
+
/** V1.5.2: Reset active plan count (e.g., on system restart) */
|
|
3233
|
+
resetActivePlans() {
|
|
3234
|
+
this.activePlanCount = 0;
|
|
3235
|
+
}
|
|
3236
|
+
/** V1.5.2: Current active plan count (for diagnostics) */
|
|
3237
|
+
getActivePlanCount() {
|
|
3238
|
+
return this.activePlanCount;
|
|
3239
|
+
}
|
|
3240
|
+
typeCooldownKey(type, scope) {
|
|
3241
|
+
const parts = [type];
|
|
3242
|
+
if (scope?.system) parts.push(`sys:${scope.system}`);
|
|
3243
|
+
if (scope?.currency) parts.push(`cur:${scope.currency}`);
|
|
3244
|
+
if (scope?.tags?.length) parts.push(`tags:${scope.tags.sort().join(",")}`);
|
|
3245
|
+
return parts.join("|");
|
|
3246
|
+
}
|
|
3247
|
+
isTypeCooldown(typeKey, currentTick, cooldownTicks) {
|
|
3248
|
+
const lastApplied = this.typeCooldowns.get(typeKey);
|
|
3249
|
+
if (lastApplied === void 0) return false;
|
|
3250
|
+
return currentTick - lastApplied < cooldownTicks;
|
|
3206
3251
|
}
|
|
3207
3252
|
};
|
|
3208
3253
|
|
|
3209
3254
|
// src/Executor.ts
|
|
3210
3255
|
var Executor = class {
|
|
3211
|
-
constructor() {
|
|
3256
|
+
constructor(settlementWindowTicks = 200) {
|
|
3212
3257
|
this.activePlans = [];
|
|
3258
|
+
this.maxActiveTicks = settlementWindowTicks;
|
|
3213
3259
|
}
|
|
3214
3260
|
async apply(plan, adapter, currentParams) {
|
|
3215
3261
|
const originalValue = currentParams[plan.parameter] ?? plan.currentValue;
|
|
@@ -3228,8 +3274,7 @@ var Executor = class {
|
|
|
3228
3274
|
for (const active of this.activePlans) {
|
|
3229
3275
|
const { plan, originalValue } = active;
|
|
3230
3276
|
const rc = plan.rollbackCondition;
|
|
3231
|
-
|
|
3232
|
-
if (plan.appliedAt !== void 0 && metrics.tick - plan.appliedAt > maxActiveTicks) {
|
|
3277
|
+
if (plan.appliedAt !== void 0 && metrics.tick - plan.appliedAt > this.maxActiveTicks) {
|
|
3233
3278
|
settled.push(plan);
|
|
3234
3279
|
continue;
|
|
3235
3280
|
}
|
|
@@ -3296,9 +3341,9 @@ var DecisionLog = class {
|
|
|
3296
3341
|
reasoning: this.buildReasoning(diagnosis, plan, result),
|
|
3297
3342
|
metricsSnapshot: metrics
|
|
3298
3343
|
};
|
|
3299
|
-
this.entries.
|
|
3300
|
-
if (this.entries.length > this.maxEntries) {
|
|
3301
|
-
this.entries.
|
|
3344
|
+
this.entries.push(entry);
|
|
3345
|
+
if (this.entries.length > this.maxEntries * 1.5) {
|
|
3346
|
+
this.entries = this.entries.slice(-this.maxEntries);
|
|
3302
3347
|
}
|
|
3303
3348
|
return entry;
|
|
3304
3349
|
}
|
|
@@ -3313,8 +3358,10 @@ var DecisionLog = class {
|
|
|
3313
3358
|
reasoning: reason,
|
|
3314
3359
|
metricsSnapshot: metrics
|
|
3315
3360
|
};
|
|
3316
|
-
this.entries.
|
|
3317
|
-
if (this.entries.length > this.maxEntries
|
|
3361
|
+
this.entries.push(entry);
|
|
3362
|
+
if (this.entries.length > this.maxEntries * 1.5) {
|
|
3363
|
+
this.entries = this.entries.slice(-this.maxEntries);
|
|
3364
|
+
}
|
|
3318
3365
|
}
|
|
3319
3366
|
query(filter) {
|
|
3320
3367
|
return this.entries.filter((e) => {
|
|
@@ -3327,7 +3374,7 @@ var DecisionLog = class {
|
|
|
3327
3374
|
});
|
|
3328
3375
|
}
|
|
3329
3376
|
latest(n = 30) {
|
|
3330
|
-
return this.entries.slice(
|
|
3377
|
+
return this.entries.slice(-n).reverse();
|
|
3331
3378
|
}
|
|
3332
3379
|
export(format = "json") {
|
|
3333
3380
|
if (format === "text") {
|
|
@@ -3556,10 +3603,13 @@ var MetricStore = class {
|
|
|
3556
3603
|
var PersonaTracker = class {
|
|
3557
3604
|
constructor() {
|
|
3558
3605
|
this.agentHistory = /* @__PURE__ */ new Map();
|
|
3606
|
+
this.lastSeen = /* @__PURE__ */ new Map();
|
|
3559
3607
|
}
|
|
3560
3608
|
/** Ingest a state snapshot and update agent signal history */
|
|
3561
3609
|
update(state) {
|
|
3610
|
+
const tick = state.tick;
|
|
3562
3611
|
for (const agentId of Object.keys(state.agentBalances)) {
|
|
3612
|
+
this.lastSeen.set(agentId, tick);
|
|
3563
3613
|
const history = this.agentHistory.get(agentId) ?? [];
|
|
3564
3614
|
const inv = state.agentInventories[agentId] ?? {};
|
|
3565
3615
|
const uniqueItems = Object.values(inv).filter((q) => q > 0).length;
|
|
@@ -3577,6 +3627,14 @@ var PersonaTracker = class {
|
|
|
3577
3627
|
if (history.length > 50) history.shift();
|
|
3578
3628
|
this.agentHistory.set(agentId, history);
|
|
3579
3629
|
}
|
|
3630
|
+
if (tick % 50 === 0) {
|
|
3631
|
+
for (const [id, lastTick] of this.lastSeen) {
|
|
3632
|
+
if (tick - lastTick > 100) {
|
|
3633
|
+
this.agentHistory.delete(id);
|
|
3634
|
+
this.lastSeen.delete(id);
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
}
|
|
3580
3638
|
}
|
|
3581
3639
|
/** Classify all agents and return persona distribution */
|
|
3582
3640
|
getDistribution() {
|
|
@@ -3640,25 +3698,30 @@ var ParameterRegistry = class {
|
|
|
3640
3698
|
* Resolve a parameterType + scope to a concrete RegisteredParameter.
|
|
3641
3699
|
* Returns the best match, or undefined if no match.
|
|
3642
3700
|
*
|
|
3643
|
-
* Matching rules
|
|
3644
|
-
* 1.
|
|
3645
|
-
* 2.
|
|
3646
|
-
* 3.
|
|
3647
|
-
* 4.
|
|
3701
|
+
* Matching rules:
|
|
3702
|
+
* 1. Filter candidates by type
|
|
3703
|
+
* 2. Score each by scope specificity (system +10, currency +5, tags +3 each)
|
|
3704
|
+
* 3. Mismatched scope fields disqualify (score = -Infinity)
|
|
3705
|
+
* 4. Ties broken by `priority` (higher wins), then registration order
|
|
3706
|
+
* 5. All disqualified → undefined
|
|
3648
3707
|
*/
|
|
3649
3708
|
resolve(type, scope) {
|
|
3650
3709
|
const candidates = this.findByType(type);
|
|
3651
3710
|
if (candidates.length === 0) return void 0;
|
|
3652
3711
|
if (candidates.length === 1) return candidates[0];
|
|
3653
|
-
let bestScore = -
|
|
3712
|
+
let bestScore = -Infinity;
|
|
3713
|
+
let bestPriority = -Infinity;
|
|
3654
3714
|
let best;
|
|
3655
3715
|
for (const candidate of candidates) {
|
|
3656
|
-
const score = this.
|
|
3657
|
-
|
|
3716
|
+
const score = this.scopeSpecificity(candidate.scope, scope);
|
|
3717
|
+
const prio = candidate.priority ?? 0;
|
|
3718
|
+
if (score > bestScore || score === bestScore && prio > bestPriority) {
|
|
3658
3719
|
bestScore = score;
|
|
3720
|
+
bestPriority = prio;
|
|
3659
3721
|
best = candidate;
|
|
3660
3722
|
}
|
|
3661
3723
|
}
|
|
3724
|
+
if (bestScore === -Infinity) return void 0;
|
|
3662
3725
|
return best;
|
|
3663
3726
|
}
|
|
3664
3727
|
/** Find all parameters of a given type. */
|
|
@@ -3700,28 +3763,60 @@ var ParameterRegistry = class {
|
|
|
3700
3763
|
get size() {
|
|
3701
3764
|
return this.parameters.size;
|
|
3702
3765
|
}
|
|
3766
|
+
/**
|
|
3767
|
+
* Validate the registry for common misconfigurations.
|
|
3768
|
+
* Returns warnings (non-fatal) and errors (likely broken).
|
|
3769
|
+
*/
|
|
3770
|
+
validate() {
|
|
3771
|
+
const warnings = [];
|
|
3772
|
+
const errors = [];
|
|
3773
|
+
const typeMap = /* @__PURE__ */ new Map();
|
|
3774
|
+
for (const param of this.parameters.values()) {
|
|
3775
|
+
const list = typeMap.get(param.type) ?? [];
|
|
3776
|
+
list.push(param);
|
|
3777
|
+
typeMap.set(param.type, list);
|
|
3778
|
+
}
|
|
3779
|
+
for (const [type, params] of typeMap) {
|
|
3780
|
+
if (params.length > 1) {
|
|
3781
|
+
const unscopedCount = params.filter((p) => !p.scope).length;
|
|
3782
|
+
if (unscopedCount > 1) {
|
|
3783
|
+
errors.push(
|
|
3784
|
+
`Type '${type}' has ${unscopedCount} unscoped parameters \u2014 resolve() cannot distinguish them`
|
|
3785
|
+
);
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
for (const param of this.parameters.values()) {
|
|
3790
|
+
if (!param.flowImpact) {
|
|
3791
|
+
warnings.push(`Parameter '${param.key}' has no flowImpact \u2014 Simulator will use inference`);
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
return {
|
|
3795
|
+
valid: errors.length === 0,
|
|
3796
|
+
warnings,
|
|
3797
|
+
errors
|
|
3798
|
+
};
|
|
3799
|
+
}
|
|
3703
3800
|
// ── Private ─────────────────────────────────────────────────────────────
|
|
3704
|
-
|
|
3801
|
+
scopeSpecificity(paramScope, queryScope) {
|
|
3705
3802
|
if (!queryScope) return 0;
|
|
3706
3803
|
if (!paramScope) return 0;
|
|
3707
3804
|
let score = 0;
|
|
3708
3805
|
if (queryScope.system && paramScope.system) {
|
|
3709
3806
|
if (queryScope.system === paramScope.system) score += 10;
|
|
3710
|
-
else return -
|
|
3807
|
+
else return -Infinity;
|
|
3711
3808
|
}
|
|
3712
3809
|
if (queryScope.currency && paramScope.currency) {
|
|
3713
3810
|
if (queryScope.currency === paramScope.currency) score += 5;
|
|
3714
|
-
else return -
|
|
3811
|
+
else return -Infinity;
|
|
3715
3812
|
}
|
|
3716
3813
|
if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
|
|
3717
3814
|
const overlap = queryScope.tags.filter((t) => paramScope.tags.includes(t)).length;
|
|
3718
3815
|
if (overlap > 0) {
|
|
3719
3816
|
score += overlap * 3;
|
|
3720
3817
|
} else {
|
|
3721
|
-
return -
|
|
3818
|
+
return -Infinity;
|
|
3722
3819
|
}
|
|
3723
|
-
} else if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
|
|
3724
|
-
return -1;
|
|
3725
3820
|
}
|
|
3726
3821
|
return score;
|
|
3727
3822
|
}
|
|
@@ -3731,7 +3826,6 @@ var ParameterRegistry = class {
|
|
|
3731
3826
|
var AgentE = class {
|
|
3732
3827
|
constructor(config) {
|
|
3733
3828
|
this.planner = new Planner();
|
|
3734
|
-
this.executor = new Executor();
|
|
3735
3829
|
this.registry = new ParameterRegistry();
|
|
3736
3830
|
// ── State ──
|
|
3737
3831
|
this.log = new DecisionLog();
|
|
@@ -3753,6 +3847,9 @@ var AgentE = class {
|
|
|
3753
3847
|
mode: this.mode,
|
|
3754
3848
|
dominantRoles: config.dominantRoles ?? [],
|
|
3755
3849
|
idealDistribution: config.idealDistribution ?? {},
|
|
3850
|
+
validateRegistry: config.validateRegistry ?? true,
|
|
3851
|
+
simulation: config.simulation ?? {},
|
|
3852
|
+
settlementWindowTicks: config.settlementWindowTicks ?? 200,
|
|
3756
3853
|
tickConfig: config.tickConfig ?? { duration: 1, unit: "tick" },
|
|
3757
3854
|
gracePeriod: config.gracePeriod ?? 50,
|
|
3758
3855
|
checkInterval: config.checkInterval ?? 5,
|
|
@@ -3773,7 +3870,13 @@ var AgentE = class {
|
|
|
3773
3870
|
if (config.parameters) {
|
|
3774
3871
|
this.registry.registerAll(config.parameters);
|
|
3775
3872
|
}
|
|
3776
|
-
|
|
3873
|
+
if (config.validateRegistry !== false && this.registry.size > 0) {
|
|
3874
|
+
const validation = this.registry.validate();
|
|
3875
|
+
for (const w of validation.warnings) console.warn(`[AgentE] Registry warning: ${w}`);
|
|
3876
|
+
for (const e of validation.errors) console.error(`[AgentE] Registry error: ${e}`);
|
|
3877
|
+
}
|
|
3878
|
+
this.executor = new Executor(config.settlementWindowTicks);
|
|
3879
|
+
this.simulator = new Simulator(this.registry, config.simulation);
|
|
3777
3880
|
if (config.onDecision) this.on("decision", config.onDecision);
|
|
3778
3881
|
if (config.onAlert) this.on("alert", config.onAlert);
|
|
3779
3882
|
if (config.onRollback) this.on("rollback", config.onRollback);
|
|
@@ -3809,7 +3912,7 @@ var AgentE = class {
|
|
|
3809
3912
|
if (!this.isRunning || this.isPaused) return;
|
|
3810
3913
|
const currentState = state ?? await Promise.resolve(this.adapter.getState());
|
|
3811
3914
|
this.currentTick = currentState.tick;
|
|
3812
|
-
const events =
|
|
3915
|
+
const events = this.eventBuffer;
|
|
3813
3916
|
this.eventBuffer = [];
|
|
3814
3917
|
let metrics;
|
|
3815
3918
|
try {
|
|
@@ -3927,7 +4030,9 @@ var AgentE = class {
|
|
|
3927
4030
|
// ── Events ──────────────────────────────────────────────────────────────────
|
|
3928
4031
|
on(event, handler) {
|
|
3929
4032
|
const list = this.handlers.get(event) ?? [];
|
|
3930
|
-
list.
|
|
4033
|
+
if (!list.includes(handler)) {
|
|
4034
|
+
list.push(handler);
|
|
4035
|
+
}
|
|
3931
4036
|
this.handlers.set(event, list);
|
|
3932
4037
|
return this;
|
|
3933
4038
|
}
|
|
@@ -3940,8 +4045,12 @@ var AgentE = class {
|
|
|
3940
4045
|
const list = this.handlers.get(event) ?? [];
|
|
3941
4046
|
let result;
|
|
3942
4047
|
for (const handler of list) {
|
|
3943
|
-
|
|
3944
|
-
|
|
4048
|
+
try {
|
|
4049
|
+
result = handler(...args);
|
|
4050
|
+
if (result === false) return false;
|
|
4051
|
+
} catch (err) {
|
|
4052
|
+
console.error(`[AgentE] Handler error on '${event}':`, err);
|
|
4053
|
+
}
|
|
3945
4054
|
}
|
|
3946
4055
|
return result;
|
|
3947
4056
|
}
|
|
@@ -3969,6 +4078,31 @@ var AgentE = class {
|
|
|
3969
4078
|
}
|
|
3970
4079
|
};
|
|
3971
4080
|
|
|
4081
|
+
// src/utils.ts
|
|
4082
|
+
function findWorstSystem(metrics, check, tolerancePercent = 0) {
|
|
4083
|
+
const systems = metrics.systems;
|
|
4084
|
+
if (systems.length === 0) return void 0;
|
|
4085
|
+
let worstSystem;
|
|
4086
|
+
let worstScore = -Infinity;
|
|
4087
|
+
let totalScore = 0;
|
|
4088
|
+
for (const sys of systems) {
|
|
4089
|
+
const score = check(sys, metrics);
|
|
4090
|
+
totalScore += score;
|
|
4091
|
+
if (score > worstScore) {
|
|
4092
|
+
worstScore = score;
|
|
4093
|
+
worstSystem = sys;
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
if (!worstSystem) return void 0;
|
|
4097
|
+
if (tolerancePercent > 0 && systems.length > 1) {
|
|
4098
|
+
const avg = totalScore / systems.length;
|
|
4099
|
+
if (avg === 0) return { system: worstSystem, score: worstScore };
|
|
4100
|
+
const excessPercent = (worstScore - avg) / Math.abs(avg) * 100;
|
|
4101
|
+
if (excessPercent < tolerancePercent) return void 0;
|
|
4102
|
+
}
|
|
4103
|
+
return { system: worstSystem, score: worstScore };
|
|
4104
|
+
}
|
|
4105
|
+
|
|
3972
4106
|
// src/StateValidator.ts
|
|
3973
4107
|
function validateEconomyState(state) {
|
|
3974
4108
|
const errors = [];
|
|
@@ -4320,7 +4454,7 @@ function describeValue(value) {
|
|
|
4320
4454
|
OPEN_ECONOMY_PRINCIPLES,
|
|
4321
4455
|
OPERATIONS_PRINCIPLES,
|
|
4322
4456
|
Observer,
|
|
4323
|
-
|
|
4457
|
+
P10_EntryWeightingUsesInversePopulation,
|
|
4324
4458
|
P11_TwoTierPressure,
|
|
4325
4459
|
P12_OnePrimaryFaucet,
|
|
4326
4460
|
P13_PotsAreZeroSumAndSelfRegulate,
|
|
@@ -4340,9 +4474,9 @@ function describeValue(value) {
|
|
|
4340
4474
|
P26_ContinuousPressureBeatsThresholdCuts,
|
|
4341
4475
|
P27_AdjustmentsNeedCooldowns,
|
|
4342
4476
|
P28_StructuralDominanceIsNotPathological,
|
|
4343
|
-
|
|
4477
|
+
P29_BottleneckDetection,
|
|
4344
4478
|
P2_ClosedLoopsNeedDirectHandoff,
|
|
4345
|
-
|
|
4479
|
+
P30_DynamicBottleneckRotation,
|
|
4346
4480
|
P31_AnchorValueTracking,
|
|
4347
4481
|
P32_VelocityAboveSupply,
|
|
4348
4482
|
P33_FairNotEqual,
|
|
@@ -4365,16 +4499,16 @@ function describeValue(value) {
|
|
|
4365
4499
|
P49_IdleAssetTax,
|
|
4366
4500
|
P4_MaterialsFlowFasterThanCooldown,
|
|
4367
4501
|
P50_PayPowerRatio,
|
|
4368
|
-
|
|
4502
|
+
P51_CyclicalEngagement,
|
|
4369
4503
|
P52_EndowmentEffect,
|
|
4370
4504
|
P53_EventCompletionRate,
|
|
4371
|
-
|
|
4505
|
+
P54_OperationalCadence,
|
|
4372
4506
|
P55_ArbitrageThermometer,
|
|
4373
|
-
|
|
4507
|
+
P56_SupplyShockAbsorption,
|
|
4374
4508
|
P57_CombinatorialPriceSpace,
|
|
4375
4509
|
P58_NoNaturalNumeraire,
|
|
4376
4510
|
P59_GiftEconomyNoise,
|
|
4377
|
-
|
|
4511
|
+
P5_ProfitabilityIsRelative,
|
|
4378
4512
|
P60_SurplusDisposalAsymmetry,
|
|
4379
4513
|
P6_CrowdingMultiplierOnAllRoles,
|
|
4380
4514
|
P7_NonSpecialistsSubsidiseSpecialists,
|
|
@@ -4393,6 +4527,7 @@ function describeValue(value) {
|
|
|
4393
4527
|
SYSTEM_DYNAMICS_PRINCIPLES,
|
|
4394
4528
|
Simulator,
|
|
4395
4529
|
emptyMetrics,
|
|
4530
|
+
findWorstSystem,
|
|
4396
4531
|
validateEconomyState
|
|
4397
4532
|
});
|
|
4398
4533
|
//# sourceMappingURL=index.js.map
|