@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.d.mts +143 -21
- package/dist/index.d.ts +143 -21
- package/dist/index.js +565 -201
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +555 -193
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -12,11 +12,11 @@ var DEFAULT_THRESHOLDS = {
|
|
|
12
12
|
smokeTestWarning: 0.3,
|
|
13
13
|
smokeTestCritical: 0.1,
|
|
14
14
|
currencyInsulationMax: 0.5,
|
|
15
|
-
//
|
|
15
|
+
// Participant Experience (P45, P50)
|
|
16
16
|
timeBudgetRatio: 0.8,
|
|
17
17
|
payPowerRatioMax: 2,
|
|
18
18
|
payPowerRatioTarget: 1.5,
|
|
19
|
-
//
|
|
19
|
+
// Operations (P51, P53)
|
|
20
20
|
sharkToothPeakDecay: 0.95,
|
|
21
21
|
sharkToothValleyDecay: 0.9,
|
|
22
22
|
eventCompletionMin: 0.4,
|
|
@@ -70,7 +70,7 @@ var PERSONA_HEALTHY_RANGES = {
|
|
|
70
70
|
Earner: { min: 0, max: 0.15 },
|
|
71
71
|
Builder: { min: 0.05, max: 0.15 },
|
|
72
72
|
Social: { min: 0.1, max: 0.2 },
|
|
73
|
-
|
|
73
|
+
HighValue: { min: 0, max: 0.05 },
|
|
74
74
|
Influencer: { min: 0, max: 0.05 }
|
|
75
75
|
};
|
|
76
76
|
var DEFAULT_TICK_CONFIG = {
|
|
@@ -107,7 +107,7 @@ var Observer = class {
|
|
|
107
107
|
const curr = e.currency ?? defaultCurrency;
|
|
108
108
|
switch (e.type) {
|
|
109
109
|
case "mint":
|
|
110
|
-
case "
|
|
110
|
+
case "enter":
|
|
111
111
|
faucetVolumeByCurrency[curr] = (faucetVolumeByCurrency[curr] ?? 0) + (e.amount ?? 0);
|
|
112
112
|
break;
|
|
113
113
|
case "burn":
|
|
@@ -129,6 +129,46 @@ var Observer = class {
|
|
|
129
129
|
break;
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
+
const flowBySystem = {};
|
|
133
|
+
const activityBySystem = {};
|
|
134
|
+
const actorsBySystem = {};
|
|
135
|
+
const flowBySource = {};
|
|
136
|
+
const flowBySink = {};
|
|
137
|
+
for (const e of recentEvents) {
|
|
138
|
+
if (e.system) {
|
|
139
|
+
activityBySystem[e.system] = (activityBySystem[e.system] ?? 0) + 1;
|
|
140
|
+
if (!actorsBySystem[e.system]) actorsBySystem[e.system] = /* @__PURE__ */ new Set();
|
|
141
|
+
actorsBySystem[e.system].add(e.actor);
|
|
142
|
+
const amt = e.amount ?? 0;
|
|
143
|
+
if (e.type === "mint") {
|
|
144
|
+
flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) + amt;
|
|
145
|
+
} else if (e.type === "burn" || e.type === "consume") {
|
|
146
|
+
flowBySystem[e.system] = (flowBySystem[e.system] ?? 0) - amt;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (e.sourceOrSink) {
|
|
150
|
+
const amt = e.amount ?? 0;
|
|
151
|
+
if (e.type === "mint") {
|
|
152
|
+
flowBySource[e.sourceOrSink] = (flowBySource[e.sourceOrSink] ?? 0) + amt;
|
|
153
|
+
} else if (e.type === "burn" || e.type === "consume") {
|
|
154
|
+
flowBySink[e.sourceOrSink] = (flowBySink[e.sourceOrSink] ?? 0) + amt;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const participantsBySystem = {};
|
|
159
|
+
for (const [sys, actors] of Object.entries(actorsBySystem)) {
|
|
160
|
+
participantsBySystem[sys] = actors.size;
|
|
161
|
+
}
|
|
162
|
+
const totalSourceFlow = Object.values(flowBySource).reduce((s, v) => s + v, 0);
|
|
163
|
+
const sourceShare = {};
|
|
164
|
+
for (const [src, vol] of Object.entries(flowBySource)) {
|
|
165
|
+
sourceShare[src] = totalSourceFlow > 0 ? vol / totalSourceFlow : 0;
|
|
166
|
+
}
|
|
167
|
+
const totalSinkFlow = Object.values(flowBySink).reduce((s, v) => s + v, 0);
|
|
168
|
+
const sinkShare = {};
|
|
169
|
+
for (const [snk, vol] of Object.entries(flowBySink)) {
|
|
170
|
+
sinkShare[snk] = totalSinkFlow > 0 ? vol / totalSinkFlow : 0;
|
|
171
|
+
}
|
|
132
172
|
const currencies = state.currencies;
|
|
133
173
|
const totalSupplyByCurrency = {};
|
|
134
174
|
const balancesByCurrency = {};
|
|
@@ -338,7 +378,8 @@ var Observer = class {
|
|
|
338
378
|
for (const [name, fn] of Object.entries(this.customMetricFns)) {
|
|
339
379
|
try {
|
|
340
380
|
custom[name] = fn(state);
|
|
341
|
-
} catch {
|
|
381
|
+
} catch (err) {
|
|
382
|
+
console.warn(`[AgentE] Custom metric '${name}' threw an error:`, err);
|
|
342
383
|
custom[name] = NaN;
|
|
343
384
|
}
|
|
344
385
|
}
|
|
@@ -415,6 +456,16 @@ var Observer = class {
|
|
|
415
456
|
sharkToothValleys: this.previousMetrics?.sharkToothValleys ?? [],
|
|
416
457
|
eventCompletionRate: NaN,
|
|
417
458
|
contentDropAge,
|
|
459
|
+
systems: state.systems ?? [],
|
|
460
|
+
sources: state.sources ?? [],
|
|
461
|
+
sinks: state.sinks ?? [],
|
|
462
|
+
flowBySystem,
|
|
463
|
+
activityBySystem,
|
|
464
|
+
participantsBySystem,
|
|
465
|
+
flowBySource,
|
|
466
|
+
flowBySink,
|
|
467
|
+
sourceShare,
|
|
468
|
+
sinkShare,
|
|
418
469
|
custom
|
|
419
470
|
};
|
|
420
471
|
this.previousMetrics = metrics;
|
|
@@ -557,6 +608,16 @@ function emptyMetrics(tick = 0) {
|
|
|
557
608
|
sharkToothValleys: [],
|
|
558
609
|
eventCompletionRate: NaN,
|
|
559
610
|
contentDropAge: 0,
|
|
611
|
+
systems: [],
|
|
612
|
+
sources: [],
|
|
613
|
+
sinks: [],
|
|
614
|
+
flowBySystem: {},
|
|
615
|
+
activityBySystem: {},
|
|
616
|
+
participantsBySystem: {},
|
|
617
|
+
flowBySource: {},
|
|
618
|
+
flowBySink: {},
|
|
619
|
+
sourceShare: {},
|
|
620
|
+
sinkShare: {},
|
|
560
621
|
custom: {}
|
|
561
622
|
};
|
|
562
623
|
}
|
|
@@ -589,7 +650,7 @@ var P1_ProductionMatchesConsumption = {
|
|
|
589
650
|
severity: 7,
|
|
590
651
|
evidence: { scarceResources: violations, dominantRole: dominantRole?.[0], dominantShare },
|
|
591
652
|
suggestedAction: {
|
|
592
|
-
|
|
653
|
+
parameterType: "cost",
|
|
593
654
|
direction: "decrease",
|
|
594
655
|
magnitude: 0.15,
|
|
595
656
|
reasoning: "Lower production cost to incentivise more production."
|
|
@@ -623,7 +684,8 @@ var P2_ClosedLoopsNeedDirectHandoff = {
|
|
|
623
684
|
severity: 5,
|
|
624
685
|
evidence: { backlogResources, velocity },
|
|
625
686
|
suggestedAction: {
|
|
626
|
-
|
|
687
|
+
parameterType: "fee",
|
|
688
|
+
scope: { tags: ["transaction"] },
|
|
627
689
|
direction: "increase",
|
|
628
690
|
magnitude: 0.2,
|
|
629
691
|
reasoning: "Raise market fees to discourage raw material listings. Direct hand-off at production zones is the correct channel."
|
|
@@ -653,7 +715,7 @@ var P3_BootstrapCapitalCoversFirstTransaction = {
|
|
|
653
715
|
severity: 8,
|
|
654
716
|
evidence: { resource, totalProducers, supply },
|
|
655
717
|
suggestedAction: {
|
|
656
|
-
|
|
718
|
+
parameterType: "cost",
|
|
657
719
|
direction: "decrease",
|
|
658
720
|
magnitude: 0.3,
|
|
659
721
|
reasoning: "Producers cannot complete first transaction. Lower production cost to unblock bootstrap."
|
|
@@ -672,7 +734,7 @@ var P4_MaterialsFlowFasterThanCooldown = {
|
|
|
672
734
|
id: "P4",
|
|
673
735
|
name: "Materials Flow Faster Than Cooldown",
|
|
674
736
|
category: "supply_chain",
|
|
675
|
-
description: "Input delivery rate must exceed or match production cooldown rate. If producers
|
|
737
|
+
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.",
|
|
676
738
|
check(metrics, _thresholds) {
|
|
677
739
|
const { supplyByResource, populationByRole, velocity, totalAgents } = metrics;
|
|
678
740
|
const totalSupply = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
@@ -685,7 +747,7 @@ var P4_MaterialsFlowFasterThanCooldown = {
|
|
|
685
747
|
severity: 5,
|
|
686
748
|
evidence: { avgSupplyPerAgent, velocity, totalRoles },
|
|
687
749
|
suggestedAction: {
|
|
688
|
-
|
|
750
|
+
parameterType: "yield",
|
|
689
751
|
direction: "increase",
|
|
690
752
|
magnitude: 0.15,
|
|
691
753
|
reasoning: "Low supply per agent with stagnant velocity. Increase yield to compensate."
|
|
@@ -700,7 +762,7 @@ var P4_MaterialsFlowFasterThanCooldown = {
|
|
|
700
762
|
severity: 4,
|
|
701
763
|
evidence: { avgSupplyPerAgent, totalSupply, totalAgents },
|
|
702
764
|
suggestedAction: {
|
|
703
|
-
|
|
765
|
+
parameterType: "yield",
|
|
704
766
|
direction: "decrease",
|
|
705
767
|
magnitude: 0.2,
|
|
706
768
|
reasoning: "Raw materials piling up. Extractors outpacing producers."
|
|
@@ -728,7 +790,7 @@ var P60_SurplusDisposalAsymmetry = {
|
|
|
728
790
|
discount: thresholds.disposalTradeWeightDiscount
|
|
729
791
|
},
|
|
730
792
|
suggestedAction: {
|
|
731
|
-
|
|
793
|
+
parameterType: "cost",
|
|
732
794
|
direction: "decrease",
|
|
733
795
|
magnitude: 0.1,
|
|
734
796
|
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.`
|
|
@@ -771,7 +833,8 @@ var P5_ProfitabilityIsCompetitive = {
|
|
|
771
833
|
population: populationByRole[dominantRole]
|
|
772
834
|
},
|
|
773
835
|
suggestedAction: {
|
|
774
|
-
|
|
836
|
+
parameterType: "fee",
|
|
837
|
+
scope: { tags: ["transaction"] },
|
|
775
838
|
direction: "increase",
|
|
776
839
|
magnitude: thresholds.maxAdjustmentPercent,
|
|
777
840
|
reasoning: `${dominantRole} share at ${((roleShares[dominantRole] ?? 0) * 100).toFixed(0)}%. Likely stampede from non-competitive profitability formula. Raise market friction to slow role accumulation.`
|
|
@@ -797,7 +860,7 @@ var P6_CrowdingMultiplierOnAllRoles = {
|
|
|
797
860
|
severity: 5,
|
|
798
861
|
evidence: { role, share },
|
|
799
862
|
suggestedAction: {
|
|
800
|
-
|
|
863
|
+
parameterType: "cost",
|
|
801
864
|
direction: "increase",
|
|
802
865
|
magnitude: 0.1,
|
|
803
866
|
reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 no crowding pressure detected. Apply role-specific cost increase to simulate saturation.`
|
|
@@ -832,7 +895,8 @@ var P7_NonSpecialistsSubsidiseSpecialists = {
|
|
|
832
895
|
severity: 6,
|
|
833
896
|
evidence: { poolName, poolSize, dominantRole, dominantShare },
|
|
834
897
|
suggestedAction: {
|
|
835
|
-
|
|
898
|
+
parameterType: "fee",
|
|
899
|
+
scope: { tags: ["entry"] },
|
|
836
900
|
direction: "decrease",
|
|
837
901
|
magnitude: 0.1,
|
|
838
902
|
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.`
|
|
@@ -860,7 +924,7 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
860
924
|
severity: 4,
|
|
861
925
|
evidence: { dominantRole: dominantRole[0], share: dominantRole[1], avgSatisfaction },
|
|
862
926
|
suggestedAction: {
|
|
863
|
-
|
|
927
|
+
parameterType: "reward",
|
|
864
928
|
direction: "increase",
|
|
865
929
|
magnitude: 0.1,
|
|
866
930
|
reasoning: `Low satisfaction with ${dominantRole[0]} dominant. Regulator may be suppressing a structurally necessary role. Ease pressure on dominant role rewards.`
|
|
@@ -885,7 +949,7 @@ var P9_RoleSwitchingNeedsFriction = {
|
|
|
885
949
|
id: "P9",
|
|
886
950
|
name: "Role Switching Needs Friction",
|
|
887
951
|
category: "population",
|
|
888
|
-
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,
|
|
952
|
+
description: "If >5% of the population switches roles in a single evaluation period, it is a herd movement, not rational rebalancing. Without friction (satisfaction cost, minimum interval), one good tick causes mass migration.",
|
|
889
953
|
check(metrics, thresholds) {
|
|
890
954
|
const { churnByRole, roleShares } = metrics;
|
|
891
955
|
const totalChurn = Object.values(churnByRole).reduce((s, v) => s + v, 0);
|
|
@@ -895,7 +959,7 @@ var P9_RoleSwitchingNeedsFriction = {
|
|
|
895
959
|
severity: 5,
|
|
896
960
|
evidence: { totalChurnRate: totalChurn, churnByRole },
|
|
897
961
|
suggestedAction: {
|
|
898
|
-
|
|
962
|
+
parameterType: "cost",
|
|
899
963
|
direction: "increase",
|
|
900
964
|
magnitude: 0.05,
|
|
901
965
|
reasoning: `Role switch rate ${(totalChurn * 100).toFixed(1)}% exceeds friction threshold. Increase production costs to slow herd movement.`
|
|
@@ -908,11 +972,11 @@ var P9_RoleSwitchingNeedsFriction = {
|
|
|
908
972
|
return { violated: false };
|
|
909
973
|
}
|
|
910
974
|
};
|
|
911
|
-
var
|
|
975
|
+
var P10_EntryWeightingUsesInversePopulation = {
|
|
912
976
|
id: "P10",
|
|
913
|
-
name: "
|
|
977
|
+
name: "Entry Weighting Uses Inverse Population",
|
|
914
978
|
category: "population",
|
|
915
|
-
description: "New
|
|
979
|
+
description: "New entrants should preferentially fill the least-populated roles. Flat entry probability causes initial imbalances to compound.",
|
|
916
980
|
check(metrics, _thresholds) {
|
|
917
981
|
const { roleShares } = metrics;
|
|
918
982
|
if (Object.keys(roleShares).length === 0) return { violated: false };
|
|
@@ -927,7 +991,7 @@ var P10_SpawnWeightingUsesInversePopulation = {
|
|
|
927
991
|
severity: 4,
|
|
928
992
|
evidence: { roleShares, stdDev, leastPopulatedRole: minRole?.[0] },
|
|
929
993
|
suggestedAction: {
|
|
930
|
-
|
|
994
|
+
parameterType: "yield",
|
|
931
995
|
direction: "increase",
|
|
932
996
|
magnitude: 0.05,
|
|
933
997
|
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.`
|
|
@@ -953,7 +1017,8 @@ var P11_TwoTierPressure = {
|
|
|
953
1017
|
severity: 6,
|
|
954
1018
|
evidence: { role, share },
|
|
955
1019
|
suggestedAction: {
|
|
956
|
-
|
|
1020
|
+
parameterType: "fee",
|
|
1021
|
+
scope: { tags: ["transaction"] },
|
|
957
1022
|
direction: "increase",
|
|
958
1023
|
magnitude: 0.15,
|
|
959
1024
|
reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 continuous pressure was insufficient. Hard intervention needed alongside resumed continuous pressure.`
|
|
@@ -981,7 +1046,7 @@ var P46_PersonaDiversity = {
|
|
|
981
1046
|
severity: 5,
|
|
982
1047
|
evidence: { dominantPersona: persona, share, personaDistribution },
|
|
983
1048
|
suggestedAction: {
|
|
984
|
-
|
|
1049
|
+
parameterType: "reward",
|
|
985
1050
|
direction: "increase",
|
|
986
1051
|
magnitude: 0.1,
|
|
987
1052
|
reasoning: `${persona} persona at ${(share * 100).toFixed(0)}% \u2014 behavioral monoculture. Diversify reward structures to attract other persona types.`
|
|
@@ -998,7 +1063,8 @@ var P46_PersonaDiversity = {
|
|
|
998
1063
|
severity: 3,
|
|
999
1064
|
evidence: { significantClusters, required: thresholds.personaMinClusters },
|
|
1000
1065
|
suggestedAction: {
|
|
1001
|
-
|
|
1066
|
+
parameterType: "fee",
|
|
1067
|
+
scope: { tags: ["transaction"] },
|
|
1002
1068
|
direction: "decrease",
|
|
1003
1069
|
magnitude: 0.05,
|
|
1004
1070
|
reasoning: `Only ${significantClusters} significant persona clusters (need ${thresholds.personaMinClusters}). Lower trade barriers to attract non-dominant persona types.`
|
|
@@ -1012,7 +1078,7 @@ var P46_PersonaDiversity = {
|
|
|
1012
1078
|
};
|
|
1013
1079
|
var POPULATION_PRINCIPLES = [
|
|
1014
1080
|
P9_RoleSwitchingNeedsFriction,
|
|
1015
|
-
|
|
1081
|
+
P10_EntryWeightingUsesInversePopulation,
|
|
1016
1082
|
P11_TwoTierPressure,
|
|
1017
1083
|
P46_PersonaDiversity
|
|
1018
1084
|
];
|
|
@@ -1022,7 +1088,7 @@ var P12_OnePrimaryFaucet = {
|
|
|
1022
1088
|
id: "P12",
|
|
1023
1089
|
name: "One Primary Faucet",
|
|
1024
1090
|
category: "currency",
|
|
1025
|
-
description: "Multiple independent currency sources (gathering + production +
|
|
1091
|
+
description: "Multiple independent currency sources (gathering + production + activities) each creating currency causes uncontrolled inflation. One clear primary faucet makes the economy predictable and auditable.",
|
|
1026
1092
|
check(metrics, thresholds) {
|
|
1027
1093
|
for (const curr of metrics.currencies) {
|
|
1028
1094
|
const netFlow = metrics.netFlowByCurrency[curr] ?? 0;
|
|
@@ -1034,9 +1100,9 @@ var P12_OnePrimaryFaucet = {
|
|
|
1034
1100
|
severity: 5,
|
|
1035
1101
|
evidence: { currency: curr, netFlow, faucetVolume, sinkVolume },
|
|
1036
1102
|
suggestedAction: {
|
|
1037
|
-
|
|
1103
|
+
parameterType: "cost",
|
|
1038
1104
|
direction: "increase",
|
|
1039
|
-
currency: curr,
|
|
1105
|
+
scope: { currency: curr },
|
|
1040
1106
|
magnitude: 0.15,
|
|
1041
1107
|
reasoning: `[${curr}] Net flow +${netFlow.toFixed(1)}/tick. Inflationary. Increase production cost (primary sink) to balance faucet output.`
|
|
1042
1108
|
},
|
|
@@ -1050,9 +1116,9 @@ var P12_OnePrimaryFaucet = {
|
|
|
1050
1116
|
severity: 4,
|
|
1051
1117
|
evidence: { currency: curr, netFlow, faucetVolume, sinkVolume },
|
|
1052
1118
|
suggestedAction: {
|
|
1053
|
-
|
|
1119
|
+
parameterType: "cost",
|
|
1054
1120
|
direction: "decrease",
|
|
1055
|
-
currency: curr,
|
|
1121
|
+
scope: { currency: curr },
|
|
1056
1122
|
magnitude: 0.15,
|
|
1057
1123
|
reasoning: `[${curr}] Net flow ${netFlow.toFixed(1)}/tick. Deflationary. Decrease production cost to ease sink pressure.`
|
|
1058
1124
|
},
|
|
@@ -1084,9 +1150,9 @@ var P13_PotsAreZeroSumAndSelfRegulate = {
|
|
|
1084
1150
|
severity: 7,
|
|
1085
1151
|
evidence: { currency: curr, pool: poolName, poolSize, participants: dominantCount, maxSustainableMultiplier },
|
|
1086
1152
|
suggestedAction: {
|
|
1087
|
-
|
|
1153
|
+
parameterType: "reward",
|
|
1088
1154
|
direction: "decrease",
|
|
1089
|
-
currency: curr,
|
|
1155
|
+
scope: { currency: curr },
|
|
1090
1156
|
magnitude: 0.15,
|
|
1091
1157
|
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.`
|
|
1092
1158
|
},
|
|
@@ -1103,7 +1169,7 @@ var P14_TrackActualInjection = {
|
|
|
1103
1169
|
id: "P14",
|
|
1104
1170
|
name: "Track Actual Currency Injection, Not Value Creation",
|
|
1105
1171
|
category: "currency",
|
|
1106
|
-
description: 'Counting resource
|
|
1172
|
+
description: 'Counting resource extraction as "currency injected" is misleading. Currency enters through faucet mechanisms (entering, rewards). Fake metrics break every downstream decision.',
|
|
1107
1173
|
check(metrics, _thresholds) {
|
|
1108
1174
|
for (const curr of metrics.currencies) {
|
|
1109
1175
|
const faucetVolume = metrics.faucetVolumeByCurrency[curr] ?? 0;
|
|
@@ -1116,9 +1182,9 @@ var P14_TrackActualInjection = {
|
|
|
1116
1182
|
severity: 4,
|
|
1117
1183
|
evidence: { currency: curr, faucetVolume, netFlow, supplyGrowthRate },
|
|
1118
1184
|
suggestedAction: {
|
|
1119
|
-
|
|
1185
|
+
parameterType: "yield",
|
|
1120
1186
|
direction: "decrease",
|
|
1121
|
-
currency: curr,
|
|
1187
|
+
scope: { currency: curr },
|
|
1122
1188
|
magnitude: 0.1,
|
|
1123
1189
|
reasoning: `[${curr}] Supply growing at ${(supplyGrowthRate * 100).toFixed(1)}%/tick. Verify currency injection tracking. Resources should not create currency directly.`
|
|
1124
1190
|
},
|
|
@@ -1148,9 +1214,9 @@ var P15_PoolsNeedCapAndDecay = {
|
|
|
1148
1214
|
severity: 6,
|
|
1149
1215
|
evidence: { currency: curr, pool, size, shareOfSupply, cap: poolCapPercent },
|
|
1150
1216
|
suggestedAction: {
|
|
1151
|
-
|
|
1217
|
+
parameterType: "fee",
|
|
1152
1218
|
direction: "decrease",
|
|
1153
|
-
currency: curr,
|
|
1219
|
+
scope: { tags: ["transaction"], currency: curr },
|
|
1154
1220
|
magnitude: 0.1,
|
|
1155
1221
|
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.`
|
|
1156
1222
|
},
|
|
@@ -1180,9 +1246,9 @@ var P16_WithdrawalPenaltyScales = {
|
|
|
1180
1246
|
severity: 3,
|
|
1181
1247
|
evidence: { currency: curr, pool: poolName, poolSize, estimatedStaked: stakedEstimate },
|
|
1182
1248
|
suggestedAction: {
|
|
1183
|
-
|
|
1249
|
+
parameterType: "fee",
|
|
1184
1250
|
direction: "increase",
|
|
1185
|
-
currency: curr,
|
|
1251
|
+
scope: { tags: ["transaction"], currency: curr },
|
|
1186
1252
|
magnitude: 0.05,
|
|
1187
1253
|
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.`
|
|
1188
1254
|
},
|
|
@@ -1212,9 +1278,9 @@ var P32_VelocityAboveSupply = {
|
|
|
1212
1278
|
severity: 4,
|
|
1213
1279
|
evidence: { currency: curr, velocity, totalSupply, totalResources },
|
|
1214
1280
|
suggestedAction: {
|
|
1215
|
-
|
|
1281
|
+
parameterType: "fee",
|
|
1216
1282
|
direction: "decrease",
|
|
1217
|
-
currency: curr,
|
|
1283
|
+
scope: { tags: ["transaction"], currency: curr },
|
|
1218
1284
|
magnitude: 0.2,
|
|
1219
1285
|
reasoning: `[${curr}] Velocity ${velocity}/t with ${totalResources} resources in system. Economy stagnant despite available supply. Lower trading friction.`
|
|
1220
1286
|
},
|
|
@@ -1254,9 +1320,9 @@ var P58_NoNaturalNumeraire = {
|
|
|
1254
1320
|
meanPrice: mean
|
|
1255
1321
|
},
|
|
1256
1322
|
suggestedAction: {
|
|
1257
|
-
|
|
1323
|
+
parameterType: "cost",
|
|
1258
1324
|
direction: "increase",
|
|
1259
|
-
currency: curr,
|
|
1325
|
+
scope: { currency: curr },
|
|
1260
1326
|
magnitude: 0.1,
|
|
1261
1327
|
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.`
|
|
1262
1328
|
},
|
|
@@ -1291,7 +1357,8 @@ var P17_GracePeriodBeforeIntervention = {
|
|
|
1291
1357
|
severity: 7,
|
|
1292
1358
|
evidence: { tick: metrics.tick, avgSatisfaction: metrics.avgSatisfaction },
|
|
1293
1359
|
suggestedAction: {
|
|
1294
|
-
|
|
1360
|
+
parameterType: "fee",
|
|
1361
|
+
scope: { tags: ["entry"] },
|
|
1295
1362
|
direction: "decrease",
|
|
1296
1363
|
magnitude: 0.2,
|
|
1297
1364
|
reasoning: `Very low satisfaction at tick ${metrics.tick}. Intervention may have fired during grace period. Ease all costs to let economy bootstrap.`
|
|
@@ -1318,7 +1385,7 @@ var P18_FirstProducerNeedsStartingInventory = {
|
|
|
1318
1385
|
severity: 8,
|
|
1319
1386
|
evidence: { tick: metrics.tick, resource, supply, totalAgents: metrics.totalAgents },
|
|
1320
1387
|
suggestedAction: {
|
|
1321
|
-
|
|
1388
|
+
parameterType: "cost",
|
|
1322
1389
|
direction: "decrease",
|
|
1323
1390
|
magnitude: 0.5,
|
|
1324
1391
|
reasoning: `Bootstrap failure: ${resource} supply is 0 at tick ${metrics.tick} with ${metrics.totalAgents} agents. Drastically reduce production cost to allow immediate output.`
|
|
@@ -1357,7 +1424,7 @@ var P19_StartingSupplyExceedsDemand = {
|
|
|
1357
1424
|
resourcesPerAgent
|
|
1358
1425
|
},
|
|
1359
1426
|
suggestedAction: {
|
|
1360
|
-
|
|
1427
|
+
parameterType: "reward",
|
|
1361
1428
|
direction: "increase",
|
|
1362
1429
|
magnitude: 0.2,
|
|
1363
1430
|
reasoning: `${mostPopulatedRole} (${population} agents) has insufficient resources (${resourcesPerAgent.toFixed(2)} per agent). Cold-start scarcity. Boost competitive pool reward to attract participation despite scarcity.`
|
|
@@ -1391,7 +1458,7 @@ var P20_DecayPreventsAccumulation = {
|
|
|
1391
1458
|
severity: 4,
|
|
1392
1459
|
evidence: { totalResources, resourcesPerAgent, velocity },
|
|
1393
1460
|
suggestedAction: {
|
|
1394
|
-
|
|
1461
|
+
parameterType: "yield",
|
|
1395
1462
|
direction: "decrease",
|
|
1396
1463
|
magnitude: 0.1,
|
|
1397
1464
|
reasoning: `${totalResources.toFixed(0)} resources with velocity ${velocity}/t. Likely hoarding. Reduce yield to increase scarcity and force circulation.`
|
|
@@ -1419,7 +1486,8 @@ var P21_PriceFromGlobalSupply = {
|
|
|
1419
1486
|
severity: 3,
|
|
1420
1487
|
evidence: { resource, volatility, supply, price: prices[resource] },
|
|
1421
1488
|
suggestedAction: {
|
|
1422
|
-
|
|
1489
|
+
parameterType: "fee",
|
|
1490
|
+
scope: { tags: ["transaction"] },
|
|
1423
1491
|
direction: "increase",
|
|
1424
1492
|
magnitude: 0.05,
|
|
1425
1493
|
reasoning: `${resource} price volatile (${(volatility * 100).toFixed(0)}%) despite supply ${supply}. Price may not reflect global inventory. Increase trading friction to stabilise.`
|
|
@@ -1436,7 +1504,7 @@ var P22_MarketAwarenessPreventsSurplus = {
|
|
|
1436
1504
|
id: "P22",
|
|
1437
1505
|
name: "Market Awareness Prevents Overproduction",
|
|
1438
1506
|
category: "feedback",
|
|
1439
|
-
description: "Producers who
|
|
1507
|
+
description: "Producers who produce without checking market prices will create surpluses that crash prices. Agents need to see prices before deciding to produce.",
|
|
1440
1508
|
check(metrics, _thresholds) {
|
|
1441
1509
|
const { supplyByResource, prices, productionIndex } = metrics;
|
|
1442
1510
|
const priceValues = Object.values(prices).filter((p) => p > 0);
|
|
@@ -1460,7 +1528,7 @@ var P22_MarketAwarenessPreventsSurplus = {
|
|
|
1460
1528
|
productionIndex
|
|
1461
1529
|
},
|
|
1462
1530
|
suggestedAction: {
|
|
1463
|
-
|
|
1531
|
+
parameterType: "cost",
|
|
1464
1532
|
direction: "increase",
|
|
1465
1533
|
magnitude: 0.1,
|
|
1466
1534
|
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.`
|
|
@@ -1487,7 +1555,7 @@ var P23_ProfitabilityFactorsFeasibility = {
|
|
|
1487
1555
|
severity: 5,
|
|
1488
1556
|
evidence: { blockedFraction, blockedAgentCount, avgSatisfaction },
|
|
1489
1557
|
suggestedAction: {
|
|
1490
|
-
|
|
1558
|
+
parameterType: "cost",
|
|
1491
1559
|
direction: "decrease",
|
|
1492
1560
|
magnitude: 0.15,
|
|
1493
1561
|
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.`
|
|
@@ -1513,7 +1581,8 @@ var P24_BlockedAgentsDecayFaster = {
|
|
|
1513
1581
|
severity: 5,
|
|
1514
1582
|
evidence: { blockedFraction, blockedAgentCount, churnRate },
|
|
1515
1583
|
suggestedAction: {
|
|
1516
|
-
|
|
1584
|
+
parameterType: "fee",
|
|
1585
|
+
scope: { tags: ["transaction"] },
|
|
1517
1586
|
direction: "decrease",
|
|
1518
1587
|
magnitude: 0.15,
|
|
1519
1588
|
reasoning: `${(blockedFraction * 100).toFixed(0)}% of agents blocked. Blocked agents churn silently, skewing metrics. Lower fees to unblock market participation.`
|
|
@@ -1558,7 +1627,7 @@ var P25_CorrectLeversForCorrectProblems = {
|
|
|
1558
1627
|
netFlow
|
|
1559
1628
|
},
|
|
1560
1629
|
suggestedAction: {
|
|
1561
|
-
|
|
1630
|
+
parameterType: "yield",
|
|
1562
1631
|
direction: "decrease",
|
|
1563
1632
|
magnitude: 0.15,
|
|
1564
1633
|
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.`
|
|
@@ -1584,7 +1653,7 @@ var P26_ContinuousPressureBeatsThresholdCuts = {
|
|
|
1584
1653
|
severity: 4,
|
|
1585
1654
|
evidence: { inflationRate },
|
|
1586
1655
|
suggestedAction: {
|
|
1587
|
-
|
|
1656
|
+
parameterType: "cost",
|
|
1588
1657
|
direction: inflationRate > 0 ? "increase" : "decrease",
|
|
1589
1658
|
magnitude: Math.min(thresholds.maxAdjustmentPercent, 0.05),
|
|
1590
1659
|
// force smaller step
|
|
@@ -1610,7 +1679,8 @@ var P27_AdjustmentsNeedCooldowns = {
|
|
|
1610
1679
|
severity: 4,
|
|
1611
1680
|
evidence: { churnRate, avgSatisfaction },
|
|
1612
1681
|
suggestedAction: {
|
|
1613
|
-
|
|
1682
|
+
parameterType: "fee",
|
|
1683
|
+
scope: { tags: ["entry"] },
|
|
1614
1684
|
direction: "decrease",
|
|
1615
1685
|
magnitude: 0.05,
|
|
1616
1686
|
reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) with low satisfaction. Possible oscillation from rapid adjustments. Apply small correction only.`
|
|
@@ -1641,7 +1711,7 @@ var P28_StructuralDominanceIsNotPathological = {
|
|
|
1641
1711
|
severity: 5,
|
|
1642
1712
|
evidence: { dominantRole, dominantShare, avgSatisfaction },
|
|
1643
1713
|
suggestedAction: {
|
|
1644
|
-
|
|
1714
|
+
parameterType: "cost",
|
|
1645
1715
|
direction: "decrease",
|
|
1646
1716
|
magnitude: 0.1,
|
|
1647
1717
|
reasoning: `${dominantRole} dominant (${(dominantShare * 100).toFixed(0)}%) with low satisfaction. Pathological dominance \u2014 agents trapped, not thriving. Ease costs to allow role switching.`
|
|
@@ -1657,7 +1727,7 @@ var P38_CommunicationPreventsRevolt = {
|
|
|
1657
1727
|
id: "P38",
|
|
1658
1728
|
name: "Communication Prevents Revolt",
|
|
1659
1729
|
category: "regulator",
|
|
1660
|
-
description: "Every adjustment must be logged with reasoning. An adjustment made without explanation to
|
|
1730
|
+
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.",
|
|
1661
1731
|
check(metrics, _thresholds) {
|
|
1662
1732
|
const { churnRate } = metrics;
|
|
1663
1733
|
if (churnRate > 0.1) {
|
|
@@ -1666,7 +1736,7 @@ var P38_CommunicationPreventsRevolt = {
|
|
|
1666
1736
|
severity: 3,
|
|
1667
1737
|
evidence: { churnRate },
|
|
1668
1738
|
suggestedAction: {
|
|
1669
|
-
|
|
1739
|
+
parameterType: "reward",
|
|
1670
1740
|
direction: "increase",
|
|
1671
1741
|
magnitude: 0.1,
|
|
1672
1742
|
reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) \u2014 agents leaving. Ensure all recent adjustments are logged with reasoning to diagnose cause.`
|
|
@@ -1687,9 +1757,9 @@ var REGULATOR_PRINCIPLES = [
|
|
|
1687
1757
|
];
|
|
1688
1758
|
|
|
1689
1759
|
// src/principles/market-dynamics.ts
|
|
1690
|
-
var
|
|
1760
|
+
var P29_BottleneckDetection = {
|
|
1691
1761
|
id: "P29",
|
|
1692
|
-
name: "
|
|
1762
|
+
name: "Bottleneck Detection",
|
|
1693
1763
|
category: "market_dynamics",
|
|
1694
1764
|
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.",
|
|
1695
1765
|
check(metrics, _thresholds) {
|
|
@@ -1703,7 +1773,7 @@ var P29_PinchPoint = {
|
|
|
1703
1773
|
severity: 7,
|
|
1704
1774
|
evidence: { resource, supply, demand, status },
|
|
1705
1775
|
suggestedAction: {
|
|
1706
|
-
|
|
1776
|
+
parameterType: "cost",
|
|
1707
1777
|
direction: "decrease",
|
|
1708
1778
|
magnitude: 0.15,
|
|
1709
1779
|
reasoning: `${resource} is a pinch point and currently SCARCE (supply ${supply}, demand ${demand}). Reduce production cost to increase throughput.`
|
|
@@ -1719,7 +1789,7 @@ var P29_PinchPoint = {
|
|
|
1719
1789
|
severity: 4,
|
|
1720
1790
|
evidence: { resource, supply, status },
|
|
1721
1791
|
suggestedAction: {
|
|
1722
|
-
|
|
1792
|
+
parameterType: "cost",
|
|
1723
1793
|
direction: "increase",
|
|
1724
1794
|
magnitude: 0.1,
|
|
1725
1795
|
reasoning: `${resource} is a pinch point and OVERSUPPLIED (supply ${supply}). Raise production cost to reduce surplus.`
|
|
@@ -1732,11 +1802,11 @@ var P29_PinchPoint = {
|
|
|
1732
1802
|
return { violated: false };
|
|
1733
1803
|
}
|
|
1734
1804
|
};
|
|
1735
|
-
var
|
|
1805
|
+
var P30_DynamicBottleneckRotation = {
|
|
1736
1806
|
id: "P30",
|
|
1737
|
-
name: "
|
|
1807
|
+
name: "Dynamic Bottleneck Rotation",
|
|
1738
1808
|
category: "market_dynamics",
|
|
1739
|
-
description: "
|
|
1809
|
+
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.",
|
|
1740
1810
|
check(metrics, _thresholds) {
|
|
1741
1811
|
const { capacityUsage, supplyByResource, avgSatisfaction } = metrics;
|
|
1742
1812
|
const totalResources = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
@@ -1747,7 +1817,7 @@ var P30_MovingPinchPoint = {
|
|
|
1747
1817
|
severity: 3,
|
|
1748
1818
|
evidence: { capacityUsage, resourcesPerAgent, avgSatisfaction },
|
|
1749
1819
|
suggestedAction: {
|
|
1750
|
-
|
|
1820
|
+
parameterType: "cost",
|
|
1751
1821
|
direction: "increase",
|
|
1752
1822
|
magnitude: 0.1,
|
|
1753
1823
|
reasoning: "Economy operating at full capacity with abundant resources and high satisfaction. Pinch point may have been cleared. Increase production cost to restore scarcity."
|
|
@@ -1763,7 +1833,7 @@ var P57_CombinatorialPriceSpace = {
|
|
|
1763
1833
|
id: "P57",
|
|
1764
1834
|
name: "Combinatorial Price Space",
|
|
1765
1835
|
category: "market_dynamics",
|
|
1766
|
-
description: "N tradeable items generate (N\u22121)N/2 relative prices. With thousands of items no single
|
|
1836
|
+
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.",
|
|
1767
1837
|
check(metrics, thresholds) {
|
|
1768
1838
|
const { prices, priceVolatility } = metrics;
|
|
1769
1839
|
const priceKeys = Object.keys(prices);
|
|
@@ -1793,7 +1863,8 @@ var P57_CombinatorialPriceSpace = {
|
|
|
1793
1863
|
target: thresholds.relativePriceConvergenceTarget
|
|
1794
1864
|
},
|
|
1795
1865
|
suggestedAction: {
|
|
1796
|
-
|
|
1866
|
+
parameterType: "fee",
|
|
1867
|
+
scope: { tags: ["transaction"] },
|
|
1797
1868
|
direction: "decrease",
|
|
1798
1869
|
magnitude: 0.1,
|
|
1799
1870
|
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.`
|
|
@@ -1806,8 +1877,8 @@ var P57_CombinatorialPriceSpace = {
|
|
|
1806
1877
|
}
|
|
1807
1878
|
};
|
|
1808
1879
|
var MARKET_DYNAMICS_PRINCIPLES = [
|
|
1809
|
-
|
|
1810
|
-
|
|
1880
|
+
P29_BottleneckDetection,
|
|
1881
|
+
P30_DynamicBottleneckRotation,
|
|
1811
1882
|
P57_CombinatorialPriceSpace
|
|
1812
1883
|
];
|
|
1813
1884
|
|
|
@@ -1825,7 +1896,7 @@ var P31_AnchorValueTracking = {
|
|
|
1825
1896
|
severity: 5,
|
|
1826
1897
|
evidence: { anchorRatioDrift, inflationRate },
|
|
1827
1898
|
suggestedAction: {
|
|
1828
|
-
|
|
1899
|
+
parameterType: "cost",
|
|
1829
1900
|
direction: anchorRatioDrift > 0 ? "increase" : "decrease",
|
|
1830
1901
|
magnitude: 0.1,
|
|
1831
1902
|
reasoning: `Anchor ratio has drifted ${(anchorRatioDrift * 100).toFixed(0)}% from baseline. Time-to-value for participants is changing. Adjust production costs to restore.`
|
|
@@ -1850,7 +1921,8 @@ var P41_MultiResolutionMonitoring = {
|
|
|
1850
1921
|
severity: 4,
|
|
1851
1922
|
evidence: { giniCoefficient, avgSatisfaction },
|
|
1852
1923
|
suggestedAction: {
|
|
1853
|
-
|
|
1924
|
+
parameterType: "fee",
|
|
1925
|
+
scope: { tags: ["transaction"] },
|
|
1854
1926
|
direction: "increase",
|
|
1855
1927
|
magnitude: 0.1,
|
|
1856
1928
|
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.`
|
|
@@ -1879,7 +1951,8 @@ var P55_ArbitrageThermometer = {
|
|
|
1879
1951
|
critical: thresholds.arbitrageIndexCritical
|
|
1880
1952
|
},
|
|
1881
1953
|
suggestedAction: {
|
|
1882
|
-
|
|
1954
|
+
parameterType: "fee",
|
|
1955
|
+
scope: { tags: ["transaction"] },
|
|
1883
1956
|
direction: "decrease",
|
|
1884
1957
|
magnitude: 0.15,
|
|
1885
1958
|
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.`
|
|
@@ -1897,7 +1970,8 @@ var P55_ArbitrageThermometer = {
|
|
|
1897
1970
|
warning: thresholds.arbitrageIndexWarning
|
|
1898
1971
|
},
|
|
1899
1972
|
suggestedAction: {
|
|
1900
|
-
|
|
1973
|
+
parameterType: "fee",
|
|
1974
|
+
scope: { tags: ["transaction"] },
|
|
1901
1975
|
direction: "decrease",
|
|
1902
1976
|
magnitude: 0.08,
|
|
1903
1977
|
reasoning: `Arbitrage index ${arbitrageIndex.toFixed(2)} above warning threshold (${thresholds.arbitrageIndexWarning}). Early sign of price divergence. Gently reduce friction to support self-correction.`
|
|
@@ -1925,7 +1999,8 @@ var P59_GiftEconomyNoise = {
|
|
|
1925
1999
|
threshold: thresholds.giftTradeFilterRatio
|
|
1926
2000
|
},
|
|
1927
2001
|
suggestedAction: {
|
|
1928
|
-
|
|
2002
|
+
parameterType: "fee",
|
|
2003
|
+
scope: { tags: ["transaction"] },
|
|
1929
2004
|
direction: "increase",
|
|
1930
2005
|
magnitude: 0.05,
|
|
1931
2006
|
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.`
|
|
@@ -1968,9 +2043,9 @@ var P42_TheMedianPrinciple = {
|
|
|
1968
2043
|
medianBalance
|
|
1969
2044
|
},
|
|
1970
2045
|
suggestedAction: {
|
|
1971
|
-
|
|
2046
|
+
parameterType: "fee",
|
|
2047
|
+
scope: { tags: ["transaction"], currency: curr },
|
|
1972
2048
|
direction: "increase",
|
|
1973
|
-
currency: curr,
|
|
1974
2049
|
magnitude: 0.15,
|
|
1975
2050
|
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.`
|
|
1976
2051
|
},
|
|
@@ -1995,7 +2070,7 @@ var P43_SimulationMinimum = {
|
|
|
1995
2070
|
severity: 3,
|
|
1996
2071
|
evidence: { inflationRate, minIterations: thresholds.simulationMinIterations },
|
|
1997
2072
|
suggestedAction: {
|
|
1998
|
-
|
|
2073
|
+
parameterType: "cost",
|
|
1999
2074
|
direction: inflationRate > 0 ? "increase" : "decrease",
|
|
2000
2075
|
magnitude: 0.05,
|
|
2001
2076
|
reasoning: `Large inflation rate swing (${(inflationRate * 100).toFixed(0)}%). Ensure all decisions use \u2265${thresholds.simulationMinIterations} simulation iterations. Apply conservative correction.`
|
|
@@ -2033,7 +2108,7 @@ var P39_TheLagPrinciple = {
|
|
|
2033
2108
|
severity: 5,
|
|
2034
2109
|
evidence: { inflationRate, netFlow, lagRange: [lagMin, lagMax] },
|
|
2035
2110
|
suggestedAction: {
|
|
2036
|
-
|
|
2111
|
+
parameterType: "cost",
|
|
2037
2112
|
direction: "increase",
|
|
2038
2113
|
magnitude: 0.03,
|
|
2039
2114
|
// very small — oscillation means over-adjusting
|
|
@@ -2060,7 +2135,8 @@ var P44_ComplexityBudget = {
|
|
|
2060
2135
|
severity: 3,
|
|
2061
2136
|
evidence: { customMetricCount, budgetMax: thresholds.complexityBudgetMax },
|
|
2062
2137
|
suggestedAction: {
|
|
2063
|
-
|
|
2138
|
+
parameterType: "fee",
|
|
2139
|
+
scope: { tags: ["transaction"] },
|
|
2064
2140
|
direction: "decrease",
|
|
2065
2141
|
magnitude: 0.01,
|
|
2066
2142
|
reasoning: `${customMetricCount} custom metrics tracked (budget: ${thresholds.complexityBudgetMax}). Consider pruning low-impact parameters. Applying minimal correction to avoid adding complexity.`
|
|
@@ -2092,7 +2168,8 @@ var P35_DestructionCreatesValue = {
|
|
|
2092
2168
|
severity: 6,
|
|
2093
2169
|
evidence: { resource, supply, sinkVolume, netFlow },
|
|
2094
2170
|
suggestedAction: {
|
|
2095
|
-
|
|
2171
|
+
parameterType: "fee",
|
|
2172
|
+
scope: { tags: ["entry"] },
|
|
2096
2173
|
direction: "decrease",
|
|
2097
2174
|
magnitude: 0.1,
|
|
2098
2175
|
reasoning: `${resource} supply at ${supply} units with low destruction (sink ${sinkVolume}/t). Resources not being consumed. Lower competitive pool entry to increase resource usage.`
|
|
@@ -2109,7 +2186,7 @@ var P40_ReplacementRate = {
|
|
|
2109
2186
|
id: "P40",
|
|
2110
2187
|
name: "Replacement Rate \u2265 2\xD7 Consumption",
|
|
2111
2188
|
category: "resource",
|
|
2112
|
-
description: "
|
|
2189
|
+
description: "Replacement/production rate must be at least 2\xD7 consumption rate for equilibrium. At 1\xD7 you drift toward depletion. At 2\xD7 you have a buffer for demand spikes.",
|
|
2113
2190
|
check(metrics, thresholds) {
|
|
2114
2191
|
const { productionIndex, sinkVolume } = metrics;
|
|
2115
2192
|
if (sinkVolume > 0 && productionIndex > 0) {
|
|
@@ -2120,7 +2197,7 @@ var P40_ReplacementRate = {
|
|
|
2120
2197
|
severity: 6,
|
|
2121
2198
|
evidence: { productionIndex, sinkVolume, replacementRatio },
|
|
2122
2199
|
suggestedAction: {
|
|
2123
|
-
|
|
2200
|
+
parameterType: "yield",
|
|
2124
2201
|
direction: "increase",
|
|
2125
2202
|
magnitude: 0.15,
|
|
2126
2203
|
reasoning: `Replacement rate ${replacementRatio.toFixed(2)} (need \u2265${thresholds.replacementRateMultiplier}). Production below consumption. Resources will deplete. Increase yield.`
|
|
@@ -2134,7 +2211,7 @@ var P40_ReplacementRate = {
|
|
|
2134
2211
|
severity: 3,
|
|
2135
2212
|
evidence: { productionIndex, sinkVolume, replacementRatio },
|
|
2136
2213
|
suggestedAction: {
|
|
2137
|
-
|
|
2214
|
+
parameterType: "yield",
|
|
2138
2215
|
direction: "decrease",
|
|
2139
2216
|
magnitude: 0.1,
|
|
2140
2217
|
reasoning: `Replacement rate ${replacementRatio.toFixed(2)} \u2014 overproducing. Production far exceeds consumption. Reduce yield to prevent glut.`
|
|
@@ -2160,7 +2237,8 @@ var P49_IdleAssetTax = {
|
|
|
2160
2237
|
severity: 5,
|
|
2161
2238
|
evidence: { giniCoefficient, top10PctShare, velocity },
|
|
2162
2239
|
suggestedAction: {
|
|
2163
|
-
|
|
2240
|
+
parameterType: "fee",
|
|
2241
|
+
scope: { tags: ["transaction"] },
|
|
2164
2242
|
direction: "increase",
|
|
2165
2243
|
magnitude: 0.15,
|
|
2166
2244
|
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.`
|
|
@@ -2178,11 +2256,11 @@ var RESOURCE_MGMT_PRINCIPLES = [
|
|
|
2178
2256
|
P49_IdleAssetTax
|
|
2179
2257
|
];
|
|
2180
2258
|
|
|
2181
|
-
// src/principles/
|
|
2259
|
+
// src/principles/participant-experience.ts
|
|
2182
2260
|
var P33_FairNotEqual = {
|
|
2183
2261
|
id: "P33",
|
|
2184
2262
|
name: "Fair \u2260 Equal",
|
|
2185
|
-
category: "
|
|
2263
|
+
category: "participant_experience",
|
|
2186
2264
|
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.",
|
|
2187
2265
|
check(metrics, thresholds) {
|
|
2188
2266
|
for (const curr of metrics.currencies) {
|
|
@@ -2193,9 +2271,9 @@ var P33_FairNotEqual = {
|
|
|
2193
2271
|
severity: 3,
|
|
2194
2272
|
evidence: { currency: curr, giniCoefficient },
|
|
2195
2273
|
suggestedAction: {
|
|
2196
|
-
|
|
2274
|
+
parameterType: "reward",
|
|
2197
2275
|
direction: "increase",
|
|
2198
|
-
currency: curr,
|
|
2276
|
+
scope: { currency: curr },
|
|
2199
2277
|
magnitude: 0.1,
|
|
2200
2278
|
reasoning: `[${curr}] Gini ${giniCoefficient.toFixed(2)} \u2014 near-perfect equality. Economy lacks stakes. Increase winner rewards to create meaningful spread.`
|
|
2201
2279
|
},
|
|
@@ -2209,9 +2287,9 @@ var P33_FairNotEqual = {
|
|
|
2209
2287
|
severity: 7,
|
|
2210
2288
|
evidence: { currency: curr, giniCoefficient },
|
|
2211
2289
|
suggestedAction: {
|
|
2212
|
-
|
|
2290
|
+
parameterType: "fee",
|
|
2213
2291
|
direction: "increase",
|
|
2214
|
-
currency: curr,
|
|
2292
|
+
scope: { tags: ["transaction"], currency: curr },
|
|
2215
2293
|
magnitude: 0.2,
|
|
2216
2294
|
reasoning: `[${curr}] Gini ${giniCoefficient.toFixed(2)} \u2014 oligarchy level. Toxic inequality. Raise transaction fees to redistribute wealth from rich to pool.`
|
|
2217
2295
|
},
|
|
@@ -2225,9 +2303,9 @@ var P33_FairNotEqual = {
|
|
|
2225
2303
|
severity: 4,
|
|
2226
2304
|
evidence: { currency: curr, giniCoefficient },
|
|
2227
2305
|
suggestedAction: {
|
|
2228
|
-
|
|
2306
|
+
parameterType: "fee",
|
|
2229
2307
|
direction: "increase",
|
|
2230
|
-
currency: curr,
|
|
2308
|
+
scope: { tags: ["transaction"], currency: curr },
|
|
2231
2309
|
magnitude: 0.1,
|
|
2232
2310
|
reasoning: `[${curr}] Gini ${giniCoefficient.toFixed(2)} \u2014 high inequality warning. Gently raise fees to slow wealth concentration.`
|
|
2233
2311
|
},
|
|
@@ -2241,9 +2319,9 @@ var P33_FairNotEqual = {
|
|
|
2241
2319
|
};
|
|
2242
2320
|
var P36_MechanicFrictionDetector = {
|
|
2243
2321
|
id: "P36",
|
|
2244
|
-
name: "
|
|
2245
|
-
category: "
|
|
2246
|
-
description: "Deterministic + probabilistic systems \u2192 expectation mismatch. When
|
|
2322
|
+
name: "Mechanism Friction Detector",
|
|
2323
|
+
category: "participant_experience",
|
|
2324
|
+
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.",
|
|
2247
2325
|
check(metrics, _thresholds) {
|
|
2248
2326
|
const { avgSatisfaction, churnRate, velocity } = metrics;
|
|
2249
2327
|
if (churnRate > 0.1 && avgSatisfaction < 50 && velocity > 3) {
|
|
@@ -2252,10 +2330,10 @@ var P36_MechanicFrictionDetector = {
|
|
|
2252
2330
|
severity: 5,
|
|
2253
2331
|
evidence: { churnRate, avgSatisfaction, velocity },
|
|
2254
2332
|
suggestedAction: {
|
|
2255
|
-
|
|
2333
|
+
parameterType: "reward",
|
|
2256
2334
|
direction: "increase",
|
|
2257
2335
|
magnitude: 0.15,
|
|
2258
|
-
reasoning: `Churn ${(churnRate * 100).toFixed(1)}% with satisfaction ${avgSatisfaction.toFixed(0)} despite active economy (velocity ` + velocity.toFixed(1) + "). Suggests
|
|
2336
|
+
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."
|
|
2259
2337
|
},
|
|
2260
2338
|
confidence: 0.55,
|
|
2261
2339
|
estimatedLag: 15
|
|
@@ -2266,8 +2344,8 @@ var P36_MechanicFrictionDetector = {
|
|
|
2266
2344
|
};
|
|
2267
2345
|
var P37_LatecommerProblem = {
|
|
2268
2346
|
id: "P37",
|
|
2269
|
-
name: "
|
|
2270
|
-
category: "
|
|
2347
|
+
name: "Late Entrant Problem",
|
|
2348
|
+
category: "participant_experience",
|
|
2271
2349
|
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.",
|
|
2272
2350
|
check(metrics, _thresholds) {
|
|
2273
2351
|
const { timeToValue, avgSatisfaction, churnRate } = metrics;
|
|
@@ -2277,7 +2355,7 @@ var P37_LatecommerProblem = {
|
|
|
2277
2355
|
severity: 6,
|
|
2278
2356
|
evidence: { timeToValue, avgSatisfaction, churnRate },
|
|
2279
2357
|
suggestedAction: {
|
|
2280
|
-
|
|
2358
|
+
parameterType: "cost",
|
|
2281
2359
|
direction: "decrease",
|
|
2282
2360
|
magnitude: 0.15,
|
|
2283
2361
|
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.`
|
|
@@ -2292,7 +2370,7 @@ var P37_LatecommerProblem = {
|
|
|
2292
2370
|
var P45_TimeBudget = {
|
|
2293
2371
|
id: "P45",
|
|
2294
2372
|
name: "Time Budget",
|
|
2295
|
-
category: "
|
|
2373
|
+
category: "participant_experience",
|
|
2296
2374
|
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.",
|
|
2297
2375
|
check(metrics, thresholds) {
|
|
2298
2376
|
const { timeToValue, avgSatisfaction } = metrics;
|
|
@@ -2304,8 +2382,9 @@ var P45_TimeBudget = {
|
|
|
2304
2382
|
severity: 5,
|
|
2305
2383
|
evidence: { timeToValue, avgSatisfaction, timeBudgetRatio: thresholds.timeBudgetRatio },
|
|
2306
2384
|
suggestedAction: {
|
|
2307
|
-
|
|
2385
|
+
parameterType: "fee",
|
|
2308
2386
|
direction: "decrease",
|
|
2387
|
+
scope: { tags: ["entry"] },
|
|
2309
2388
|
magnitude: 0.15,
|
|
2310
2389
|
reasoning: `Time-to-value ${timeToValue} ticks with ${avgSatisfaction.toFixed(0)} satisfaction. Economy requires too much time investment. Lower barriers to participation.`
|
|
2311
2390
|
},
|
|
@@ -2319,7 +2398,7 @@ var P45_TimeBudget = {
|
|
|
2319
2398
|
var P50_PayPowerRatio = {
|
|
2320
2399
|
id: "P50",
|
|
2321
2400
|
name: "Pay-Power Ratio",
|
|
2322
|
-
category: "
|
|
2401
|
+
category: "participant_experience",
|
|
2323
2402
|
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.",
|
|
2324
2403
|
check(metrics, thresholds) {
|
|
2325
2404
|
const { top10PctShare, giniCoefficient } = metrics;
|
|
@@ -2334,8 +2413,9 @@ var P50_PayPowerRatio = {
|
|
|
2334
2413
|
threshold: thresholds.payPowerRatioMax
|
|
2335
2414
|
},
|
|
2336
2415
|
suggestedAction: {
|
|
2337
|
-
|
|
2416
|
+
parameterType: "fee",
|
|
2338
2417
|
direction: "increase",
|
|
2418
|
+
scope: { tags: ["transaction"] },
|
|
2339
2419
|
magnitude: 0.2,
|
|
2340
2420
|
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.`
|
|
2341
2421
|
},
|
|
@@ -2346,7 +2426,7 @@ var P50_PayPowerRatio = {
|
|
|
2346
2426
|
return { violated: false };
|
|
2347
2427
|
}
|
|
2348
2428
|
};
|
|
2349
|
-
var
|
|
2429
|
+
var PARTICIPANT_EXPERIENCE_PRINCIPLES = [
|
|
2350
2430
|
P33_FairNotEqual,
|
|
2351
2431
|
P36_MechanicFrictionDetector,
|
|
2352
2432
|
P37_LatecommerProblem,
|
|
@@ -2369,7 +2449,8 @@ var P34_ExtractionRatio = {
|
|
|
2369
2449
|
severity: 8,
|
|
2370
2450
|
evidence: { extractionRatio, threshold: thresholds.extractionRatioRed },
|
|
2371
2451
|
suggestedAction: {
|
|
2372
|
-
|
|
2452
|
+
parameterType: "fee",
|
|
2453
|
+
scope: { tags: ["transaction"] },
|
|
2373
2454
|
direction: "increase",
|
|
2374
2455
|
magnitude: 0.25,
|
|
2375
2456
|
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.`
|
|
@@ -2384,7 +2465,8 @@ var P34_ExtractionRatio = {
|
|
|
2384
2465
|
severity: 5,
|
|
2385
2466
|
evidence: { extractionRatio, threshold: thresholds.extractionRatioYellow },
|
|
2386
2467
|
suggestedAction: {
|
|
2387
|
-
|
|
2468
|
+
parameterType: "fee",
|
|
2469
|
+
scope: { tags: ["transaction"] },
|
|
2388
2470
|
direction: "increase",
|
|
2389
2471
|
magnitude: 0.1,
|
|
2390
2472
|
reasoning: `Extraction ratio ${(extractionRatio * 100).toFixed(0)}% (warning: ${(thresholds.extractionRatioYellow * 100).toFixed(0)}%). Economy trending toward extraction-heavy. Apply early pressure.`
|
|
@@ -2410,7 +2492,7 @@ var P47_SmokeTest = {
|
|
|
2410
2492
|
severity: 9,
|
|
2411
2493
|
evidence: { smokeTestRatio, threshold: thresholds.smokeTestCritical },
|
|
2412
2494
|
suggestedAction: {
|
|
2413
|
-
|
|
2495
|
+
parameterType: "reward",
|
|
2414
2496
|
direction: "increase",
|
|
2415
2497
|
magnitude: 0.2,
|
|
2416
2498
|
reasoning: `Utility/market ratio ${(smokeTestRatio * 100).toFixed(0)}% (critical). Economy is >90% speculative. Collapse risk is extreme. Increase utility rewards to anchor real value.`
|
|
@@ -2425,7 +2507,7 @@ var P47_SmokeTest = {
|
|
|
2425
2507
|
severity: 6,
|
|
2426
2508
|
evidence: { smokeTestRatio, threshold: thresholds.smokeTestWarning },
|
|
2427
2509
|
suggestedAction: {
|
|
2428
|
-
|
|
2510
|
+
parameterType: "reward",
|
|
2429
2511
|
direction: "increase",
|
|
2430
2512
|
magnitude: 0.1,
|
|
2431
2513
|
reasoning: `Utility/market ratio ${(smokeTestRatio * 100).toFixed(0)}% (warning). Economy is >70% speculative. Boost utility rewards to restore intrinsic value anchor.`
|
|
@@ -2451,7 +2533,8 @@ var P48_CurrencyInsulation = {
|
|
|
2451
2533
|
severity: 6,
|
|
2452
2534
|
evidence: { currencyInsulation, threshold: thresholds.currencyInsulationMax },
|
|
2453
2535
|
suggestedAction: {
|
|
2454
|
-
|
|
2536
|
+
parameterType: "fee",
|
|
2537
|
+
scope: { tags: ["transaction"] },
|
|
2455
2538
|
direction: "increase",
|
|
2456
2539
|
magnitude: 0.1,
|
|
2457
2540
|
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.`
|
|
@@ -2469,12 +2552,12 @@ var OPEN_ECONOMY_PRINCIPLES = [
|
|
|
2469
2552
|
P48_CurrencyInsulation
|
|
2470
2553
|
];
|
|
2471
2554
|
|
|
2472
|
-
// src/principles/
|
|
2473
|
-
var
|
|
2555
|
+
// src/principles/operations.ts
|
|
2556
|
+
var P51_CyclicalEngagement = {
|
|
2474
2557
|
id: "P51",
|
|
2475
|
-
name: "
|
|
2476
|
-
category: "
|
|
2477
|
-
description: "Each
|
|
2558
|
+
name: "Cyclical Engagement Pattern",
|
|
2559
|
+
category: "operations",
|
|
2560
|
+
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.",
|
|
2478
2561
|
check(metrics, thresholds) {
|
|
2479
2562
|
const { sharkToothPeaks, sharkToothValleys } = metrics;
|
|
2480
2563
|
if (sharkToothPeaks.length < 2) return { violated: false };
|
|
@@ -2491,10 +2574,10 @@ var P51_SharkTooth = {
|
|
|
2491
2574
|
threshold: thresholds.sharkToothPeakDecay
|
|
2492
2575
|
},
|
|
2493
2576
|
suggestedAction: {
|
|
2494
|
-
|
|
2577
|
+
parameterType: "reward",
|
|
2495
2578
|
direction: "increase",
|
|
2496
2579
|
magnitude: 0.1,
|
|
2497
|
-
reasoning: `Peak engagement dropped to ${(lastPeak / prevPeak * 100).toFixed(0)}% of previous peak (threshold: ${(thresholds.sharkToothPeakDecay * 100).toFixed(0)}%).
|
|
2580
|
+
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.`
|
|
2498
2581
|
},
|
|
2499
2582
|
confidence: 0.75,
|
|
2500
2583
|
estimatedLag: 30
|
|
@@ -2509,10 +2592,10 @@ var P51_SharkTooth = {
|
|
|
2509
2592
|
severity: 4,
|
|
2510
2593
|
evidence: { lastValley, prevValley, ratio: lastValley / prevValley },
|
|
2511
2594
|
suggestedAction: {
|
|
2512
|
-
|
|
2595
|
+
parameterType: "cost",
|
|
2513
2596
|
direction: "decrease",
|
|
2514
2597
|
magnitude: 0.1,
|
|
2515
|
-
reasoning: "Between-
|
|
2598
|
+
reasoning: "Between-activity engagement declining (deepening valleys). Base economy not sustaining participants between activities. Lower production costs to improve off-activity value."
|
|
2516
2599
|
},
|
|
2517
2600
|
confidence: 0.65,
|
|
2518
2601
|
estimatedLag: 20
|
|
@@ -2525,8 +2608,8 @@ var P51_SharkTooth = {
|
|
|
2525
2608
|
var P52_EndowmentEffect = {
|
|
2526
2609
|
id: "P52",
|
|
2527
2610
|
name: "Endowment Effect",
|
|
2528
|
-
category: "
|
|
2529
|
-
description: "Participants who never owned premium
|
|
2611
|
+
category: "operations",
|
|
2612
|
+
description: "Participants who never owned premium assets do not value them. Free trial activities that let participants experience premium assets drive conversions because ownership creates perceived value (endowment effect).",
|
|
2530
2613
|
check(metrics, _thresholds) {
|
|
2531
2614
|
const { avgSatisfaction, churnRate } = metrics;
|
|
2532
2615
|
const { eventCompletionRate } = metrics;
|
|
@@ -2537,10 +2620,10 @@ var P52_EndowmentEffect = {
|
|
|
2537
2620
|
severity: 4,
|
|
2538
2621
|
evidence: { eventCompletionRate, avgSatisfaction, churnRate },
|
|
2539
2622
|
suggestedAction: {
|
|
2540
|
-
|
|
2623
|
+
parameterType: "reward",
|
|
2541
2624
|
direction: "increase",
|
|
2542
2625
|
magnitude: 0.15,
|
|
2543
|
-
reasoning: `${(eventCompletionRate * 100).toFixed(0)}%
|
|
2626
|
+
reasoning: `${(eventCompletionRate * 100).toFixed(0)}% activity completion but satisfaction only ${avgSatisfaction.toFixed(0)}. Activities not creating perceived value. Increase reward quality/quantity.`
|
|
2544
2627
|
},
|
|
2545
2628
|
confidence: 0.6,
|
|
2546
2629
|
estimatedLag: 20
|
|
@@ -2551,8 +2634,8 @@ var P52_EndowmentEffect = {
|
|
|
2551
2634
|
};
|
|
2552
2635
|
var P53_EventCompletionRate = {
|
|
2553
2636
|
id: "P53",
|
|
2554
|
-
name: "
|
|
2555
|
-
category: "
|
|
2637
|
+
name: "Activity Completion Rate Sweet Spot",
|
|
2638
|
+
category: "operations",
|
|
2556
2639
|
description: "Free completion at 60-80% is the sweet spot. <40% = predatory design. >80% = no monetization pressure. 100% free = zero reason to ever spend.",
|
|
2557
2640
|
check(metrics, thresholds) {
|
|
2558
2641
|
const { eventCompletionRate } = metrics;
|
|
@@ -2567,10 +2650,10 @@ var P53_EventCompletionRate = {
|
|
|
2567
2650
|
max: thresholds.eventCompletionMax
|
|
2568
2651
|
},
|
|
2569
2652
|
suggestedAction: {
|
|
2570
|
-
|
|
2653
|
+
parameterType: "cost",
|
|
2571
2654
|
direction: "decrease",
|
|
2572
2655
|
magnitude: 0.15,
|
|
2573
|
-
reasoning: `
|
|
2656
|
+
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.`
|
|
2574
2657
|
},
|
|
2575
2658
|
confidence: 0.8,
|
|
2576
2659
|
estimatedLag: 10
|
|
@@ -2582,10 +2665,11 @@ var P53_EventCompletionRate = {
|
|
|
2582
2665
|
severity: 3,
|
|
2583
2666
|
evidence: { eventCompletionRate, max: thresholds.eventCompletionMax },
|
|
2584
2667
|
suggestedAction: {
|
|
2585
|
-
|
|
2668
|
+
parameterType: "fee",
|
|
2669
|
+
scope: { tags: ["entry"] },
|
|
2586
2670
|
direction: "increase",
|
|
2587
2671
|
magnitude: 0.05,
|
|
2588
|
-
reasoning: `
|
|
2672
|
+
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.`
|
|
2589
2673
|
},
|
|
2590
2674
|
confidence: 0.55,
|
|
2591
2675
|
estimatedLag: 10
|
|
@@ -2594,11 +2678,11 @@ var P53_EventCompletionRate = {
|
|
|
2594
2678
|
return { violated: false };
|
|
2595
2679
|
}
|
|
2596
2680
|
};
|
|
2597
|
-
var
|
|
2681
|
+
var P54_OperationalCadence = {
|
|
2598
2682
|
id: "P54",
|
|
2599
|
-
name: "
|
|
2600
|
-
category: "
|
|
2601
|
-
description: ">50% of
|
|
2683
|
+
name: "Operational Cadence",
|
|
2684
|
+
category: "operations",
|
|
2685
|
+
description: ">50% of activities that are re-wrapped existing supply \u2192 stagnation. The cadence must include genuinely new supply at regular intervals. This is an advisory principle \u2014 AgentE can flag but cannot fix supply.",
|
|
2602
2686
|
check(metrics, _thresholds) {
|
|
2603
2687
|
const { velocity, avgSatisfaction } = metrics;
|
|
2604
2688
|
if (velocity < 2 && avgSatisfaction < 55 && metrics.tick > 100) {
|
|
@@ -2607,10 +2691,10 @@ var P54_LiveOpsCadence = {
|
|
|
2607
2691
|
severity: 3,
|
|
2608
2692
|
evidence: { velocity, avgSatisfaction, tick: metrics.tick },
|
|
2609
2693
|
suggestedAction: {
|
|
2610
|
-
|
|
2694
|
+
parameterType: "reward",
|
|
2611
2695
|
direction: "increase",
|
|
2612
2696
|
magnitude: 0.1,
|
|
2613
|
-
reasoning: "Low velocity and satisfaction after long runtime. Possible
|
|
2697
|
+
reasoning: "Low velocity and satisfaction after long runtime. Possible supply stagnation. Increase rewards as bridge while new supply is developed (developer action required)."
|
|
2614
2698
|
},
|
|
2615
2699
|
confidence: 0.4,
|
|
2616
2700
|
estimatedLag: 30
|
|
@@ -2619,11 +2703,11 @@ var P54_LiveOpsCadence = {
|
|
|
2619
2703
|
return { violated: false };
|
|
2620
2704
|
}
|
|
2621
2705
|
};
|
|
2622
|
-
var
|
|
2706
|
+
var P56_SupplyShockAbsorption = {
|
|
2623
2707
|
id: "P56",
|
|
2624
|
-
name: "
|
|
2625
|
-
category: "
|
|
2626
|
-
description: "Every new-item injection shatters existing price equilibria \u2014 arbitrage spikes as participants re-price. Build
|
|
2708
|
+
name: "Supply Shock Absorption",
|
|
2709
|
+
category: "operations",
|
|
2710
|
+
description: "Every new-item injection shatters existing price equilibria \u2014 arbitrage spikes as participants re-price. Build stabilization windows for price discovery before measuring post-injection economic health.",
|
|
2627
2711
|
check(metrics, thresholds) {
|
|
2628
2712
|
const { contentDropAge, arbitrageIndex } = metrics;
|
|
2629
2713
|
if (contentDropAge > 0 && contentDropAge <= thresholds.contentDropCooldownTicks) {
|
|
@@ -2638,10 +2722,11 @@ var P56_ContentDropShock = {
|
|
|
2638
2722
|
postDropMax: thresholds.postDropArbitrageMax
|
|
2639
2723
|
},
|
|
2640
2724
|
suggestedAction: {
|
|
2641
|
-
|
|
2725
|
+
parameterType: "fee",
|
|
2726
|
+
scope: { tags: ["transaction"] },
|
|
2642
2727
|
direction: "decrease",
|
|
2643
2728
|
magnitude: 0.1,
|
|
2644
|
-
reasoning: `
|
|
2729
|
+
reasoning: `Supply injection ${contentDropAge} ticks ago \u2014 arbitrage at ${arbitrageIndex.toFixed(2)} exceeds post-injection max (${thresholds.postDropArbitrageMax}). Price discovery struggling. Lower trading friction temporarily.`
|
|
2645
2730
|
},
|
|
2646
2731
|
confidence: 0.6,
|
|
2647
2732
|
estimatedLag: 5
|
|
@@ -2651,12 +2736,12 @@ var P56_ContentDropShock = {
|
|
|
2651
2736
|
return { violated: false };
|
|
2652
2737
|
}
|
|
2653
2738
|
};
|
|
2654
|
-
var
|
|
2655
|
-
|
|
2739
|
+
var OPERATIONS_PRINCIPLES = [
|
|
2740
|
+
P51_CyclicalEngagement,
|
|
2656
2741
|
P52_EndowmentEffect,
|
|
2657
2742
|
P53_EventCompletionRate,
|
|
2658
|
-
|
|
2659
|
-
|
|
2743
|
+
P54_OperationalCadence,
|
|
2744
|
+
P56_SupplyShockAbsorption
|
|
2660
2745
|
];
|
|
2661
2746
|
|
|
2662
2747
|
// src/principles/index.ts
|
|
@@ -2685,23 +2770,24 @@ var ALL_PRINCIPLES = [
|
|
|
2685
2770
|
// P39, P44
|
|
2686
2771
|
...RESOURCE_MGMT_PRINCIPLES,
|
|
2687
2772
|
// P35, P40, P49
|
|
2688
|
-
...
|
|
2773
|
+
...PARTICIPANT_EXPERIENCE_PRINCIPLES,
|
|
2689
2774
|
// P33, P36, P37, P45, P50
|
|
2690
2775
|
...OPEN_ECONOMY_PRINCIPLES,
|
|
2691
2776
|
// P34, P47-P48
|
|
2692
|
-
...
|
|
2777
|
+
...OPERATIONS_PRINCIPLES
|
|
2693
2778
|
// P51-P54, P56
|
|
2694
2779
|
];
|
|
2695
2780
|
|
|
2696
2781
|
// src/Simulator.ts
|
|
2697
2782
|
var Simulator = class {
|
|
2698
|
-
constructor() {
|
|
2783
|
+
constructor(registry) {
|
|
2699
2784
|
this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
|
|
2700
2785
|
// Cache beforeViolations for the *current* tick only (one entry max).
|
|
2701
2786
|
// Using a Map here is intentional but the cache must be bounded — we only
|
|
2702
2787
|
// care about the tick that is currently being evaluated, so we evict any
|
|
2703
2788
|
// entries whose key differs from the incoming tick.
|
|
2704
2789
|
this.beforeViolationsCache = /* @__PURE__ */ new Map();
|
|
2790
|
+
this.registry = registry;
|
|
2705
2791
|
}
|
|
2706
2792
|
/**
|
|
2707
2793
|
* Simulate the effect of applying `action` to the current economy forward `forwardTicks`.
|
|
@@ -2768,7 +2854,7 @@ var Simulator = class {
|
|
|
2768
2854
|
const multiplier = this.actionMultiplier(action);
|
|
2769
2855
|
const noise = () => 1 + (Math.random() - 0.5) * 0.1;
|
|
2770
2856
|
const currencies = metrics.currencies;
|
|
2771
|
-
const targetCurrency = action.currency;
|
|
2857
|
+
const targetCurrency = action.scope?.currency;
|
|
2772
2858
|
const supplies = { ...metrics.totalSupplyByCurrency };
|
|
2773
2859
|
const netFlows = { ...metrics.netFlowByCurrency };
|
|
2774
2860
|
const ginis = { ...metrics.giniCoefficientByCurrency };
|
|
@@ -2810,26 +2896,54 @@ var Simulator = class {
|
|
|
2810
2896
|
return action.direction === "increase" ? 1 + base : 1 - base;
|
|
2811
2897
|
}
|
|
2812
2898
|
flowEffect(action, metrics, currency) {
|
|
2813
|
-
const {
|
|
2899
|
+
const { direction } = action;
|
|
2814
2900
|
const sign = direction === "increase" ? -1 : 1;
|
|
2815
2901
|
const roleEntries = Object.entries(metrics.populationByRole).sort((a, b) => b[1] - a[1]);
|
|
2816
2902
|
const dominantRoleCount = roleEntries[0]?.[1] ?? 0;
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
if (parameter === "entryFee") {
|
|
2824
|
-
return sign * dominantRoleCount * 0.5;
|
|
2825
|
-
}
|
|
2826
|
-
if (parameter === "rewardRate") {
|
|
2827
|
-
return -sign * dominantRoleCount * 0.3;
|
|
2903
|
+
let impact;
|
|
2904
|
+
if (this.registry) {
|
|
2905
|
+
const resolved = this.registry.resolve(action.parameterType, action.scope);
|
|
2906
|
+
if (resolved) {
|
|
2907
|
+
impact = resolved.flowImpact;
|
|
2908
|
+
}
|
|
2828
2909
|
}
|
|
2829
|
-
if (
|
|
2830
|
-
|
|
2910
|
+
if (!impact) {
|
|
2911
|
+
impact = this.inferFlowImpact(action.parameterType);
|
|
2912
|
+
}
|
|
2913
|
+
switch (impact) {
|
|
2914
|
+
case "sink":
|
|
2915
|
+
return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.2;
|
|
2916
|
+
case "faucet":
|
|
2917
|
+
return -sign * dominantRoleCount * 0.3;
|
|
2918
|
+
case "neutral":
|
|
2919
|
+
return sign * dominantRoleCount * 0.5;
|
|
2920
|
+
case "mixed":
|
|
2921
|
+
return sign * (metrics.faucetVolumeByCurrency[currency] ?? 0) * 0.15;
|
|
2922
|
+
case "friction":
|
|
2923
|
+
return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
|
|
2924
|
+
case "redistribution":
|
|
2925
|
+
return sign * dominantRoleCount * 0.05;
|
|
2926
|
+
default:
|
|
2927
|
+
return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
/** Infer flow impact from parameter type when registry is unavailable */
|
|
2931
|
+
inferFlowImpact(parameterType) {
|
|
2932
|
+
switch (parameterType) {
|
|
2933
|
+
case "cost":
|
|
2934
|
+
case "fee":
|
|
2935
|
+
case "penalty":
|
|
2936
|
+
return "sink";
|
|
2937
|
+
case "reward":
|
|
2938
|
+
return "faucet";
|
|
2939
|
+
case "yield":
|
|
2940
|
+
return "mixed";
|
|
2941
|
+
case "cap":
|
|
2942
|
+
case "multiplier":
|
|
2943
|
+
return "neutral";
|
|
2944
|
+
default:
|
|
2945
|
+
return "mixed";
|
|
2831
2946
|
}
|
|
2832
|
-
return sign * (metrics.netFlowByCurrency[currency] ?? 0) * 0.1;
|
|
2833
2947
|
}
|
|
2834
2948
|
checkImprovement(before, after, action) {
|
|
2835
2949
|
const satisfactionImproved = after.avgSatisfaction >= before.avgSatisfaction - 2;
|
|
@@ -2891,6 +3005,8 @@ var Planner = class {
|
|
|
2891
3005
|
this.constraints = /* @__PURE__ */ new Map();
|
|
2892
3006
|
this.cooldowns = /* @__PURE__ */ new Map();
|
|
2893
3007
|
// param → last-applied-tick
|
|
3008
|
+
this.typeCooldowns = /* @__PURE__ */ new Map();
|
|
3009
|
+
// type+scope key → last-applied-tick
|
|
2894
3010
|
this.activePlanCount = 0;
|
|
2895
3011
|
}
|
|
2896
3012
|
lock(param) {
|
|
@@ -2909,16 +3025,32 @@ var Planner = class {
|
|
|
2909
3025
|
* - parameter is still in cooldown
|
|
2910
3026
|
* - simulation result failed
|
|
2911
3027
|
* - complexity budget exceeded
|
|
3028
|
+
* - no matching parameter in registry
|
|
2912
3029
|
*/
|
|
2913
|
-
plan(diagnosis, metrics, simulationResult, currentParams, thresholds) {
|
|
3030
|
+
plan(diagnosis, metrics, simulationResult, currentParams, thresholds, registry) {
|
|
2914
3031
|
const action = diagnosis.violation.suggestedAction;
|
|
2915
|
-
const
|
|
3032
|
+
const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
|
|
3033
|
+
if (this.isTypeCooldown(typeKey, metrics.tick, thresholds.cooldownTicks)) return null;
|
|
3034
|
+
let param;
|
|
3035
|
+
let resolvedBaseline;
|
|
3036
|
+
let scope;
|
|
3037
|
+
if (registry) {
|
|
3038
|
+
const resolved = registry.resolve(action.parameterType, action.scope);
|
|
3039
|
+
if (!resolved) return null;
|
|
3040
|
+
param = resolved.key;
|
|
3041
|
+
resolvedBaseline = resolved.currentValue;
|
|
3042
|
+
scope = resolved.scope;
|
|
3043
|
+
action.resolvedParameter = param;
|
|
3044
|
+
} else {
|
|
3045
|
+
param = action.resolvedParameter ?? action.parameterType;
|
|
3046
|
+
scope = action.scope;
|
|
3047
|
+
}
|
|
2916
3048
|
if (this.lockedParams.has(param)) return null;
|
|
2917
3049
|
if (this.isOnCooldown(param, metrics.tick, thresholds.cooldownTicks)) return null;
|
|
2918
3050
|
if (!simulationResult.netImprovement) return null;
|
|
2919
3051
|
if (!simulationResult.noNewProblems) return null;
|
|
2920
3052
|
if (this.activePlanCount >= thresholds.complexityBudgetMax) return null;
|
|
2921
|
-
const currentValue = currentParams[param] ?? 1;
|
|
3053
|
+
const currentValue = resolvedBaseline ?? currentParams[param] ?? action.absoluteValue ?? 1;
|
|
2922
3054
|
const magnitude = Math.min(action.magnitude ?? 0.1, thresholds.maxAdjustmentPercent);
|
|
2923
3055
|
let targetValue;
|
|
2924
3056
|
if (action.direction === "set" && action.absoluteValue !== void 0) {
|
|
@@ -2938,7 +3070,7 @@ var Planner = class {
|
|
|
2938
3070
|
id: `plan_${metrics.tick}_${param}`,
|
|
2939
3071
|
diagnosis,
|
|
2940
3072
|
parameter: param,
|
|
2941
|
-
...
|
|
3073
|
+
...scope !== void 0 ? { scope } : {},
|
|
2942
3074
|
currentValue,
|
|
2943
3075
|
targetValue,
|
|
2944
3076
|
maxChangePercent: thresholds.maxAdjustmentPercent,
|
|
@@ -2947,7 +3079,6 @@ var Planner = class {
|
|
|
2947
3079
|
metric: "avgSatisfaction",
|
|
2948
3080
|
direction: "below",
|
|
2949
3081
|
threshold: Math.max(20, metrics.avgSatisfaction - 10),
|
|
2950
|
-
// rollback if sat drops >10 pts
|
|
2951
3082
|
checkAfterTick: metrics.tick + estimatedLag + 3
|
|
2952
3083
|
},
|
|
2953
3084
|
simulationResult,
|
|
@@ -2957,11 +3088,17 @@ var Planner = class {
|
|
|
2957
3088
|
}
|
|
2958
3089
|
recordApplied(plan, tick) {
|
|
2959
3090
|
this.cooldowns.set(plan.parameter, tick);
|
|
3091
|
+
const action = plan.diagnosis.violation.suggestedAction;
|
|
3092
|
+
const typeKey = this.typeCooldownKey(action.parameterType, action.scope);
|
|
3093
|
+
this.typeCooldowns.set(typeKey, tick);
|
|
2960
3094
|
this.activePlanCount++;
|
|
2961
3095
|
}
|
|
2962
3096
|
recordRolledBack(_plan) {
|
|
2963
3097
|
this.activePlanCount = Math.max(0, this.activePlanCount - 1);
|
|
2964
3098
|
}
|
|
3099
|
+
recordSettled(_plan) {
|
|
3100
|
+
this.activePlanCount = Math.max(0, this.activePlanCount - 1);
|
|
3101
|
+
}
|
|
2965
3102
|
isOnCooldown(param, currentTick, cooldownTicks) {
|
|
2966
3103
|
const lastApplied = this.cooldowns.get(param);
|
|
2967
3104
|
if (lastApplied === void 0) return false;
|
|
@@ -2970,6 +3107,19 @@ var Planner = class {
|
|
|
2970
3107
|
/** Reset all cooldowns (useful for testing) */
|
|
2971
3108
|
resetCooldowns() {
|
|
2972
3109
|
this.cooldowns.clear();
|
|
3110
|
+
this.typeCooldowns.clear();
|
|
3111
|
+
}
|
|
3112
|
+
typeCooldownKey(type, scope) {
|
|
3113
|
+
const parts = [type];
|
|
3114
|
+
if (scope?.system) parts.push(`sys:${scope.system}`);
|
|
3115
|
+
if (scope?.currency) parts.push(`cur:${scope.currency}`);
|
|
3116
|
+
if (scope?.tags?.length) parts.push(`tags:${scope.tags.sort().join(",")}`);
|
|
3117
|
+
return parts.join("|");
|
|
3118
|
+
}
|
|
3119
|
+
isTypeCooldown(typeKey, currentTick, cooldownTicks) {
|
|
3120
|
+
const lastApplied = this.typeCooldowns.get(typeKey);
|
|
3121
|
+
if (lastApplied === void 0) return false;
|
|
3122
|
+
return currentTick - lastApplied < cooldownTicks;
|
|
2973
3123
|
}
|
|
2974
3124
|
};
|
|
2975
3125
|
|
|
@@ -2980,40 +3130,54 @@ var Executor = class {
|
|
|
2980
3130
|
}
|
|
2981
3131
|
async apply(plan, adapter, currentParams) {
|
|
2982
3132
|
const originalValue = currentParams[plan.parameter] ?? plan.currentValue;
|
|
2983
|
-
await adapter.setParam(plan.parameter, plan.targetValue, plan.
|
|
3133
|
+
await adapter.setParam(plan.parameter, plan.targetValue, plan.scope);
|
|
2984
3134
|
plan.appliedAt = plan.diagnosis.tick;
|
|
2985
3135
|
this.activePlans.push({ plan, originalValue });
|
|
2986
3136
|
}
|
|
2987
3137
|
/**
|
|
2988
3138
|
* Check all active plans for rollback conditions.
|
|
2989
|
-
*
|
|
2990
|
-
* Returns list of plans that were rolled back.
|
|
3139
|
+
* Returns { rolledBack, settled } — plans that were undone and plans that passed their window.
|
|
2991
3140
|
*/
|
|
2992
3141
|
async checkRollbacks(metrics, adapter) {
|
|
2993
3142
|
const rolledBack = [];
|
|
3143
|
+
const settled = [];
|
|
2994
3144
|
const remaining = [];
|
|
2995
3145
|
for (const active of this.activePlans) {
|
|
2996
3146
|
const { plan, originalValue } = active;
|
|
2997
3147
|
const rc = plan.rollbackCondition;
|
|
3148
|
+
const maxActiveTicks = 200;
|
|
3149
|
+
if (plan.appliedAt !== void 0 && metrics.tick - plan.appliedAt > maxActiveTicks) {
|
|
3150
|
+
settled.push(plan);
|
|
3151
|
+
continue;
|
|
3152
|
+
}
|
|
2998
3153
|
if (metrics.tick < rc.checkAfterTick) {
|
|
2999
3154
|
remaining.push(active);
|
|
3000
3155
|
continue;
|
|
3001
3156
|
}
|
|
3002
3157
|
const metricValue = this.getMetricValue(metrics, rc.metric);
|
|
3158
|
+
if (Number.isNaN(metricValue)) {
|
|
3159
|
+
console.warn(
|
|
3160
|
+
`[AgentE] Rollback check: metric path '${rc.metric}' resolved to NaN for plan '${plan.id}'. Triggering rollback as fail-safe.`
|
|
3161
|
+
);
|
|
3162
|
+
await adapter.setParam(plan.parameter, originalValue, plan.scope);
|
|
3163
|
+
rolledBack.push(plan);
|
|
3164
|
+
continue;
|
|
3165
|
+
}
|
|
3003
3166
|
const shouldRollback = rc.direction === "below" ? metricValue < rc.threshold : metricValue > rc.threshold;
|
|
3004
3167
|
if (shouldRollback) {
|
|
3005
|
-
await adapter.setParam(plan.parameter, originalValue, plan.
|
|
3168
|
+
await adapter.setParam(plan.parameter, originalValue, plan.scope);
|
|
3006
3169
|
rolledBack.push(plan);
|
|
3007
3170
|
} else {
|
|
3008
3171
|
const settledTick = rc.checkAfterTick + 10;
|
|
3009
3172
|
if (metrics.tick > settledTick) {
|
|
3173
|
+
settled.push(plan);
|
|
3010
3174
|
} else {
|
|
3011
3175
|
remaining.push(active);
|
|
3012
3176
|
}
|
|
3013
3177
|
}
|
|
3014
3178
|
}
|
|
3015
3179
|
this.activePlans = remaining;
|
|
3016
|
-
return rolledBack;
|
|
3180
|
+
return { rolledBack, settled };
|
|
3017
3181
|
}
|
|
3018
3182
|
getMetricValue(metrics, metricPath) {
|
|
3019
3183
|
const parts = metricPath.split(".");
|
|
@@ -3102,7 +3266,8 @@ var DecisionLog = class {
|
|
|
3102
3266
|
return {
|
|
3103
3267
|
id: `stub_${metrics.tick}`,
|
|
3104
3268
|
diagnosis,
|
|
3105
|
-
parameter: action.
|
|
3269
|
+
parameter: action.resolvedParameter ?? action.parameterType,
|
|
3270
|
+
...action.scope !== void 0 ? { scope: action.scope } : {},
|
|
3106
3271
|
currentValue: 1,
|
|
3107
3272
|
targetValue: 1,
|
|
3108
3273
|
maxChangePercent: 0,
|
|
@@ -3340,13 +3505,13 @@ var PersonaTracker = class {
|
|
|
3340
3505
|
Earner: 0,
|
|
3341
3506
|
Builder: 0,
|
|
3342
3507
|
Social: 0,
|
|
3343
|
-
|
|
3508
|
+
HighValue: 0,
|
|
3344
3509
|
Influencer: 0
|
|
3345
3510
|
};
|
|
3346
3511
|
let total = 0;
|
|
3347
3512
|
for (const [, history] of this.agentHistory) {
|
|
3348
3513
|
const persona = this.classify(history);
|
|
3349
|
-
counts[persona]
|
|
3514
|
+
counts[persona] = (counts[persona] ?? 0) + 1;
|
|
3350
3515
|
total++;
|
|
3351
3516
|
}
|
|
3352
3517
|
if (total === 0) return {};
|
|
@@ -3366,7 +3531,7 @@ var PersonaTracker = class {
|
|
|
3366
3531
|
const extraction = avg("netExtraction");
|
|
3367
3532
|
const uniqueItems = avg("uniqueItemsHeld");
|
|
3368
3533
|
const spend = avg("spendAmount");
|
|
3369
|
-
if (spend > 1e3) return "
|
|
3534
|
+
if (spend > 1e3) return "HighValue";
|
|
3370
3535
|
if (txRate > 10) return "Trader";
|
|
3371
3536
|
if (uniqueItems > 5 && extraction < 0) return "Collector";
|
|
3372
3537
|
if (extraction > 100) return "Earner";
|
|
@@ -3375,12 +3540,153 @@ var PersonaTracker = class {
|
|
|
3375
3540
|
}
|
|
3376
3541
|
};
|
|
3377
3542
|
|
|
3543
|
+
// src/ParameterRegistry.ts
|
|
3544
|
+
var ParameterRegistry = class {
|
|
3545
|
+
constructor() {
|
|
3546
|
+
this.parameters = /* @__PURE__ */ new Map();
|
|
3547
|
+
}
|
|
3548
|
+
/** Register a parameter. Overwrites if key already exists. */
|
|
3549
|
+
register(param) {
|
|
3550
|
+
this.parameters.set(param.key, { ...param });
|
|
3551
|
+
}
|
|
3552
|
+
/** Register multiple parameters at once. */
|
|
3553
|
+
registerAll(params) {
|
|
3554
|
+
for (const p of params) this.register(p);
|
|
3555
|
+
}
|
|
3556
|
+
/**
|
|
3557
|
+
* Resolve a parameterType + scope to a concrete RegisteredParameter.
|
|
3558
|
+
* Returns the best match, or undefined if no match.
|
|
3559
|
+
*
|
|
3560
|
+
* Matching rules:
|
|
3561
|
+
* 1. Filter candidates by type
|
|
3562
|
+
* 2. Score each by scope specificity (system +10, currency +5, tags +3 each)
|
|
3563
|
+
* 3. Mismatched scope fields disqualify (score = -Infinity)
|
|
3564
|
+
* 4. Ties broken by `priority` (higher wins), then registration order
|
|
3565
|
+
* 5. All disqualified → undefined
|
|
3566
|
+
*/
|
|
3567
|
+
resolve(type, scope) {
|
|
3568
|
+
const candidates = this.findByType(type);
|
|
3569
|
+
if (candidates.length === 0) return void 0;
|
|
3570
|
+
if (candidates.length === 1) return candidates[0];
|
|
3571
|
+
let bestScore = -Infinity;
|
|
3572
|
+
let bestPriority = -Infinity;
|
|
3573
|
+
let best;
|
|
3574
|
+
for (const candidate of candidates) {
|
|
3575
|
+
const score = this.scopeSpecificity(candidate.scope, scope);
|
|
3576
|
+
const prio = candidate.priority ?? 0;
|
|
3577
|
+
if (score > bestScore || score === bestScore && prio > bestPriority) {
|
|
3578
|
+
bestScore = score;
|
|
3579
|
+
bestPriority = prio;
|
|
3580
|
+
best = candidate;
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
if (bestScore === -Infinity) return void 0;
|
|
3584
|
+
return best;
|
|
3585
|
+
}
|
|
3586
|
+
/** Find all parameters of a given type. */
|
|
3587
|
+
findByType(type) {
|
|
3588
|
+
const results = [];
|
|
3589
|
+
for (const param of this.parameters.values()) {
|
|
3590
|
+
if (param.type === type) results.push(param);
|
|
3591
|
+
}
|
|
3592
|
+
return results;
|
|
3593
|
+
}
|
|
3594
|
+
/** Find all parameters belonging to a given system. */
|
|
3595
|
+
findBySystem(system) {
|
|
3596
|
+
const results = [];
|
|
3597
|
+
for (const param of this.parameters.values()) {
|
|
3598
|
+
if (param.scope?.system === system) results.push(param);
|
|
3599
|
+
}
|
|
3600
|
+
return results;
|
|
3601
|
+
}
|
|
3602
|
+
/** Get a parameter by its concrete key. */
|
|
3603
|
+
get(key) {
|
|
3604
|
+
return this.parameters.get(key);
|
|
3605
|
+
}
|
|
3606
|
+
/** Get the flow impact of a parameter by its concrete key. */
|
|
3607
|
+
getFlowImpact(key) {
|
|
3608
|
+
return this.parameters.get(key)?.flowImpact;
|
|
3609
|
+
}
|
|
3610
|
+
/** Update the current value of a registered parameter. */
|
|
3611
|
+
updateValue(key, value) {
|
|
3612
|
+
const param = this.parameters.get(key);
|
|
3613
|
+
if (param) {
|
|
3614
|
+
param.currentValue = value;
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3617
|
+
/** Get all registered parameters. */
|
|
3618
|
+
getAll() {
|
|
3619
|
+
return [...this.parameters.values()];
|
|
3620
|
+
}
|
|
3621
|
+
/** Number of registered parameters. */
|
|
3622
|
+
get size() {
|
|
3623
|
+
return this.parameters.size;
|
|
3624
|
+
}
|
|
3625
|
+
/**
|
|
3626
|
+
* Validate the registry for common misconfigurations.
|
|
3627
|
+
* Returns warnings (non-fatal) and errors (likely broken).
|
|
3628
|
+
*/
|
|
3629
|
+
validate() {
|
|
3630
|
+
const warnings = [];
|
|
3631
|
+
const errors = [];
|
|
3632
|
+
const typeMap = /* @__PURE__ */ new Map();
|
|
3633
|
+
for (const param of this.parameters.values()) {
|
|
3634
|
+
const list = typeMap.get(param.type) ?? [];
|
|
3635
|
+
list.push(param);
|
|
3636
|
+
typeMap.set(param.type, list);
|
|
3637
|
+
}
|
|
3638
|
+
for (const [type, params] of typeMap) {
|
|
3639
|
+
if (params.length > 1) {
|
|
3640
|
+
const unscopedCount = params.filter((p) => !p.scope).length;
|
|
3641
|
+
if (unscopedCount > 1) {
|
|
3642
|
+
errors.push(
|
|
3643
|
+
`Type '${type}' has ${unscopedCount} unscoped parameters \u2014 resolve() cannot distinguish them`
|
|
3644
|
+
);
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
for (const param of this.parameters.values()) {
|
|
3649
|
+
if (!param.flowImpact) {
|
|
3650
|
+
warnings.push(`Parameter '${param.key}' has no flowImpact \u2014 Simulator will use inference`);
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
return {
|
|
3654
|
+
valid: errors.length === 0,
|
|
3655
|
+
warnings,
|
|
3656
|
+
errors
|
|
3657
|
+
};
|
|
3658
|
+
}
|
|
3659
|
+
// ── Private ─────────────────────────────────────────────────────────────
|
|
3660
|
+
scopeSpecificity(paramScope, queryScope) {
|
|
3661
|
+
if (!queryScope) return 0;
|
|
3662
|
+
if (!paramScope) return 0;
|
|
3663
|
+
let score = 0;
|
|
3664
|
+
if (queryScope.system && paramScope.system) {
|
|
3665
|
+
if (queryScope.system === paramScope.system) score += 10;
|
|
3666
|
+
else return -Infinity;
|
|
3667
|
+
}
|
|
3668
|
+
if (queryScope.currency && paramScope.currency) {
|
|
3669
|
+
if (queryScope.currency === paramScope.currency) score += 5;
|
|
3670
|
+
else return -Infinity;
|
|
3671
|
+
}
|
|
3672
|
+
if (queryScope.tags && queryScope.tags.length > 0 && paramScope.tags && paramScope.tags.length > 0) {
|
|
3673
|
+
const overlap = queryScope.tags.filter((t) => paramScope.tags.includes(t)).length;
|
|
3674
|
+
if (overlap > 0) {
|
|
3675
|
+
score += overlap * 3;
|
|
3676
|
+
} else {
|
|
3677
|
+
return -Infinity;
|
|
3678
|
+
}
|
|
3679
|
+
}
|
|
3680
|
+
return score;
|
|
3681
|
+
}
|
|
3682
|
+
};
|
|
3683
|
+
|
|
3378
3684
|
// src/AgentE.ts
|
|
3379
3685
|
var AgentE = class {
|
|
3380
3686
|
constructor(config) {
|
|
3381
|
-
this.simulator = new Simulator();
|
|
3382
3687
|
this.planner = new Planner();
|
|
3383
3688
|
this.executor = new Executor();
|
|
3689
|
+
this.registry = new ParameterRegistry();
|
|
3384
3690
|
// ── State ──
|
|
3385
3691
|
this.log = new DecisionLog();
|
|
3386
3692
|
this.personaTracker = new PersonaTracker();
|
|
@@ -3401,11 +3707,13 @@ var AgentE = class {
|
|
|
3401
3707
|
mode: this.mode,
|
|
3402
3708
|
dominantRoles: config.dominantRoles ?? [],
|
|
3403
3709
|
idealDistribution: config.idealDistribution ?? {},
|
|
3710
|
+
validateRegistry: config.validateRegistry ?? true,
|
|
3404
3711
|
tickConfig: config.tickConfig ?? { duration: 1, unit: "tick" },
|
|
3405
3712
|
gracePeriod: config.gracePeriod ?? 50,
|
|
3406
3713
|
checkInterval: config.checkInterval ?? 5,
|
|
3407
3714
|
maxAdjustmentPercent: config.maxAdjustmentPercent ?? 0.15,
|
|
3408
|
-
cooldownTicks: config.cooldownTicks ?? 15
|
|
3715
|
+
cooldownTicks: config.cooldownTicks ?? 15,
|
|
3716
|
+
parameters: config.parameters ?? []
|
|
3409
3717
|
};
|
|
3410
3718
|
this.thresholds = {
|
|
3411
3719
|
...DEFAULT_THRESHOLDS,
|
|
@@ -3417,6 +3725,15 @@ var AgentE = class {
|
|
|
3417
3725
|
this.observer = new Observer(tickConfig);
|
|
3418
3726
|
this.store = new MetricStore(tickConfig);
|
|
3419
3727
|
this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
|
|
3728
|
+
if (config.parameters) {
|
|
3729
|
+
this.registry.registerAll(config.parameters);
|
|
3730
|
+
}
|
|
3731
|
+
if (config.validateRegistry !== false && this.registry.size > 0) {
|
|
3732
|
+
const validation = this.registry.validate();
|
|
3733
|
+
for (const w of validation.warnings) console.warn(`[AgentE] Registry warning: ${w}`);
|
|
3734
|
+
for (const e of validation.errors) console.error(`[AgentE] Registry error: ${e}`);
|
|
3735
|
+
}
|
|
3736
|
+
this.simulator = new Simulator(this.registry);
|
|
3420
3737
|
if (config.onDecision) this.on("decision", config.onDecision);
|
|
3421
3738
|
if (config.onAlert) this.on("alert", config.onAlert);
|
|
3422
3739
|
if (config.onRollback) this.on("rollback", config.onRollback);
|
|
@@ -3454,15 +3771,24 @@ var AgentE = class {
|
|
|
3454
3771
|
this.currentTick = currentState.tick;
|
|
3455
3772
|
const events = [...this.eventBuffer];
|
|
3456
3773
|
this.eventBuffer = [];
|
|
3457
|
-
|
|
3774
|
+
let metrics;
|
|
3775
|
+
try {
|
|
3776
|
+
metrics = this.observer.compute(currentState, events);
|
|
3777
|
+
} catch (err) {
|
|
3778
|
+
console.error(`[AgentE] Observer.compute() failed at tick ${currentState.tick}:`, err);
|
|
3779
|
+
return;
|
|
3780
|
+
}
|
|
3458
3781
|
this.store.record(metrics);
|
|
3459
3782
|
this.personaTracker.update(currentState);
|
|
3460
3783
|
metrics.personaDistribution = this.personaTracker.getDistribution();
|
|
3461
|
-
const rolledBack = await this.executor.checkRollbacks(metrics, this.adapter);
|
|
3784
|
+
const { rolledBack, settled } = await this.executor.checkRollbacks(metrics, this.adapter);
|
|
3462
3785
|
for (const plan2 of rolledBack) {
|
|
3463
3786
|
this.planner.recordRolledBack(plan2);
|
|
3464
3787
|
this.emit("rollback", plan2, "rollback condition triggered");
|
|
3465
3788
|
}
|
|
3789
|
+
for (const plan2 of settled) {
|
|
3790
|
+
this.planner.recordSettled(plan2);
|
|
3791
|
+
}
|
|
3466
3792
|
if (metrics.tick < this.config.gracePeriod) return;
|
|
3467
3793
|
if (metrics.tick % this.config.checkInterval !== 0) return;
|
|
3468
3794
|
const diagnoses = this.diagnoser.diagnose(metrics, this.thresholds);
|
|
@@ -3484,7 +3810,8 @@ var AgentE = class {
|
|
|
3484
3810
|
metrics,
|
|
3485
3811
|
simulationResult,
|
|
3486
3812
|
this.params,
|
|
3487
|
-
this.thresholds
|
|
3813
|
+
this.thresholds,
|
|
3814
|
+
this.registry
|
|
3488
3815
|
);
|
|
3489
3816
|
if (!plan) {
|
|
3490
3817
|
let reason = "skipped_cooldown";
|
|
@@ -3504,6 +3831,7 @@ var AgentE = class {
|
|
|
3504
3831
|
}
|
|
3505
3832
|
await this.executor.apply(plan, this.adapter, this.params);
|
|
3506
3833
|
this.params[plan.parameter] = plan.targetValue;
|
|
3834
|
+
this.registry.updateValue(plan.parameter, plan.targetValue);
|
|
3507
3835
|
this.planner.recordApplied(plan, metrics.tick);
|
|
3508
3836
|
const entry = this.log.record(topDiagnosis, plan, "applied", metrics);
|
|
3509
3837
|
this.emit("decision", entry);
|
|
@@ -3513,6 +3841,7 @@ var AgentE = class {
|
|
|
3513
3841
|
async apply(plan) {
|
|
3514
3842
|
await this.executor.apply(plan, this.adapter, this.params);
|
|
3515
3843
|
this.params[plan.parameter] = plan.targetValue;
|
|
3844
|
+
this.registry.updateValue(plan.parameter, plan.targetValue);
|
|
3516
3845
|
this.planner.recordApplied(plan, this.currentTick);
|
|
3517
3846
|
}
|
|
3518
3847
|
// ── Developer API ───────────────────────────────────────────────────────────
|
|
@@ -3537,6 +3866,12 @@ var AgentE = class {
|
|
|
3537
3866
|
removePrinciple(id) {
|
|
3538
3867
|
this.diagnoser.removePrinciple(id);
|
|
3539
3868
|
}
|
|
3869
|
+
registerParameter(param) {
|
|
3870
|
+
this.registry.register(param);
|
|
3871
|
+
}
|
|
3872
|
+
getRegistry() {
|
|
3873
|
+
return this.registry;
|
|
3874
|
+
}
|
|
3540
3875
|
registerCustomMetric(name, fn) {
|
|
3541
3876
|
this.observer.registerCustomMetric(name, fn);
|
|
3542
3877
|
}
|
|
@@ -3594,6 +3929,31 @@ var AgentE = class {
|
|
|
3594
3929
|
}
|
|
3595
3930
|
};
|
|
3596
3931
|
|
|
3932
|
+
// src/utils.ts
|
|
3933
|
+
function findWorstSystem(metrics, check, tolerancePercent = 0) {
|
|
3934
|
+
const systems = metrics.systems;
|
|
3935
|
+
if (systems.length === 0) return void 0;
|
|
3936
|
+
let worstSystem;
|
|
3937
|
+
let worstScore = -Infinity;
|
|
3938
|
+
let totalScore = 0;
|
|
3939
|
+
for (const sys of systems) {
|
|
3940
|
+
const score = check(sys, metrics);
|
|
3941
|
+
totalScore += score;
|
|
3942
|
+
if (score > worstScore) {
|
|
3943
|
+
worstScore = score;
|
|
3944
|
+
worstSystem = sys;
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
if (!worstSystem) return void 0;
|
|
3948
|
+
if (tolerancePercent > 0 && systems.length > 1) {
|
|
3949
|
+
const avg = totalScore / systems.length;
|
|
3950
|
+
if (avg === 0) return { system: worstSystem, score: worstScore };
|
|
3951
|
+
const excessPercent = (worstScore - avg) / Math.abs(avg) * 100;
|
|
3952
|
+
if (excessPercent < tolerancePercent) return void 0;
|
|
3953
|
+
}
|
|
3954
|
+
return { system: worstSystem, score: worstScore };
|
|
3955
|
+
}
|
|
3956
|
+
|
|
3597
3957
|
// src/StateValidator.ts
|
|
3598
3958
|
function validateEconomyState(state) {
|
|
3599
3959
|
const errors = [];
|
|
@@ -3938,13 +4298,13 @@ export {
|
|
|
3938
4298
|
Executor,
|
|
3939
4299
|
FEEDBACK_LOOP_PRINCIPLES,
|
|
3940
4300
|
INCENTIVE_PRINCIPLES,
|
|
3941
|
-
LIVEOPS_PRINCIPLES,
|
|
3942
4301
|
MARKET_DYNAMICS_PRINCIPLES,
|
|
3943
4302
|
MEASUREMENT_PRINCIPLES,
|
|
3944
4303
|
MetricStore,
|
|
3945
4304
|
OPEN_ECONOMY_PRINCIPLES,
|
|
4305
|
+
OPERATIONS_PRINCIPLES,
|
|
3946
4306
|
Observer,
|
|
3947
|
-
|
|
4307
|
+
P10_EntryWeightingUsesInversePopulation,
|
|
3948
4308
|
P11_TwoTierPressure,
|
|
3949
4309
|
P12_OnePrimaryFaucet,
|
|
3950
4310
|
P13_PotsAreZeroSumAndSelfRegulate,
|
|
@@ -3964,9 +4324,9 @@ export {
|
|
|
3964
4324
|
P26_ContinuousPressureBeatsThresholdCuts,
|
|
3965
4325
|
P27_AdjustmentsNeedCooldowns,
|
|
3966
4326
|
P28_StructuralDominanceIsNotPathological,
|
|
3967
|
-
|
|
4327
|
+
P29_BottleneckDetection,
|
|
3968
4328
|
P2_ClosedLoopsNeedDirectHandoff,
|
|
3969
|
-
|
|
4329
|
+
P30_DynamicBottleneckRotation,
|
|
3970
4330
|
P31_AnchorValueTracking,
|
|
3971
4331
|
P32_VelocityAboveSupply,
|
|
3972
4332
|
P33_FairNotEqual,
|
|
@@ -3989,12 +4349,12 @@ export {
|
|
|
3989
4349
|
P49_IdleAssetTax,
|
|
3990
4350
|
P4_MaterialsFlowFasterThanCooldown,
|
|
3991
4351
|
P50_PayPowerRatio,
|
|
3992
|
-
|
|
4352
|
+
P51_CyclicalEngagement,
|
|
3993
4353
|
P52_EndowmentEffect,
|
|
3994
4354
|
P53_EventCompletionRate,
|
|
3995
|
-
|
|
4355
|
+
P54_OperationalCadence,
|
|
3996
4356
|
P55_ArbitrageThermometer,
|
|
3997
|
-
|
|
4357
|
+
P56_SupplyShockAbsorption,
|
|
3998
4358
|
P57_CombinatorialPriceSpace,
|
|
3999
4359
|
P58_NoNaturalNumeraire,
|
|
4000
4360
|
P59_GiftEconomyNoise,
|
|
@@ -4004,9 +4364,10 @@ export {
|
|
|
4004
4364
|
P7_NonSpecialistsSubsidiseSpecialists,
|
|
4005
4365
|
P8_RegulatorCannotFightDesign,
|
|
4006
4366
|
P9_RoleSwitchingNeedsFriction,
|
|
4367
|
+
PARTICIPANT_EXPERIENCE_PRINCIPLES,
|
|
4007
4368
|
PERSONA_HEALTHY_RANGES,
|
|
4008
|
-
PLAYER_EXPERIENCE_PRINCIPLES,
|
|
4009
4369
|
POPULATION_PRINCIPLES,
|
|
4370
|
+
ParameterRegistry,
|
|
4010
4371
|
PersonaTracker,
|
|
4011
4372
|
Planner,
|
|
4012
4373
|
REGULATOR_PRINCIPLES,
|
|
@@ -4016,6 +4377,7 @@ export {
|
|
|
4016
4377
|
SYSTEM_DYNAMICS_PRINCIPLES,
|
|
4017
4378
|
Simulator,
|
|
4018
4379
|
emptyMetrics,
|
|
4380
|
+
findWorstSystem,
|
|
4019
4381
|
validateEconomyState
|
|
4020
4382
|
};
|
|
4021
4383
|
//# sourceMappingURL=index.mjs.map
|