@agent-e/core 1.1.3 → 1.2.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/README.md +42 -23
- package/dist/index.d.mts +23 -7
- package/dist/index.d.ts +23 -7
- package/dist/index.js +371 -310
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +371 -310
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -144,8 +144,8 @@ var DEFAULT_THRESHOLDS = {
|
|
|
144
144
|
maxAdjustmentPercent: 0.15,
|
|
145
145
|
cooldownTicks: 15,
|
|
146
146
|
// Currency (P13)
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
poolWinRate: 0.65,
|
|
148
|
+
poolHouseCut: 0.1,
|
|
149
149
|
// Population balance (P9)
|
|
150
150
|
roleSwitchFrictionMax: 0.05,
|
|
151
151
|
// >5% of population switching in one period = herd
|
|
@@ -176,7 +176,7 @@ var DEFAULT_THRESHOLDS = {
|
|
|
176
176
|
disposalTradeWeightDiscount: 0.5
|
|
177
177
|
};
|
|
178
178
|
var PERSONA_HEALTHY_RANGES = {
|
|
179
|
-
|
|
179
|
+
Active: { min: 0.2, max: 0.4 },
|
|
180
180
|
Trader: { min: 0.05, max: 0.15 },
|
|
181
181
|
Collector: { min: 0.05, max: 0.15 },
|
|
182
182
|
Speculator: { min: 0, max: 0.1 },
|
|
@@ -186,14 +186,21 @@ var PERSONA_HEALTHY_RANGES = {
|
|
|
186
186
|
Whale: { min: 0, max: 0.05 },
|
|
187
187
|
Influencer: { min: 0, max: 0.05 }
|
|
188
188
|
};
|
|
189
|
+
var DEFAULT_TICK_CONFIG = {
|
|
190
|
+
duration: 1,
|
|
191
|
+
unit: "tick",
|
|
192
|
+
mediumWindow: 10,
|
|
193
|
+
coarseWindow: 100
|
|
194
|
+
};
|
|
189
195
|
|
|
190
196
|
// src/Observer.ts
|
|
191
197
|
var Observer = class {
|
|
192
|
-
constructor() {
|
|
198
|
+
constructor(tickConfig) {
|
|
193
199
|
this.previousMetrics = null;
|
|
194
200
|
this.previousPrices = {};
|
|
195
201
|
this.customMetricFns = {};
|
|
196
202
|
this.anchorBaseline = null;
|
|
203
|
+
this.tickConfig = { ...DEFAULT_TICK_CONFIG, ...tickConfig };
|
|
197
204
|
}
|
|
198
205
|
registerCustomMetric(name, fn) {
|
|
199
206
|
this.customMetricFns[name] = fn;
|
|
@@ -208,6 +215,7 @@ var Observer = class {
|
|
|
208
215
|
const tradeEvents = [];
|
|
209
216
|
const roleChangeEvents = [];
|
|
210
217
|
let churnCount = 0;
|
|
218
|
+
let productionAmount = 0;
|
|
211
219
|
for (const e of recentEvents) {
|
|
212
220
|
switch (e.type) {
|
|
213
221
|
case "mint":
|
|
@@ -218,6 +226,9 @@ var Observer = class {
|
|
|
218
226
|
case "consume":
|
|
219
227
|
sinkVolume += e.amount ?? 0;
|
|
220
228
|
break;
|
|
229
|
+
case "produce":
|
|
230
|
+
productionAmount += e.amount ?? 1;
|
|
231
|
+
break;
|
|
221
232
|
case "trade":
|
|
222
233
|
tradeEvents.push(e);
|
|
223
234
|
break;
|
|
@@ -291,24 +302,24 @@ var Observer = class {
|
|
|
291
302
|
pinchPoints[resource] = "optimal";
|
|
292
303
|
}
|
|
293
304
|
}
|
|
294
|
-
const productionIndex =
|
|
305
|
+
const productionIndex = productionAmount;
|
|
295
306
|
const maxPossibleProduction = productionIndex + sinkVolume;
|
|
296
307
|
const capacityUsage = maxPossibleProduction > 0 ? productionIndex / maxPossibleProduction : 0;
|
|
297
308
|
const satisfactions = Object.values(state.agentSatisfaction ?? {});
|
|
298
309
|
const avgSatisfaction = satisfactions.length > 0 ? satisfactions.reduce((s, v) => s + v, 0) / satisfactions.length : 80;
|
|
299
310
|
const blockedAgentCount = satisfactions.filter((s) => s < 20).length;
|
|
300
|
-
const timeToValue =
|
|
311
|
+
const timeToValue = totalAgents > 0 ? blockedAgentCount / totalAgents * 100 : 0;
|
|
301
312
|
const poolSizes = { ...state.poolSizes ?? {} };
|
|
302
313
|
if (!this.anchorBaseline && tick === 1 && totalSupply > 0) {
|
|
303
314
|
this.anchorBaseline = {
|
|
304
|
-
|
|
305
|
-
|
|
315
|
+
currencyPerPeriod: totalSupply / Math.max(1, totalAgents),
|
|
316
|
+
itemsPerCurrency: priceIndex > 0 ? 1 / priceIndex : 0
|
|
306
317
|
};
|
|
307
318
|
}
|
|
308
319
|
let anchorRatioDrift = 0;
|
|
309
320
|
if (this.anchorBaseline && totalAgents > 0) {
|
|
310
|
-
const
|
|
311
|
-
anchorRatioDrift = this.anchorBaseline.
|
|
321
|
+
const currentCurrencyPerPeriod = totalSupply / totalAgents;
|
|
322
|
+
anchorRatioDrift = this.anchorBaseline.currencyPerPeriod > 0 ? (currentCurrencyPerPeriod - this.anchorBaseline.currencyPerPeriod) / this.anchorBaseline.currencyPerPeriod : 0;
|
|
312
323
|
}
|
|
313
324
|
let arbitrageIndex = 0;
|
|
314
325
|
const priceKeys = Object.keys(prices).filter((k) => prices[k] > 0);
|
|
@@ -533,7 +544,7 @@ var P1_ProductionMatchesConsumption = {
|
|
|
533
544
|
id: "P1",
|
|
534
545
|
name: "Production Must Match Consumption",
|
|
535
546
|
category: "supply_chain",
|
|
536
|
-
description: "If producer rate < consumer rate, supply deficit kills the economy.
|
|
547
|
+
description: "If producer rate < consumer rate, supply deficit kills the economy. Raw materials piling at production locations happened because this was out of balance.",
|
|
537
548
|
check(metrics, _thresholds) {
|
|
538
549
|
const { supplyByResource, demandSignals, populationByRole } = metrics;
|
|
539
550
|
const violations = [];
|
|
@@ -544,19 +555,22 @@ var P1_ProductionMatchesConsumption = {
|
|
|
544
555
|
violations.push(resource);
|
|
545
556
|
}
|
|
546
557
|
}
|
|
547
|
-
const
|
|
548
|
-
const
|
|
549
|
-
const
|
|
550
|
-
|
|
558
|
+
const roleEntries = Object.entries(populationByRole).sort((a, b) => b[1] - a[1]);
|
|
559
|
+
const totalPop = metrics.totalAgents;
|
|
560
|
+
const dominantRole = roleEntries[0];
|
|
561
|
+
const dominantCount = dominantRole?.[1] ?? 0;
|
|
562
|
+
const dominantShare = totalPop > 0 ? dominantCount / totalPop : 0;
|
|
563
|
+
const populationImbalance = dominantShare > 0.4 && violations.length > 0;
|
|
564
|
+
if (violations.length > 0 || populationImbalance) {
|
|
551
565
|
return {
|
|
552
566
|
violated: true,
|
|
553
567
|
severity: 7,
|
|
554
|
-
evidence: { scarceResources: violations,
|
|
568
|
+
evidence: { scarceResources: violations, dominantRole: dominantRole?.[0], dominantShare },
|
|
555
569
|
suggestedAction: {
|
|
556
|
-
parameter: "
|
|
570
|
+
parameter: "productionCost",
|
|
557
571
|
direction: "decrease",
|
|
558
572
|
magnitude: 0.15,
|
|
559
|
-
reasoning: "Lower
|
|
573
|
+
reasoning: "Lower production cost to incentivise more production."
|
|
560
574
|
},
|
|
561
575
|
confidence: violations.length > 0 ? 0.85 : 0.6,
|
|
562
576
|
estimatedLag: 10
|
|
@@ -569,26 +583,28 @@ var P2_ClosedLoopsNeedDirectHandoff = {
|
|
|
569
583
|
id: "P2",
|
|
570
584
|
name: "Closed Loops Need Direct Handoff",
|
|
571
585
|
category: "supply_chain",
|
|
572
|
-
description: "Raw materials listed on an open market create noise and liquidity problems. Gatherers delivering
|
|
586
|
+
description: "Raw materials listed on an open market create noise and liquidity problems. Gatherers delivering raw materials directly to producers at production zones is faster and cleaner.",
|
|
573
587
|
check(metrics, _thresholds) {
|
|
574
|
-
const { supplyByResource, prices, velocity } = metrics;
|
|
575
|
-
const
|
|
576
|
-
const
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
588
|
+
const { supplyByResource, prices, velocity, totalAgents } = metrics;
|
|
589
|
+
const avgSupplyPerAgent = totalAgents > 0 ? Object.values(supplyByResource).reduce((s, v) => s + v, 0) / totalAgents : 0;
|
|
590
|
+
const backlogResources = [];
|
|
591
|
+
for (const [resource, supply] of Object.entries(supplyByResource)) {
|
|
592
|
+
const price = prices[resource] ?? 0;
|
|
593
|
+
if (supply > avgSupplyPerAgent * 0.5 && price > 0) {
|
|
594
|
+
backlogResources.push(resource);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
581
597
|
const stagnant = velocity < 3;
|
|
582
|
-
if (
|
|
598
|
+
if (backlogResources.length > 0 && stagnant) {
|
|
583
599
|
return {
|
|
584
600
|
violated: true,
|
|
585
601
|
severity: 5,
|
|
586
|
-
evidence: {
|
|
602
|
+
evidence: { backlogResources, velocity },
|
|
587
603
|
suggestedAction: {
|
|
588
|
-
parameter: "
|
|
604
|
+
parameter: "transactionFee",
|
|
589
605
|
direction: "increase",
|
|
590
606
|
magnitude: 0.2,
|
|
591
|
-
reasoning: "Raise
|
|
607
|
+
reasoning: "Raise market fees to discourage raw material listings. Direct hand-off at production zones is the correct channel."
|
|
592
608
|
},
|
|
593
609
|
confidence: 0.7,
|
|
594
610
|
estimatedLag: 5
|
|
@@ -601,29 +617,31 @@ var P3_BootstrapCapitalCoversFirstTransaction = {
|
|
|
601
617
|
id: "P3",
|
|
602
618
|
name: "Bootstrap Capital Covers First Transaction",
|
|
603
619
|
category: "supply_chain",
|
|
604
|
-
description: "A new producer must be able to afford their first transaction without selling anything first.
|
|
620
|
+
description: "A new producer must be able to afford their first transaction without selling anything first. Producer starting with low currency but needing more to accept raw material hand-off blocks the entire supply chain from tick 1.",
|
|
605
621
|
check(metrics, _thresholds) {
|
|
606
|
-
const { populationByRole, supplyByResource, prices } = metrics;
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
622
|
+
const { populationByRole, supplyByResource, prices, totalAgents } = metrics;
|
|
623
|
+
const totalProducers = Object.values(populationByRole).reduce((s, v) => s + v, 0);
|
|
624
|
+
if (totalProducers > 0) {
|
|
625
|
+
for (const [resource, supply] of Object.entries(supplyByResource)) {
|
|
626
|
+
if (supply === 0) {
|
|
627
|
+
const anyInputPriced = Object.values(prices).some((p) => p > 0);
|
|
628
|
+
if (anyInputPriced) {
|
|
629
|
+
return {
|
|
630
|
+
violated: true,
|
|
631
|
+
severity: 8,
|
|
632
|
+
evidence: { resource, totalProducers, supply },
|
|
633
|
+
suggestedAction: {
|
|
634
|
+
parameter: "productionCost",
|
|
635
|
+
direction: "decrease",
|
|
636
|
+
magnitude: 0.3,
|
|
637
|
+
reasoning: "Producers cannot complete first transaction. Lower production cost to unblock bootstrap."
|
|
638
|
+
},
|
|
639
|
+
confidence: 0.8,
|
|
640
|
+
estimatedLag: 3
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
627
645
|
}
|
|
628
646
|
return { violated: false };
|
|
629
647
|
}
|
|
@@ -632,41 +650,38 @@ var P4_MaterialsFlowFasterThanCooldown = {
|
|
|
632
650
|
id: "P4",
|
|
633
651
|
name: "Materials Flow Faster Than Cooldown",
|
|
634
652
|
category: "supply_chain",
|
|
635
|
-
description: "Input delivery rate must exceed or match production cooldown rate. If
|
|
653
|
+
description: "Input delivery rate must exceed or match production cooldown rate. If producers craft every 5 ticks but only receive raw materials every 10 ticks, they starve regardless of supply levels.",
|
|
636
654
|
check(metrics, _thresholds) {
|
|
637
|
-
const { supplyByResource, populationByRole, velocity } = metrics;
|
|
638
|
-
const
|
|
639
|
-
const
|
|
640
|
-
const
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
if (producers > 0 && gathererToProcuderRatio < 0.5 && velocity < 5) {
|
|
655
|
+
const { supplyByResource, populationByRole, velocity, totalAgents } = metrics;
|
|
656
|
+
const totalSupply = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
657
|
+
const avgSupplyPerAgent = totalAgents > 0 ? totalSupply / totalAgents : 0;
|
|
658
|
+
const roleEntries = Object.entries(populationByRole);
|
|
659
|
+
const totalRoles = roleEntries.length;
|
|
660
|
+
if (totalRoles >= 2 && velocity < 5 && avgSupplyPerAgent < 0.5) {
|
|
644
661
|
return {
|
|
645
662
|
violated: true,
|
|
646
663
|
severity: 5,
|
|
647
|
-
evidence: {
|
|
664
|
+
evidence: { avgSupplyPerAgent, velocity, totalRoles },
|
|
648
665
|
suggestedAction: {
|
|
649
|
-
parameter: "
|
|
666
|
+
parameter: "yieldRate",
|
|
650
667
|
direction: "increase",
|
|
651
668
|
magnitude: 0.15,
|
|
652
|
-
reasoning: "
|
|
669
|
+
reasoning: "Low supply per agent with stagnant velocity. Increase yield to compensate."
|
|
653
670
|
},
|
|
654
671
|
confidence: 0.65,
|
|
655
672
|
estimatedLag: 8
|
|
656
673
|
};
|
|
657
674
|
}
|
|
658
|
-
|
|
659
|
-
const wood = supplyByResource["wood"] ?? 0;
|
|
660
|
-
if (ore > 80 || wood > 80) {
|
|
675
|
+
if (avgSupplyPerAgent > 2) {
|
|
661
676
|
return {
|
|
662
677
|
violated: true,
|
|
663
678
|
severity: 4,
|
|
664
|
-
evidence: {
|
|
679
|
+
evidence: { avgSupplyPerAgent, totalSupply, totalAgents },
|
|
665
680
|
suggestedAction: {
|
|
666
|
-
parameter: "
|
|
681
|
+
parameter: "yieldRate",
|
|
667
682
|
direction: "decrease",
|
|
668
683
|
magnitude: 0.2,
|
|
669
|
-
reasoning: "Raw materials piling up.
|
|
684
|
+
reasoning: "Raw materials piling up. Extractors outpacing producers."
|
|
670
685
|
},
|
|
671
686
|
confidence: 0.8,
|
|
672
687
|
estimatedLag: 5
|
|
@@ -691,7 +706,7 @@ var P60_SurplusDisposalAsymmetry = {
|
|
|
691
706
|
discount: thresholds.disposalTradeWeightDiscount
|
|
692
707
|
},
|
|
693
708
|
suggestedAction: {
|
|
694
|
-
parameter: "
|
|
709
|
+
parameter: "productionCost",
|
|
695
710
|
direction: "decrease",
|
|
696
711
|
magnitude: 0.1,
|
|
697
712
|
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.`
|
|
@@ -716,7 +731,7 @@ var P5_ProfitabilityIsCompetitive = {
|
|
|
716
731
|
id: "P5",
|
|
717
732
|
name: "Profitability Is Competitive, Not Absolute",
|
|
718
733
|
category: "incentive",
|
|
719
|
-
description: "Any profitability formula that returns the same number regardless of how many agents are already in that role will cause stampedes. 97
|
|
734
|
+
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.",
|
|
720
735
|
check(metrics, thresholds) {
|
|
721
736
|
const { roleShares, populationByRole } = metrics;
|
|
722
737
|
const highShareRoles = [];
|
|
@@ -734,7 +749,7 @@ var P5_ProfitabilityIsCompetitive = {
|
|
|
734
749
|
population: populationByRole[dominantRole]
|
|
735
750
|
},
|
|
736
751
|
suggestedAction: {
|
|
737
|
-
parameter: "
|
|
752
|
+
parameter: "transactionFee",
|
|
738
753
|
direction: "increase",
|
|
739
754
|
magnitude: thresholds.maxAdjustmentPercent,
|
|
740
755
|
reasoning: `${dominantRole} share at ${((roleShares[dominantRole] ?? 0) * 100).toFixed(0)}%. Likely stampede from non-competitive profitability formula. Raise market friction to slow role accumulation.`
|
|
@@ -760,7 +775,7 @@ var P6_CrowdingMultiplierOnAllRoles = {
|
|
|
760
775
|
severity: 5,
|
|
761
776
|
evidence: { role, share },
|
|
762
777
|
suggestedAction: {
|
|
763
|
-
parameter: "
|
|
778
|
+
parameter: "productionCost",
|
|
764
779
|
direction: "increase",
|
|
765
780
|
magnitude: 0.1,
|
|
766
781
|
reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 no crowding pressure detected. Apply role-specific cost increase to simulate saturation.`
|
|
@@ -777,28 +792,33 @@ var P7_NonSpecialistsSubsidiseSpecialists = {
|
|
|
777
792
|
id: "P7",
|
|
778
793
|
name: "Non-Specialists Subsidise Specialists in Zero-Sum Games",
|
|
779
794
|
category: "incentive",
|
|
780
|
-
description: "In zero-sum pools (
|
|
795
|
+
description: "In zero-sum pools (competitive pool, staking), 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.",
|
|
781
796
|
check(metrics, _thresholds) {
|
|
782
|
-
const {
|
|
783
|
-
const
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
797
|
+
const { poolSizes } = metrics;
|
|
798
|
+
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
799
|
+
if (poolSize <= 0) continue;
|
|
800
|
+
const roleEntries = Object.entries(metrics.populationByRole);
|
|
801
|
+
if (roleEntries.length === 0) continue;
|
|
802
|
+
const [dominantRole, dominantPop] = roleEntries.reduce(
|
|
803
|
+
(max, entry) => entry[1] > max[1] ? entry : max
|
|
804
|
+
);
|
|
805
|
+
const total = metrics.totalAgents;
|
|
806
|
+
const dominantShare = dominantPop / Math.max(1, total);
|
|
807
|
+
if (dominantShare > 0.7 && poolSize < 100) {
|
|
808
|
+
return {
|
|
809
|
+
violated: true,
|
|
810
|
+
severity: 6,
|
|
811
|
+
evidence: { poolName, poolSize, dominantRole, dominantShare },
|
|
812
|
+
suggestedAction: {
|
|
813
|
+
parameter: "entryFee",
|
|
814
|
+
direction: "decrease",
|
|
815
|
+
magnitude: 0.1,
|
|
816
|
+
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.`
|
|
817
|
+
},
|
|
818
|
+
confidence: 0.75,
|
|
819
|
+
estimatedLag: 5
|
|
820
|
+
};
|
|
821
|
+
}
|
|
802
822
|
}
|
|
803
823
|
return { violated: false };
|
|
804
824
|
}
|
|
@@ -807,7 +827,7 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
807
827
|
id: "P8",
|
|
808
828
|
name: "Regulator Cannot Fight the Design",
|
|
809
829
|
category: "incentive",
|
|
810
|
-
description: "If the economy is designed to have a majority role (e.g. 55%
|
|
830
|
+
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 competitive pool rewards is overreach.",
|
|
811
831
|
check(metrics, _thresholds) {
|
|
812
832
|
const { roleShares, avgSatisfaction } = metrics;
|
|
813
833
|
if (avgSatisfaction < 45) {
|
|
@@ -818,7 +838,7 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
818
838
|
severity: 4,
|
|
819
839
|
evidence: { dominantRole: dominantRole[0], share: dominantRole[1], avgSatisfaction },
|
|
820
840
|
suggestedAction: {
|
|
821
|
-
parameter: "
|
|
841
|
+
parameter: "rewardRate",
|
|
822
842
|
direction: "increase",
|
|
823
843
|
magnitude: 0.1,
|
|
824
844
|
reasoning: `Low satisfaction with ${dominantRole[0]} dominant. Regulator may be suppressing a structurally necessary role. Ease pressure on dominant role rewards.`
|
|
@@ -853,7 +873,7 @@ var P9_RoleSwitchingNeedsFriction = {
|
|
|
853
873
|
severity: 5,
|
|
854
874
|
evidence: { totalChurnRate: totalChurn, churnByRole },
|
|
855
875
|
suggestedAction: {
|
|
856
|
-
parameter: "
|
|
876
|
+
parameter: "productionCost",
|
|
857
877
|
direction: "increase",
|
|
858
878
|
magnitude: 0.05,
|
|
859
879
|
reasoning: `Role switch rate ${(totalChurn * 100).toFixed(1)}% exceeds friction threshold. Increase production costs to slow herd movement.`
|
|
@@ -870,7 +890,7 @@ var P10_SpawnWeightingUsesInversePopulation = {
|
|
|
870
890
|
id: "P10",
|
|
871
891
|
name: "Spawn Weighting Uses Inverse Population",
|
|
872
892
|
category: "population",
|
|
873
|
-
description: "New agents should preferentially fill the least-populated roles. Flat
|
|
893
|
+
description: "New agents should preferentially fill the least-populated roles. Flat entry probability causes initial imbalances to compound.",
|
|
874
894
|
check(metrics, _thresholds) {
|
|
875
895
|
const { roleShares } = metrics;
|
|
876
896
|
if (Object.keys(roleShares).length === 0) return { violated: false };
|
|
@@ -885,10 +905,10 @@ var P10_SpawnWeightingUsesInversePopulation = {
|
|
|
885
905
|
severity: 4,
|
|
886
906
|
evidence: { roleShares, stdDev, leastPopulatedRole: minRole?.[0] },
|
|
887
907
|
suggestedAction: {
|
|
888
|
-
parameter: "
|
|
908
|
+
parameter: "yieldRate",
|
|
889
909
|
direction: "increase",
|
|
890
910
|
magnitude: 0.05,
|
|
891
|
-
reasoning: `High role share variance (\u03C3=${stdDev.toFixed(2)}).
|
|
911
|
+
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.`
|
|
892
912
|
},
|
|
893
913
|
confidence: 0.6,
|
|
894
914
|
estimatedLag: 20
|
|
@@ -911,7 +931,7 @@ var P11_TwoTierPressure = {
|
|
|
911
931
|
severity: 6,
|
|
912
932
|
evidence: { role, share },
|
|
913
933
|
suggestedAction: {
|
|
914
|
-
parameter: "
|
|
934
|
+
parameter: "transactionFee",
|
|
915
935
|
direction: "increase",
|
|
916
936
|
magnitude: 0.15,
|
|
917
937
|
reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 continuous pressure was insufficient. Hard intervention needed alongside resumed continuous pressure.`
|
|
@@ -939,7 +959,7 @@ var P46_PersonaDiversity = {
|
|
|
939
959
|
severity: 5,
|
|
940
960
|
evidence: { dominantPersona: persona, share, personaDistribution },
|
|
941
961
|
suggestedAction: {
|
|
942
|
-
parameter: "
|
|
962
|
+
parameter: "rewardRate",
|
|
943
963
|
direction: "increase",
|
|
944
964
|
magnitude: 0.1,
|
|
945
965
|
reasoning: `${persona} persona at ${(share * 100).toFixed(0)}% \u2014 behavioral monoculture. Diversify reward structures to attract other persona types.`
|
|
@@ -956,7 +976,7 @@ var P46_PersonaDiversity = {
|
|
|
956
976
|
severity: 3,
|
|
957
977
|
evidence: { significantClusters, required: thresholds.personaMinClusters },
|
|
958
978
|
suggestedAction: {
|
|
959
|
-
parameter: "
|
|
979
|
+
parameter: "transactionFee",
|
|
960
980
|
direction: "decrease",
|
|
961
981
|
magnitude: 0.05,
|
|
962
982
|
reasoning: `Only ${significantClusters} significant persona clusters (need ${thresholds.personaMinClusters}). Lower trade barriers to attract non-dominant persona types.`
|
|
@@ -980,7 +1000,7 @@ var P12_OnePrimaryFaucet = {
|
|
|
980
1000
|
id: "P12",
|
|
981
1001
|
name: "One Primary Faucet",
|
|
982
1002
|
category: "currency",
|
|
983
|
-
description: "Multiple independent currency sources (gathering +
|
|
1003
|
+
description: "Multiple independent currency sources (gathering + production + quests) each creating currency causes uncontrolled inflation. One clear primary faucet makes the economy predictable and auditable.",
|
|
984
1004
|
check(metrics, thresholds) {
|
|
985
1005
|
const { netFlow, faucetVolume, sinkVolume } = metrics;
|
|
986
1006
|
if (netFlow > thresholds.netFlowWarnThreshold) {
|
|
@@ -989,10 +1009,10 @@ var P12_OnePrimaryFaucet = {
|
|
|
989
1009
|
severity: 5,
|
|
990
1010
|
evidence: { netFlow, faucetVolume, sinkVolume },
|
|
991
1011
|
suggestedAction: {
|
|
992
|
-
parameter: "
|
|
1012
|
+
parameter: "productionCost",
|
|
993
1013
|
direction: "increase",
|
|
994
1014
|
magnitude: 0.15,
|
|
995
|
-
reasoning: `Net flow +${netFlow.toFixed(1)}
|
|
1015
|
+
reasoning: `Net flow +${netFlow.toFixed(1)}/tick. Inflationary. Increase production cost (primary sink) to balance faucet output.`
|
|
996
1016
|
},
|
|
997
1017
|
confidence: 0.8,
|
|
998
1018
|
estimatedLag: 8
|
|
@@ -1004,10 +1024,10 @@ var P12_OnePrimaryFaucet = {
|
|
|
1004
1024
|
severity: 4,
|
|
1005
1025
|
evidence: { netFlow, faucetVolume, sinkVolume },
|
|
1006
1026
|
suggestedAction: {
|
|
1007
|
-
parameter: "
|
|
1027
|
+
parameter: "productionCost",
|
|
1008
1028
|
direction: "decrease",
|
|
1009
1029
|
magnitude: 0.15,
|
|
1010
|
-
reasoning: `Net flow ${netFlow.toFixed(1)}
|
|
1030
|
+
reasoning: `Net flow ${netFlow.toFixed(1)}/tick. Deflationary. Decrease production cost to ease sink pressure.`
|
|
1011
1031
|
},
|
|
1012
1032
|
confidence: 0.8,
|
|
1013
1033
|
estimatedLag: 8
|
|
@@ -1020,36 +1040,40 @@ var P13_PotsAreZeroSumAndSelfRegulate = {
|
|
|
1020
1040
|
id: "P13",
|
|
1021
1041
|
name: "Pots Self-Regulate with Correct Multiplier",
|
|
1022
1042
|
category: "currency",
|
|
1023
|
-
description: "
|
|
1043
|
+
description: "Competitive pot math: winRate \xD7 multiplier > (1 - houseCut) drains the pot. At 65% win rate, multiplier must be \u2264 1.38. We use 1.5 for slight surplus buffer.",
|
|
1024
1044
|
check(metrics, thresholds) {
|
|
1025
|
-
const { poolSizes } = metrics;
|
|
1026
|
-
const
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1045
|
+
const { poolSizes, populationByRole } = metrics;
|
|
1046
|
+
const totalAgents = metrics.totalAgents;
|
|
1047
|
+
const roleEntries = Object.entries(populationByRole).sort((a, b) => b[1] - a[1]);
|
|
1048
|
+
const dominantRole = roleEntries[0]?.[0];
|
|
1049
|
+
const dominantCount = roleEntries[0]?.[1] ?? 0;
|
|
1050
|
+
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
1051
|
+
if (dominantCount > 5 && poolSize < 50) {
|
|
1052
|
+
const { poolWinRate, poolHouseCut } = thresholds;
|
|
1053
|
+
const maxSustainableMultiplier = (1 - poolHouseCut) / poolWinRate;
|
|
1054
|
+
return {
|
|
1055
|
+
violated: true,
|
|
1056
|
+
severity: 7,
|
|
1057
|
+
evidence: { pool: poolName, poolSize, participants: dominantCount, maxSustainableMultiplier },
|
|
1058
|
+
suggestedAction: {
|
|
1059
|
+
parameter: "rewardRate",
|
|
1060
|
+
direction: "decrease",
|
|
1061
|
+
magnitude: 0.15,
|
|
1062
|
+
reasoning: `${poolName} pool at ${poolSize.toFixed(0)} currency with ${dominantCount} active participants. Sustainable multiplier \u2264 ${maxSustainableMultiplier.toFixed(2)}. Reduce reward multiplier to prevent pool drain.`
|
|
1063
|
+
},
|
|
1064
|
+
confidence: 0.85,
|
|
1065
|
+
estimatedLag: 3
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1044
1068
|
}
|
|
1045
1069
|
return { violated: false };
|
|
1046
1070
|
}
|
|
1047
1071
|
};
|
|
1048
1072
|
var P14_TrackActualInjection = {
|
|
1049
1073
|
id: "P14",
|
|
1050
|
-
name: "Track Actual
|
|
1074
|
+
name: "Track Actual Currency Injection, Not Value Creation",
|
|
1051
1075
|
category: "currency",
|
|
1052
|
-
description: 'Counting resource gathering as "
|
|
1076
|
+
description: 'Counting resource gathering as "currency injected" is misleading. Currency enters through faucet mechanisms (spawning, rewards). Fake metrics break every downstream decision.',
|
|
1053
1077
|
check(metrics, _thresholds) {
|
|
1054
1078
|
const { faucetVolume, netFlow, totalSupply } = metrics;
|
|
1055
1079
|
const supplyGrowthRate = Math.abs(netFlow) / Math.max(1, totalSupply);
|
|
@@ -1059,10 +1083,10 @@ var P14_TrackActualInjection = {
|
|
|
1059
1083
|
severity: 4,
|
|
1060
1084
|
evidence: { faucetVolume, netFlow, supplyGrowthRate },
|
|
1061
1085
|
suggestedAction: {
|
|
1062
|
-
parameter: "
|
|
1086
|
+
parameter: "yieldRate",
|
|
1063
1087
|
direction: "decrease",
|
|
1064
1088
|
magnitude: 0.1,
|
|
1065
|
-
reasoning: `Supply growing at ${(supplyGrowthRate * 100).toFixed(1)}%/tick. Verify
|
|
1089
|
+
reasoning: `Supply growing at ${(supplyGrowthRate * 100).toFixed(1)}%/tick. Verify currency injection tracking. Resources should not create currency directly.`
|
|
1066
1090
|
},
|
|
1067
1091
|
confidence: 0.55,
|
|
1068
1092
|
estimatedLag: 5
|
|
@@ -1075,12 +1099,11 @@ var P15_PoolsNeedCapAndDecay = {
|
|
|
1075
1099
|
id: "P15",
|
|
1076
1100
|
name: "Pools Need Cap + Decay",
|
|
1077
1101
|
category: "currency",
|
|
1078
|
-
description: "Any pool (bank, reward pool) without a cap accumulates infinitely.
|
|
1102
|
+
description: "Any pool (bank, reward pool) without a cap accumulates infinitely. A pool at 42% of total supply means 42% of the economy is frozen. Cap at 5%, decay at 2%/tick.",
|
|
1079
1103
|
check(metrics, thresholds) {
|
|
1080
1104
|
const { poolSizes, totalSupply } = metrics;
|
|
1081
1105
|
const { poolCapPercent } = thresholds;
|
|
1082
1106
|
for (const [pool, size] of Object.entries(poolSizes)) {
|
|
1083
|
-
if (pool === "arena" || pool === "arenaPot") continue;
|
|
1084
1107
|
const shareOfSupply = size / Math.max(1, totalSupply);
|
|
1085
1108
|
if (shareOfSupply > poolCapPercent * 2) {
|
|
1086
1109
|
return {
|
|
@@ -1088,10 +1111,10 @@ var P15_PoolsNeedCapAndDecay = {
|
|
|
1088
1111
|
severity: 6,
|
|
1089
1112
|
evidence: { pool, size, shareOfSupply, cap: poolCapPercent },
|
|
1090
1113
|
suggestedAction: {
|
|
1091
|
-
parameter: "
|
|
1114
|
+
parameter: "transactionFee",
|
|
1092
1115
|
direction: "decrease",
|
|
1093
1116
|
magnitude: 0.1,
|
|
1094
|
-
reasoning: `${pool} pool at ${(shareOfSupply * 100).toFixed(1)}% of supply (cap: ${(poolCapPercent * 100).toFixed(0)}%).
|
|
1117
|
+
reasoning: `${pool} pool at ${(shareOfSupply * 100).toFixed(1)}% of supply (cap: ${(poolCapPercent * 100).toFixed(0)}%). Currency frozen. Lower fees to encourage circulation over accumulation.`
|
|
1095
1118
|
},
|
|
1096
1119
|
confidence: 0.85,
|
|
1097
1120
|
estimatedLag: 5
|
|
@@ -1108,22 +1131,23 @@ var P16_WithdrawalPenaltyScales = {
|
|
|
1108
1131
|
description: "A 50-tick lock period with a penalty calculated as /100 means agents can exit after 1 tick and keep 99% of accrued yield. Penalty must scale linearly: (1 - ticksStaked/lockDuration) \xD7 yield.",
|
|
1109
1132
|
check(metrics, _thresholds) {
|
|
1110
1133
|
const { poolSizes, totalSupply } = metrics;
|
|
1111
|
-
const bankPool = poolSizes["bank"] ?? poolSizes["bankPool"] ?? 0;
|
|
1112
1134
|
const stakedEstimate = totalSupply * 0.15;
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1135
|
+
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
1136
|
+
if (poolSize < 10 && stakedEstimate > 100) {
|
|
1137
|
+
return {
|
|
1138
|
+
violated: true,
|
|
1139
|
+
severity: 3,
|
|
1140
|
+
evidence: { pool: poolName, poolSize, estimatedStaked: stakedEstimate },
|
|
1141
|
+
suggestedAction: {
|
|
1142
|
+
parameter: "transactionFee",
|
|
1143
|
+
direction: "increase",
|
|
1144
|
+
magnitude: 0.05,
|
|
1145
|
+
reasoning: `${poolName} pool depleted while significant currency should be locked. Early withdrawals may be draining the pool. Ensure withdrawal penalty scales with lock duration.`
|
|
1146
|
+
},
|
|
1147
|
+
confidence: 0.45,
|
|
1148
|
+
estimatedLag: 10
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1127
1151
|
}
|
|
1128
1152
|
return { violated: false };
|
|
1129
1153
|
}
|
|
@@ -1142,7 +1166,7 @@ var P32_VelocityAboveSupply = {
|
|
|
1142
1166
|
severity: 4,
|
|
1143
1167
|
evidence: { velocity, totalSupply, totalResources },
|
|
1144
1168
|
suggestedAction: {
|
|
1145
|
-
parameter: "
|
|
1169
|
+
parameter: "transactionFee",
|
|
1146
1170
|
direction: "decrease",
|
|
1147
1171
|
magnitude: 0.2,
|
|
1148
1172
|
reasoning: `Velocity ${velocity}/t with ${totalResources} resources in system. Economy stagnant despite available supply. Lower trading friction.`
|
|
@@ -1178,7 +1202,7 @@ var P58_NoNaturalNumeraire = {
|
|
|
1178
1202
|
meanPrice: mean
|
|
1179
1203
|
},
|
|
1180
1204
|
suggestedAction: {
|
|
1181
|
-
parameter: "
|
|
1205
|
+
parameter: "productionCost",
|
|
1182
1206
|
direction: "increase",
|
|
1183
1207
|
magnitude: 0.1,
|
|
1184
1208
|
reasoning: `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.`
|
|
@@ -1205,7 +1229,7 @@ var P17_GracePeriodBeforeIntervention = {
|
|
|
1205
1229
|
id: "P17",
|
|
1206
1230
|
name: "Grace Period Before Intervention",
|
|
1207
1231
|
category: "bootstrap",
|
|
1208
|
-
description: "Any intervention before tick 50 is premature. The economy needs time to bootstrap with designed distributions. AgentE intervening at tick 1 against 55%
|
|
1232
|
+
description: "Any intervention before tick 50 is premature. The economy needs time to bootstrap with designed distributions. AgentE intervening at tick 1 against dominant role exceeds 55% (designed) killed the economy instantly.",
|
|
1209
1233
|
check(metrics, _thresholds) {
|
|
1210
1234
|
if (metrics.tick < 30 && metrics.avgSatisfaction < 40) {
|
|
1211
1235
|
return {
|
|
@@ -1213,7 +1237,7 @@ var P17_GracePeriodBeforeIntervention = {
|
|
|
1213
1237
|
severity: 7,
|
|
1214
1238
|
evidence: { tick: metrics.tick, avgSatisfaction: metrics.avgSatisfaction },
|
|
1215
1239
|
suggestedAction: {
|
|
1216
|
-
parameter: "
|
|
1240
|
+
parameter: "entryFee",
|
|
1217
1241
|
direction: "decrease",
|
|
1218
1242
|
magnitude: 0.2,
|
|
1219
1243
|
reasoning: `Very low satisfaction at tick ${metrics.tick}. Intervention may have fired during grace period. Ease all costs to let economy bootstrap.`
|
|
@@ -1229,27 +1253,26 @@ var P18_FirstProducerNeedsStartingInventory = {
|
|
|
1229
1253
|
id: "P18",
|
|
1230
1254
|
name: "First Producer Needs Starting Inventory + Capital",
|
|
1231
1255
|
category: "bootstrap",
|
|
1232
|
-
description: "A
|
|
1256
|
+
description: "A producer with 0 resources and 0 currency must sell nothing to get currency before they can buy raw materials. This creates a chicken-and-egg freeze. Starting inventory (2 goods + 4 raw materials + 40 currency) breaks the deadlock.",
|
|
1233
1257
|
check(metrics, _thresholds) {
|
|
1234
1258
|
if (metrics.tick > 20) return { violated: false };
|
|
1235
|
-
const
|
|
1236
|
-
const
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
};
|
|
1259
|
+
const hasAgents = metrics.totalAgents > 0;
|
|
1260
|
+
for (const [resource, supply] of Object.entries(metrics.supplyByResource)) {
|
|
1261
|
+
if (supply === 0 && hasAgents) {
|
|
1262
|
+
return {
|
|
1263
|
+
violated: true,
|
|
1264
|
+
severity: 8,
|
|
1265
|
+
evidence: { tick: metrics.tick, resource, supply, totalAgents: metrics.totalAgents },
|
|
1266
|
+
suggestedAction: {
|
|
1267
|
+
parameter: "productionCost",
|
|
1268
|
+
direction: "decrease",
|
|
1269
|
+
magnitude: 0.5,
|
|
1270
|
+
reasoning: `Bootstrap failure: ${resource} supply is 0 at tick ${metrics.tick} with ${metrics.totalAgents} agents. Drastically reduce production cost to allow immediate output.`
|
|
1271
|
+
},
|
|
1272
|
+
confidence: 0.9,
|
|
1273
|
+
estimatedLag: 2
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1253
1276
|
}
|
|
1254
1277
|
return { violated: false };
|
|
1255
1278
|
}
|
|
@@ -1258,22 +1281,32 @@ var P19_StartingSupplyExceedsDemand = {
|
|
|
1258
1281
|
id: "P19",
|
|
1259
1282
|
name: "Starting Supply Exceeds Initial Demand",
|
|
1260
1283
|
category: "bootstrap",
|
|
1261
|
-
description: "Launch with more consumables than you think you need. Early scarcity creates
|
|
1284
|
+
description: "Launch with more consumables than you think you need. Early scarcity creates a market gridlock where everyone wants to buy and nobody has anything to sell.",
|
|
1262
1285
|
check(metrics, _thresholds) {
|
|
1263
1286
|
if (metrics.tick > 30) return { violated: false };
|
|
1264
|
-
const
|
|
1265
|
-
|
|
1266
|
-
const
|
|
1267
|
-
|
|
1287
|
+
const roleEntries = Object.entries(metrics.populationByRole);
|
|
1288
|
+
if (roleEntries.length === 0) return { violated: false };
|
|
1289
|
+
const [mostPopulatedRole, population] = roleEntries.reduce(
|
|
1290
|
+
(max, entry) => entry[1] > max[1] ? entry : max
|
|
1291
|
+
);
|
|
1292
|
+
if (population < 5) return { violated: false };
|
|
1293
|
+
const totalResourceSupply = Object.values(metrics.supplyByResource).reduce((sum, s) => sum + s, 0);
|
|
1294
|
+
const resourcesPerAgent = totalResourceSupply / Math.max(1, population);
|
|
1295
|
+
if (resourcesPerAgent < 0.5) {
|
|
1268
1296
|
return {
|
|
1269
1297
|
violated: true,
|
|
1270
1298
|
severity: 6,
|
|
1271
|
-
evidence: {
|
|
1299
|
+
evidence: {
|
|
1300
|
+
mostPopulatedRole,
|
|
1301
|
+
population,
|
|
1302
|
+
totalResourceSupply,
|
|
1303
|
+
resourcesPerAgent
|
|
1304
|
+
},
|
|
1272
1305
|
suggestedAction: {
|
|
1273
|
-
parameter: "
|
|
1306
|
+
parameter: "rewardRate",
|
|
1274
1307
|
direction: "increase",
|
|
1275
1308
|
magnitude: 0.2,
|
|
1276
|
-
reasoning: `${
|
|
1309
|
+
reasoning: `${mostPopulatedRole} (${population} agents) has insufficient resources (${resourcesPerAgent.toFixed(2)} per agent). Cold-start scarcity. Boost competitive pool reward to attract participation despite scarcity.`
|
|
1277
1310
|
},
|
|
1278
1311
|
confidence: 0.75,
|
|
1279
1312
|
estimatedLag: 5
|
|
@@ -1293,7 +1326,7 @@ var P20_DecayPreventsAccumulation = {
|
|
|
1293
1326
|
id: "P20",
|
|
1294
1327
|
name: "Decay Prevents Accumulation",
|
|
1295
1328
|
category: "feedback",
|
|
1296
|
-
description: "Resources without decay create infinite hoarding. A
|
|
1329
|
+
description: "Resources without decay create infinite hoarding. A gatherer who never sells has 500 raw materials rotting in their pocket while producers starve. 2-10% decay per period forces circulation.",
|
|
1297
1330
|
check(metrics, _thresholds) {
|
|
1298
1331
|
const { supplyByResource, velocity, totalAgents } = metrics;
|
|
1299
1332
|
const totalResources = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
@@ -1304,7 +1337,7 @@ var P20_DecayPreventsAccumulation = {
|
|
|
1304
1337
|
severity: 4,
|
|
1305
1338
|
evidence: { totalResources, resourcesPerAgent, velocity },
|
|
1306
1339
|
suggestedAction: {
|
|
1307
|
-
parameter: "
|
|
1340
|
+
parameter: "yieldRate",
|
|
1308
1341
|
direction: "decrease",
|
|
1309
1342
|
magnitude: 0.1,
|
|
1310
1343
|
reasoning: `${totalResources.toFixed(0)} resources with velocity ${velocity}/t. Likely hoarding. Reduce yield to increase scarcity and force circulation.`
|
|
@@ -1320,7 +1353,7 @@ var P21_PriceFromGlobalSupply = {
|
|
|
1320
1353
|
id: "P21",
|
|
1321
1354
|
name: "Price Reflects Global Supply, Not Just AH Listings",
|
|
1322
1355
|
category: "feedback",
|
|
1323
|
-
description: "If prices only update from
|
|
1356
|
+
description: "If prices only update from market activity, agents with hoarded inventory see artificially high prices and keep gathering when they should stop.",
|
|
1324
1357
|
check(metrics, _thresholds) {
|
|
1325
1358
|
const { priceVolatility, supplyByResource, prices } = metrics;
|
|
1326
1359
|
for (const resource of Object.keys(prices)) {
|
|
@@ -1332,7 +1365,7 @@ var P21_PriceFromGlobalSupply = {
|
|
|
1332
1365
|
severity: 3,
|
|
1333
1366
|
evidence: { resource, volatility, supply, price: prices[resource] },
|
|
1334
1367
|
suggestedAction: {
|
|
1335
|
-
parameter: "
|
|
1368
|
+
parameter: "transactionFee",
|
|
1336
1369
|
direction: "increase",
|
|
1337
1370
|
magnitude: 0.05,
|
|
1338
1371
|
reasoning: `${resource} price volatile (${(volatility * 100).toFixed(0)}%) despite supply ${supply}. Price may not reflect global inventory. Increase trading friction to stabilise.`
|
|
@@ -1352,23 +1385,36 @@ var P22_MarketAwarenessPreventsSurplus = {
|
|
|
1352
1385
|
description: "Producers who craft without checking market prices will create surpluses that crash prices. Agents need to see prices before deciding to produce.",
|
|
1353
1386
|
check(metrics, _thresholds) {
|
|
1354
1387
|
const { supplyByResource, prices, productionIndex } = metrics;
|
|
1355
|
-
const
|
|
1356
|
-
|
|
1357
|
-
const
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1388
|
+
const priceValues = Object.values(prices).filter((p) => p > 0);
|
|
1389
|
+
if (priceValues.length === 0) return { violated: false };
|
|
1390
|
+
const sortedPrices = [...priceValues].sort((a, b) => a - b);
|
|
1391
|
+
const medianPrice = sortedPrices[Math.floor(sortedPrices.length / 2)] ?? 0;
|
|
1392
|
+
for (const [resource, price] of Object.entries(prices)) {
|
|
1393
|
+
if (price <= 0) continue;
|
|
1394
|
+
const supply = supplyByResource[resource] ?? 0;
|
|
1395
|
+
const priceDeviation = price / Math.max(1, medianPrice);
|
|
1396
|
+
if (priceDeviation < 0.33 && supply > 100 && productionIndex > 0) {
|
|
1397
|
+
return {
|
|
1398
|
+
violated: true,
|
|
1399
|
+
severity: 4,
|
|
1400
|
+
evidence: {
|
|
1401
|
+
resource,
|
|
1402
|
+
price,
|
|
1403
|
+
medianPrice,
|
|
1404
|
+
priceDeviation,
|
|
1405
|
+
supply,
|
|
1406
|
+
productionIndex
|
|
1407
|
+
},
|
|
1408
|
+
suggestedAction: {
|
|
1409
|
+
parameter: "productionCost",
|
|
1410
|
+
direction: "increase",
|
|
1411
|
+
magnitude: 0.1,
|
|
1412
|
+
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.`
|
|
1413
|
+
},
|
|
1414
|
+
confidence: 0.7,
|
|
1415
|
+
estimatedLag: 8
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1372
1418
|
}
|
|
1373
1419
|
return { violated: false };
|
|
1374
1420
|
}
|
|
@@ -1377,7 +1423,7 @@ var P23_ProfitabilityFactorsFeasibility = {
|
|
|
1377
1423
|
id: "P23",
|
|
1378
1424
|
name: "Profitability Factors Execution Feasibility",
|
|
1379
1425
|
category: "feedback",
|
|
1380
|
-
description: "An agent who calculates profit =
|
|
1426
|
+
description: "An agent who calculates profit = goods_price - materials_cost but has no currency to buy raw materials is chasing phantom profit. Feasibility (can I afford the inputs?) must be part of the profitability calc.",
|
|
1381
1427
|
check(metrics, _thresholds) {
|
|
1382
1428
|
const { avgSatisfaction, blockedAgentCount, totalAgents } = metrics;
|
|
1383
1429
|
const blockedFraction = blockedAgentCount / Math.max(1, totalAgents);
|
|
@@ -1387,7 +1433,7 @@ var P23_ProfitabilityFactorsFeasibility = {
|
|
|
1387
1433
|
severity: 5,
|
|
1388
1434
|
evidence: { blockedFraction, blockedAgentCount, avgSatisfaction },
|
|
1389
1435
|
suggestedAction: {
|
|
1390
|
-
parameter: "
|
|
1436
|
+
parameter: "productionCost",
|
|
1391
1437
|
direction: "decrease",
|
|
1392
1438
|
magnitude: 0.15,
|
|
1393
1439
|
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.`
|
|
@@ -1413,7 +1459,7 @@ var P24_BlockedAgentsDecayFaster = {
|
|
|
1413
1459
|
severity: 5,
|
|
1414
1460
|
evidence: { blockedFraction, blockedAgentCount, churnRate },
|
|
1415
1461
|
suggestedAction: {
|
|
1416
|
-
parameter: "
|
|
1462
|
+
parameter: "transactionFee",
|
|
1417
1463
|
direction: "decrease",
|
|
1418
1464
|
magnitude: 0.15,
|
|
1419
1465
|
reasoning: `${(blockedFraction * 100).toFixed(0)}% of agents blocked. Blocked agents churn silently, skewing metrics. Lower fees to unblock market participation.`
|
|
@@ -1438,26 +1484,35 @@ var P25_CorrectLeversForCorrectProblems = {
|
|
|
1438
1484
|
id: "P25",
|
|
1439
1485
|
name: "Target the Correct Lever",
|
|
1440
1486
|
category: "regulator",
|
|
1441
|
-
description: "Adjusting sinks for supply-side inflation is wrong. Inflation from too much gathering \u2192 reduce
|
|
1487
|
+
description: "Adjusting sinks for supply-side inflation is wrong. Inflation from too much gathering \u2192 reduce yield rate. Inflation from pot payout \u2192 reduce reward multiplier. Matching lever to cause prevents oscillation.",
|
|
1442
1488
|
check(metrics, thresholds) {
|
|
1443
1489
|
const { netFlow, supplyByResource } = metrics;
|
|
1444
|
-
const
|
|
1445
|
-
|
|
1446
|
-
const
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1490
|
+
const resourceEntries = Object.entries(supplyByResource);
|
|
1491
|
+
if (resourceEntries.length === 0) return { violated: false };
|
|
1492
|
+
const totalSupply = resourceEntries.reduce((sum, [_, s]) => sum + s, 0);
|
|
1493
|
+
const avgSupply = totalSupply / resourceEntries.length;
|
|
1494
|
+
for (const [resource, supply] of resourceEntries) {
|
|
1495
|
+
if (supply > avgSupply * 3 && netFlow > thresholds.netFlowWarnThreshold) {
|
|
1496
|
+
return {
|
|
1497
|
+
violated: true,
|
|
1498
|
+
severity: 4,
|
|
1499
|
+
evidence: {
|
|
1500
|
+
resource,
|
|
1501
|
+
supply,
|
|
1502
|
+
avgSupply,
|
|
1503
|
+
ratio: supply / Math.max(1, avgSupply),
|
|
1504
|
+
netFlow
|
|
1505
|
+
},
|
|
1506
|
+
suggestedAction: {
|
|
1507
|
+
parameter: "yieldRate",
|
|
1508
|
+
direction: "decrease",
|
|
1509
|
+
magnitude: 0.15,
|
|
1510
|
+
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.`
|
|
1511
|
+
},
|
|
1512
|
+
confidence: 0.75,
|
|
1513
|
+
estimatedLag: 8
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1461
1516
|
}
|
|
1462
1517
|
return { violated: false };
|
|
1463
1518
|
}
|
|
@@ -1475,7 +1530,7 @@ var P26_ContinuousPressureBeatsThresholdCuts = {
|
|
|
1475
1530
|
severity: 4,
|
|
1476
1531
|
evidence: { inflationRate },
|
|
1477
1532
|
suggestedAction: {
|
|
1478
|
-
parameter: "
|
|
1533
|
+
parameter: "productionCost",
|
|
1479
1534
|
direction: inflationRate > 0 ? "increase" : "decrease",
|
|
1480
1535
|
magnitude: Math.min(thresholds.maxAdjustmentPercent, 0.05),
|
|
1481
1536
|
// force smaller step
|
|
@@ -1501,7 +1556,7 @@ var P27_AdjustmentsNeedCooldowns = {
|
|
|
1501
1556
|
severity: 4,
|
|
1502
1557
|
evidence: { churnRate, avgSatisfaction },
|
|
1503
1558
|
suggestedAction: {
|
|
1504
|
-
parameter: "
|
|
1559
|
+
parameter: "entryFee",
|
|
1505
1560
|
direction: "decrease",
|
|
1506
1561
|
magnitude: 0.05,
|
|
1507
1562
|
reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) with low satisfaction. Possible oscillation from rapid adjustments. Apply small correction only.`
|
|
@@ -1517,7 +1572,7 @@ var P28_StructuralDominanceIsNotPathological = {
|
|
|
1517
1572
|
id: "P28",
|
|
1518
1573
|
name: "Structural Dominance \u2260 Pathological Monopoly",
|
|
1519
1574
|
category: "regulator",
|
|
1520
|
-
description: 'A designed
|
|
1575
|
+
description: 'A designed dominant role (majority exceeds 55%) should not trigger population suppression. AgentE must distinguish between "this role is dominant BY DESIGN" (configured via dominantRoles) and "this role took over unexpectedly".',
|
|
1521
1576
|
check(metrics, _thresholds) {
|
|
1522
1577
|
const { roleShares, avgSatisfaction } = metrics;
|
|
1523
1578
|
const dominant = Object.entries(roleShares).sort((a, b) => b[1] - a[1])[0];
|
|
@@ -1532,7 +1587,7 @@ var P28_StructuralDominanceIsNotPathological = {
|
|
|
1532
1587
|
severity: 5,
|
|
1533
1588
|
evidence: { dominantRole, dominantShare, avgSatisfaction },
|
|
1534
1589
|
suggestedAction: {
|
|
1535
|
-
parameter: "
|
|
1590
|
+
parameter: "productionCost",
|
|
1536
1591
|
direction: "decrease",
|
|
1537
1592
|
magnitude: 0.1,
|
|
1538
1593
|
reasoning: `${dominantRole} dominant (${(dominantShare * 100).toFixed(0)}%) with low satisfaction. Pathological dominance \u2014 agents trapped, not thriving. Ease costs to allow role switching.`
|
|
@@ -1557,7 +1612,7 @@ var P38_CommunicationPreventsRevolt = {
|
|
|
1557
1612
|
severity: 3,
|
|
1558
1613
|
evidence: { churnRate },
|
|
1559
1614
|
suggestedAction: {
|
|
1560
|
-
parameter: "
|
|
1615
|
+
parameter: "rewardRate",
|
|
1561
1616
|
direction: "increase",
|
|
1562
1617
|
magnitude: 0.1,
|
|
1563
1618
|
reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) \u2014 agents leaving. Ensure all recent adjustments are logged with reasoning to diagnose cause.`
|
|
@@ -1582,7 +1637,7 @@ var P29_PinchPoint = {
|
|
|
1582
1637
|
id: "P29",
|
|
1583
1638
|
name: "Pinch Point",
|
|
1584
1639
|
category: "market_dynamics",
|
|
1585
|
-
description: "Every economy has a resource that constrains all downstream activity.
|
|
1640
|
+
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.",
|
|
1586
1641
|
check(metrics, _thresholds) {
|
|
1587
1642
|
const { pinchPoints, supplyByResource, demandSignals } = metrics;
|
|
1588
1643
|
for (const [resource, status] of Object.entries(pinchPoints)) {
|
|
@@ -1594,7 +1649,7 @@ var P29_PinchPoint = {
|
|
|
1594
1649
|
severity: 7,
|
|
1595
1650
|
evidence: { resource, supply, demand, status },
|
|
1596
1651
|
suggestedAction: {
|
|
1597
|
-
parameter: "
|
|
1652
|
+
parameter: "productionCost",
|
|
1598
1653
|
direction: "decrease",
|
|
1599
1654
|
magnitude: 0.15,
|
|
1600
1655
|
reasoning: `${resource} is a pinch point and currently SCARCE (supply ${supply}, demand ${demand}). Reduce production cost to increase throughput.`
|
|
@@ -1610,7 +1665,7 @@ var P29_PinchPoint = {
|
|
|
1610
1665
|
severity: 4,
|
|
1611
1666
|
evidence: { resource, supply, status },
|
|
1612
1667
|
suggestedAction: {
|
|
1613
|
-
parameter: "
|
|
1668
|
+
parameter: "productionCost",
|
|
1614
1669
|
direction: "increase",
|
|
1615
1670
|
magnitude: 0.1,
|
|
1616
1671
|
reasoning: `${resource} is a pinch point and OVERSUPPLIED (supply ${supply}). Raise production cost to reduce surplus.`
|
|
@@ -1627,7 +1682,7 @@ var P30_MovingPinchPoint = {
|
|
|
1627
1682
|
id: "P30",
|
|
1628
1683
|
name: "Moving Pinch Point",
|
|
1629
1684
|
category: "market_dynamics",
|
|
1630
|
-
description: "
|
|
1685
|
+
description: "Agent progression shifts the demand curve. A static pinch point that works early will be cleared later. The pinch point must move with agent progression to maintain ongoing scarcity and engagement.",
|
|
1631
1686
|
check(metrics, _thresholds) {
|
|
1632
1687
|
const { capacityUsage, supplyByResource, avgSatisfaction } = metrics;
|
|
1633
1688
|
const totalResources = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
@@ -1638,7 +1693,7 @@ var P30_MovingPinchPoint = {
|
|
|
1638
1693
|
severity: 3,
|
|
1639
1694
|
evidence: { capacityUsage, resourcesPerAgent, avgSatisfaction },
|
|
1640
1695
|
suggestedAction: {
|
|
1641
|
-
parameter: "
|
|
1696
|
+
parameter: "productionCost",
|
|
1642
1697
|
direction: "increase",
|
|
1643
1698
|
magnitude: 0.1,
|
|
1644
1699
|
reasoning: "Economy operating at full capacity with abundant resources and high satisfaction. Pinch point may have been cleared. Increase production cost to restore scarcity."
|
|
@@ -1684,7 +1739,7 @@ var P57_CombinatorialPriceSpace = {
|
|
|
1684
1739
|
target: thresholds.relativePriceConvergenceTarget
|
|
1685
1740
|
},
|
|
1686
1741
|
suggestedAction: {
|
|
1687
|
-
parameter: "
|
|
1742
|
+
parameter: "transactionFee",
|
|
1688
1743
|
direction: "decrease",
|
|
1689
1744
|
magnitude: 0.1,
|
|
1690
1745
|
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.`
|
|
@@ -1707,7 +1762,7 @@ var P31_AnchorValueTracking = {
|
|
|
1707
1762
|
id: "P31",
|
|
1708
1763
|
name: "Anchor Value Tracking",
|
|
1709
1764
|
category: "measurement",
|
|
1710
|
-
description: "1
|
|
1765
|
+
description: "1 period of activity = X currency = Y resources. If this ratio drifts, the economy is inflating or deflating in ways that participants feel before metrics catch it. Track the ratio constantly.",
|
|
1711
1766
|
check(metrics, _thresholds) {
|
|
1712
1767
|
const { anchorRatioDrift, inflationRate } = metrics;
|
|
1713
1768
|
if (Math.abs(anchorRatioDrift) > 0.25) {
|
|
@@ -1716,10 +1771,10 @@ var P31_AnchorValueTracking = {
|
|
|
1716
1771
|
severity: 5,
|
|
1717
1772
|
evidence: { anchorRatioDrift, inflationRate },
|
|
1718
1773
|
suggestedAction: {
|
|
1719
|
-
parameter: "
|
|
1774
|
+
parameter: "productionCost",
|
|
1720
1775
|
direction: anchorRatioDrift > 0 ? "increase" : "decrease",
|
|
1721
1776
|
magnitude: 0.1,
|
|
1722
|
-
reasoning: `Anchor ratio has drifted ${(anchorRatioDrift * 100).toFixed(0)}% from baseline. Time-to-value for
|
|
1777
|
+
reasoning: `Anchor ratio has drifted ${(anchorRatioDrift * 100).toFixed(0)}% from baseline. Time-to-value for participants is changing. Adjust production costs to restore.`
|
|
1723
1778
|
},
|
|
1724
1779
|
confidence: 0.65,
|
|
1725
1780
|
estimatedLag: 10
|
|
@@ -1741,7 +1796,7 @@ var P41_MultiResolutionMonitoring = {
|
|
|
1741
1796
|
severity: 4,
|
|
1742
1797
|
evidence: { giniCoefficient, avgSatisfaction },
|
|
1743
1798
|
suggestedAction: {
|
|
1744
|
-
parameter: "
|
|
1799
|
+
parameter: "transactionFee",
|
|
1745
1800
|
direction: "increase",
|
|
1746
1801
|
magnitude: 0.1,
|
|
1747
1802
|
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.`
|
|
@@ -1770,7 +1825,7 @@ var P55_ArbitrageThermometer = {
|
|
|
1770
1825
|
critical: thresholds.arbitrageIndexCritical
|
|
1771
1826
|
},
|
|
1772
1827
|
suggestedAction: {
|
|
1773
|
-
parameter: "
|
|
1828
|
+
parameter: "transactionFee",
|
|
1774
1829
|
direction: "decrease",
|
|
1775
1830
|
magnitude: 0.15,
|
|
1776
1831
|
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.`
|
|
@@ -1788,7 +1843,7 @@ var P55_ArbitrageThermometer = {
|
|
|
1788
1843
|
warning: thresholds.arbitrageIndexWarning
|
|
1789
1844
|
},
|
|
1790
1845
|
suggestedAction: {
|
|
1791
|
-
parameter: "
|
|
1846
|
+
parameter: "transactionFee",
|
|
1792
1847
|
direction: "decrease",
|
|
1793
1848
|
magnitude: 0.08,
|
|
1794
1849
|
reasoning: `Arbitrage index ${arbitrageIndex.toFixed(2)} above warning threshold (${thresholds.arbitrageIndexWarning}). Early sign of price divergence. Gently reduce friction to support self-correction.`
|
|
@@ -1816,7 +1871,7 @@ var P59_GiftEconomyNoise = {
|
|
|
1816
1871
|
threshold: thresholds.giftTradeFilterRatio
|
|
1817
1872
|
},
|
|
1818
1873
|
suggestedAction: {
|
|
1819
|
-
parameter: "
|
|
1874
|
+
parameter: "transactionFee",
|
|
1820
1875
|
direction: "increase",
|
|
1821
1876
|
magnitude: 0.05,
|
|
1822
1877
|
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.`
|
|
@@ -1840,7 +1895,7 @@ var P42_TheMedianPrinciple = {
|
|
|
1840
1895
|
id: "P42",
|
|
1841
1896
|
name: "The Median Principle",
|
|
1842
1897
|
category: "statistical",
|
|
1843
|
-
description: "When (mean - median) / median > 0.3, mean is a lie. A few
|
|
1898
|
+
description: "When (mean - median) / median > 0.3, mean is a lie. A few high-balance agents raise the mean while most agents have low balances. Always balance to median when divergence exceeds 30%.",
|
|
1844
1899
|
check(metrics, thresholds) {
|
|
1845
1900
|
const { meanMedianDivergence, giniCoefficient } = metrics;
|
|
1846
1901
|
if (meanMedianDivergence > thresholds.meanMedianDivergenceMax) {
|
|
@@ -1854,10 +1909,10 @@ var P42_TheMedianPrinciple = {
|
|
|
1854
1909
|
medianBalance: metrics.medianBalance
|
|
1855
1910
|
},
|
|
1856
1911
|
suggestedAction: {
|
|
1857
|
-
parameter: "
|
|
1912
|
+
parameter: "transactionFee",
|
|
1858
1913
|
direction: "increase",
|
|
1859
1914
|
magnitude: 0.15,
|
|
1860
|
-
reasoning: `Mean/median divergence ${(meanMedianDivergence * 100).toFixed(0)}% (threshold: ${(thresholds.meanMedianDivergenceMax * 100).toFixed(0)}%). Economy has outliers skewing metrics. Use median for decisions. Raise
|
|
1915
|
+
reasoning: `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.`
|
|
1861
1916
|
},
|
|
1862
1917
|
confidence: 0.85,
|
|
1863
1918
|
estimatedLag: 15
|
|
@@ -1879,7 +1934,7 @@ var P43_SimulationMinimum = {
|
|
|
1879
1934
|
severity: 3,
|
|
1880
1935
|
evidence: { inflationRate, minIterations: thresholds.simulationMinIterations },
|
|
1881
1936
|
suggestedAction: {
|
|
1882
|
-
parameter: "
|
|
1937
|
+
parameter: "productionCost",
|
|
1883
1938
|
direction: inflationRate > 0 ? "increase" : "decrease",
|
|
1884
1939
|
magnitude: 0.05,
|
|
1885
1940
|
reasoning: `Large inflation rate swing (${(inflationRate * 100).toFixed(0)}%). Ensure all decisions use \u2265${thresholds.simulationMinIterations} simulation iterations. Apply conservative correction.`
|
|
@@ -1917,7 +1972,7 @@ var P39_TheLagPrinciple = {
|
|
|
1917
1972
|
severity: 5,
|
|
1918
1973
|
evidence: { inflationRate, netFlow, lagRange: [lagMin, lagMax] },
|
|
1919
1974
|
suggestedAction: {
|
|
1920
|
-
parameter: "
|
|
1975
|
+
parameter: "productionCost",
|
|
1921
1976
|
direction: "increase",
|
|
1922
1977
|
magnitude: 0.03,
|
|
1923
1978
|
// very small — oscillation means over-adjusting
|
|
@@ -1944,7 +1999,7 @@ var P44_ComplexityBudget = {
|
|
|
1944
1999
|
severity: 3,
|
|
1945
2000
|
evidence: { customMetricCount, budgetMax: thresholds.complexityBudgetMax },
|
|
1946
2001
|
suggestedAction: {
|
|
1947
|
-
parameter: "
|
|
2002
|
+
parameter: "transactionFee",
|
|
1948
2003
|
direction: "decrease",
|
|
1949
2004
|
magnitude: 0.01,
|
|
1950
2005
|
reasoning: `${customMetricCount} custom metrics tracked (budget: ${thresholds.complexityBudgetMax}). Consider pruning low-impact parameters. Applying minimal correction to avoid adding complexity.`
|
|
@@ -1966,25 +2021,25 @@ var P35_DestructionCreatesValue = {
|
|
|
1966
2021
|
id: "P35",
|
|
1967
2022
|
name: "Destruction Creates Value",
|
|
1968
2023
|
category: "resource",
|
|
1969
|
-
description: "If nothing is ever permanently lost, inflation is inevitable.
|
|
2024
|
+
description: "If nothing is ever permanently lost, inflation is inevitable. Resource durability and consumption mechanisms create destruction. Without them, supply grows without bound.",
|
|
1970
2025
|
check(metrics, _thresholds) {
|
|
1971
2026
|
const { supplyByResource, sinkVolume, netFlow } = metrics;
|
|
1972
|
-
const
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
}
|
|
2027
|
+
for (const [resource, supply] of Object.entries(supplyByResource)) {
|
|
2028
|
+
if (supply > 200 && sinkVolume < 5 && netFlow > 0) {
|
|
2029
|
+
return {
|
|
2030
|
+
violated: true,
|
|
2031
|
+
severity: 6,
|
|
2032
|
+
evidence: { resource, supply, sinkVolume, netFlow },
|
|
2033
|
+
suggestedAction: {
|
|
2034
|
+
parameter: "entryFee",
|
|
2035
|
+
direction: "decrease",
|
|
2036
|
+
magnitude: 0.1,
|
|
2037
|
+
reasoning: `${resource} supply at ${supply} units with low destruction (sink ${sinkVolume}/t). Resources not being consumed. Lower competitive pool entry to increase resource usage.`
|
|
2038
|
+
},
|
|
2039
|
+
confidence: 0.7,
|
|
2040
|
+
estimatedLag: 5
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
1988
2043
|
}
|
|
1989
2044
|
return { violated: false };
|
|
1990
2045
|
}
|
|
@@ -2004,7 +2059,7 @@ var P40_ReplacementRate = {
|
|
|
2004
2059
|
severity: 6,
|
|
2005
2060
|
evidence: { productionIndex, sinkVolume, replacementRatio },
|
|
2006
2061
|
suggestedAction: {
|
|
2007
|
-
parameter: "
|
|
2062
|
+
parameter: "yieldRate",
|
|
2008
2063
|
direction: "increase",
|
|
2009
2064
|
magnitude: 0.15,
|
|
2010
2065
|
reasoning: `Replacement rate ${replacementRatio.toFixed(2)} (need \u2265${thresholds.replacementRateMultiplier}). Production below consumption. Resources will deplete. Increase yield.`
|
|
@@ -2018,7 +2073,7 @@ var P40_ReplacementRate = {
|
|
|
2018
2073
|
severity: 3,
|
|
2019
2074
|
evidence: { productionIndex, sinkVolume, replacementRatio },
|
|
2020
2075
|
suggestedAction: {
|
|
2021
|
-
parameter: "
|
|
2076
|
+
parameter: "yieldRate",
|
|
2022
2077
|
direction: "decrease",
|
|
2023
2078
|
magnitude: 0.1,
|
|
2024
2079
|
reasoning: `Replacement rate ${replacementRatio.toFixed(2)} \u2014 overproducing. Production far exceeds consumption. Reduce yield to prevent glut.`
|
|
@@ -2044,7 +2099,7 @@ var P49_IdleAssetTax = {
|
|
|
2044
2099
|
severity: 5,
|
|
2045
2100
|
evidence: { giniCoefficient, top10PctShare, velocity },
|
|
2046
2101
|
suggestedAction: {
|
|
2047
|
-
parameter: "
|
|
2102
|
+
parameter: "transactionFee",
|
|
2048
2103
|
direction: "increase",
|
|
2049
2104
|
magnitude: 0.15,
|
|
2050
2105
|
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.`
|
|
@@ -2076,7 +2131,7 @@ var P33_FairNotEqual = {
|
|
|
2076
2131
|
severity: 3,
|
|
2077
2132
|
evidence: { giniCoefficient },
|
|
2078
2133
|
suggestedAction: {
|
|
2079
|
-
parameter: "
|
|
2134
|
+
parameter: "rewardRate",
|
|
2080
2135
|
direction: "increase",
|
|
2081
2136
|
magnitude: 0.1,
|
|
2082
2137
|
reasoning: `Gini ${giniCoefficient.toFixed(2)} \u2014 near-perfect equality. Economy lacks stakes. Increase winner rewards to create meaningful spread.`
|
|
@@ -2091,7 +2146,7 @@ var P33_FairNotEqual = {
|
|
|
2091
2146
|
severity: 7,
|
|
2092
2147
|
evidence: { giniCoefficient },
|
|
2093
2148
|
suggestedAction: {
|
|
2094
|
-
parameter: "
|
|
2149
|
+
parameter: "transactionFee",
|
|
2095
2150
|
direction: "increase",
|
|
2096
2151
|
magnitude: 0.2,
|
|
2097
2152
|
reasoning: `Gini ${giniCoefficient.toFixed(2)} \u2014 oligarchy level. Toxic inequality. Raise transaction fees to redistribute wealth from rich to pool.`
|
|
@@ -2106,7 +2161,7 @@ var P33_FairNotEqual = {
|
|
|
2106
2161
|
severity: 4,
|
|
2107
2162
|
evidence: { giniCoefficient },
|
|
2108
2163
|
suggestedAction: {
|
|
2109
|
-
parameter: "
|
|
2164
|
+
parameter: "transactionFee",
|
|
2110
2165
|
direction: "increase",
|
|
2111
2166
|
magnitude: 0.1,
|
|
2112
2167
|
reasoning: `Gini ${giniCoefficient.toFixed(2)} \u2014 high inequality warning. Gently raise fees to slow wealth concentration.`
|
|
@@ -2131,7 +2186,7 @@ var P36_MechanicFrictionDetector = {
|
|
|
2131
2186
|
severity: 5,
|
|
2132
2187
|
evidence: { churnRate, avgSatisfaction, velocity },
|
|
2133
2188
|
suggestedAction: {
|
|
2134
|
-
parameter: "
|
|
2189
|
+
parameter: "rewardRate",
|
|
2135
2190
|
direction: "increase",
|
|
2136
2191
|
magnitude: 0.15,
|
|
2137
2192
|
reasoning: `Churn ${(churnRate * 100).toFixed(1)}% with satisfaction ${avgSatisfaction.toFixed(0)} despite active economy (velocity ` + velocity.toFixed(1) + "). Suggests mechanic friction (deterministic vs random systems). Increase rewards to compensate for perceived unfairness. ADVISORY: Review if mixing guaranteed and probabilistic mechanics."
|
|
@@ -2156,7 +2211,7 @@ var P37_LatecommerProblem = {
|
|
|
2156
2211
|
severity: 6,
|
|
2157
2212
|
evidence: { timeToValue, avgSatisfaction, churnRate },
|
|
2158
2213
|
suggestedAction: {
|
|
2159
|
-
parameter: "
|
|
2214
|
+
parameter: "productionCost",
|
|
2160
2215
|
direction: "decrease",
|
|
2161
2216
|
magnitude: 0.15,
|
|
2162
2217
|
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.`
|
|
@@ -2183,7 +2238,7 @@ var P45_TimeBudget = {
|
|
|
2183
2238
|
severity: 5,
|
|
2184
2239
|
evidence: { timeToValue, avgSatisfaction, timeBudgetRatio: thresholds.timeBudgetRatio },
|
|
2185
2240
|
suggestedAction: {
|
|
2186
|
-
parameter: "
|
|
2241
|
+
parameter: "entryFee",
|
|
2187
2242
|
direction: "decrease",
|
|
2188
2243
|
magnitude: 0.15,
|
|
2189
2244
|
reasoning: `Time-to-value ${timeToValue} ticks with ${avgSatisfaction.toFixed(0)} satisfaction. Economy requires too much time investment. Lower barriers to participation.`
|
|
@@ -2213,7 +2268,7 @@ var P50_PayPowerRatio = {
|
|
|
2213
2268
|
threshold: thresholds.payPowerRatioMax
|
|
2214
2269
|
},
|
|
2215
2270
|
suggestedAction: {
|
|
2216
|
-
parameter: "
|
|
2271
|
+
parameter: "transactionFee",
|
|
2217
2272
|
direction: "increase",
|
|
2218
2273
|
magnitude: 0.2,
|
|
2219
2274
|
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.`
|
|
@@ -2248,7 +2303,7 @@ var P34_ExtractionRatio = {
|
|
|
2248
2303
|
severity: 8,
|
|
2249
2304
|
evidence: { extractionRatio, threshold: thresholds.extractionRatioRed },
|
|
2250
2305
|
suggestedAction: {
|
|
2251
|
-
parameter: "
|
|
2306
|
+
parameter: "transactionFee",
|
|
2252
2307
|
direction: "increase",
|
|
2253
2308
|
magnitude: 0.25,
|
|
2254
2309
|
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.`
|
|
@@ -2263,7 +2318,7 @@ var P34_ExtractionRatio = {
|
|
|
2263
2318
|
severity: 5,
|
|
2264
2319
|
evidence: { extractionRatio, threshold: thresholds.extractionRatioYellow },
|
|
2265
2320
|
suggestedAction: {
|
|
2266
|
-
parameter: "
|
|
2321
|
+
parameter: "transactionFee",
|
|
2267
2322
|
direction: "increase",
|
|
2268
2323
|
magnitude: 0.1,
|
|
2269
2324
|
reasoning: `Extraction ratio ${(extractionRatio * 100).toFixed(0)}% (warning: ${(thresholds.extractionRatioYellow * 100).toFixed(0)}%). Economy trending toward extraction-heavy. Apply early pressure.`
|
|
@@ -2279,7 +2334,7 @@ var P47_SmokeTest = {
|
|
|
2279
2334
|
id: "P47",
|
|
2280
2335
|
name: "Smoke Test",
|
|
2281
2336
|
category: "open_economy",
|
|
2282
|
-
description: "intrinsic_utility_value / total_market_value < 0.3 = economy is >70% speculation. If utility value drops below 10%, a single bad week can collapse the entire market. Real utility (
|
|
2337
|
+
description: "intrinsic_utility_value / total_market_value < 0.3 = economy is >70% speculation. If utility value drops below 10%, a single bad week can collapse the entire market. Real utility (resources in the economy serve distinct utility functions) must anchor value.",
|
|
2283
2338
|
check(metrics, thresholds) {
|
|
2284
2339
|
const { smokeTestRatio } = metrics;
|
|
2285
2340
|
if (isNaN(smokeTestRatio)) return { violated: false };
|
|
@@ -2289,7 +2344,7 @@ var P47_SmokeTest = {
|
|
|
2289
2344
|
severity: 9,
|
|
2290
2345
|
evidence: { smokeTestRatio, threshold: thresholds.smokeTestCritical },
|
|
2291
2346
|
suggestedAction: {
|
|
2292
|
-
parameter: "
|
|
2347
|
+
parameter: "rewardRate",
|
|
2293
2348
|
direction: "increase",
|
|
2294
2349
|
magnitude: 0.2,
|
|
2295
2350
|
reasoning: `Utility/market ratio ${(smokeTestRatio * 100).toFixed(0)}% (critical). Economy is >90% speculative. Collapse risk is extreme. Increase utility rewards to anchor real value.`
|
|
@@ -2304,7 +2359,7 @@ var P47_SmokeTest = {
|
|
|
2304
2359
|
severity: 6,
|
|
2305
2360
|
evidence: { smokeTestRatio, threshold: thresholds.smokeTestWarning },
|
|
2306
2361
|
suggestedAction: {
|
|
2307
|
-
parameter: "
|
|
2362
|
+
parameter: "rewardRate",
|
|
2308
2363
|
direction: "increase",
|
|
2309
2364
|
magnitude: 0.1,
|
|
2310
2365
|
reasoning: `Utility/market ratio ${(smokeTestRatio * 100).toFixed(0)}% (warning). Economy is >70% speculative. Boost utility rewards to restore intrinsic value anchor.`
|
|
@@ -2320,7 +2375,7 @@ var P48_CurrencyInsulation = {
|
|
|
2320
2375
|
id: "P48",
|
|
2321
2376
|
name: "Currency Insulation",
|
|
2322
2377
|
category: "open_economy",
|
|
2323
|
-
description: "Gameplay economy correlation with external markets > 0.5 = insulation failure. When your
|
|
2378
|
+
description: "Gameplay economy correlation with external markets > 0.5 = insulation failure. When your native currency price correlates with external asset, external market crashes destroy internal economies. Good design insulates the two.",
|
|
2324
2379
|
check(metrics, thresholds) {
|
|
2325
2380
|
const { currencyInsulation } = metrics;
|
|
2326
2381
|
if (isNaN(currencyInsulation)) return { violated: false };
|
|
@@ -2330,7 +2385,7 @@ var P48_CurrencyInsulation = {
|
|
|
2330
2385
|
severity: 6,
|
|
2331
2386
|
evidence: { currencyInsulation, threshold: thresholds.currencyInsulationMax },
|
|
2332
2387
|
suggestedAction: {
|
|
2333
|
-
parameter: "
|
|
2388
|
+
parameter: "transactionFee",
|
|
2334
2389
|
direction: "increase",
|
|
2335
2390
|
magnitude: 0.1,
|
|
2336
2391
|
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.`
|
|
@@ -2370,7 +2425,7 @@ var P51_SharkTooth = {
|
|
|
2370
2425
|
threshold: thresholds.sharkToothPeakDecay
|
|
2371
2426
|
},
|
|
2372
2427
|
suggestedAction: {
|
|
2373
|
-
parameter: "
|
|
2428
|
+
parameter: "rewardRate",
|
|
2374
2429
|
direction: "increase",
|
|
2375
2430
|
magnitude: 0.1,
|
|
2376
2431
|
reasoning: `Peak engagement dropped to ${(lastPeak / prevPeak * 100).toFixed(0)}% of previous peak (threshold: ${(thresholds.sharkToothPeakDecay * 100).toFixed(0)}%). Event fatigue detected. Boost event rewards to restore peak engagement.`
|
|
@@ -2388,7 +2443,7 @@ var P51_SharkTooth = {
|
|
|
2388
2443
|
severity: 4,
|
|
2389
2444
|
evidence: { lastValley, prevValley, ratio: lastValley / prevValley },
|
|
2390
2445
|
suggestedAction: {
|
|
2391
|
-
parameter: "
|
|
2446
|
+
parameter: "productionCost",
|
|
2392
2447
|
direction: "decrease",
|
|
2393
2448
|
magnitude: 0.1,
|
|
2394
2449
|
reasoning: "Between-event engagement declining (deepening valleys). Base economy not sustaining participants between events. Lower production costs to improve off-event value."
|
|
@@ -2405,7 +2460,7 @@ var P52_EndowmentEffect = {
|
|
|
2405
2460
|
id: "P52",
|
|
2406
2461
|
name: "Endowment Effect",
|
|
2407
2462
|
category: "liveops",
|
|
2408
|
-
description: "
|
|
2463
|
+
description: "Participants who never owned premium items do not value them. Free trial events that let participants experience premium items drive conversions because ownership creates perceived value (endowment effect).",
|
|
2409
2464
|
check(metrics, _thresholds) {
|
|
2410
2465
|
const { avgSatisfaction, churnRate } = metrics;
|
|
2411
2466
|
const { eventCompletionRate } = metrics;
|
|
@@ -2416,7 +2471,7 @@ var P52_EndowmentEffect = {
|
|
|
2416
2471
|
severity: 4,
|
|
2417
2472
|
evidence: { eventCompletionRate, avgSatisfaction, churnRate },
|
|
2418
2473
|
suggestedAction: {
|
|
2419
|
-
parameter: "
|
|
2474
|
+
parameter: "rewardRate",
|
|
2420
2475
|
direction: "increase",
|
|
2421
2476
|
magnitude: 0.15,
|
|
2422
2477
|
reasoning: `${(eventCompletionRate * 100).toFixed(0)}% event completion but satisfaction only ${avgSatisfaction.toFixed(0)}. Events not creating perceived value. Increase reward quality/quantity.`
|
|
@@ -2446,10 +2501,10 @@ var P53_EventCompletionRate = {
|
|
|
2446
2501
|
max: thresholds.eventCompletionMax
|
|
2447
2502
|
},
|
|
2448
2503
|
suggestedAction: {
|
|
2449
|
-
parameter: "
|
|
2504
|
+
parameter: "productionCost",
|
|
2450
2505
|
direction: "decrease",
|
|
2451
2506
|
magnitude: 0.15,
|
|
2452
|
-
reasoning: `Event completion rate ${(eventCompletionRate * 100).toFixed(0)}% \u2014 predatory territory (min: ${(thresholds.eventCompletionMin * 100).toFixed(0)}%). Too hard for free
|
|
2507
|
+
reasoning: `Event completion rate ${(eventCompletionRate * 100).toFixed(0)}% \u2014 predatory territory (min: ${(thresholds.eventCompletionMin * 100).toFixed(0)}%). Too hard for free participants. Lower barriers to participation.`
|
|
2453
2508
|
},
|
|
2454
2509
|
confidence: 0.8,
|
|
2455
2510
|
estimatedLag: 10
|
|
@@ -2461,7 +2516,7 @@ var P53_EventCompletionRate = {
|
|
|
2461
2516
|
severity: 3,
|
|
2462
2517
|
evidence: { eventCompletionRate, max: thresholds.eventCompletionMax },
|
|
2463
2518
|
suggestedAction: {
|
|
2464
|
-
parameter: "
|
|
2519
|
+
parameter: "entryFee",
|
|
2465
2520
|
direction: "increase",
|
|
2466
2521
|
magnitude: 0.05,
|
|
2467
2522
|
reasoning: `Event completion rate ${(eventCompletionRate * 100).toFixed(0)}% \u2014 no monetization pressure (max: ${(thresholds.eventCompletionMax * 100).toFixed(0)}%). Slightly raise costs to create meaningful premium differentiation.`
|
|
@@ -2486,7 +2541,7 @@ var P54_LiveOpsCadence = {
|
|
|
2486
2541
|
severity: 3,
|
|
2487
2542
|
evidence: { velocity, avgSatisfaction, tick: metrics.tick },
|
|
2488
2543
|
suggestedAction: {
|
|
2489
|
-
parameter: "
|
|
2544
|
+
parameter: "rewardRate",
|
|
2490
2545
|
direction: "increase",
|
|
2491
2546
|
magnitude: 0.1,
|
|
2492
2547
|
reasoning: "Low velocity and satisfaction after long runtime. Possible content staleness. Increase rewards as bridge while new content is developed (developer action required)."
|
|
@@ -2517,7 +2572,7 @@ var P56_ContentDropShock = {
|
|
|
2517
2572
|
postDropMax: thresholds.postDropArbitrageMax
|
|
2518
2573
|
},
|
|
2519
2574
|
suggestedAction: {
|
|
2520
|
-
parameter: "
|
|
2575
|
+
parameter: "transactionFee",
|
|
2521
2576
|
direction: "decrease",
|
|
2522
2577
|
magnitude: 0.1,
|
|
2523
2578
|
reasoning: `Content drop ${contentDropAge} ticks ago \u2014 arbitrage at ${arbitrageIndex.toFixed(2)} exceeds post-drop max (${thresholds.postDropArbitrageMax}). Price discovery struggling. Lower trading friction temporarily.`
|
|
@@ -2683,19 +2738,21 @@ var Simulator = class {
|
|
|
2683
2738
|
flowEffect(action, metrics) {
|
|
2684
2739
|
const { parameter, direction } = action;
|
|
2685
2740
|
const sign = direction === "increase" ? -1 : 1;
|
|
2686
|
-
|
|
2741
|
+
const roleEntries = Object.entries(metrics.populationByRole).sort((a, b) => b[1] - a[1]);
|
|
2742
|
+
const dominantRoleCount = roleEntries[0]?.[1] ?? 0;
|
|
2743
|
+
if (parameter === "productionCost") {
|
|
2687
2744
|
return sign * metrics.netFlow * 0.2;
|
|
2688
2745
|
}
|
|
2689
|
-
if (parameter === "
|
|
2746
|
+
if (parameter === "transactionFee") {
|
|
2690
2747
|
return sign * metrics.velocity * 10 * 0.1;
|
|
2691
2748
|
}
|
|
2692
|
-
if (parameter === "
|
|
2693
|
-
return sign *
|
|
2749
|
+
if (parameter === "entryFee") {
|
|
2750
|
+
return sign * dominantRoleCount * 0.5;
|
|
2694
2751
|
}
|
|
2695
|
-
if (parameter === "
|
|
2696
|
-
return -sign *
|
|
2752
|
+
if (parameter === "rewardRate") {
|
|
2753
|
+
return -sign * dominantRoleCount * 0.3;
|
|
2697
2754
|
}
|
|
2698
|
-
if (parameter === "
|
|
2755
|
+
if (parameter === "yieldRate") {
|
|
2699
2756
|
return sign * metrics.faucetVolume * 0.15;
|
|
2700
2757
|
}
|
|
2701
2758
|
return sign * metrics.netFlow * 0.1;
|
|
@@ -3008,30 +3065,33 @@ var RingBuffer = class {
|
|
|
3008
3065
|
}
|
|
3009
3066
|
};
|
|
3010
3067
|
var MetricStore = class {
|
|
3011
|
-
constructor() {
|
|
3068
|
+
constructor(tickConfig) {
|
|
3012
3069
|
/** Fine: last 200 ticks, one entry per tick */
|
|
3013
3070
|
this.fine = new RingBuffer(200);
|
|
3014
|
-
/** Medium: last 200 windows
|
|
3071
|
+
/** Medium: last 200 windows */
|
|
3015
3072
|
this.medium = new RingBuffer(200);
|
|
3016
|
-
/** Coarse: last 200 epochs
|
|
3073
|
+
/** Coarse: last 200 epochs */
|
|
3017
3074
|
this.coarse = new RingBuffer(200);
|
|
3018
3075
|
this.ticksSinceLastMedium = 0;
|
|
3019
3076
|
this.ticksSinceLastCoarse = 0;
|
|
3020
3077
|
this.mediumAccumulator = [];
|
|
3021
3078
|
this.coarseAccumulator = [];
|
|
3079
|
+
const config = { ...DEFAULT_TICK_CONFIG, ...tickConfig };
|
|
3080
|
+
this.mediumWindow = config.mediumWindow;
|
|
3081
|
+
this.coarseWindow = config.coarseWindow;
|
|
3022
3082
|
}
|
|
3023
3083
|
record(metrics) {
|
|
3024
3084
|
this.fine.push(metrics);
|
|
3025
3085
|
this.mediumAccumulator.push(metrics);
|
|
3026
3086
|
this.ticksSinceLastMedium++;
|
|
3027
|
-
if (this.ticksSinceLastMedium >=
|
|
3087
|
+
if (this.ticksSinceLastMedium >= this.mediumWindow) {
|
|
3028
3088
|
this.medium.push(this.aggregate(this.mediumAccumulator));
|
|
3029
3089
|
this.mediumAccumulator = [];
|
|
3030
3090
|
this.ticksSinceLastMedium = 0;
|
|
3031
3091
|
}
|
|
3032
3092
|
this.coarseAccumulator.push(metrics);
|
|
3033
3093
|
this.ticksSinceLastCoarse++;
|
|
3034
|
-
if (this.ticksSinceLastCoarse >=
|
|
3094
|
+
if (this.ticksSinceLastCoarse >= this.coarseWindow) {
|
|
3035
3095
|
this.coarse.push(this.aggregate(this.coarseAccumulator));
|
|
3036
3096
|
this.coarseAccumulator = [];
|
|
3037
3097
|
this.ticksSinceLastCoarse = 0;
|
|
@@ -3131,7 +3191,7 @@ var PersonaTracker = class {
|
|
|
3131
3191
|
/** Classify all agents and return persona distribution */
|
|
3132
3192
|
getDistribution() {
|
|
3133
3193
|
const counts = {
|
|
3134
|
-
|
|
3194
|
+
Active: 0,
|
|
3135
3195
|
Trader: 0,
|
|
3136
3196
|
Collector: 0,
|
|
3137
3197
|
Speculator: 0,
|
|
@@ -3155,7 +3215,7 @@ var PersonaTracker = class {
|
|
|
3155
3215
|
return distribution;
|
|
3156
3216
|
}
|
|
3157
3217
|
classify(history) {
|
|
3158
|
-
if (history.length === 0) return "
|
|
3218
|
+
if (history.length === 0) return "Active";
|
|
3159
3219
|
const avg = (key) => {
|
|
3160
3220
|
const vals = history.map((h) => h[key]);
|
|
3161
3221
|
return vals.reduce((s, v) => s + v, 0) / vals.length;
|
|
@@ -3169,21 +3229,18 @@ var PersonaTracker = class {
|
|
|
3169
3229
|
if (uniqueItems > 5 && extraction < 0) return "Collector";
|
|
3170
3230
|
if (extraction > 100) return "Earner";
|
|
3171
3231
|
if (extraction > 50) return "Speculator";
|
|
3172
|
-
return "
|
|
3232
|
+
return "Active";
|
|
3173
3233
|
}
|
|
3174
3234
|
};
|
|
3175
3235
|
|
|
3176
3236
|
// src/AgentE.ts
|
|
3177
3237
|
var AgentE = class {
|
|
3178
3238
|
constructor(config) {
|
|
3179
|
-
// ── Pipeline ──
|
|
3180
|
-
this.observer = new Observer();
|
|
3181
3239
|
this.simulator = new Simulator();
|
|
3182
3240
|
this.planner = new Planner();
|
|
3183
3241
|
this.executor = new Executor();
|
|
3184
3242
|
// ── State ──
|
|
3185
3243
|
this.log = new DecisionLog();
|
|
3186
|
-
this.store = new MetricStore();
|
|
3187
3244
|
this.personaTracker = new PersonaTracker();
|
|
3188
3245
|
this.params = {};
|
|
3189
3246
|
this.eventBuffer = [];
|
|
@@ -3202,6 +3259,7 @@ var AgentE = class {
|
|
|
3202
3259
|
mode: this.mode,
|
|
3203
3260
|
dominantRoles: config.dominantRoles ?? [],
|
|
3204
3261
|
idealDistribution: config.idealDistribution ?? {},
|
|
3262
|
+
tickConfig: config.tickConfig ?? { duration: 1, unit: "tick" },
|
|
3205
3263
|
gracePeriod: config.gracePeriod ?? 50,
|
|
3206
3264
|
checkInterval: config.checkInterval ?? 5,
|
|
3207
3265
|
maxAdjustmentPercent: config.maxAdjustmentPercent ?? 0.15,
|
|
@@ -3213,6 +3271,9 @@ var AgentE = class {
|
|
|
3213
3271
|
maxAdjustmentPercent: config.maxAdjustmentPercent ?? DEFAULT_THRESHOLDS.maxAdjustmentPercent,
|
|
3214
3272
|
cooldownTicks: config.cooldownTicks ?? DEFAULT_THRESHOLDS.cooldownTicks
|
|
3215
3273
|
};
|
|
3274
|
+
const tickConfig = { ...DEFAULT_TICK_CONFIG, ...config.tickConfig };
|
|
3275
|
+
this.observer = new Observer(tickConfig);
|
|
3276
|
+
this.store = new MetricStore(tickConfig);
|
|
3216
3277
|
this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
|
|
3217
3278
|
if (config.onDecision) this.on("decision", config.onDecision);
|
|
3218
3279
|
if (config.onAlert) this.on("alert", config.onAlert);
|
|
@@ -3244,7 +3305,7 @@ var AgentE = class {
|
|
|
3244
3305
|
this.isRunning = false;
|
|
3245
3306
|
this.isPaused = false;
|
|
3246
3307
|
}
|
|
3247
|
-
// ── Main cycle (call once per tick from your
|
|
3308
|
+
// ── Main cycle (call once per tick from your economy loop) ─────────────────
|
|
3248
3309
|
async tick(state) {
|
|
3249
3310
|
if (!this.isRunning || this.isPaused) return;
|
|
3250
3311
|
const currentState = state ?? await Promise.resolve(this.adapter.getState());
|