@agent-e/core 1.1.2 → 1.2.0
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 +23 -9
- package/dist/index.d.mts +23 -7
- package/dist/index.d.ts +23 -7
- package/dist/index.js +369 -302
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +369 -302
- 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;
|
|
@@ -297,18 +304,18 @@ var Observer = class {
|
|
|
297
304
|
const satisfactions = Object.values(state.agentSatisfaction ?? {});
|
|
298
305
|
const avgSatisfaction = satisfactions.length > 0 ? satisfactions.reduce((s, v) => s + v, 0) / satisfactions.length : 80;
|
|
299
306
|
const blockedAgentCount = satisfactions.filter((s) => s < 20).length;
|
|
300
|
-
const timeToValue =
|
|
307
|
+
const timeToValue = totalAgents > 0 ? blockedAgentCount / totalAgents * 100 : 0;
|
|
301
308
|
const poolSizes = { ...state.poolSizes ?? {} };
|
|
302
309
|
if (!this.anchorBaseline && tick === 1 && totalSupply > 0) {
|
|
303
310
|
this.anchorBaseline = {
|
|
304
|
-
|
|
305
|
-
|
|
311
|
+
currencyPerPeriod: totalSupply / Math.max(1, totalAgents),
|
|
312
|
+
itemsPerCurrency: priceIndex > 0 ? 1 / priceIndex : 0
|
|
306
313
|
};
|
|
307
314
|
}
|
|
308
315
|
let anchorRatioDrift = 0;
|
|
309
316
|
if (this.anchorBaseline && totalAgents > 0) {
|
|
310
|
-
const
|
|
311
|
-
anchorRatioDrift = this.anchorBaseline.
|
|
317
|
+
const currentCurrencyPerPeriod = totalSupply / totalAgents;
|
|
318
|
+
anchorRatioDrift = this.anchorBaseline.currencyPerPeriod > 0 ? (currentCurrencyPerPeriod - this.anchorBaseline.currencyPerPeriod) / this.anchorBaseline.currencyPerPeriod : 0;
|
|
312
319
|
}
|
|
313
320
|
let arbitrageIndex = 0;
|
|
314
321
|
const priceKeys = Object.keys(prices).filter((k) => prices[k] > 0);
|
|
@@ -533,7 +540,7 @@ var P1_ProductionMatchesConsumption = {
|
|
|
533
540
|
id: "P1",
|
|
534
541
|
name: "Production Must Match Consumption",
|
|
535
542
|
category: "supply_chain",
|
|
536
|
-
description: "If producer rate < consumer rate, supply deficit kills the economy.
|
|
543
|
+
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
544
|
check(metrics, _thresholds) {
|
|
538
545
|
const { supplyByResource, demandSignals, populationByRole } = metrics;
|
|
539
546
|
const violations = [];
|
|
@@ -544,19 +551,22 @@ var P1_ProductionMatchesConsumption = {
|
|
|
544
551
|
violations.push(resource);
|
|
545
552
|
}
|
|
546
553
|
}
|
|
547
|
-
const
|
|
548
|
-
const
|
|
549
|
-
const
|
|
550
|
-
|
|
554
|
+
const roleEntries = Object.entries(populationByRole).sort((a, b) => b[1] - a[1]);
|
|
555
|
+
const totalPop = metrics.totalAgents;
|
|
556
|
+
const dominantRole = roleEntries[0];
|
|
557
|
+
const dominantCount = dominantRole?.[1] ?? 0;
|
|
558
|
+
const dominantShare = totalPop > 0 ? dominantCount / totalPop : 0;
|
|
559
|
+
const populationImbalance = dominantShare > 0.4 && violations.length > 0;
|
|
560
|
+
if (violations.length > 0 || populationImbalance) {
|
|
551
561
|
return {
|
|
552
562
|
violated: true,
|
|
553
563
|
severity: 7,
|
|
554
|
-
evidence: { scarceResources: violations,
|
|
564
|
+
evidence: { scarceResources: violations, dominantRole: dominantRole?.[0], dominantShare },
|
|
555
565
|
suggestedAction: {
|
|
556
|
-
parameter: "
|
|
566
|
+
parameter: "productionCost",
|
|
557
567
|
direction: "decrease",
|
|
558
568
|
magnitude: 0.15,
|
|
559
|
-
reasoning: "Lower
|
|
569
|
+
reasoning: "Lower production cost to incentivise more production."
|
|
560
570
|
},
|
|
561
571
|
confidence: violations.length > 0 ? 0.85 : 0.6,
|
|
562
572
|
estimatedLag: 10
|
|
@@ -569,26 +579,28 @@ var P2_ClosedLoopsNeedDirectHandoff = {
|
|
|
569
579
|
id: "P2",
|
|
570
580
|
name: "Closed Loops Need Direct Handoff",
|
|
571
581
|
category: "supply_chain",
|
|
572
|
-
description: "Raw materials listed on an open market create noise and liquidity problems. Gatherers delivering
|
|
582
|
+
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
583
|
check(metrics, _thresholds) {
|
|
574
|
-
const { supplyByResource, prices, velocity } = metrics;
|
|
575
|
-
const
|
|
576
|
-
const
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
584
|
+
const { supplyByResource, prices, velocity, totalAgents } = metrics;
|
|
585
|
+
const avgSupplyPerAgent = totalAgents > 0 ? Object.values(supplyByResource).reduce((s, v) => s + v, 0) / totalAgents : 0;
|
|
586
|
+
const backlogResources = [];
|
|
587
|
+
for (const [resource, supply] of Object.entries(supplyByResource)) {
|
|
588
|
+
const price = prices[resource] ?? 0;
|
|
589
|
+
if (supply > avgSupplyPerAgent * 0.5 && price > 0) {
|
|
590
|
+
backlogResources.push(resource);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
581
593
|
const stagnant = velocity < 3;
|
|
582
|
-
if (
|
|
594
|
+
if (backlogResources.length > 0 && stagnant) {
|
|
583
595
|
return {
|
|
584
596
|
violated: true,
|
|
585
597
|
severity: 5,
|
|
586
|
-
evidence: {
|
|
598
|
+
evidence: { backlogResources, velocity },
|
|
587
599
|
suggestedAction: {
|
|
588
|
-
parameter: "
|
|
600
|
+
parameter: "transactionFee",
|
|
589
601
|
direction: "increase",
|
|
590
602
|
magnitude: 0.2,
|
|
591
|
-
reasoning: "Raise
|
|
603
|
+
reasoning: "Raise market fees to discourage raw material listings. Direct hand-off at production zones is the correct channel."
|
|
592
604
|
},
|
|
593
605
|
confidence: 0.7,
|
|
594
606
|
estimatedLag: 5
|
|
@@ -601,29 +613,31 @@ var P3_BootstrapCapitalCoversFirstTransaction = {
|
|
|
601
613
|
id: "P3",
|
|
602
614
|
name: "Bootstrap Capital Covers First Transaction",
|
|
603
615
|
category: "supply_chain",
|
|
604
|
-
description: "A new producer must be able to afford their first transaction without selling anything first.
|
|
616
|
+
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
617
|
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
|
-
|
|
618
|
+
const { populationByRole, supplyByResource, prices, totalAgents } = metrics;
|
|
619
|
+
const totalProducers = Object.values(populationByRole).reduce((s, v) => s + v, 0);
|
|
620
|
+
if (totalProducers > 0) {
|
|
621
|
+
for (const [resource, supply] of Object.entries(supplyByResource)) {
|
|
622
|
+
if (supply === 0) {
|
|
623
|
+
const anyInputPriced = Object.values(prices).some((p) => p > 0);
|
|
624
|
+
if (anyInputPriced) {
|
|
625
|
+
return {
|
|
626
|
+
violated: true,
|
|
627
|
+
severity: 8,
|
|
628
|
+
evidence: { resource, totalProducers, supply },
|
|
629
|
+
suggestedAction: {
|
|
630
|
+
parameter: "productionCost",
|
|
631
|
+
direction: "decrease",
|
|
632
|
+
magnitude: 0.3,
|
|
633
|
+
reasoning: "Producers cannot complete first transaction. Lower production cost to unblock bootstrap."
|
|
634
|
+
},
|
|
635
|
+
confidence: 0.8,
|
|
636
|
+
estimatedLag: 3
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
627
641
|
}
|
|
628
642
|
return { violated: false };
|
|
629
643
|
}
|
|
@@ -632,41 +646,38 @@ var P4_MaterialsFlowFasterThanCooldown = {
|
|
|
632
646
|
id: "P4",
|
|
633
647
|
name: "Materials Flow Faster Than Cooldown",
|
|
634
648
|
category: "supply_chain",
|
|
635
|
-
description: "Input delivery rate must exceed or match production cooldown rate. If
|
|
649
|
+
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
650
|
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) {
|
|
651
|
+
const { supplyByResource, populationByRole, velocity, totalAgents } = metrics;
|
|
652
|
+
const totalSupply = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
653
|
+
const avgSupplyPerAgent = totalAgents > 0 ? totalSupply / totalAgents : 0;
|
|
654
|
+
const roleEntries = Object.entries(populationByRole);
|
|
655
|
+
const totalRoles = roleEntries.length;
|
|
656
|
+
if (totalRoles >= 2 && velocity < 5 && avgSupplyPerAgent < 0.5) {
|
|
644
657
|
return {
|
|
645
658
|
violated: true,
|
|
646
659
|
severity: 5,
|
|
647
|
-
evidence: {
|
|
660
|
+
evidence: { avgSupplyPerAgent, velocity, totalRoles },
|
|
648
661
|
suggestedAction: {
|
|
649
|
-
parameter: "
|
|
662
|
+
parameter: "yieldRate",
|
|
650
663
|
direction: "increase",
|
|
651
664
|
magnitude: 0.15,
|
|
652
|
-
reasoning: "
|
|
665
|
+
reasoning: "Low supply per agent with stagnant velocity. Increase yield to compensate."
|
|
653
666
|
},
|
|
654
667
|
confidence: 0.65,
|
|
655
668
|
estimatedLag: 8
|
|
656
669
|
};
|
|
657
670
|
}
|
|
658
|
-
|
|
659
|
-
const wood = supplyByResource["wood"] ?? 0;
|
|
660
|
-
if (ore > 80 || wood > 80) {
|
|
671
|
+
if (avgSupplyPerAgent > 2) {
|
|
661
672
|
return {
|
|
662
673
|
violated: true,
|
|
663
674
|
severity: 4,
|
|
664
|
-
evidence: {
|
|
675
|
+
evidence: { avgSupplyPerAgent, totalSupply, totalAgents },
|
|
665
676
|
suggestedAction: {
|
|
666
|
-
parameter: "
|
|
677
|
+
parameter: "yieldRate",
|
|
667
678
|
direction: "decrease",
|
|
668
679
|
magnitude: 0.2,
|
|
669
|
-
reasoning: "Raw materials piling up.
|
|
680
|
+
reasoning: "Raw materials piling up. Extractors outpacing producers."
|
|
670
681
|
},
|
|
671
682
|
confidence: 0.8,
|
|
672
683
|
estimatedLag: 5
|
|
@@ -691,7 +702,7 @@ var P60_SurplusDisposalAsymmetry = {
|
|
|
691
702
|
discount: thresholds.disposalTradeWeightDiscount
|
|
692
703
|
},
|
|
693
704
|
suggestedAction: {
|
|
694
|
-
parameter: "
|
|
705
|
+
parameter: "productionCost",
|
|
695
706
|
direction: "decrease",
|
|
696
707
|
magnitude: 0.1,
|
|
697
708
|
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 +727,7 @@ var P5_ProfitabilityIsCompetitive = {
|
|
|
716
727
|
id: "P5",
|
|
717
728
|
name: "Profitability Is Competitive, Not Absolute",
|
|
718
729
|
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
|
|
730
|
+
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
731
|
check(metrics, thresholds) {
|
|
721
732
|
const { roleShares, populationByRole } = metrics;
|
|
722
733
|
const highShareRoles = [];
|
|
@@ -734,7 +745,7 @@ var P5_ProfitabilityIsCompetitive = {
|
|
|
734
745
|
population: populationByRole[dominantRole]
|
|
735
746
|
},
|
|
736
747
|
suggestedAction: {
|
|
737
|
-
parameter: "
|
|
748
|
+
parameter: "transactionFee",
|
|
738
749
|
direction: "increase",
|
|
739
750
|
magnitude: thresholds.maxAdjustmentPercent,
|
|
740
751
|
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 +771,7 @@ var P6_CrowdingMultiplierOnAllRoles = {
|
|
|
760
771
|
severity: 5,
|
|
761
772
|
evidence: { role, share },
|
|
762
773
|
suggestedAction: {
|
|
763
|
-
parameter: "
|
|
774
|
+
parameter: "productionCost",
|
|
764
775
|
direction: "increase",
|
|
765
776
|
magnitude: 0.1,
|
|
766
777
|
reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 no crowding pressure detected. Apply role-specific cost increase to simulate saturation.`
|
|
@@ -777,28 +788,33 @@ var P7_NonSpecialistsSubsidiseSpecialists = {
|
|
|
777
788
|
id: "P7",
|
|
778
789
|
name: "Non-Specialists Subsidise Specialists in Zero-Sum Games",
|
|
779
790
|
category: "incentive",
|
|
780
|
-
description: "In zero-sum pools (
|
|
791
|
+
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
792
|
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
|
-
|
|
793
|
+
const { poolSizes } = metrics;
|
|
794
|
+
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
795
|
+
if (poolSize <= 0) continue;
|
|
796
|
+
const roleEntries = Object.entries(metrics.populationByRole);
|
|
797
|
+
if (roleEntries.length === 0) continue;
|
|
798
|
+
const [dominantRole, dominantPop] = roleEntries.reduce(
|
|
799
|
+
(max, entry) => entry[1] > max[1] ? entry : max
|
|
800
|
+
);
|
|
801
|
+
const total = metrics.totalAgents;
|
|
802
|
+
const dominantShare = dominantPop / Math.max(1, total);
|
|
803
|
+
if (dominantShare > 0.7 && poolSize < 100) {
|
|
804
|
+
return {
|
|
805
|
+
violated: true,
|
|
806
|
+
severity: 6,
|
|
807
|
+
evidence: { poolName, poolSize, dominantRole, dominantShare },
|
|
808
|
+
suggestedAction: {
|
|
809
|
+
parameter: "entryFee",
|
|
810
|
+
direction: "decrease",
|
|
811
|
+
magnitude: 0.1,
|
|
812
|
+
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.`
|
|
813
|
+
},
|
|
814
|
+
confidence: 0.75,
|
|
815
|
+
estimatedLag: 5
|
|
816
|
+
};
|
|
817
|
+
}
|
|
802
818
|
}
|
|
803
819
|
return { violated: false };
|
|
804
820
|
}
|
|
@@ -807,7 +823,7 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
807
823
|
id: "P8",
|
|
808
824
|
name: "Regulator Cannot Fight the Design",
|
|
809
825
|
category: "incentive",
|
|
810
|
-
description: "If the economy is designed to have a majority role (e.g. 55%
|
|
826
|
+
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
827
|
check(metrics, _thresholds) {
|
|
812
828
|
const { roleShares, avgSatisfaction } = metrics;
|
|
813
829
|
if (avgSatisfaction < 45) {
|
|
@@ -818,7 +834,7 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
818
834
|
severity: 4,
|
|
819
835
|
evidence: { dominantRole: dominantRole[0], share: dominantRole[1], avgSatisfaction },
|
|
820
836
|
suggestedAction: {
|
|
821
|
-
parameter: "
|
|
837
|
+
parameter: "rewardRate",
|
|
822
838
|
direction: "increase",
|
|
823
839
|
magnitude: 0.1,
|
|
824
840
|
reasoning: `Low satisfaction with ${dominantRole[0]} dominant. Regulator may be suppressing a structurally necessary role. Ease pressure on dominant role rewards.`
|
|
@@ -853,7 +869,7 @@ var P9_RoleSwitchingNeedsFriction = {
|
|
|
853
869
|
severity: 5,
|
|
854
870
|
evidence: { totalChurnRate: totalChurn, churnByRole },
|
|
855
871
|
suggestedAction: {
|
|
856
|
-
parameter: "
|
|
872
|
+
parameter: "productionCost",
|
|
857
873
|
direction: "increase",
|
|
858
874
|
magnitude: 0.05,
|
|
859
875
|
reasoning: `Role switch rate ${(totalChurn * 100).toFixed(1)}% exceeds friction threshold. Increase production costs to slow herd movement.`
|
|
@@ -870,7 +886,7 @@ var P10_SpawnWeightingUsesInversePopulation = {
|
|
|
870
886
|
id: "P10",
|
|
871
887
|
name: "Spawn Weighting Uses Inverse Population",
|
|
872
888
|
category: "population",
|
|
873
|
-
description: "New agents should preferentially fill the least-populated roles. Flat
|
|
889
|
+
description: "New agents should preferentially fill the least-populated roles. Flat entry probability causes initial imbalances to compound.",
|
|
874
890
|
check(metrics, _thresholds) {
|
|
875
891
|
const { roleShares } = metrics;
|
|
876
892
|
if (Object.keys(roleShares).length === 0) return { violated: false };
|
|
@@ -885,10 +901,10 @@ var P10_SpawnWeightingUsesInversePopulation = {
|
|
|
885
901
|
severity: 4,
|
|
886
902
|
evidence: { roleShares, stdDev, leastPopulatedRole: minRole?.[0] },
|
|
887
903
|
suggestedAction: {
|
|
888
|
-
parameter: "
|
|
904
|
+
parameter: "yieldRate",
|
|
889
905
|
direction: "increase",
|
|
890
906
|
magnitude: 0.05,
|
|
891
|
-
reasoning: `High role share variance (\u03C3=${stdDev.toFixed(2)}).
|
|
907
|
+
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
908
|
},
|
|
893
909
|
confidence: 0.6,
|
|
894
910
|
estimatedLag: 20
|
|
@@ -911,7 +927,7 @@ var P11_TwoTierPressure = {
|
|
|
911
927
|
severity: 6,
|
|
912
928
|
evidence: { role, share },
|
|
913
929
|
suggestedAction: {
|
|
914
|
-
parameter: "
|
|
930
|
+
parameter: "transactionFee",
|
|
915
931
|
direction: "increase",
|
|
916
932
|
magnitude: 0.15,
|
|
917
933
|
reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 continuous pressure was insufficient. Hard intervention needed alongside resumed continuous pressure.`
|
|
@@ -939,7 +955,7 @@ var P46_PersonaDiversity = {
|
|
|
939
955
|
severity: 5,
|
|
940
956
|
evidence: { dominantPersona: persona, share, personaDistribution },
|
|
941
957
|
suggestedAction: {
|
|
942
|
-
parameter: "
|
|
958
|
+
parameter: "rewardRate",
|
|
943
959
|
direction: "increase",
|
|
944
960
|
magnitude: 0.1,
|
|
945
961
|
reasoning: `${persona} persona at ${(share * 100).toFixed(0)}% \u2014 behavioral monoculture. Diversify reward structures to attract other persona types.`
|
|
@@ -956,7 +972,7 @@ var P46_PersonaDiversity = {
|
|
|
956
972
|
severity: 3,
|
|
957
973
|
evidence: { significantClusters, required: thresholds.personaMinClusters },
|
|
958
974
|
suggestedAction: {
|
|
959
|
-
parameter: "
|
|
975
|
+
parameter: "transactionFee",
|
|
960
976
|
direction: "decrease",
|
|
961
977
|
magnitude: 0.05,
|
|
962
978
|
reasoning: `Only ${significantClusters} significant persona clusters (need ${thresholds.personaMinClusters}). Lower trade barriers to attract non-dominant persona types.`
|
|
@@ -989,7 +1005,7 @@ var P12_OnePrimaryFaucet = {
|
|
|
989
1005
|
severity: 5,
|
|
990
1006
|
evidence: { netFlow, faucetVolume, sinkVolume },
|
|
991
1007
|
suggestedAction: {
|
|
992
|
-
parameter: "
|
|
1008
|
+
parameter: "productionCost",
|
|
993
1009
|
direction: "increase",
|
|
994
1010
|
magnitude: 0.15,
|
|
995
1011
|
reasoning: `Net flow +${netFlow.toFixed(1)} g/t. Inflationary. Increase crafting cost (primary sink) to balance faucet output.`
|
|
@@ -1004,7 +1020,7 @@ var P12_OnePrimaryFaucet = {
|
|
|
1004
1020
|
severity: 4,
|
|
1005
1021
|
evidence: { netFlow, faucetVolume, sinkVolume },
|
|
1006
1022
|
suggestedAction: {
|
|
1007
|
-
parameter: "
|
|
1023
|
+
parameter: "productionCost",
|
|
1008
1024
|
direction: "decrease",
|
|
1009
1025
|
magnitude: 0.15,
|
|
1010
1026
|
reasoning: `Net flow ${netFlow.toFixed(1)} g/t. Deflationary. Decrease crafting cost to ease sink pressure.`
|
|
@@ -1020,36 +1036,40 @@ var P13_PotsAreZeroSumAndSelfRegulate = {
|
|
|
1020
1036
|
id: "P13",
|
|
1021
1037
|
name: "Pots Self-Regulate with Correct Multiplier",
|
|
1022
1038
|
category: "currency",
|
|
1023
|
-
description: "
|
|
1039
|
+
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
1040
|
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
|
-
|
|
1041
|
+
const { poolSizes, populationByRole } = metrics;
|
|
1042
|
+
const totalAgents = metrics.totalAgents;
|
|
1043
|
+
const roleEntries = Object.entries(populationByRole).sort((a, b) => b[1] - a[1]);
|
|
1044
|
+
const dominantRole = roleEntries[0]?.[0];
|
|
1045
|
+
const dominantCount = roleEntries[0]?.[1] ?? 0;
|
|
1046
|
+
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
1047
|
+
if (dominantCount > 5 && poolSize < 50) {
|
|
1048
|
+
const { poolWinRate, poolHouseCut } = thresholds;
|
|
1049
|
+
const maxSustainableMultiplier = (1 - poolHouseCut) / poolWinRate;
|
|
1050
|
+
return {
|
|
1051
|
+
violated: true,
|
|
1052
|
+
severity: 7,
|
|
1053
|
+
evidence: { pool: poolName, poolSize, participants: dominantCount, maxSustainableMultiplier },
|
|
1054
|
+
suggestedAction: {
|
|
1055
|
+
parameter: "rewardRate",
|
|
1056
|
+
direction: "decrease",
|
|
1057
|
+
magnitude: 0.15,
|
|
1058
|
+
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.`
|
|
1059
|
+
},
|
|
1060
|
+
confidence: 0.85,
|
|
1061
|
+
estimatedLag: 3
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1044
1064
|
}
|
|
1045
1065
|
return { violated: false };
|
|
1046
1066
|
}
|
|
1047
1067
|
};
|
|
1048
1068
|
var P14_TrackActualInjection = {
|
|
1049
1069
|
id: "P14",
|
|
1050
|
-
name: "Track Actual
|
|
1070
|
+
name: "Track Actual Currency Injection, Not Value Creation",
|
|
1051
1071
|
category: "currency",
|
|
1052
|
-
description: 'Counting resource gathering as "
|
|
1072
|
+
description: 'Counting resource gathering as "currency injected" is misleading. Currency enters through faucet mechanisms (spawning, rewards). Fake metrics break every downstream decision.',
|
|
1053
1073
|
check(metrics, _thresholds) {
|
|
1054
1074
|
const { faucetVolume, netFlow, totalSupply } = metrics;
|
|
1055
1075
|
const supplyGrowthRate = Math.abs(netFlow) / Math.max(1, totalSupply);
|
|
@@ -1059,7 +1079,7 @@ var P14_TrackActualInjection = {
|
|
|
1059
1079
|
severity: 4,
|
|
1060
1080
|
evidence: { faucetVolume, netFlow, supplyGrowthRate },
|
|
1061
1081
|
suggestedAction: {
|
|
1062
|
-
parameter: "
|
|
1082
|
+
parameter: "yieldRate",
|
|
1063
1083
|
direction: "decrease",
|
|
1064
1084
|
magnitude: 0.1,
|
|
1065
1085
|
reasoning: `Supply growing at ${(supplyGrowthRate * 100).toFixed(1)}%/tick. Verify gold injection tracking. Resources should not create gold directly.`
|
|
@@ -1080,7 +1100,6 @@ var P15_PoolsNeedCapAndDecay = {
|
|
|
1080
1100
|
const { poolSizes, totalSupply } = metrics;
|
|
1081
1101
|
const { poolCapPercent } = thresholds;
|
|
1082
1102
|
for (const [pool, size] of Object.entries(poolSizes)) {
|
|
1083
|
-
if (pool === "arena" || pool === "arenaPot") continue;
|
|
1084
1103
|
const shareOfSupply = size / Math.max(1, totalSupply);
|
|
1085
1104
|
if (shareOfSupply > poolCapPercent * 2) {
|
|
1086
1105
|
return {
|
|
@@ -1088,7 +1107,7 @@ var P15_PoolsNeedCapAndDecay = {
|
|
|
1088
1107
|
severity: 6,
|
|
1089
1108
|
evidence: { pool, size, shareOfSupply, cap: poolCapPercent },
|
|
1090
1109
|
suggestedAction: {
|
|
1091
|
-
parameter: "
|
|
1110
|
+
parameter: "transactionFee",
|
|
1092
1111
|
direction: "decrease",
|
|
1093
1112
|
magnitude: 0.1,
|
|
1094
1113
|
reasoning: `${pool} pool at ${(shareOfSupply * 100).toFixed(1)}% of supply (cap: ${(poolCapPercent * 100).toFixed(0)}%). Gold frozen. Lower fees to encourage circulation over accumulation.`
|
|
@@ -1108,22 +1127,23 @@ var P16_WithdrawalPenaltyScales = {
|
|
|
1108
1127
|
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
1128
|
check(metrics, _thresholds) {
|
|
1110
1129
|
const { poolSizes, totalSupply } = metrics;
|
|
1111
|
-
const bankPool = poolSizes["bank"] ?? poolSizes["bankPool"] ?? 0;
|
|
1112
1130
|
const stakedEstimate = totalSupply * 0.15;
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1131
|
+
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
1132
|
+
if (poolSize < 10 && stakedEstimate > 100) {
|
|
1133
|
+
return {
|
|
1134
|
+
violated: true,
|
|
1135
|
+
severity: 3,
|
|
1136
|
+
evidence: { pool: poolName, poolSize, estimatedStaked: stakedEstimate },
|
|
1137
|
+
suggestedAction: {
|
|
1138
|
+
parameter: "transactionFee",
|
|
1139
|
+
direction: "increase",
|
|
1140
|
+
magnitude: 0.05,
|
|
1141
|
+
reasoning: `${poolName} pool depleted while significant currency should be locked. Early withdrawals may be draining the pool. Ensure withdrawal penalty scales with lock duration.`
|
|
1142
|
+
},
|
|
1143
|
+
confidence: 0.45,
|
|
1144
|
+
estimatedLag: 10
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1127
1147
|
}
|
|
1128
1148
|
return { violated: false };
|
|
1129
1149
|
}
|
|
@@ -1142,7 +1162,7 @@ var P32_VelocityAboveSupply = {
|
|
|
1142
1162
|
severity: 4,
|
|
1143
1163
|
evidence: { velocity, totalSupply, totalResources },
|
|
1144
1164
|
suggestedAction: {
|
|
1145
|
-
parameter: "
|
|
1165
|
+
parameter: "transactionFee",
|
|
1146
1166
|
direction: "decrease",
|
|
1147
1167
|
magnitude: 0.2,
|
|
1148
1168
|
reasoning: `Velocity ${velocity}/t with ${totalResources} resources in system. Economy stagnant despite available supply. Lower trading friction.`
|
|
@@ -1178,7 +1198,7 @@ var P58_NoNaturalNumeraire = {
|
|
|
1178
1198
|
meanPrice: mean
|
|
1179
1199
|
},
|
|
1180
1200
|
suggestedAction: {
|
|
1181
|
-
parameter: "
|
|
1201
|
+
parameter: "productionCost",
|
|
1182
1202
|
direction: "increase",
|
|
1183
1203
|
magnitude: 0.1,
|
|
1184
1204
|
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 +1225,7 @@ var P17_GracePeriodBeforeIntervention = {
|
|
|
1205
1225
|
id: "P17",
|
|
1206
1226
|
name: "Grace Period Before Intervention",
|
|
1207
1227
|
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%
|
|
1228
|
+
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
1229
|
check(metrics, _thresholds) {
|
|
1210
1230
|
if (metrics.tick < 30 && metrics.avgSatisfaction < 40) {
|
|
1211
1231
|
return {
|
|
@@ -1213,7 +1233,7 @@ var P17_GracePeriodBeforeIntervention = {
|
|
|
1213
1233
|
severity: 7,
|
|
1214
1234
|
evidence: { tick: metrics.tick, avgSatisfaction: metrics.avgSatisfaction },
|
|
1215
1235
|
suggestedAction: {
|
|
1216
|
-
parameter: "
|
|
1236
|
+
parameter: "entryFee",
|
|
1217
1237
|
direction: "decrease",
|
|
1218
1238
|
magnitude: 0.2,
|
|
1219
1239
|
reasoning: `Very low satisfaction at tick ${metrics.tick}. Intervention may have fired during grace period. Ease all costs to let economy bootstrap.`
|
|
@@ -1229,27 +1249,29 @@ var P18_FirstProducerNeedsStartingInventory = {
|
|
|
1229
1249
|
id: "P18",
|
|
1230
1250
|
name: "First Producer Needs Starting Inventory + Capital",
|
|
1231
1251
|
category: "bootstrap",
|
|
1232
|
-
description: "A
|
|
1252
|
+
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
1253
|
check(metrics, _thresholds) {
|
|
1234
1254
|
if (metrics.tick > 20) return { violated: false };
|
|
1235
|
-
const
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1255
|
+
for (const [resource, supply] of Object.entries(metrics.supplyByResource)) {
|
|
1256
|
+
if (supply === 0) {
|
|
1257
|
+
for (const [role, population] of Object.entries(metrics.populationByRole)) {
|
|
1258
|
+
if (population > 0) {
|
|
1259
|
+
return {
|
|
1260
|
+
violated: true,
|
|
1261
|
+
severity: 8,
|
|
1262
|
+
evidence: { tick: metrics.tick, resource, supply, role, population },
|
|
1263
|
+
suggestedAction: {
|
|
1264
|
+
parameter: "productionCost",
|
|
1265
|
+
direction: "decrease",
|
|
1266
|
+
magnitude: 0.5,
|
|
1267
|
+
reasoning: `Bootstrap failure: ${role} exists but ${resource} supply is 0 on tick 1-20. Drastically reduce production cost to allow immediate output.`
|
|
1268
|
+
},
|
|
1269
|
+
confidence: 0.9,
|
|
1270
|
+
estimatedLag: 2
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1253
1275
|
}
|
|
1254
1276
|
return { violated: false };
|
|
1255
1277
|
}
|
|
@@ -1258,22 +1280,32 @@ var P19_StartingSupplyExceedsDemand = {
|
|
|
1258
1280
|
id: "P19",
|
|
1259
1281
|
name: "Starting Supply Exceeds Initial Demand",
|
|
1260
1282
|
category: "bootstrap",
|
|
1261
|
-
description: "Launch with more consumables than you think you need. Early scarcity creates
|
|
1283
|
+
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
1284
|
check(metrics, _thresholds) {
|
|
1263
1285
|
if (metrics.tick > 30) return { violated: false };
|
|
1264
|
-
const
|
|
1265
|
-
|
|
1266
|
-
const
|
|
1267
|
-
|
|
1286
|
+
const roleEntries = Object.entries(metrics.populationByRole);
|
|
1287
|
+
if (roleEntries.length === 0) return { violated: false };
|
|
1288
|
+
const [mostPopulatedRole, population] = roleEntries.reduce(
|
|
1289
|
+
(max, entry) => entry[1] > max[1] ? entry : max
|
|
1290
|
+
);
|
|
1291
|
+
if (population < 5) return { violated: false };
|
|
1292
|
+
const totalResourceSupply = Object.values(metrics.supplyByResource).reduce((sum, s) => sum + s, 0);
|
|
1293
|
+
const resourcesPerAgent = totalResourceSupply / Math.max(1, population);
|
|
1294
|
+
if (resourcesPerAgent < 0.5) {
|
|
1268
1295
|
return {
|
|
1269
1296
|
violated: true,
|
|
1270
1297
|
severity: 6,
|
|
1271
|
-
evidence: {
|
|
1298
|
+
evidence: {
|
|
1299
|
+
mostPopulatedRole,
|
|
1300
|
+
population,
|
|
1301
|
+
totalResourceSupply,
|
|
1302
|
+
resourcesPerAgent
|
|
1303
|
+
},
|
|
1272
1304
|
suggestedAction: {
|
|
1273
|
-
parameter: "
|
|
1305
|
+
parameter: "rewardRate",
|
|
1274
1306
|
direction: "increase",
|
|
1275
1307
|
magnitude: 0.2,
|
|
1276
|
-
reasoning: `${
|
|
1308
|
+
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
1309
|
},
|
|
1278
1310
|
confidence: 0.75,
|
|
1279
1311
|
estimatedLag: 5
|
|
@@ -1293,7 +1325,7 @@ var P20_DecayPreventsAccumulation = {
|
|
|
1293
1325
|
id: "P20",
|
|
1294
1326
|
name: "Decay Prevents Accumulation",
|
|
1295
1327
|
category: "feedback",
|
|
1296
|
-
description: "Resources without decay create infinite hoarding. A
|
|
1328
|
+
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
1329
|
check(metrics, _thresholds) {
|
|
1298
1330
|
const { supplyByResource, velocity, totalAgents } = metrics;
|
|
1299
1331
|
const totalResources = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
@@ -1304,7 +1336,7 @@ var P20_DecayPreventsAccumulation = {
|
|
|
1304
1336
|
severity: 4,
|
|
1305
1337
|
evidence: { totalResources, resourcesPerAgent, velocity },
|
|
1306
1338
|
suggestedAction: {
|
|
1307
|
-
parameter: "
|
|
1339
|
+
parameter: "yieldRate",
|
|
1308
1340
|
direction: "decrease",
|
|
1309
1341
|
magnitude: 0.1,
|
|
1310
1342
|
reasoning: `${totalResources.toFixed(0)} resources with velocity ${velocity}/t. Likely hoarding. Reduce yield to increase scarcity and force circulation.`
|
|
@@ -1320,7 +1352,7 @@ var P21_PriceFromGlobalSupply = {
|
|
|
1320
1352
|
id: "P21",
|
|
1321
1353
|
name: "Price Reflects Global Supply, Not Just AH Listings",
|
|
1322
1354
|
category: "feedback",
|
|
1323
|
-
description: "If prices only update from
|
|
1355
|
+
description: "If prices only update from market activity, agents with hoarded inventory see artificially high prices and keep gathering when they should stop.",
|
|
1324
1356
|
check(metrics, _thresholds) {
|
|
1325
1357
|
const { priceVolatility, supplyByResource, prices } = metrics;
|
|
1326
1358
|
for (const resource of Object.keys(prices)) {
|
|
@@ -1332,7 +1364,7 @@ var P21_PriceFromGlobalSupply = {
|
|
|
1332
1364
|
severity: 3,
|
|
1333
1365
|
evidence: { resource, volatility, supply, price: prices[resource] },
|
|
1334
1366
|
suggestedAction: {
|
|
1335
|
-
parameter: "
|
|
1367
|
+
parameter: "transactionFee",
|
|
1336
1368
|
direction: "increase",
|
|
1337
1369
|
magnitude: 0.05,
|
|
1338
1370
|
reasoning: `${resource} price volatile (${(volatility * 100).toFixed(0)}%) despite supply ${supply}. Price may not reflect global inventory. Increase trading friction to stabilise.`
|
|
@@ -1352,23 +1384,36 @@ var P22_MarketAwarenessPreventsSurplus = {
|
|
|
1352
1384
|
description: "Producers who craft without checking market prices will create surpluses that crash prices. Agents need to see prices before deciding to produce.",
|
|
1353
1385
|
check(metrics, _thresholds) {
|
|
1354
1386
|
const { supplyByResource, prices, productionIndex } = metrics;
|
|
1355
|
-
const
|
|
1356
|
-
|
|
1357
|
-
const
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1387
|
+
const priceValues = Object.values(prices).filter((p) => p > 0);
|
|
1388
|
+
if (priceValues.length === 0) return { violated: false };
|
|
1389
|
+
const sortedPrices = [...priceValues].sort((a, b) => a - b);
|
|
1390
|
+
const medianPrice = sortedPrices[Math.floor(sortedPrices.length / 2)] ?? 0;
|
|
1391
|
+
for (const [resource, price] of Object.entries(prices)) {
|
|
1392
|
+
if (price <= 0) continue;
|
|
1393
|
+
const supply = supplyByResource[resource] ?? 0;
|
|
1394
|
+
const priceDeviation = price / Math.max(1, medianPrice);
|
|
1395
|
+
if (priceDeviation < 0.33 && supply > 100 && productionIndex > 0) {
|
|
1396
|
+
return {
|
|
1397
|
+
violated: true,
|
|
1398
|
+
severity: 4,
|
|
1399
|
+
evidence: {
|
|
1400
|
+
resource,
|
|
1401
|
+
price,
|
|
1402
|
+
medianPrice,
|
|
1403
|
+
priceDeviation,
|
|
1404
|
+
supply,
|
|
1405
|
+
productionIndex
|
|
1406
|
+
},
|
|
1407
|
+
suggestedAction: {
|
|
1408
|
+
parameter: "productionCost",
|
|
1409
|
+
direction: "increase",
|
|
1410
|
+
magnitude: 0.1,
|
|
1411
|
+
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.`
|
|
1412
|
+
},
|
|
1413
|
+
confidence: 0.7,
|
|
1414
|
+
estimatedLag: 8
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1372
1417
|
}
|
|
1373
1418
|
return { violated: false };
|
|
1374
1419
|
}
|
|
@@ -1377,7 +1422,7 @@ var P23_ProfitabilityFactorsFeasibility = {
|
|
|
1377
1422
|
id: "P23",
|
|
1378
1423
|
name: "Profitability Factors Execution Feasibility",
|
|
1379
1424
|
category: "feedback",
|
|
1380
|
-
description: "An agent who calculates profit =
|
|
1425
|
+
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
1426
|
check(metrics, _thresholds) {
|
|
1382
1427
|
const { avgSatisfaction, blockedAgentCount, totalAgents } = metrics;
|
|
1383
1428
|
const blockedFraction = blockedAgentCount / Math.max(1, totalAgents);
|
|
@@ -1387,7 +1432,7 @@ var P23_ProfitabilityFactorsFeasibility = {
|
|
|
1387
1432
|
severity: 5,
|
|
1388
1433
|
evidence: { blockedFraction, blockedAgentCount, avgSatisfaction },
|
|
1389
1434
|
suggestedAction: {
|
|
1390
|
-
parameter: "
|
|
1435
|
+
parameter: "productionCost",
|
|
1391
1436
|
direction: "decrease",
|
|
1392
1437
|
magnitude: 0.15,
|
|
1393
1438
|
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 +1458,7 @@ var P24_BlockedAgentsDecayFaster = {
|
|
|
1413
1458
|
severity: 5,
|
|
1414
1459
|
evidence: { blockedFraction, blockedAgentCount, churnRate },
|
|
1415
1460
|
suggestedAction: {
|
|
1416
|
-
parameter: "
|
|
1461
|
+
parameter: "transactionFee",
|
|
1417
1462
|
direction: "decrease",
|
|
1418
1463
|
magnitude: 0.15,
|
|
1419
1464
|
reasoning: `${(blockedFraction * 100).toFixed(0)}% of agents blocked. Blocked agents churn silently, skewing metrics. Lower fees to unblock market participation.`
|
|
@@ -1438,26 +1483,35 @@ var P25_CorrectLeversForCorrectProblems = {
|
|
|
1438
1483
|
id: "P25",
|
|
1439
1484
|
name: "Target the Correct Lever",
|
|
1440
1485
|
category: "regulator",
|
|
1441
|
-
description: "Adjusting sinks for supply-side inflation is wrong. Inflation from too much gathering \u2192 reduce
|
|
1486
|
+
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
1487
|
check(metrics, thresholds) {
|
|
1443
1488
|
const { netFlow, supplyByResource } = metrics;
|
|
1444
|
-
const
|
|
1445
|
-
|
|
1446
|
-
const
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1489
|
+
const resourceEntries = Object.entries(supplyByResource);
|
|
1490
|
+
if (resourceEntries.length === 0) return { violated: false };
|
|
1491
|
+
const totalSupply = resourceEntries.reduce((sum, [_, s]) => sum + s, 0);
|
|
1492
|
+
const avgSupply = totalSupply / resourceEntries.length;
|
|
1493
|
+
for (const [resource, supply] of resourceEntries) {
|
|
1494
|
+
if (supply > avgSupply * 3 && netFlow > thresholds.netFlowWarnThreshold) {
|
|
1495
|
+
return {
|
|
1496
|
+
violated: true,
|
|
1497
|
+
severity: 4,
|
|
1498
|
+
evidence: {
|
|
1499
|
+
resource,
|
|
1500
|
+
supply,
|
|
1501
|
+
avgSupply,
|
|
1502
|
+
ratio: supply / Math.max(1, avgSupply),
|
|
1503
|
+
netFlow
|
|
1504
|
+
},
|
|
1505
|
+
suggestedAction: {
|
|
1506
|
+
parameter: "yieldRate",
|
|
1507
|
+
direction: "decrease",
|
|
1508
|
+
magnitude: 0.15,
|
|
1509
|
+
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.`
|
|
1510
|
+
},
|
|
1511
|
+
confidence: 0.75,
|
|
1512
|
+
estimatedLag: 8
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1461
1515
|
}
|
|
1462
1516
|
return { violated: false };
|
|
1463
1517
|
}
|
|
@@ -1475,7 +1529,7 @@ var P26_ContinuousPressureBeatsThresholdCuts = {
|
|
|
1475
1529
|
severity: 4,
|
|
1476
1530
|
evidence: { inflationRate },
|
|
1477
1531
|
suggestedAction: {
|
|
1478
|
-
parameter: "
|
|
1532
|
+
parameter: "productionCost",
|
|
1479
1533
|
direction: inflationRate > 0 ? "increase" : "decrease",
|
|
1480
1534
|
magnitude: Math.min(thresholds.maxAdjustmentPercent, 0.05),
|
|
1481
1535
|
// force smaller step
|
|
@@ -1501,7 +1555,7 @@ var P27_AdjustmentsNeedCooldowns = {
|
|
|
1501
1555
|
severity: 4,
|
|
1502
1556
|
evidence: { churnRate, avgSatisfaction },
|
|
1503
1557
|
suggestedAction: {
|
|
1504
|
-
parameter: "
|
|
1558
|
+
parameter: "entryFee",
|
|
1505
1559
|
direction: "decrease",
|
|
1506
1560
|
magnitude: 0.05,
|
|
1507
1561
|
reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) with low satisfaction. Possible oscillation from rapid adjustments. Apply small correction only.`
|
|
@@ -1517,7 +1571,7 @@ var P28_StructuralDominanceIsNotPathological = {
|
|
|
1517
1571
|
id: "P28",
|
|
1518
1572
|
name: "Structural Dominance \u2260 Pathological Monopoly",
|
|
1519
1573
|
category: "regulator",
|
|
1520
|
-
description: 'A designed
|
|
1574
|
+
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
1575
|
check(metrics, _thresholds) {
|
|
1522
1576
|
const { roleShares, avgSatisfaction } = metrics;
|
|
1523
1577
|
const dominant = Object.entries(roleShares).sort((a, b) => b[1] - a[1])[0];
|
|
@@ -1532,7 +1586,7 @@ var P28_StructuralDominanceIsNotPathological = {
|
|
|
1532
1586
|
severity: 5,
|
|
1533
1587
|
evidence: { dominantRole, dominantShare, avgSatisfaction },
|
|
1534
1588
|
suggestedAction: {
|
|
1535
|
-
parameter: "
|
|
1589
|
+
parameter: "productionCost",
|
|
1536
1590
|
direction: "decrease",
|
|
1537
1591
|
magnitude: 0.1,
|
|
1538
1592
|
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 +1611,7 @@ var P38_CommunicationPreventsRevolt = {
|
|
|
1557
1611
|
severity: 3,
|
|
1558
1612
|
evidence: { churnRate },
|
|
1559
1613
|
suggestedAction: {
|
|
1560
|
-
parameter: "
|
|
1614
|
+
parameter: "rewardRate",
|
|
1561
1615
|
direction: "increase",
|
|
1562
1616
|
magnitude: 0.1,
|
|
1563
1617
|
reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) \u2014 agents leaving. Ensure all recent adjustments are logged with reasoning to diagnose cause.`
|
|
@@ -1582,7 +1636,7 @@ var P29_PinchPoint = {
|
|
|
1582
1636
|
id: "P29",
|
|
1583
1637
|
name: "Pinch Point",
|
|
1584
1638
|
category: "market_dynamics",
|
|
1585
|
-
description: "Every economy has a resource that constrains all downstream activity.
|
|
1639
|
+
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
1640
|
check(metrics, _thresholds) {
|
|
1587
1641
|
const { pinchPoints, supplyByResource, demandSignals } = metrics;
|
|
1588
1642
|
for (const [resource, status] of Object.entries(pinchPoints)) {
|
|
@@ -1594,7 +1648,7 @@ var P29_PinchPoint = {
|
|
|
1594
1648
|
severity: 7,
|
|
1595
1649
|
evidence: { resource, supply, demand, status },
|
|
1596
1650
|
suggestedAction: {
|
|
1597
|
-
parameter: "
|
|
1651
|
+
parameter: "productionCost",
|
|
1598
1652
|
direction: "decrease",
|
|
1599
1653
|
magnitude: 0.15,
|
|
1600
1654
|
reasoning: `${resource} is a pinch point and currently SCARCE (supply ${supply}, demand ${demand}). Reduce production cost to increase throughput.`
|
|
@@ -1610,7 +1664,7 @@ var P29_PinchPoint = {
|
|
|
1610
1664
|
severity: 4,
|
|
1611
1665
|
evidence: { resource, supply, status },
|
|
1612
1666
|
suggestedAction: {
|
|
1613
|
-
parameter: "
|
|
1667
|
+
parameter: "productionCost",
|
|
1614
1668
|
direction: "increase",
|
|
1615
1669
|
magnitude: 0.1,
|
|
1616
1670
|
reasoning: `${resource} is a pinch point and OVERSUPPLIED (supply ${supply}). Raise production cost to reduce surplus.`
|
|
@@ -1627,7 +1681,7 @@ var P30_MovingPinchPoint = {
|
|
|
1627
1681
|
id: "P30",
|
|
1628
1682
|
name: "Moving Pinch Point",
|
|
1629
1683
|
category: "market_dynamics",
|
|
1630
|
-
description: "
|
|
1684
|
+
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
1685
|
check(metrics, _thresholds) {
|
|
1632
1686
|
const { capacityUsage, supplyByResource, avgSatisfaction } = metrics;
|
|
1633
1687
|
const totalResources = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
@@ -1638,7 +1692,7 @@ var P30_MovingPinchPoint = {
|
|
|
1638
1692
|
severity: 3,
|
|
1639
1693
|
evidence: { capacityUsage, resourcesPerAgent, avgSatisfaction },
|
|
1640
1694
|
suggestedAction: {
|
|
1641
|
-
parameter: "
|
|
1695
|
+
parameter: "productionCost",
|
|
1642
1696
|
direction: "increase",
|
|
1643
1697
|
magnitude: 0.1,
|
|
1644
1698
|
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 +1738,7 @@ var P57_CombinatorialPriceSpace = {
|
|
|
1684
1738
|
target: thresholds.relativePriceConvergenceTarget
|
|
1685
1739
|
},
|
|
1686
1740
|
suggestedAction: {
|
|
1687
|
-
parameter: "
|
|
1741
|
+
parameter: "transactionFee",
|
|
1688
1742
|
direction: "decrease",
|
|
1689
1743
|
magnitude: 0.1,
|
|
1690
1744
|
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 +1761,7 @@ var P31_AnchorValueTracking = {
|
|
|
1707
1761
|
id: "P31",
|
|
1708
1762
|
name: "Anchor Value Tracking",
|
|
1709
1763
|
category: "measurement",
|
|
1710
|
-
description: "1
|
|
1764
|
+
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
1765
|
check(metrics, _thresholds) {
|
|
1712
1766
|
const { anchorRatioDrift, inflationRate } = metrics;
|
|
1713
1767
|
if (Math.abs(anchorRatioDrift) > 0.25) {
|
|
@@ -1716,10 +1770,10 @@ var P31_AnchorValueTracking = {
|
|
|
1716
1770
|
severity: 5,
|
|
1717
1771
|
evidence: { anchorRatioDrift, inflationRate },
|
|
1718
1772
|
suggestedAction: {
|
|
1719
|
-
parameter: "
|
|
1773
|
+
parameter: "productionCost",
|
|
1720
1774
|
direction: anchorRatioDrift > 0 ? "increase" : "decrease",
|
|
1721
1775
|
magnitude: 0.1,
|
|
1722
|
-
reasoning: `Anchor ratio has drifted ${(anchorRatioDrift * 100).toFixed(0)}% from baseline. Time-to-value for
|
|
1776
|
+
reasoning: `Anchor ratio has drifted ${(anchorRatioDrift * 100).toFixed(0)}% from baseline. Time-to-value for participants is changing. Adjust production costs to restore.`
|
|
1723
1777
|
},
|
|
1724
1778
|
confidence: 0.65,
|
|
1725
1779
|
estimatedLag: 10
|
|
@@ -1741,7 +1795,7 @@ var P41_MultiResolutionMonitoring = {
|
|
|
1741
1795
|
severity: 4,
|
|
1742
1796
|
evidence: { giniCoefficient, avgSatisfaction },
|
|
1743
1797
|
suggestedAction: {
|
|
1744
|
-
parameter: "
|
|
1798
|
+
parameter: "transactionFee",
|
|
1745
1799
|
direction: "increase",
|
|
1746
1800
|
magnitude: 0.1,
|
|
1747
1801
|
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 +1824,7 @@ var P55_ArbitrageThermometer = {
|
|
|
1770
1824
|
critical: thresholds.arbitrageIndexCritical
|
|
1771
1825
|
},
|
|
1772
1826
|
suggestedAction: {
|
|
1773
|
-
parameter: "
|
|
1827
|
+
parameter: "transactionFee",
|
|
1774
1828
|
direction: "decrease",
|
|
1775
1829
|
magnitude: 0.15,
|
|
1776
1830
|
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 +1842,7 @@ var P55_ArbitrageThermometer = {
|
|
|
1788
1842
|
warning: thresholds.arbitrageIndexWarning
|
|
1789
1843
|
},
|
|
1790
1844
|
suggestedAction: {
|
|
1791
|
-
parameter: "
|
|
1845
|
+
parameter: "transactionFee",
|
|
1792
1846
|
direction: "decrease",
|
|
1793
1847
|
magnitude: 0.08,
|
|
1794
1848
|
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 +1870,7 @@ var P59_GiftEconomyNoise = {
|
|
|
1816
1870
|
threshold: thresholds.giftTradeFilterRatio
|
|
1817
1871
|
},
|
|
1818
1872
|
suggestedAction: {
|
|
1819
|
-
parameter: "
|
|
1873
|
+
parameter: "transactionFee",
|
|
1820
1874
|
direction: "increase",
|
|
1821
1875
|
magnitude: 0.05,
|
|
1822
1876
|
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 +1894,7 @@ var P42_TheMedianPrinciple = {
|
|
|
1840
1894
|
id: "P42",
|
|
1841
1895
|
name: "The Median Principle",
|
|
1842
1896
|
category: "statistical",
|
|
1843
|
-
description: "When (mean - median) / median > 0.3, mean is a lie. A few
|
|
1897
|
+
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
1898
|
check(metrics, thresholds) {
|
|
1845
1899
|
const { meanMedianDivergence, giniCoefficient } = metrics;
|
|
1846
1900
|
if (meanMedianDivergence > thresholds.meanMedianDivergenceMax) {
|
|
@@ -1854,7 +1908,7 @@ var P42_TheMedianPrinciple = {
|
|
|
1854
1908
|
medianBalance: metrics.medianBalance
|
|
1855
1909
|
},
|
|
1856
1910
|
suggestedAction: {
|
|
1857
|
-
parameter: "
|
|
1911
|
+
parameter: "transactionFee",
|
|
1858
1912
|
direction: "increase",
|
|
1859
1913
|
magnitude: 0.15,
|
|
1860
1914
|
reasoning: `Mean/median divergence ${(meanMedianDivergence * 100).toFixed(0)}% (threshold: ${(thresholds.meanMedianDivergenceMax * 100).toFixed(0)}%). Economy has outliers skewing metrics. Use median for decisions. Raise auction fees to redistribute wealth.`
|
|
@@ -1879,7 +1933,7 @@ var P43_SimulationMinimum = {
|
|
|
1879
1933
|
severity: 3,
|
|
1880
1934
|
evidence: { inflationRate, minIterations: thresholds.simulationMinIterations },
|
|
1881
1935
|
suggestedAction: {
|
|
1882
|
-
parameter: "
|
|
1936
|
+
parameter: "productionCost",
|
|
1883
1937
|
direction: inflationRate > 0 ? "increase" : "decrease",
|
|
1884
1938
|
magnitude: 0.05,
|
|
1885
1939
|
reasoning: `Large inflation rate swing (${(inflationRate * 100).toFixed(0)}%). Ensure all decisions use \u2265${thresholds.simulationMinIterations} simulation iterations. Apply conservative correction.`
|
|
@@ -1917,7 +1971,7 @@ var P39_TheLagPrinciple = {
|
|
|
1917
1971
|
severity: 5,
|
|
1918
1972
|
evidence: { inflationRate, netFlow, lagRange: [lagMin, lagMax] },
|
|
1919
1973
|
suggestedAction: {
|
|
1920
|
-
parameter: "
|
|
1974
|
+
parameter: "productionCost",
|
|
1921
1975
|
direction: "increase",
|
|
1922
1976
|
magnitude: 0.03,
|
|
1923
1977
|
// very small — oscillation means over-adjusting
|
|
@@ -1944,7 +1998,7 @@ var P44_ComplexityBudget = {
|
|
|
1944
1998
|
severity: 3,
|
|
1945
1999
|
evidence: { customMetricCount, budgetMax: thresholds.complexityBudgetMax },
|
|
1946
2000
|
suggestedAction: {
|
|
1947
|
-
parameter: "
|
|
2001
|
+
parameter: "transactionFee",
|
|
1948
2002
|
direction: "decrease",
|
|
1949
2003
|
magnitude: 0.01,
|
|
1950
2004
|
reasoning: `${customMetricCount} custom metrics tracked (budget: ${thresholds.complexityBudgetMax}). Consider pruning low-impact parameters. Applying minimal correction to avoid adding complexity.`
|
|
@@ -1966,25 +2020,25 @@ var P35_DestructionCreatesValue = {
|
|
|
1966
2020
|
id: "P35",
|
|
1967
2021
|
name: "Destruction Creates Value",
|
|
1968
2022
|
category: "resource",
|
|
1969
|
-
description: "If nothing is ever permanently lost, inflation is inevitable.
|
|
2023
|
+
description: "If nothing is ever permanently lost, inflation is inevitable. Resource durability and consumption mechanisms create destruction. Without them, supply grows without bound.",
|
|
1970
2024
|
check(metrics, _thresholds) {
|
|
1971
2025
|
const { supplyByResource, sinkVolume, netFlow } = metrics;
|
|
1972
|
-
const
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
}
|
|
2026
|
+
for (const [resource, supply] of Object.entries(supplyByResource)) {
|
|
2027
|
+
if (supply > 200 && sinkVolume < 5 && netFlow > 0) {
|
|
2028
|
+
return {
|
|
2029
|
+
violated: true,
|
|
2030
|
+
severity: 6,
|
|
2031
|
+
evidence: { resource, supply, sinkVolume, netFlow },
|
|
2032
|
+
suggestedAction: {
|
|
2033
|
+
parameter: "entryFee",
|
|
2034
|
+
direction: "decrease",
|
|
2035
|
+
magnitude: 0.1,
|
|
2036
|
+
reasoning: `${resource} supply at ${supply} units with low destruction (sink ${sinkVolume}/t). Resources not being consumed. Lower competitive pool entry to increase resource usage.`
|
|
2037
|
+
},
|
|
2038
|
+
confidence: 0.7,
|
|
2039
|
+
estimatedLag: 5
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
1988
2042
|
}
|
|
1989
2043
|
return { violated: false };
|
|
1990
2044
|
}
|
|
@@ -2004,7 +2058,7 @@ var P40_ReplacementRate = {
|
|
|
2004
2058
|
severity: 6,
|
|
2005
2059
|
evidence: { productionIndex, sinkVolume, replacementRatio },
|
|
2006
2060
|
suggestedAction: {
|
|
2007
|
-
parameter: "
|
|
2061
|
+
parameter: "yieldRate",
|
|
2008
2062
|
direction: "increase",
|
|
2009
2063
|
magnitude: 0.15,
|
|
2010
2064
|
reasoning: `Replacement rate ${replacementRatio.toFixed(2)} (need \u2265${thresholds.replacementRateMultiplier}). Production below consumption. Resources will deplete. Increase yield.`
|
|
@@ -2018,7 +2072,7 @@ var P40_ReplacementRate = {
|
|
|
2018
2072
|
severity: 3,
|
|
2019
2073
|
evidence: { productionIndex, sinkVolume, replacementRatio },
|
|
2020
2074
|
suggestedAction: {
|
|
2021
|
-
parameter: "
|
|
2075
|
+
parameter: "yieldRate",
|
|
2022
2076
|
direction: "decrease",
|
|
2023
2077
|
magnitude: 0.1,
|
|
2024
2078
|
reasoning: `Replacement rate ${replacementRatio.toFixed(2)} \u2014 overproducing. Production far exceeds consumption. Reduce yield to prevent glut.`
|
|
@@ -2044,7 +2098,7 @@ var P49_IdleAssetTax = {
|
|
|
2044
2098
|
severity: 5,
|
|
2045
2099
|
evidence: { giniCoefficient, top10PctShare, velocity },
|
|
2046
2100
|
suggestedAction: {
|
|
2047
|
-
parameter: "
|
|
2101
|
+
parameter: "transactionFee",
|
|
2048
2102
|
direction: "increase",
|
|
2049
2103
|
magnitude: 0.15,
|
|
2050
2104
|
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 +2130,7 @@ var P33_FairNotEqual = {
|
|
|
2076
2130
|
severity: 3,
|
|
2077
2131
|
evidence: { giniCoefficient },
|
|
2078
2132
|
suggestedAction: {
|
|
2079
|
-
parameter: "
|
|
2133
|
+
parameter: "rewardRate",
|
|
2080
2134
|
direction: "increase",
|
|
2081
2135
|
magnitude: 0.1,
|
|
2082
2136
|
reasoning: `Gini ${giniCoefficient.toFixed(2)} \u2014 near-perfect equality. Economy lacks stakes. Increase winner rewards to create meaningful spread.`
|
|
@@ -2091,7 +2145,7 @@ var P33_FairNotEqual = {
|
|
|
2091
2145
|
severity: 7,
|
|
2092
2146
|
evidence: { giniCoefficient },
|
|
2093
2147
|
suggestedAction: {
|
|
2094
|
-
parameter: "
|
|
2148
|
+
parameter: "transactionFee",
|
|
2095
2149
|
direction: "increase",
|
|
2096
2150
|
magnitude: 0.2,
|
|
2097
2151
|
reasoning: `Gini ${giniCoefficient.toFixed(2)} \u2014 oligarchy level. Toxic inequality. Raise transaction fees to redistribute wealth from rich to pool.`
|
|
@@ -2106,7 +2160,7 @@ var P33_FairNotEqual = {
|
|
|
2106
2160
|
severity: 4,
|
|
2107
2161
|
evidence: { giniCoefficient },
|
|
2108
2162
|
suggestedAction: {
|
|
2109
|
-
parameter: "
|
|
2163
|
+
parameter: "transactionFee",
|
|
2110
2164
|
direction: "increase",
|
|
2111
2165
|
magnitude: 0.1,
|
|
2112
2166
|
reasoning: `Gini ${giniCoefficient.toFixed(2)} \u2014 high inequality warning. Gently raise fees to slow wealth concentration.`
|
|
@@ -2131,7 +2185,7 @@ var P36_MechanicFrictionDetector = {
|
|
|
2131
2185
|
severity: 5,
|
|
2132
2186
|
evidence: { churnRate, avgSatisfaction, velocity },
|
|
2133
2187
|
suggestedAction: {
|
|
2134
|
-
parameter: "
|
|
2188
|
+
parameter: "rewardRate",
|
|
2135
2189
|
direction: "increase",
|
|
2136
2190
|
magnitude: 0.15,
|
|
2137
2191
|
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 +2210,7 @@ var P37_LatecommerProblem = {
|
|
|
2156
2210
|
severity: 6,
|
|
2157
2211
|
evidence: { timeToValue, avgSatisfaction, churnRate },
|
|
2158
2212
|
suggestedAction: {
|
|
2159
|
-
parameter: "
|
|
2213
|
+
parameter: "productionCost",
|
|
2160
2214
|
direction: "decrease",
|
|
2161
2215
|
magnitude: 0.15,
|
|
2162
2216
|
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 +2237,7 @@ var P45_TimeBudget = {
|
|
|
2183
2237
|
severity: 5,
|
|
2184
2238
|
evidence: { timeToValue, avgSatisfaction, timeBudgetRatio: thresholds.timeBudgetRatio },
|
|
2185
2239
|
suggestedAction: {
|
|
2186
|
-
parameter: "
|
|
2240
|
+
parameter: "entryFee",
|
|
2187
2241
|
direction: "decrease",
|
|
2188
2242
|
magnitude: 0.15,
|
|
2189
2243
|
reasoning: `Time-to-value ${timeToValue} ticks with ${avgSatisfaction.toFixed(0)} satisfaction. Economy requires too much time investment. Lower barriers to participation.`
|
|
@@ -2213,7 +2267,7 @@ var P50_PayPowerRatio = {
|
|
|
2213
2267
|
threshold: thresholds.payPowerRatioMax
|
|
2214
2268
|
},
|
|
2215
2269
|
suggestedAction: {
|
|
2216
|
-
parameter: "
|
|
2270
|
+
parameter: "transactionFee",
|
|
2217
2271
|
direction: "increase",
|
|
2218
2272
|
magnitude: 0.2,
|
|
2219
2273
|
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 +2302,7 @@ var P34_ExtractionRatio = {
|
|
|
2248
2302
|
severity: 8,
|
|
2249
2303
|
evidence: { extractionRatio, threshold: thresholds.extractionRatioRed },
|
|
2250
2304
|
suggestedAction: {
|
|
2251
|
-
parameter: "
|
|
2305
|
+
parameter: "transactionFee",
|
|
2252
2306
|
direction: "increase",
|
|
2253
2307
|
magnitude: 0.25,
|
|
2254
2308
|
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 +2317,7 @@ var P34_ExtractionRatio = {
|
|
|
2263
2317
|
severity: 5,
|
|
2264
2318
|
evidence: { extractionRatio, threshold: thresholds.extractionRatioYellow },
|
|
2265
2319
|
suggestedAction: {
|
|
2266
|
-
parameter: "
|
|
2320
|
+
parameter: "transactionFee",
|
|
2267
2321
|
direction: "increase",
|
|
2268
2322
|
magnitude: 0.1,
|
|
2269
2323
|
reasoning: `Extraction ratio ${(extractionRatio * 100).toFixed(0)}% (warning: ${(thresholds.extractionRatioYellow * 100).toFixed(0)}%). Economy trending toward extraction-heavy. Apply early pressure.`
|
|
@@ -2279,7 +2333,7 @@ var P47_SmokeTest = {
|
|
|
2279
2333
|
id: "P47",
|
|
2280
2334
|
name: "Smoke Test",
|
|
2281
2335
|
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 (
|
|
2336
|
+
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
2337
|
check(metrics, thresholds) {
|
|
2284
2338
|
const { smokeTestRatio } = metrics;
|
|
2285
2339
|
if (isNaN(smokeTestRatio)) return { violated: false };
|
|
@@ -2289,7 +2343,7 @@ var P47_SmokeTest = {
|
|
|
2289
2343
|
severity: 9,
|
|
2290
2344
|
evidence: { smokeTestRatio, threshold: thresholds.smokeTestCritical },
|
|
2291
2345
|
suggestedAction: {
|
|
2292
|
-
parameter: "
|
|
2346
|
+
parameter: "rewardRate",
|
|
2293
2347
|
direction: "increase",
|
|
2294
2348
|
magnitude: 0.2,
|
|
2295
2349
|
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 +2358,7 @@ var P47_SmokeTest = {
|
|
|
2304
2358
|
severity: 6,
|
|
2305
2359
|
evidence: { smokeTestRatio, threshold: thresholds.smokeTestWarning },
|
|
2306
2360
|
suggestedAction: {
|
|
2307
|
-
parameter: "
|
|
2361
|
+
parameter: "rewardRate",
|
|
2308
2362
|
direction: "increase",
|
|
2309
2363
|
magnitude: 0.1,
|
|
2310
2364
|
reasoning: `Utility/market ratio ${(smokeTestRatio * 100).toFixed(0)}% (warning). Economy is >70% speculative. Boost utility rewards to restore intrinsic value anchor.`
|
|
@@ -2320,7 +2374,7 @@ var P48_CurrencyInsulation = {
|
|
|
2320
2374
|
id: "P48",
|
|
2321
2375
|
name: "Currency Insulation",
|
|
2322
2376
|
category: "open_economy",
|
|
2323
|
-
description: "Gameplay economy correlation with external markets > 0.5 = insulation failure. When your
|
|
2377
|
+
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
2378
|
check(metrics, thresholds) {
|
|
2325
2379
|
const { currencyInsulation } = metrics;
|
|
2326
2380
|
if (isNaN(currencyInsulation)) return { violated: false };
|
|
@@ -2330,7 +2384,7 @@ var P48_CurrencyInsulation = {
|
|
|
2330
2384
|
severity: 6,
|
|
2331
2385
|
evidence: { currencyInsulation, threshold: thresholds.currencyInsulationMax },
|
|
2332
2386
|
suggestedAction: {
|
|
2333
|
-
parameter: "
|
|
2387
|
+
parameter: "transactionFee",
|
|
2334
2388
|
direction: "increase",
|
|
2335
2389
|
magnitude: 0.1,
|
|
2336
2390
|
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 +2424,7 @@ var P51_SharkTooth = {
|
|
|
2370
2424
|
threshold: thresholds.sharkToothPeakDecay
|
|
2371
2425
|
},
|
|
2372
2426
|
suggestedAction: {
|
|
2373
|
-
parameter: "
|
|
2427
|
+
parameter: "rewardRate",
|
|
2374
2428
|
direction: "increase",
|
|
2375
2429
|
magnitude: 0.1,
|
|
2376
2430
|
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 +2442,7 @@ var P51_SharkTooth = {
|
|
|
2388
2442
|
severity: 4,
|
|
2389
2443
|
evidence: { lastValley, prevValley, ratio: lastValley / prevValley },
|
|
2390
2444
|
suggestedAction: {
|
|
2391
|
-
parameter: "
|
|
2445
|
+
parameter: "productionCost",
|
|
2392
2446
|
direction: "decrease",
|
|
2393
2447
|
magnitude: 0.1,
|
|
2394
2448
|
reasoning: "Between-event engagement declining (deepening valleys). Base economy not sustaining participants between events. Lower production costs to improve off-event value."
|
|
@@ -2405,7 +2459,7 @@ var P52_EndowmentEffect = {
|
|
|
2405
2459
|
id: "P52",
|
|
2406
2460
|
name: "Endowment Effect",
|
|
2407
2461
|
category: "liveops",
|
|
2408
|
-
description: "
|
|
2462
|
+
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
2463
|
check(metrics, _thresholds) {
|
|
2410
2464
|
const { avgSatisfaction, churnRate } = metrics;
|
|
2411
2465
|
const { eventCompletionRate } = metrics;
|
|
@@ -2416,7 +2470,7 @@ var P52_EndowmentEffect = {
|
|
|
2416
2470
|
severity: 4,
|
|
2417
2471
|
evidence: { eventCompletionRate, avgSatisfaction, churnRate },
|
|
2418
2472
|
suggestedAction: {
|
|
2419
|
-
parameter: "
|
|
2473
|
+
parameter: "rewardRate",
|
|
2420
2474
|
direction: "increase",
|
|
2421
2475
|
magnitude: 0.15,
|
|
2422
2476
|
reasoning: `${(eventCompletionRate * 100).toFixed(0)}% event completion but satisfaction only ${avgSatisfaction.toFixed(0)}. Events not creating perceived value. Increase reward quality/quantity.`
|
|
@@ -2446,10 +2500,10 @@ var P53_EventCompletionRate = {
|
|
|
2446
2500
|
max: thresholds.eventCompletionMax
|
|
2447
2501
|
},
|
|
2448
2502
|
suggestedAction: {
|
|
2449
|
-
parameter: "
|
|
2503
|
+
parameter: "productionCost",
|
|
2450
2504
|
direction: "decrease",
|
|
2451
2505
|
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
|
|
2506
|
+
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
2507
|
},
|
|
2454
2508
|
confidence: 0.8,
|
|
2455
2509
|
estimatedLag: 10
|
|
@@ -2461,7 +2515,7 @@ var P53_EventCompletionRate = {
|
|
|
2461
2515
|
severity: 3,
|
|
2462
2516
|
evidence: { eventCompletionRate, max: thresholds.eventCompletionMax },
|
|
2463
2517
|
suggestedAction: {
|
|
2464
|
-
parameter: "
|
|
2518
|
+
parameter: "entryFee",
|
|
2465
2519
|
direction: "increase",
|
|
2466
2520
|
magnitude: 0.05,
|
|
2467
2521
|
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 +2540,7 @@ var P54_LiveOpsCadence = {
|
|
|
2486
2540
|
severity: 3,
|
|
2487
2541
|
evidence: { velocity, avgSatisfaction, tick: metrics.tick },
|
|
2488
2542
|
suggestedAction: {
|
|
2489
|
-
parameter: "
|
|
2543
|
+
parameter: "rewardRate",
|
|
2490
2544
|
direction: "increase",
|
|
2491
2545
|
magnitude: 0.1,
|
|
2492
2546
|
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 +2571,7 @@ var P56_ContentDropShock = {
|
|
|
2517
2571
|
postDropMax: thresholds.postDropArbitrageMax
|
|
2518
2572
|
},
|
|
2519
2573
|
suggestedAction: {
|
|
2520
|
-
parameter: "
|
|
2574
|
+
parameter: "transactionFee",
|
|
2521
2575
|
direction: "decrease",
|
|
2522
2576
|
magnitude: 0.1,
|
|
2523
2577
|
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.`
|
|
@@ -2576,6 +2630,10 @@ var ALL_PRINCIPLES = [
|
|
|
2576
2630
|
var Simulator = class {
|
|
2577
2631
|
constructor() {
|
|
2578
2632
|
this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
|
|
2633
|
+
// Cache beforeViolations for the *current* tick only (one entry max).
|
|
2634
|
+
// Using a Map here is intentional but the cache must be bounded — we only
|
|
2635
|
+
// care about the tick that is currently being evaluated, so we evict any
|
|
2636
|
+
// entries whose key differs from the incoming tick.
|
|
2579
2637
|
this.beforeViolationsCache = /* @__PURE__ */ new Map();
|
|
2580
2638
|
}
|
|
2581
2639
|
/**
|
|
@@ -2600,6 +2658,9 @@ var Simulator = class {
|
|
|
2600
2658
|
const mean = this.averageMetrics(outcomes);
|
|
2601
2659
|
const netImprovement = this.checkImprovement(currentMetrics, p50, action);
|
|
2602
2660
|
const tick = currentMetrics.tick;
|
|
2661
|
+
if (this.beforeViolationsCache.size > 0 && !this.beforeViolationsCache.has(tick)) {
|
|
2662
|
+
this.beforeViolationsCache.clear();
|
|
2663
|
+
}
|
|
2603
2664
|
let beforeViolations = this.beforeViolationsCache.get(tick);
|
|
2604
2665
|
if (!beforeViolations) {
|
|
2605
2666
|
beforeViolations = new Set(
|
|
@@ -2676,19 +2737,21 @@ var Simulator = class {
|
|
|
2676
2737
|
flowEffect(action, metrics) {
|
|
2677
2738
|
const { parameter, direction } = action;
|
|
2678
2739
|
const sign = direction === "increase" ? -1 : 1;
|
|
2679
|
-
|
|
2740
|
+
const roleEntries = Object.entries(metrics.populationByRole).sort((a, b) => b[1] - a[1]);
|
|
2741
|
+
const dominantRoleCount = roleEntries[0]?.[1] ?? 0;
|
|
2742
|
+
if (parameter === "productionCost") {
|
|
2680
2743
|
return sign * metrics.netFlow * 0.2;
|
|
2681
2744
|
}
|
|
2682
|
-
if (parameter === "
|
|
2745
|
+
if (parameter === "transactionFee") {
|
|
2683
2746
|
return sign * metrics.velocity * 10 * 0.1;
|
|
2684
2747
|
}
|
|
2685
|
-
if (parameter === "
|
|
2686
|
-
return sign *
|
|
2748
|
+
if (parameter === "entryFee") {
|
|
2749
|
+
return sign * dominantRoleCount * 0.5;
|
|
2687
2750
|
}
|
|
2688
|
-
if (parameter === "
|
|
2689
|
-
return -sign *
|
|
2751
|
+
if (parameter === "rewardRate") {
|
|
2752
|
+
return -sign * dominantRoleCount * 0.3;
|
|
2690
2753
|
}
|
|
2691
|
-
if (parameter === "
|
|
2754
|
+
if (parameter === "yieldRate") {
|
|
2692
2755
|
return sign * metrics.faucetVolume * 0.15;
|
|
2693
2756
|
}
|
|
2694
2757
|
return sign * metrics.netFlow * 0.1;
|
|
@@ -3001,30 +3064,33 @@ var RingBuffer = class {
|
|
|
3001
3064
|
}
|
|
3002
3065
|
};
|
|
3003
3066
|
var MetricStore = class {
|
|
3004
|
-
constructor() {
|
|
3067
|
+
constructor(tickConfig) {
|
|
3005
3068
|
/** Fine: last 200 ticks, one entry per tick */
|
|
3006
3069
|
this.fine = new RingBuffer(200);
|
|
3007
|
-
/** Medium: last 200 windows
|
|
3070
|
+
/** Medium: last 200 windows */
|
|
3008
3071
|
this.medium = new RingBuffer(200);
|
|
3009
|
-
/** Coarse: last 200 epochs
|
|
3072
|
+
/** Coarse: last 200 epochs */
|
|
3010
3073
|
this.coarse = new RingBuffer(200);
|
|
3011
3074
|
this.ticksSinceLastMedium = 0;
|
|
3012
3075
|
this.ticksSinceLastCoarse = 0;
|
|
3013
3076
|
this.mediumAccumulator = [];
|
|
3014
3077
|
this.coarseAccumulator = [];
|
|
3078
|
+
const config = { ...DEFAULT_TICK_CONFIG, ...tickConfig };
|
|
3079
|
+
this.mediumWindow = config.mediumWindow;
|
|
3080
|
+
this.coarseWindow = config.coarseWindow;
|
|
3015
3081
|
}
|
|
3016
3082
|
record(metrics) {
|
|
3017
3083
|
this.fine.push(metrics);
|
|
3018
3084
|
this.mediumAccumulator.push(metrics);
|
|
3019
3085
|
this.ticksSinceLastMedium++;
|
|
3020
|
-
if (this.ticksSinceLastMedium >=
|
|
3086
|
+
if (this.ticksSinceLastMedium >= this.mediumWindow) {
|
|
3021
3087
|
this.medium.push(this.aggregate(this.mediumAccumulator));
|
|
3022
3088
|
this.mediumAccumulator = [];
|
|
3023
3089
|
this.ticksSinceLastMedium = 0;
|
|
3024
3090
|
}
|
|
3025
3091
|
this.coarseAccumulator.push(metrics);
|
|
3026
3092
|
this.ticksSinceLastCoarse++;
|
|
3027
|
-
if (this.ticksSinceLastCoarse >=
|
|
3093
|
+
if (this.ticksSinceLastCoarse >= this.coarseWindow) {
|
|
3028
3094
|
this.coarse.push(this.aggregate(this.coarseAccumulator));
|
|
3029
3095
|
this.coarseAccumulator = [];
|
|
3030
3096
|
this.ticksSinceLastCoarse = 0;
|
|
@@ -3124,7 +3190,7 @@ var PersonaTracker = class {
|
|
|
3124
3190
|
/** Classify all agents and return persona distribution */
|
|
3125
3191
|
getDistribution() {
|
|
3126
3192
|
const counts = {
|
|
3127
|
-
|
|
3193
|
+
Active: 0,
|
|
3128
3194
|
Trader: 0,
|
|
3129
3195
|
Collector: 0,
|
|
3130
3196
|
Speculator: 0,
|
|
@@ -3148,7 +3214,7 @@ var PersonaTracker = class {
|
|
|
3148
3214
|
return distribution;
|
|
3149
3215
|
}
|
|
3150
3216
|
classify(history) {
|
|
3151
|
-
if (history.length === 0) return "
|
|
3217
|
+
if (history.length === 0) return "Active";
|
|
3152
3218
|
const avg = (key) => {
|
|
3153
3219
|
const vals = history.map((h) => h[key]);
|
|
3154
3220
|
return vals.reduce((s, v) => s + v, 0) / vals.length;
|
|
@@ -3162,21 +3228,18 @@ var PersonaTracker = class {
|
|
|
3162
3228
|
if (uniqueItems > 5 && extraction < 0) return "Collector";
|
|
3163
3229
|
if (extraction > 100) return "Earner";
|
|
3164
3230
|
if (extraction > 50) return "Speculator";
|
|
3165
|
-
return "
|
|
3231
|
+
return "Active";
|
|
3166
3232
|
}
|
|
3167
3233
|
};
|
|
3168
3234
|
|
|
3169
3235
|
// src/AgentE.ts
|
|
3170
3236
|
var AgentE = class {
|
|
3171
3237
|
constructor(config) {
|
|
3172
|
-
// ── Pipeline ──
|
|
3173
|
-
this.observer = new Observer();
|
|
3174
3238
|
this.simulator = new Simulator();
|
|
3175
3239
|
this.planner = new Planner();
|
|
3176
3240
|
this.executor = new Executor();
|
|
3177
3241
|
// ── State ──
|
|
3178
3242
|
this.log = new DecisionLog();
|
|
3179
|
-
this.store = new MetricStore();
|
|
3180
3243
|
this.personaTracker = new PersonaTracker();
|
|
3181
3244
|
this.params = {};
|
|
3182
3245
|
this.eventBuffer = [];
|
|
@@ -3195,6 +3258,7 @@ var AgentE = class {
|
|
|
3195
3258
|
mode: this.mode,
|
|
3196
3259
|
dominantRoles: config.dominantRoles ?? [],
|
|
3197
3260
|
idealDistribution: config.idealDistribution ?? {},
|
|
3261
|
+
tickConfig: config.tickConfig ?? { duration: 1, unit: "tick" },
|
|
3198
3262
|
gracePeriod: config.gracePeriod ?? 50,
|
|
3199
3263
|
checkInterval: config.checkInterval ?? 5,
|
|
3200
3264
|
maxAdjustmentPercent: config.maxAdjustmentPercent ?? 0.15,
|
|
@@ -3206,6 +3270,9 @@ var AgentE = class {
|
|
|
3206
3270
|
maxAdjustmentPercent: config.maxAdjustmentPercent ?? DEFAULT_THRESHOLDS.maxAdjustmentPercent,
|
|
3207
3271
|
cooldownTicks: config.cooldownTicks ?? DEFAULT_THRESHOLDS.cooldownTicks
|
|
3208
3272
|
};
|
|
3273
|
+
const tickConfig = { ...DEFAULT_TICK_CONFIG, ...config.tickConfig };
|
|
3274
|
+
this.observer = new Observer(tickConfig);
|
|
3275
|
+
this.store = new MetricStore(tickConfig);
|
|
3209
3276
|
this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
|
|
3210
3277
|
if (config.onDecision) this.on("decision", config.onDecision);
|
|
3211
3278
|
if (config.onAlert) this.on("alert", config.onAlert);
|
|
@@ -3237,7 +3304,7 @@ var AgentE = class {
|
|
|
3237
3304
|
this.isRunning = false;
|
|
3238
3305
|
this.isPaused = false;
|
|
3239
3306
|
}
|
|
3240
|
-
// ── Main cycle (call once per tick from your
|
|
3307
|
+
// ── Main cycle (call once per tick from your economy loop) ─────────────────
|
|
3241
3308
|
async tick(state) {
|
|
3242
3309
|
if (!this.isRunning || this.isPaused) return;
|
|
3243
3310
|
const currentState = state ?? await Promise.resolve(this.adapter.getState());
|