@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.mjs
CHANGED
|
@@ -31,8 +31,8 @@ var DEFAULT_THRESHOLDS = {
|
|
|
31
31
|
maxAdjustmentPercent: 0.15,
|
|
32
32
|
cooldownTicks: 15,
|
|
33
33
|
// Currency (P13)
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
poolWinRate: 0.65,
|
|
35
|
+
poolHouseCut: 0.1,
|
|
36
36
|
// Population balance (P9)
|
|
37
37
|
roleSwitchFrictionMax: 0.05,
|
|
38
38
|
// >5% of population switching in one period = herd
|
|
@@ -63,7 +63,7 @@ var DEFAULT_THRESHOLDS = {
|
|
|
63
63
|
disposalTradeWeightDiscount: 0.5
|
|
64
64
|
};
|
|
65
65
|
var PERSONA_HEALTHY_RANGES = {
|
|
66
|
-
|
|
66
|
+
Active: { min: 0.2, max: 0.4 },
|
|
67
67
|
Trader: { min: 0.05, max: 0.15 },
|
|
68
68
|
Collector: { min: 0.05, max: 0.15 },
|
|
69
69
|
Speculator: { min: 0, max: 0.1 },
|
|
@@ -73,14 +73,21 @@ var PERSONA_HEALTHY_RANGES = {
|
|
|
73
73
|
Whale: { min: 0, max: 0.05 },
|
|
74
74
|
Influencer: { min: 0, max: 0.05 }
|
|
75
75
|
};
|
|
76
|
+
var DEFAULT_TICK_CONFIG = {
|
|
77
|
+
duration: 1,
|
|
78
|
+
unit: "tick",
|
|
79
|
+
mediumWindow: 10,
|
|
80
|
+
coarseWindow: 100
|
|
81
|
+
};
|
|
76
82
|
|
|
77
83
|
// src/Observer.ts
|
|
78
84
|
var Observer = class {
|
|
79
|
-
constructor() {
|
|
85
|
+
constructor(tickConfig) {
|
|
80
86
|
this.previousMetrics = null;
|
|
81
87
|
this.previousPrices = {};
|
|
82
88
|
this.customMetricFns = {};
|
|
83
89
|
this.anchorBaseline = null;
|
|
90
|
+
this.tickConfig = { ...DEFAULT_TICK_CONFIG, ...tickConfig };
|
|
84
91
|
}
|
|
85
92
|
registerCustomMetric(name, fn) {
|
|
86
93
|
this.customMetricFns[name] = fn;
|
|
@@ -95,6 +102,7 @@ var Observer = class {
|
|
|
95
102
|
const tradeEvents = [];
|
|
96
103
|
const roleChangeEvents = [];
|
|
97
104
|
let churnCount = 0;
|
|
105
|
+
let productionAmount = 0;
|
|
98
106
|
for (const e of recentEvents) {
|
|
99
107
|
switch (e.type) {
|
|
100
108
|
case "mint":
|
|
@@ -105,6 +113,9 @@ var Observer = class {
|
|
|
105
113
|
case "consume":
|
|
106
114
|
sinkVolume += e.amount ?? 0;
|
|
107
115
|
break;
|
|
116
|
+
case "produce":
|
|
117
|
+
productionAmount += e.amount ?? 1;
|
|
118
|
+
break;
|
|
108
119
|
case "trade":
|
|
109
120
|
tradeEvents.push(e);
|
|
110
121
|
break;
|
|
@@ -178,24 +189,24 @@ var Observer = class {
|
|
|
178
189
|
pinchPoints[resource] = "optimal";
|
|
179
190
|
}
|
|
180
191
|
}
|
|
181
|
-
const productionIndex =
|
|
192
|
+
const productionIndex = productionAmount;
|
|
182
193
|
const maxPossibleProduction = productionIndex + sinkVolume;
|
|
183
194
|
const capacityUsage = maxPossibleProduction > 0 ? productionIndex / maxPossibleProduction : 0;
|
|
184
195
|
const satisfactions = Object.values(state.agentSatisfaction ?? {});
|
|
185
196
|
const avgSatisfaction = satisfactions.length > 0 ? satisfactions.reduce((s, v) => s + v, 0) / satisfactions.length : 80;
|
|
186
197
|
const blockedAgentCount = satisfactions.filter((s) => s < 20).length;
|
|
187
|
-
const timeToValue =
|
|
198
|
+
const timeToValue = totalAgents > 0 ? blockedAgentCount / totalAgents * 100 : 0;
|
|
188
199
|
const poolSizes = { ...state.poolSizes ?? {} };
|
|
189
200
|
if (!this.anchorBaseline && tick === 1 && totalSupply > 0) {
|
|
190
201
|
this.anchorBaseline = {
|
|
191
|
-
|
|
192
|
-
|
|
202
|
+
currencyPerPeriod: totalSupply / Math.max(1, totalAgents),
|
|
203
|
+
itemsPerCurrency: priceIndex > 0 ? 1 / priceIndex : 0
|
|
193
204
|
};
|
|
194
205
|
}
|
|
195
206
|
let anchorRatioDrift = 0;
|
|
196
207
|
if (this.anchorBaseline && totalAgents > 0) {
|
|
197
|
-
const
|
|
198
|
-
anchorRatioDrift = this.anchorBaseline.
|
|
208
|
+
const currentCurrencyPerPeriod = totalSupply / totalAgents;
|
|
209
|
+
anchorRatioDrift = this.anchorBaseline.currencyPerPeriod > 0 ? (currentCurrencyPerPeriod - this.anchorBaseline.currencyPerPeriod) / this.anchorBaseline.currencyPerPeriod : 0;
|
|
199
210
|
}
|
|
200
211
|
let arbitrageIndex = 0;
|
|
201
212
|
const priceKeys = Object.keys(prices).filter((k) => prices[k] > 0);
|
|
@@ -420,7 +431,7 @@ var P1_ProductionMatchesConsumption = {
|
|
|
420
431
|
id: "P1",
|
|
421
432
|
name: "Production Must Match Consumption",
|
|
422
433
|
category: "supply_chain",
|
|
423
|
-
description: "If producer rate < consumer rate, supply deficit kills the economy.
|
|
434
|
+
description: "If producer rate < consumer rate, supply deficit kills the economy. Raw materials piling at production locations happened because this was out of balance.",
|
|
424
435
|
check(metrics, _thresholds) {
|
|
425
436
|
const { supplyByResource, demandSignals, populationByRole } = metrics;
|
|
426
437
|
const violations = [];
|
|
@@ -431,19 +442,22 @@ var P1_ProductionMatchesConsumption = {
|
|
|
431
442
|
violations.push(resource);
|
|
432
443
|
}
|
|
433
444
|
}
|
|
434
|
-
const
|
|
435
|
-
const
|
|
436
|
-
const
|
|
437
|
-
|
|
445
|
+
const roleEntries = Object.entries(populationByRole).sort((a, b) => b[1] - a[1]);
|
|
446
|
+
const totalPop = metrics.totalAgents;
|
|
447
|
+
const dominantRole = roleEntries[0];
|
|
448
|
+
const dominantCount = dominantRole?.[1] ?? 0;
|
|
449
|
+
const dominantShare = totalPop > 0 ? dominantCount / totalPop : 0;
|
|
450
|
+
const populationImbalance = dominantShare > 0.4 && violations.length > 0;
|
|
451
|
+
if (violations.length > 0 || populationImbalance) {
|
|
438
452
|
return {
|
|
439
453
|
violated: true,
|
|
440
454
|
severity: 7,
|
|
441
|
-
evidence: { scarceResources: violations,
|
|
455
|
+
evidence: { scarceResources: violations, dominantRole: dominantRole?.[0], dominantShare },
|
|
442
456
|
suggestedAction: {
|
|
443
|
-
parameter: "
|
|
457
|
+
parameter: "productionCost",
|
|
444
458
|
direction: "decrease",
|
|
445
459
|
magnitude: 0.15,
|
|
446
|
-
reasoning: "Lower
|
|
460
|
+
reasoning: "Lower production cost to incentivise more production."
|
|
447
461
|
},
|
|
448
462
|
confidence: violations.length > 0 ? 0.85 : 0.6,
|
|
449
463
|
estimatedLag: 10
|
|
@@ -456,26 +470,28 @@ var P2_ClosedLoopsNeedDirectHandoff = {
|
|
|
456
470
|
id: "P2",
|
|
457
471
|
name: "Closed Loops Need Direct Handoff",
|
|
458
472
|
category: "supply_chain",
|
|
459
|
-
description: "Raw materials listed on an open market create noise and liquidity problems. Gatherers delivering
|
|
473
|
+
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.",
|
|
460
474
|
check(metrics, _thresholds) {
|
|
461
|
-
const { supplyByResource, prices, velocity } = metrics;
|
|
462
|
-
const
|
|
463
|
-
const
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
475
|
+
const { supplyByResource, prices, velocity, totalAgents } = metrics;
|
|
476
|
+
const avgSupplyPerAgent = totalAgents > 0 ? Object.values(supplyByResource).reduce((s, v) => s + v, 0) / totalAgents : 0;
|
|
477
|
+
const backlogResources = [];
|
|
478
|
+
for (const [resource, supply] of Object.entries(supplyByResource)) {
|
|
479
|
+
const price = prices[resource] ?? 0;
|
|
480
|
+
if (supply > avgSupplyPerAgent * 0.5 && price > 0) {
|
|
481
|
+
backlogResources.push(resource);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
468
484
|
const stagnant = velocity < 3;
|
|
469
|
-
if (
|
|
485
|
+
if (backlogResources.length > 0 && stagnant) {
|
|
470
486
|
return {
|
|
471
487
|
violated: true,
|
|
472
488
|
severity: 5,
|
|
473
|
-
evidence: {
|
|
489
|
+
evidence: { backlogResources, velocity },
|
|
474
490
|
suggestedAction: {
|
|
475
|
-
parameter: "
|
|
491
|
+
parameter: "transactionFee",
|
|
476
492
|
direction: "increase",
|
|
477
493
|
magnitude: 0.2,
|
|
478
|
-
reasoning: "Raise
|
|
494
|
+
reasoning: "Raise market fees to discourage raw material listings. Direct hand-off at production zones is the correct channel."
|
|
479
495
|
},
|
|
480
496
|
confidence: 0.7,
|
|
481
497
|
estimatedLag: 5
|
|
@@ -488,29 +504,31 @@ var P3_BootstrapCapitalCoversFirstTransaction = {
|
|
|
488
504
|
id: "P3",
|
|
489
505
|
name: "Bootstrap Capital Covers First Transaction",
|
|
490
506
|
category: "supply_chain",
|
|
491
|
-
description: "A new producer must be able to afford their first transaction without selling anything first.
|
|
507
|
+
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.",
|
|
492
508
|
check(metrics, _thresholds) {
|
|
493
|
-
const { populationByRole, supplyByResource, prices } = metrics;
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
509
|
+
const { populationByRole, supplyByResource, prices, totalAgents } = metrics;
|
|
510
|
+
const totalProducers = Object.values(populationByRole).reduce((s, v) => s + v, 0);
|
|
511
|
+
if (totalProducers > 0) {
|
|
512
|
+
for (const [resource, supply] of Object.entries(supplyByResource)) {
|
|
513
|
+
if (supply === 0) {
|
|
514
|
+
const anyInputPriced = Object.values(prices).some((p) => p > 0);
|
|
515
|
+
if (anyInputPriced) {
|
|
516
|
+
return {
|
|
517
|
+
violated: true,
|
|
518
|
+
severity: 8,
|
|
519
|
+
evidence: { resource, totalProducers, supply },
|
|
520
|
+
suggestedAction: {
|
|
521
|
+
parameter: "productionCost",
|
|
522
|
+
direction: "decrease",
|
|
523
|
+
magnitude: 0.3,
|
|
524
|
+
reasoning: "Producers cannot complete first transaction. Lower production cost to unblock bootstrap."
|
|
525
|
+
},
|
|
526
|
+
confidence: 0.8,
|
|
527
|
+
estimatedLag: 3
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
514
532
|
}
|
|
515
533
|
return { violated: false };
|
|
516
534
|
}
|
|
@@ -519,41 +537,38 @@ var P4_MaterialsFlowFasterThanCooldown = {
|
|
|
519
537
|
id: "P4",
|
|
520
538
|
name: "Materials Flow Faster Than Cooldown",
|
|
521
539
|
category: "supply_chain",
|
|
522
|
-
description: "Input delivery rate must exceed or match production cooldown rate. If
|
|
540
|
+
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.",
|
|
523
541
|
check(metrics, _thresholds) {
|
|
524
|
-
const { supplyByResource, populationByRole, velocity } = metrics;
|
|
525
|
-
const
|
|
526
|
-
const
|
|
527
|
-
const
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
if (producers > 0 && gathererToProcuderRatio < 0.5 && velocity < 5) {
|
|
542
|
+
const { supplyByResource, populationByRole, velocity, totalAgents } = metrics;
|
|
543
|
+
const totalSupply = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
544
|
+
const avgSupplyPerAgent = totalAgents > 0 ? totalSupply / totalAgents : 0;
|
|
545
|
+
const roleEntries = Object.entries(populationByRole);
|
|
546
|
+
const totalRoles = roleEntries.length;
|
|
547
|
+
if (totalRoles >= 2 && velocity < 5 && avgSupplyPerAgent < 0.5) {
|
|
531
548
|
return {
|
|
532
549
|
violated: true,
|
|
533
550
|
severity: 5,
|
|
534
|
-
evidence: {
|
|
551
|
+
evidence: { avgSupplyPerAgent, velocity, totalRoles },
|
|
535
552
|
suggestedAction: {
|
|
536
|
-
parameter: "
|
|
553
|
+
parameter: "yieldRate",
|
|
537
554
|
direction: "increase",
|
|
538
555
|
magnitude: 0.15,
|
|
539
|
-
reasoning: "
|
|
556
|
+
reasoning: "Low supply per agent with stagnant velocity. Increase yield to compensate."
|
|
540
557
|
},
|
|
541
558
|
confidence: 0.65,
|
|
542
559
|
estimatedLag: 8
|
|
543
560
|
};
|
|
544
561
|
}
|
|
545
|
-
|
|
546
|
-
const wood = supplyByResource["wood"] ?? 0;
|
|
547
|
-
if (ore > 80 || wood > 80) {
|
|
562
|
+
if (avgSupplyPerAgent > 2) {
|
|
548
563
|
return {
|
|
549
564
|
violated: true,
|
|
550
565
|
severity: 4,
|
|
551
|
-
evidence: {
|
|
566
|
+
evidence: { avgSupplyPerAgent, totalSupply, totalAgents },
|
|
552
567
|
suggestedAction: {
|
|
553
|
-
parameter: "
|
|
568
|
+
parameter: "yieldRate",
|
|
554
569
|
direction: "decrease",
|
|
555
570
|
magnitude: 0.2,
|
|
556
|
-
reasoning: "Raw materials piling up.
|
|
571
|
+
reasoning: "Raw materials piling up. Extractors outpacing producers."
|
|
557
572
|
},
|
|
558
573
|
confidence: 0.8,
|
|
559
574
|
estimatedLag: 5
|
|
@@ -578,7 +593,7 @@ var P60_SurplusDisposalAsymmetry = {
|
|
|
578
593
|
discount: thresholds.disposalTradeWeightDiscount
|
|
579
594
|
},
|
|
580
595
|
suggestedAction: {
|
|
581
|
-
parameter: "
|
|
596
|
+
parameter: "productionCost",
|
|
582
597
|
direction: "decrease",
|
|
583
598
|
magnitude: 0.1,
|
|
584
599
|
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.`
|
|
@@ -603,7 +618,7 @@ var P5_ProfitabilityIsCompetitive = {
|
|
|
603
618
|
id: "P5",
|
|
604
619
|
name: "Profitability Is Competitive, Not Absolute",
|
|
605
620
|
category: "incentive",
|
|
606
|
-
description: "Any profitability formula that returns the same number regardless of how many agents are already in that role will cause stampedes. 97
|
|
621
|
+
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.",
|
|
607
622
|
check(metrics, thresholds) {
|
|
608
623
|
const { roleShares, populationByRole } = metrics;
|
|
609
624
|
const highShareRoles = [];
|
|
@@ -621,7 +636,7 @@ var P5_ProfitabilityIsCompetitive = {
|
|
|
621
636
|
population: populationByRole[dominantRole]
|
|
622
637
|
},
|
|
623
638
|
suggestedAction: {
|
|
624
|
-
parameter: "
|
|
639
|
+
parameter: "transactionFee",
|
|
625
640
|
direction: "increase",
|
|
626
641
|
magnitude: thresholds.maxAdjustmentPercent,
|
|
627
642
|
reasoning: `${dominantRole} share at ${((roleShares[dominantRole] ?? 0) * 100).toFixed(0)}%. Likely stampede from non-competitive profitability formula. Raise market friction to slow role accumulation.`
|
|
@@ -647,7 +662,7 @@ var P6_CrowdingMultiplierOnAllRoles = {
|
|
|
647
662
|
severity: 5,
|
|
648
663
|
evidence: { role, share },
|
|
649
664
|
suggestedAction: {
|
|
650
|
-
parameter: "
|
|
665
|
+
parameter: "productionCost",
|
|
651
666
|
direction: "increase",
|
|
652
667
|
magnitude: 0.1,
|
|
653
668
|
reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 no crowding pressure detected. Apply role-specific cost increase to simulate saturation.`
|
|
@@ -664,28 +679,33 @@ var P7_NonSpecialistsSubsidiseSpecialists = {
|
|
|
664
679
|
id: "P7",
|
|
665
680
|
name: "Non-Specialists Subsidise Specialists in Zero-Sum Games",
|
|
666
681
|
category: "incentive",
|
|
667
|
-
description: "In zero-sum pools (
|
|
682
|
+
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.",
|
|
668
683
|
check(metrics, _thresholds) {
|
|
669
|
-
const {
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
684
|
+
const { poolSizes } = metrics;
|
|
685
|
+
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
686
|
+
if (poolSize <= 0) continue;
|
|
687
|
+
const roleEntries = Object.entries(metrics.populationByRole);
|
|
688
|
+
if (roleEntries.length === 0) continue;
|
|
689
|
+
const [dominantRole, dominantPop] = roleEntries.reduce(
|
|
690
|
+
(max, entry) => entry[1] > max[1] ? entry : max
|
|
691
|
+
);
|
|
692
|
+
const total = metrics.totalAgents;
|
|
693
|
+
const dominantShare = dominantPop / Math.max(1, total);
|
|
694
|
+
if (dominantShare > 0.7 && poolSize < 100) {
|
|
695
|
+
return {
|
|
696
|
+
violated: true,
|
|
697
|
+
severity: 6,
|
|
698
|
+
evidence: { poolName, poolSize, dominantRole, dominantShare },
|
|
699
|
+
suggestedAction: {
|
|
700
|
+
parameter: "entryFee",
|
|
701
|
+
direction: "decrease",
|
|
702
|
+
magnitude: 0.1,
|
|
703
|
+
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.`
|
|
704
|
+
},
|
|
705
|
+
confidence: 0.75,
|
|
706
|
+
estimatedLag: 5
|
|
707
|
+
};
|
|
708
|
+
}
|
|
689
709
|
}
|
|
690
710
|
return { violated: false };
|
|
691
711
|
}
|
|
@@ -694,7 +714,7 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
694
714
|
id: "P8",
|
|
695
715
|
name: "Regulator Cannot Fight the Design",
|
|
696
716
|
category: "incentive",
|
|
697
|
-
description: "If the economy is designed to have a majority role (e.g. 55%
|
|
717
|
+
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.",
|
|
698
718
|
check(metrics, _thresholds) {
|
|
699
719
|
const { roleShares, avgSatisfaction } = metrics;
|
|
700
720
|
if (avgSatisfaction < 45) {
|
|
@@ -705,7 +725,7 @@ var P8_RegulatorCannotFightDesign = {
|
|
|
705
725
|
severity: 4,
|
|
706
726
|
evidence: { dominantRole: dominantRole[0], share: dominantRole[1], avgSatisfaction },
|
|
707
727
|
suggestedAction: {
|
|
708
|
-
parameter: "
|
|
728
|
+
parameter: "rewardRate",
|
|
709
729
|
direction: "increase",
|
|
710
730
|
magnitude: 0.1,
|
|
711
731
|
reasoning: `Low satisfaction with ${dominantRole[0]} dominant. Regulator may be suppressing a structurally necessary role. Ease pressure on dominant role rewards.`
|
|
@@ -740,7 +760,7 @@ var P9_RoleSwitchingNeedsFriction = {
|
|
|
740
760
|
severity: 5,
|
|
741
761
|
evidence: { totalChurnRate: totalChurn, churnByRole },
|
|
742
762
|
suggestedAction: {
|
|
743
|
-
parameter: "
|
|
763
|
+
parameter: "productionCost",
|
|
744
764
|
direction: "increase",
|
|
745
765
|
magnitude: 0.05,
|
|
746
766
|
reasoning: `Role switch rate ${(totalChurn * 100).toFixed(1)}% exceeds friction threshold. Increase production costs to slow herd movement.`
|
|
@@ -757,7 +777,7 @@ var P10_SpawnWeightingUsesInversePopulation = {
|
|
|
757
777
|
id: "P10",
|
|
758
778
|
name: "Spawn Weighting Uses Inverse Population",
|
|
759
779
|
category: "population",
|
|
760
|
-
description: "New agents should preferentially fill the least-populated roles. Flat
|
|
780
|
+
description: "New agents should preferentially fill the least-populated roles. Flat entry probability causes initial imbalances to compound.",
|
|
761
781
|
check(metrics, _thresholds) {
|
|
762
782
|
const { roleShares } = metrics;
|
|
763
783
|
if (Object.keys(roleShares).length === 0) return { violated: false };
|
|
@@ -772,10 +792,10 @@ var P10_SpawnWeightingUsesInversePopulation = {
|
|
|
772
792
|
severity: 4,
|
|
773
793
|
evidence: { roleShares, stdDev, leastPopulatedRole: minRole?.[0] },
|
|
774
794
|
suggestedAction: {
|
|
775
|
-
parameter: "
|
|
795
|
+
parameter: "yieldRate",
|
|
776
796
|
direction: "increase",
|
|
777
797
|
magnitude: 0.05,
|
|
778
|
-
reasoning: `High role share variance (\u03C3=${stdDev.toFixed(2)}).
|
|
798
|
+
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.`
|
|
779
799
|
},
|
|
780
800
|
confidence: 0.6,
|
|
781
801
|
estimatedLag: 20
|
|
@@ -798,7 +818,7 @@ var P11_TwoTierPressure = {
|
|
|
798
818
|
severity: 6,
|
|
799
819
|
evidence: { role, share },
|
|
800
820
|
suggestedAction: {
|
|
801
|
-
parameter: "
|
|
821
|
+
parameter: "transactionFee",
|
|
802
822
|
direction: "increase",
|
|
803
823
|
magnitude: 0.15,
|
|
804
824
|
reasoning: `${role} at ${(share * 100).toFixed(0)}% \u2014 continuous pressure was insufficient. Hard intervention needed alongside resumed continuous pressure.`
|
|
@@ -826,7 +846,7 @@ var P46_PersonaDiversity = {
|
|
|
826
846
|
severity: 5,
|
|
827
847
|
evidence: { dominantPersona: persona, share, personaDistribution },
|
|
828
848
|
suggestedAction: {
|
|
829
|
-
parameter: "
|
|
849
|
+
parameter: "rewardRate",
|
|
830
850
|
direction: "increase",
|
|
831
851
|
magnitude: 0.1,
|
|
832
852
|
reasoning: `${persona} persona at ${(share * 100).toFixed(0)}% \u2014 behavioral monoculture. Diversify reward structures to attract other persona types.`
|
|
@@ -843,7 +863,7 @@ var P46_PersonaDiversity = {
|
|
|
843
863
|
severity: 3,
|
|
844
864
|
evidence: { significantClusters, required: thresholds.personaMinClusters },
|
|
845
865
|
suggestedAction: {
|
|
846
|
-
parameter: "
|
|
866
|
+
parameter: "transactionFee",
|
|
847
867
|
direction: "decrease",
|
|
848
868
|
magnitude: 0.05,
|
|
849
869
|
reasoning: `Only ${significantClusters} significant persona clusters (need ${thresholds.personaMinClusters}). Lower trade barriers to attract non-dominant persona types.`
|
|
@@ -867,7 +887,7 @@ var P12_OnePrimaryFaucet = {
|
|
|
867
887
|
id: "P12",
|
|
868
888
|
name: "One Primary Faucet",
|
|
869
889
|
category: "currency",
|
|
870
|
-
description: "Multiple independent currency sources (gathering +
|
|
890
|
+
description: "Multiple independent currency sources (gathering + production + quests) each creating currency causes uncontrolled inflation. One clear primary faucet makes the economy predictable and auditable.",
|
|
871
891
|
check(metrics, thresholds) {
|
|
872
892
|
const { netFlow, faucetVolume, sinkVolume } = metrics;
|
|
873
893
|
if (netFlow > thresholds.netFlowWarnThreshold) {
|
|
@@ -876,10 +896,10 @@ var P12_OnePrimaryFaucet = {
|
|
|
876
896
|
severity: 5,
|
|
877
897
|
evidence: { netFlow, faucetVolume, sinkVolume },
|
|
878
898
|
suggestedAction: {
|
|
879
|
-
parameter: "
|
|
899
|
+
parameter: "productionCost",
|
|
880
900
|
direction: "increase",
|
|
881
901
|
magnitude: 0.15,
|
|
882
|
-
reasoning: `Net flow +${netFlow.toFixed(1)}
|
|
902
|
+
reasoning: `Net flow +${netFlow.toFixed(1)}/tick. Inflationary. Increase production cost (primary sink) to balance faucet output.`
|
|
883
903
|
},
|
|
884
904
|
confidence: 0.8,
|
|
885
905
|
estimatedLag: 8
|
|
@@ -891,10 +911,10 @@ var P12_OnePrimaryFaucet = {
|
|
|
891
911
|
severity: 4,
|
|
892
912
|
evidence: { netFlow, faucetVolume, sinkVolume },
|
|
893
913
|
suggestedAction: {
|
|
894
|
-
parameter: "
|
|
914
|
+
parameter: "productionCost",
|
|
895
915
|
direction: "decrease",
|
|
896
916
|
magnitude: 0.15,
|
|
897
|
-
reasoning: `Net flow ${netFlow.toFixed(1)}
|
|
917
|
+
reasoning: `Net flow ${netFlow.toFixed(1)}/tick. Deflationary. Decrease production cost to ease sink pressure.`
|
|
898
918
|
},
|
|
899
919
|
confidence: 0.8,
|
|
900
920
|
estimatedLag: 8
|
|
@@ -907,36 +927,40 @@ var P13_PotsAreZeroSumAndSelfRegulate = {
|
|
|
907
927
|
id: "P13",
|
|
908
928
|
name: "Pots Self-Regulate with Correct Multiplier",
|
|
909
929
|
category: "currency",
|
|
910
|
-
description: "
|
|
930
|
+
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.",
|
|
911
931
|
check(metrics, thresholds) {
|
|
912
|
-
const { poolSizes } = metrics;
|
|
913
|
-
const
|
|
914
|
-
const
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
932
|
+
const { poolSizes, populationByRole } = metrics;
|
|
933
|
+
const totalAgents = metrics.totalAgents;
|
|
934
|
+
const roleEntries = Object.entries(populationByRole).sort((a, b) => b[1] - a[1]);
|
|
935
|
+
const dominantRole = roleEntries[0]?.[0];
|
|
936
|
+
const dominantCount = roleEntries[0]?.[1] ?? 0;
|
|
937
|
+
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
938
|
+
if (dominantCount > 5 && poolSize < 50) {
|
|
939
|
+
const { poolWinRate, poolHouseCut } = thresholds;
|
|
940
|
+
const maxSustainableMultiplier = (1 - poolHouseCut) / poolWinRate;
|
|
941
|
+
return {
|
|
942
|
+
violated: true,
|
|
943
|
+
severity: 7,
|
|
944
|
+
evidence: { pool: poolName, poolSize, participants: dominantCount, maxSustainableMultiplier },
|
|
945
|
+
suggestedAction: {
|
|
946
|
+
parameter: "rewardRate",
|
|
947
|
+
direction: "decrease",
|
|
948
|
+
magnitude: 0.15,
|
|
949
|
+
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.`
|
|
950
|
+
},
|
|
951
|
+
confidence: 0.85,
|
|
952
|
+
estimatedLag: 3
|
|
953
|
+
};
|
|
954
|
+
}
|
|
931
955
|
}
|
|
932
956
|
return { violated: false };
|
|
933
957
|
}
|
|
934
958
|
};
|
|
935
959
|
var P14_TrackActualInjection = {
|
|
936
960
|
id: "P14",
|
|
937
|
-
name: "Track Actual
|
|
961
|
+
name: "Track Actual Currency Injection, Not Value Creation",
|
|
938
962
|
category: "currency",
|
|
939
|
-
description: 'Counting resource gathering as "
|
|
963
|
+
description: 'Counting resource gathering as "currency injected" is misleading. Currency enters through faucet mechanisms (spawning, rewards). Fake metrics break every downstream decision.',
|
|
940
964
|
check(metrics, _thresholds) {
|
|
941
965
|
const { faucetVolume, netFlow, totalSupply } = metrics;
|
|
942
966
|
const supplyGrowthRate = Math.abs(netFlow) / Math.max(1, totalSupply);
|
|
@@ -946,10 +970,10 @@ var P14_TrackActualInjection = {
|
|
|
946
970
|
severity: 4,
|
|
947
971
|
evidence: { faucetVolume, netFlow, supplyGrowthRate },
|
|
948
972
|
suggestedAction: {
|
|
949
|
-
parameter: "
|
|
973
|
+
parameter: "yieldRate",
|
|
950
974
|
direction: "decrease",
|
|
951
975
|
magnitude: 0.1,
|
|
952
|
-
reasoning: `Supply growing at ${(supplyGrowthRate * 100).toFixed(1)}%/tick. Verify
|
|
976
|
+
reasoning: `Supply growing at ${(supplyGrowthRate * 100).toFixed(1)}%/tick. Verify currency injection tracking. Resources should not create currency directly.`
|
|
953
977
|
},
|
|
954
978
|
confidence: 0.55,
|
|
955
979
|
estimatedLag: 5
|
|
@@ -962,12 +986,11 @@ var P15_PoolsNeedCapAndDecay = {
|
|
|
962
986
|
id: "P15",
|
|
963
987
|
name: "Pools Need Cap + Decay",
|
|
964
988
|
category: "currency",
|
|
965
|
-
description: "Any pool (bank, reward pool) without a cap accumulates infinitely.
|
|
989
|
+
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.",
|
|
966
990
|
check(metrics, thresholds) {
|
|
967
991
|
const { poolSizes, totalSupply } = metrics;
|
|
968
992
|
const { poolCapPercent } = thresholds;
|
|
969
993
|
for (const [pool, size] of Object.entries(poolSizes)) {
|
|
970
|
-
if (pool === "arena" || pool === "arenaPot") continue;
|
|
971
994
|
const shareOfSupply = size / Math.max(1, totalSupply);
|
|
972
995
|
if (shareOfSupply > poolCapPercent * 2) {
|
|
973
996
|
return {
|
|
@@ -975,10 +998,10 @@ var P15_PoolsNeedCapAndDecay = {
|
|
|
975
998
|
severity: 6,
|
|
976
999
|
evidence: { pool, size, shareOfSupply, cap: poolCapPercent },
|
|
977
1000
|
suggestedAction: {
|
|
978
|
-
parameter: "
|
|
1001
|
+
parameter: "transactionFee",
|
|
979
1002
|
direction: "decrease",
|
|
980
1003
|
magnitude: 0.1,
|
|
981
|
-
reasoning: `${pool} pool at ${(shareOfSupply * 100).toFixed(1)}% of supply (cap: ${(poolCapPercent * 100).toFixed(0)}%).
|
|
1004
|
+
reasoning: `${pool} pool at ${(shareOfSupply * 100).toFixed(1)}% of supply (cap: ${(poolCapPercent * 100).toFixed(0)}%). Currency frozen. Lower fees to encourage circulation over accumulation.`
|
|
982
1005
|
},
|
|
983
1006
|
confidence: 0.85,
|
|
984
1007
|
estimatedLag: 5
|
|
@@ -995,22 +1018,23 @@ var P16_WithdrawalPenaltyScales = {
|
|
|
995
1018
|
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.",
|
|
996
1019
|
check(metrics, _thresholds) {
|
|
997
1020
|
const { poolSizes, totalSupply } = metrics;
|
|
998
|
-
const bankPool = poolSizes["bank"] ?? poolSizes["bankPool"] ?? 0;
|
|
999
1021
|
const stakedEstimate = totalSupply * 0.15;
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1022
|
+
for (const [poolName, poolSize] of Object.entries(poolSizes)) {
|
|
1023
|
+
if (poolSize < 10 && stakedEstimate > 100) {
|
|
1024
|
+
return {
|
|
1025
|
+
violated: true,
|
|
1026
|
+
severity: 3,
|
|
1027
|
+
evidence: { pool: poolName, poolSize, estimatedStaked: stakedEstimate },
|
|
1028
|
+
suggestedAction: {
|
|
1029
|
+
parameter: "transactionFee",
|
|
1030
|
+
direction: "increase",
|
|
1031
|
+
magnitude: 0.05,
|
|
1032
|
+
reasoning: `${poolName} pool depleted while significant currency should be locked. Early withdrawals may be draining the pool. Ensure withdrawal penalty scales with lock duration.`
|
|
1033
|
+
},
|
|
1034
|
+
confidence: 0.45,
|
|
1035
|
+
estimatedLag: 10
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1014
1038
|
}
|
|
1015
1039
|
return { violated: false };
|
|
1016
1040
|
}
|
|
@@ -1029,7 +1053,7 @@ var P32_VelocityAboveSupply = {
|
|
|
1029
1053
|
severity: 4,
|
|
1030
1054
|
evidence: { velocity, totalSupply, totalResources },
|
|
1031
1055
|
suggestedAction: {
|
|
1032
|
-
parameter: "
|
|
1056
|
+
parameter: "transactionFee",
|
|
1033
1057
|
direction: "decrease",
|
|
1034
1058
|
magnitude: 0.2,
|
|
1035
1059
|
reasoning: `Velocity ${velocity}/t with ${totalResources} resources in system. Economy stagnant despite available supply. Lower trading friction.`
|
|
@@ -1065,7 +1089,7 @@ var P58_NoNaturalNumeraire = {
|
|
|
1065
1089
|
meanPrice: mean
|
|
1066
1090
|
},
|
|
1067
1091
|
suggestedAction: {
|
|
1068
|
-
parameter: "
|
|
1092
|
+
parameter: "productionCost",
|
|
1069
1093
|
direction: "increase",
|
|
1070
1094
|
magnitude: 0.1,
|
|
1071
1095
|
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.`
|
|
@@ -1092,7 +1116,7 @@ var P17_GracePeriodBeforeIntervention = {
|
|
|
1092
1116
|
id: "P17",
|
|
1093
1117
|
name: "Grace Period Before Intervention",
|
|
1094
1118
|
category: "bootstrap",
|
|
1095
|
-
description: "Any intervention before tick 50 is premature. The economy needs time to bootstrap with designed distributions. AgentE intervening at tick 1 against 55%
|
|
1119
|
+
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.",
|
|
1096
1120
|
check(metrics, _thresholds) {
|
|
1097
1121
|
if (metrics.tick < 30 && metrics.avgSatisfaction < 40) {
|
|
1098
1122
|
return {
|
|
@@ -1100,7 +1124,7 @@ var P17_GracePeriodBeforeIntervention = {
|
|
|
1100
1124
|
severity: 7,
|
|
1101
1125
|
evidence: { tick: metrics.tick, avgSatisfaction: metrics.avgSatisfaction },
|
|
1102
1126
|
suggestedAction: {
|
|
1103
|
-
parameter: "
|
|
1127
|
+
parameter: "entryFee",
|
|
1104
1128
|
direction: "decrease",
|
|
1105
1129
|
magnitude: 0.2,
|
|
1106
1130
|
reasoning: `Very low satisfaction at tick ${metrics.tick}. Intervention may have fired during grace period. Ease all costs to let economy bootstrap.`
|
|
@@ -1116,27 +1140,26 @@ var P18_FirstProducerNeedsStartingInventory = {
|
|
|
1116
1140
|
id: "P18",
|
|
1117
1141
|
name: "First Producer Needs Starting Inventory + Capital",
|
|
1118
1142
|
category: "bootstrap",
|
|
1119
|
-
description: "A
|
|
1143
|
+
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.",
|
|
1120
1144
|
check(metrics, _thresholds) {
|
|
1121
1145
|
if (metrics.tick > 20) return { violated: false };
|
|
1122
|
-
const
|
|
1123
|
-
const
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
};
|
|
1146
|
+
const hasAgents = metrics.totalAgents > 0;
|
|
1147
|
+
for (const [resource, supply] of Object.entries(metrics.supplyByResource)) {
|
|
1148
|
+
if (supply === 0 && hasAgents) {
|
|
1149
|
+
return {
|
|
1150
|
+
violated: true,
|
|
1151
|
+
severity: 8,
|
|
1152
|
+
evidence: { tick: metrics.tick, resource, supply, totalAgents: metrics.totalAgents },
|
|
1153
|
+
suggestedAction: {
|
|
1154
|
+
parameter: "productionCost",
|
|
1155
|
+
direction: "decrease",
|
|
1156
|
+
magnitude: 0.5,
|
|
1157
|
+
reasoning: `Bootstrap failure: ${resource} supply is 0 at tick ${metrics.tick} with ${metrics.totalAgents} agents. Drastically reduce production cost to allow immediate output.`
|
|
1158
|
+
},
|
|
1159
|
+
confidence: 0.9,
|
|
1160
|
+
estimatedLag: 2
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1140
1163
|
}
|
|
1141
1164
|
return { violated: false };
|
|
1142
1165
|
}
|
|
@@ -1145,22 +1168,32 @@ var P19_StartingSupplyExceedsDemand = {
|
|
|
1145
1168
|
id: "P19",
|
|
1146
1169
|
name: "Starting Supply Exceeds Initial Demand",
|
|
1147
1170
|
category: "bootstrap",
|
|
1148
|
-
description: "Launch with more consumables than you think you need. Early scarcity creates
|
|
1171
|
+
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.",
|
|
1149
1172
|
check(metrics, _thresholds) {
|
|
1150
1173
|
if (metrics.tick > 30) return { violated: false };
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
const
|
|
1154
|
-
|
|
1174
|
+
const roleEntries = Object.entries(metrics.populationByRole);
|
|
1175
|
+
if (roleEntries.length === 0) return { violated: false };
|
|
1176
|
+
const [mostPopulatedRole, population] = roleEntries.reduce(
|
|
1177
|
+
(max, entry) => entry[1] > max[1] ? entry : max
|
|
1178
|
+
);
|
|
1179
|
+
if (population < 5) return { violated: false };
|
|
1180
|
+
const totalResourceSupply = Object.values(metrics.supplyByResource).reduce((sum, s) => sum + s, 0);
|
|
1181
|
+
const resourcesPerAgent = totalResourceSupply / Math.max(1, population);
|
|
1182
|
+
if (resourcesPerAgent < 0.5) {
|
|
1155
1183
|
return {
|
|
1156
1184
|
violated: true,
|
|
1157
1185
|
severity: 6,
|
|
1158
|
-
evidence: {
|
|
1186
|
+
evidence: {
|
|
1187
|
+
mostPopulatedRole,
|
|
1188
|
+
population,
|
|
1189
|
+
totalResourceSupply,
|
|
1190
|
+
resourcesPerAgent
|
|
1191
|
+
},
|
|
1159
1192
|
suggestedAction: {
|
|
1160
|
-
parameter: "
|
|
1193
|
+
parameter: "rewardRate",
|
|
1161
1194
|
direction: "increase",
|
|
1162
1195
|
magnitude: 0.2,
|
|
1163
|
-
reasoning: `${
|
|
1196
|
+
reasoning: `${mostPopulatedRole} (${population} agents) has insufficient resources (${resourcesPerAgent.toFixed(2)} per agent). Cold-start scarcity. Boost competitive pool reward to attract participation despite scarcity.`
|
|
1164
1197
|
},
|
|
1165
1198
|
confidence: 0.75,
|
|
1166
1199
|
estimatedLag: 5
|
|
@@ -1180,7 +1213,7 @@ var P20_DecayPreventsAccumulation = {
|
|
|
1180
1213
|
id: "P20",
|
|
1181
1214
|
name: "Decay Prevents Accumulation",
|
|
1182
1215
|
category: "feedback",
|
|
1183
|
-
description: "Resources without decay create infinite hoarding. A
|
|
1216
|
+
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.",
|
|
1184
1217
|
check(metrics, _thresholds) {
|
|
1185
1218
|
const { supplyByResource, velocity, totalAgents } = metrics;
|
|
1186
1219
|
const totalResources = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
@@ -1191,7 +1224,7 @@ var P20_DecayPreventsAccumulation = {
|
|
|
1191
1224
|
severity: 4,
|
|
1192
1225
|
evidence: { totalResources, resourcesPerAgent, velocity },
|
|
1193
1226
|
suggestedAction: {
|
|
1194
|
-
parameter: "
|
|
1227
|
+
parameter: "yieldRate",
|
|
1195
1228
|
direction: "decrease",
|
|
1196
1229
|
magnitude: 0.1,
|
|
1197
1230
|
reasoning: `${totalResources.toFixed(0)} resources with velocity ${velocity}/t. Likely hoarding. Reduce yield to increase scarcity and force circulation.`
|
|
@@ -1207,7 +1240,7 @@ var P21_PriceFromGlobalSupply = {
|
|
|
1207
1240
|
id: "P21",
|
|
1208
1241
|
name: "Price Reflects Global Supply, Not Just AH Listings",
|
|
1209
1242
|
category: "feedback",
|
|
1210
|
-
description: "If prices only update from
|
|
1243
|
+
description: "If prices only update from market activity, agents with hoarded inventory see artificially high prices and keep gathering when they should stop.",
|
|
1211
1244
|
check(metrics, _thresholds) {
|
|
1212
1245
|
const { priceVolatility, supplyByResource, prices } = metrics;
|
|
1213
1246
|
for (const resource of Object.keys(prices)) {
|
|
@@ -1219,7 +1252,7 @@ var P21_PriceFromGlobalSupply = {
|
|
|
1219
1252
|
severity: 3,
|
|
1220
1253
|
evidence: { resource, volatility, supply, price: prices[resource] },
|
|
1221
1254
|
suggestedAction: {
|
|
1222
|
-
parameter: "
|
|
1255
|
+
parameter: "transactionFee",
|
|
1223
1256
|
direction: "increase",
|
|
1224
1257
|
magnitude: 0.05,
|
|
1225
1258
|
reasoning: `${resource} price volatile (${(volatility * 100).toFixed(0)}%) despite supply ${supply}. Price may not reflect global inventory. Increase trading friction to stabilise.`
|
|
@@ -1239,23 +1272,36 @@ var P22_MarketAwarenessPreventsSurplus = {
|
|
|
1239
1272
|
description: "Producers who craft without checking market prices will create surpluses that crash prices. Agents need to see prices before deciding to produce.",
|
|
1240
1273
|
check(metrics, _thresholds) {
|
|
1241
1274
|
const { supplyByResource, prices, productionIndex } = metrics;
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1275
|
+
const priceValues = Object.values(prices).filter((p) => p > 0);
|
|
1276
|
+
if (priceValues.length === 0) return { violated: false };
|
|
1277
|
+
const sortedPrices = [...priceValues].sort((a, b) => a - b);
|
|
1278
|
+
const medianPrice = sortedPrices[Math.floor(sortedPrices.length / 2)] ?? 0;
|
|
1279
|
+
for (const [resource, price] of Object.entries(prices)) {
|
|
1280
|
+
if (price <= 0) continue;
|
|
1281
|
+
const supply = supplyByResource[resource] ?? 0;
|
|
1282
|
+
const priceDeviation = price / Math.max(1, medianPrice);
|
|
1283
|
+
if (priceDeviation < 0.33 && supply > 100 && productionIndex > 0) {
|
|
1284
|
+
return {
|
|
1285
|
+
violated: true,
|
|
1286
|
+
severity: 4,
|
|
1287
|
+
evidence: {
|
|
1288
|
+
resource,
|
|
1289
|
+
price,
|
|
1290
|
+
medianPrice,
|
|
1291
|
+
priceDeviation,
|
|
1292
|
+
supply,
|
|
1293
|
+
productionIndex
|
|
1294
|
+
},
|
|
1295
|
+
suggestedAction: {
|
|
1296
|
+
parameter: "productionCost",
|
|
1297
|
+
direction: "increase",
|
|
1298
|
+
magnitude: 0.1,
|
|
1299
|
+
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.`
|
|
1300
|
+
},
|
|
1301
|
+
confidence: 0.7,
|
|
1302
|
+
estimatedLag: 8
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1259
1305
|
}
|
|
1260
1306
|
return { violated: false };
|
|
1261
1307
|
}
|
|
@@ -1264,7 +1310,7 @@ var P23_ProfitabilityFactorsFeasibility = {
|
|
|
1264
1310
|
id: "P23",
|
|
1265
1311
|
name: "Profitability Factors Execution Feasibility",
|
|
1266
1312
|
category: "feedback",
|
|
1267
|
-
description: "An agent who calculates profit =
|
|
1313
|
+
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.",
|
|
1268
1314
|
check(metrics, _thresholds) {
|
|
1269
1315
|
const { avgSatisfaction, blockedAgentCount, totalAgents } = metrics;
|
|
1270
1316
|
const blockedFraction = blockedAgentCount / Math.max(1, totalAgents);
|
|
@@ -1274,7 +1320,7 @@ var P23_ProfitabilityFactorsFeasibility = {
|
|
|
1274
1320
|
severity: 5,
|
|
1275
1321
|
evidence: { blockedFraction, blockedAgentCount, avgSatisfaction },
|
|
1276
1322
|
suggestedAction: {
|
|
1277
|
-
parameter: "
|
|
1323
|
+
parameter: "productionCost",
|
|
1278
1324
|
direction: "decrease",
|
|
1279
1325
|
magnitude: 0.15,
|
|
1280
1326
|
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.`
|
|
@@ -1300,7 +1346,7 @@ var P24_BlockedAgentsDecayFaster = {
|
|
|
1300
1346
|
severity: 5,
|
|
1301
1347
|
evidence: { blockedFraction, blockedAgentCount, churnRate },
|
|
1302
1348
|
suggestedAction: {
|
|
1303
|
-
parameter: "
|
|
1349
|
+
parameter: "transactionFee",
|
|
1304
1350
|
direction: "decrease",
|
|
1305
1351
|
magnitude: 0.15,
|
|
1306
1352
|
reasoning: `${(blockedFraction * 100).toFixed(0)}% of agents blocked. Blocked agents churn silently, skewing metrics. Lower fees to unblock market participation.`
|
|
@@ -1325,26 +1371,35 @@ var P25_CorrectLeversForCorrectProblems = {
|
|
|
1325
1371
|
id: "P25",
|
|
1326
1372
|
name: "Target the Correct Lever",
|
|
1327
1373
|
category: "regulator",
|
|
1328
|
-
description: "Adjusting sinks for supply-side inflation is wrong. Inflation from too much gathering \u2192 reduce
|
|
1374
|
+
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.",
|
|
1329
1375
|
check(metrics, thresholds) {
|
|
1330
1376
|
const { netFlow, supplyByResource } = metrics;
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
const
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1377
|
+
const resourceEntries = Object.entries(supplyByResource);
|
|
1378
|
+
if (resourceEntries.length === 0) return { violated: false };
|
|
1379
|
+
const totalSupply = resourceEntries.reduce((sum, [_, s]) => sum + s, 0);
|
|
1380
|
+
const avgSupply = totalSupply / resourceEntries.length;
|
|
1381
|
+
for (const [resource, supply] of resourceEntries) {
|
|
1382
|
+
if (supply > avgSupply * 3 && netFlow > thresholds.netFlowWarnThreshold) {
|
|
1383
|
+
return {
|
|
1384
|
+
violated: true,
|
|
1385
|
+
severity: 4,
|
|
1386
|
+
evidence: {
|
|
1387
|
+
resource,
|
|
1388
|
+
supply,
|
|
1389
|
+
avgSupply,
|
|
1390
|
+
ratio: supply / Math.max(1, avgSupply),
|
|
1391
|
+
netFlow
|
|
1392
|
+
},
|
|
1393
|
+
suggestedAction: {
|
|
1394
|
+
parameter: "yieldRate",
|
|
1395
|
+
direction: "decrease",
|
|
1396
|
+
magnitude: 0.15,
|
|
1397
|
+
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.`
|
|
1398
|
+
},
|
|
1399
|
+
confidence: 0.75,
|
|
1400
|
+
estimatedLag: 8
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1348
1403
|
}
|
|
1349
1404
|
return { violated: false };
|
|
1350
1405
|
}
|
|
@@ -1362,7 +1417,7 @@ var P26_ContinuousPressureBeatsThresholdCuts = {
|
|
|
1362
1417
|
severity: 4,
|
|
1363
1418
|
evidence: { inflationRate },
|
|
1364
1419
|
suggestedAction: {
|
|
1365
|
-
parameter: "
|
|
1420
|
+
parameter: "productionCost",
|
|
1366
1421
|
direction: inflationRate > 0 ? "increase" : "decrease",
|
|
1367
1422
|
magnitude: Math.min(thresholds.maxAdjustmentPercent, 0.05),
|
|
1368
1423
|
// force smaller step
|
|
@@ -1388,7 +1443,7 @@ var P27_AdjustmentsNeedCooldowns = {
|
|
|
1388
1443
|
severity: 4,
|
|
1389
1444
|
evidence: { churnRate, avgSatisfaction },
|
|
1390
1445
|
suggestedAction: {
|
|
1391
|
-
parameter: "
|
|
1446
|
+
parameter: "entryFee",
|
|
1392
1447
|
direction: "decrease",
|
|
1393
1448
|
magnitude: 0.05,
|
|
1394
1449
|
reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) with low satisfaction. Possible oscillation from rapid adjustments. Apply small correction only.`
|
|
@@ -1404,7 +1459,7 @@ var P28_StructuralDominanceIsNotPathological = {
|
|
|
1404
1459
|
id: "P28",
|
|
1405
1460
|
name: "Structural Dominance \u2260 Pathological Monopoly",
|
|
1406
1461
|
category: "regulator",
|
|
1407
|
-
description: 'A designed
|
|
1462
|
+
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".',
|
|
1408
1463
|
check(metrics, _thresholds) {
|
|
1409
1464
|
const { roleShares, avgSatisfaction } = metrics;
|
|
1410
1465
|
const dominant = Object.entries(roleShares).sort((a, b) => b[1] - a[1])[0];
|
|
@@ -1419,7 +1474,7 @@ var P28_StructuralDominanceIsNotPathological = {
|
|
|
1419
1474
|
severity: 5,
|
|
1420
1475
|
evidence: { dominantRole, dominantShare, avgSatisfaction },
|
|
1421
1476
|
suggestedAction: {
|
|
1422
|
-
parameter: "
|
|
1477
|
+
parameter: "productionCost",
|
|
1423
1478
|
direction: "decrease",
|
|
1424
1479
|
magnitude: 0.1,
|
|
1425
1480
|
reasoning: `${dominantRole} dominant (${(dominantShare * 100).toFixed(0)}%) with low satisfaction. Pathological dominance \u2014 agents trapped, not thriving. Ease costs to allow role switching.`
|
|
@@ -1444,7 +1499,7 @@ var P38_CommunicationPreventsRevolt = {
|
|
|
1444
1499
|
severity: 3,
|
|
1445
1500
|
evidence: { churnRate },
|
|
1446
1501
|
suggestedAction: {
|
|
1447
|
-
parameter: "
|
|
1502
|
+
parameter: "rewardRate",
|
|
1448
1503
|
direction: "increase",
|
|
1449
1504
|
magnitude: 0.1,
|
|
1450
1505
|
reasoning: `High churn (${(churnRate * 100).toFixed(1)}%) \u2014 agents leaving. Ensure all recent adjustments are logged with reasoning to diagnose cause.`
|
|
@@ -1469,7 +1524,7 @@ var P29_PinchPoint = {
|
|
|
1469
1524
|
id: "P29",
|
|
1470
1525
|
name: "Pinch Point",
|
|
1471
1526
|
category: "market_dynamics",
|
|
1472
|
-
description: "Every economy has a resource that constrains all downstream activity.
|
|
1527
|
+
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.",
|
|
1473
1528
|
check(metrics, _thresholds) {
|
|
1474
1529
|
const { pinchPoints, supplyByResource, demandSignals } = metrics;
|
|
1475
1530
|
for (const [resource, status] of Object.entries(pinchPoints)) {
|
|
@@ -1481,7 +1536,7 @@ var P29_PinchPoint = {
|
|
|
1481
1536
|
severity: 7,
|
|
1482
1537
|
evidence: { resource, supply, demand, status },
|
|
1483
1538
|
suggestedAction: {
|
|
1484
|
-
parameter: "
|
|
1539
|
+
parameter: "productionCost",
|
|
1485
1540
|
direction: "decrease",
|
|
1486
1541
|
magnitude: 0.15,
|
|
1487
1542
|
reasoning: `${resource} is a pinch point and currently SCARCE (supply ${supply}, demand ${demand}). Reduce production cost to increase throughput.`
|
|
@@ -1497,7 +1552,7 @@ var P29_PinchPoint = {
|
|
|
1497
1552
|
severity: 4,
|
|
1498
1553
|
evidence: { resource, supply, status },
|
|
1499
1554
|
suggestedAction: {
|
|
1500
|
-
parameter: "
|
|
1555
|
+
parameter: "productionCost",
|
|
1501
1556
|
direction: "increase",
|
|
1502
1557
|
magnitude: 0.1,
|
|
1503
1558
|
reasoning: `${resource} is a pinch point and OVERSUPPLIED (supply ${supply}). Raise production cost to reduce surplus.`
|
|
@@ -1514,7 +1569,7 @@ var P30_MovingPinchPoint = {
|
|
|
1514
1569
|
id: "P30",
|
|
1515
1570
|
name: "Moving Pinch Point",
|
|
1516
1571
|
category: "market_dynamics",
|
|
1517
|
-
description: "
|
|
1572
|
+
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.",
|
|
1518
1573
|
check(metrics, _thresholds) {
|
|
1519
1574
|
const { capacityUsage, supplyByResource, avgSatisfaction } = metrics;
|
|
1520
1575
|
const totalResources = Object.values(supplyByResource).reduce((s, v) => s + v, 0);
|
|
@@ -1525,7 +1580,7 @@ var P30_MovingPinchPoint = {
|
|
|
1525
1580
|
severity: 3,
|
|
1526
1581
|
evidence: { capacityUsage, resourcesPerAgent, avgSatisfaction },
|
|
1527
1582
|
suggestedAction: {
|
|
1528
|
-
parameter: "
|
|
1583
|
+
parameter: "productionCost",
|
|
1529
1584
|
direction: "increase",
|
|
1530
1585
|
magnitude: 0.1,
|
|
1531
1586
|
reasoning: "Economy operating at full capacity with abundant resources and high satisfaction. Pinch point may have been cleared. Increase production cost to restore scarcity."
|
|
@@ -1571,7 +1626,7 @@ var P57_CombinatorialPriceSpace = {
|
|
|
1571
1626
|
target: thresholds.relativePriceConvergenceTarget
|
|
1572
1627
|
},
|
|
1573
1628
|
suggestedAction: {
|
|
1574
|
-
parameter: "
|
|
1629
|
+
parameter: "transactionFee",
|
|
1575
1630
|
direction: "decrease",
|
|
1576
1631
|
magnitude: 0.1,
|
|
1577
1632
|
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.`
|
|
@@ -1594,7 +1649,7 @@ var P31_AnchorValueTracking = {
|
|
|
1594
1649
|
id: "P31",
|
|
1595
1650
|
name: "Anchor Value Tracking",
|
|
1596
1651
|
category: "measurement",
|
|
1597
|
-
description: "1
|
|
1652
|
+
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.",
|
|
1598
1653
|
check(metrics, _thresholds) {
|
|
1599
1654
|
const { anchorRatioDrift, inflationRate } = metrics;
|
|
1600
1655
|
if (Math.abs(anchorRatioDrift) > 0.25) {
|
|
@@ -1603,10 +1658,10 @@ var P31_AnchorValueTracking = {
|
|
|
1603
1658
|
severity: 5,
|
|
1604
1659
|
evidence: { anchorRatioDrift, inflationRate },
|
|
1605
1660
|
suggestedAction: {
|
|
1606
|
-
parameter: "
|
|
1661
|
+
parameter: "productionCost",
|
|
1607
1662
|
direction: anchorRatioDrift > 0 ? "increase" : "decrease",
|
|
1608
1663
|
magnitude: 0.1,
|
|
1609
|
-
reasoning: `Anchor ratio has drifted ${(anchorRatioDrift * 100).toFixed(0)}% from baseline. Time-to-value for
|
|
1664
|
+
reasoning: `Anchor ratio has drifted ${(anchorRatioDrift * 100).toFixed(0)}% from baseline. Time-to-value for participants is changing. Adjust production costs to restore.`
|
|
1610
1665
|
},
|
|
1611
1666
|
confidence: 0.65,
|
|
1612
1667
|
estimatedLag: 10
|
|
@@ -1628,7 +1683,7 @@ var P41_MultiResolutionMonitoring = {
|
|
|
1628
1683
|
severity: 4,
|
|
1629
1684
|
evidence: { giniCoefficient, avgSatisfaction },
|
|
1630
1685
|
suggestedAction: {
|
|
1631
|
-
parameter: "
|
|
1686
|
+
parameter: "transactionFee",
|
|
1632
1687
|
direction: "increase",
|
|
1633
1688
|
magnitude: 0.1,
|
|
1634
1689
|
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.`
|
|
@@ -1657,7 +1712,7 @@ var P55_ArbitrageThermometer = {
|
|
|
1657
1712
|
critical: thresholds.arbitrageIndexCritical
|
|
1658
1713
|
},
|
|
1659
1714
|
suggestedAction: {
|
|
1660
|
-
parameter: "
|
|
1715
|
+
parameter: "transactionFee",
|
|
1661
1716
|
direction: "decrease",
|
|
1662
1717
|
magnitude: 0.15,
|
|
1663
1718
|
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.`
|
|
@@ -1675,7 +1730,7 @@ var P55_ArbitrageThermometer = {
|
|
|
1675
1730
|
warning: thresholds.arbitrageIndexWarning
|
|
1676
1731
|
},
|
|
1677
1732
|
suggestedAction: {
|
|
1678
|
-
parameter: "
|
|
1733
|
+
parameter: "transactionFee",
|
|
1679
1734
|
direction: "decrease",
|
|
1680
1735
|
magnitude: 0.08,
|
|
1681
1736
|
reasoning: `Arbitrage index ${arbitrageIndex.toFixed(2)} above warning threshold (${thresholds.arbitrageIndexWarning}). Early sign of price divergence. Gently reduce friction to support self-correction.`
|
|
@@ -1703,7 +1758,7 @@ var P59_GiftEconomyNoise = {
|
|
|
1703
1758
|
threshold: thresholds.giftTradeFilterRatio
|
|
1704
1759
|
},
|
|
1705
1760
|
suggestedAction: {
|
|
1706
|
-
parameter: "
|
|
1761
|
+
parameter: "transactionFee",
|
|
1707
1762
|
direction: "increase",
|
|
1708
1763
|
magnitude: 0.05,
|
|
1709
1764
|
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.`
|
|
@@ -1727,7 +1782,7 @@ var P42_TheMedianPrinciple = {
|
|
|
1727
1782
|
id: "P42",
|
|
1728
1783
|
name: "The Median Principle",
|
|
1729
1784
|
category: "statistical",
|
|
1730
|
-
description: "When (mean - median) / median > 0.3, mean is a lie. A few
|
|
1785
|
+
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%.",
|
|
1731
1786
|
check(metrics, thresholds) {
|
|
1732
1787
|
const { meanMedianDivergence, giniCoefficient } = metrics;
|
|
1733
1788
|
if (meanMedianDivergence > thresholds.meanMedianDivergenceMax) {
|
|
@@ -1741,10 +1796,10 @@ var P42_TheMedianPrinciple = {
|
|
|
1741
1796
|
medianBalance: metrics.medianBalance
|
|
1742
1797
|
},
|
|
1743
1798
|
suggestedAction: {
|
|
1744
|
-
parameter: "
|
|
1799
|
+
parameter: "transactionFee",
|
|
1745
1800
|
direction: "increase",
|
|
1746
1801
|
magnitude: 0.15,
|
|
1747
|
-
reasoning: `Mean/median divergence ${(meanMedianDivergence * 100).toFixed(0)}% (threshold: ${(thresholds.meanMedianDivergenceMax * 100).toFixed(0)}%). Economy has outliers skewing metrics. Use median for decisions. Raise
|
|
1802
|
+
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.`
|
|
1748
1803
|
},
|
|
1749
1804
|
confidence: 0.85,
|
|
1750
1805
|
estimatedLag: 15
|
|
@@ -1766,7 +1821,7 @@ var P43_SimulationMinimum = {
|
|
|
1766
1821
|
severity: 3,
|
|
1767
1822
|
evidence: { inflationRate, minIterations: thresholds.simulationMinIterations },
|
|
1768
1823
|
suggestedAction: {
|
|
1769
|
-
parameter: "
|
|
1824
|
+
parameter: "productionCost",
|
|
1770
1825
|
direction: inflationRate > 0 ? "increase" : "decrease",
|
|
1771
1826
|
magnitude: 0.05,
|
|
1772
1827
|
reasoning: `Large inflation rate swing (${(inflationRate * 100).toFixed(0)}%). Ensure all decisions use \u2265${thresholds.simulationMinIterations} simulation iterations. Apply conservative correction.`
|
|
@@ -1804,7 +1859,7 @@ var P39_TheLagPrinciple = {
|
|
|
1804
1859
|
severity: 5,
|
|
1805
1860
|
evidence: { inflationRate, netFlow, lagRange: [lagMin, lagMax] },
|
|
1806
1861
|
suggestedAction: {
|
|
1807
|
-
parameter: "
|
|
1862
|
+
parameter: "productionCost",
|
|
1808
1863
|
direction: "increase",
|
|
1809
1864
|
magnitude: 0.03,
|
|
1810
1865
|
// very small — oscillation means over-adjusting
|
|
@@ -1831,7 +1886,7 @@ var P44_ComplexityBudget = {
|
|
|
1831
1886
|
severity: 3,
|
|
1832
1887
|
evidence: { customMetricCount, budgetMax: thresholds.complexityBudgetMax },
|
|
1833
1888
|
suggestedAction: {
|
|
1834
|
-
parameter: "
|
|
1889
|
+
parameter: "transactionFee",
|
|
1835
1890
|
direction: "decrease",
|
|
1836
1891
|
magnitude: 0.01,
|
|
1837
1892
|
reasoning: `${customMetricCount} custom metrics tracked (budget: ${thresholds.complexityBudgetMax}). Consider pruning low-impact parameters. Applying minimal correction to avoid adding complexity.`
|
|
@@ -1853,25 +1908,25 @@ var P35_DestructionCreatesValue = {
|
|
|
1853
1908
|
id: "P35",
|
|
1854
1909
|
name: "Destruction Creates Value",
|
|
1855
1910
|
category: "resource",
|
|
1856
|
-
description: "If nothing is ever permanently lost, inflation is inevitable.
|
|
1911
|
+
description: "If nothing is ever permanently lost, inflation is inevitable. Resource durability and consumption mechanisms create destruction. Without them, supply grows without bound.",
|
|
1857
1912
|
check(metrics, _thresholds) {
|
|
1858
1913
|
const { supplyByResource, sinkVolume, netFlow } = metrics;
|
|
1859
|
-
const
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
}
|
|
1914
|
+
for (const [resource, supply] of Object.entries(supplyByResource)) {
|
|
1915
|
+
if (supply > 200 && sinkVolume < 5 && netFlow > 0) {
|
|
1916
|
+
return {
|
|
1917
|
+
violated: true,
|
|
1918
|
+
severity: 6,
|
|
1919
|
+
evidence: { resource, supply, sinkVolume, netFlow },
|
|
1920
|
+
suggestedAction: {
|
|
1921
|
+
parameter: "entryFee",
|
|
1922
|
+
direction: "decrease",
|
|
1923
|
+
magnitude: 0.1,
|
|
1924
|
+
reasoning: `${resource} supply at ${supply} units with low destruction (sink ${sinkVolume}/t). Resources not being consumed. Lower competitive pool entry to increase resource usage.`
|
|
1925
|
+
},
|
|
1926
|
+
confidence: 0.7,
|
|
1927
|
+
estimatedLag: 5
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1875
1930
|
}
|
|
1876
1931
|
return { violated: false };
|
|
1877
1932
|
}
|
|
@@ -1891,7 +1946,7 @@ var P40_ReplacementRate = {
|
|
|
1891
1946
|
severity: 6,
|
|
1892
1947
|
evidence: { productionIndex, sinkVolume, replacementRatio },
|
|
1893
1948
|
suggestedAction: {
|
|
1894
|
-
parameter: "
|
|
1949
|
+
parameter: "yieldRate",
|
|
1895
1950
|
direction: "increase",
|
|
1896
1951
|
magnitude: 0.15,
|
|
1897
1952
|
reasoning: `Replacement rate ${replacementRatio.toFixed(2)} (need \u2265${thresholds.replacementRateMultiplier}). Production below consumption. Resources will deplete. Increase yield.`
|
|
@@ -1905,7 +1960,7 @@ var P40_ReplacementRate = {
|
|
|
1905
1960
|
severity: 3,
|
|
1906
1961
|
evidence: { productionIndex, sinkVolume, replacementRatio },
|
|
1907
1962
|
suggestedAction: {
|
|
1908
|
-
parameter: "
|
|
1963
|
+
parameter: "yieldRate",
|
|
1909
1964
|
direction: "decrease",
|
|
1910
1965
|
magnitude: 0.1,
|
|
1911
1966
|
reasoning: `Replacement rate ${replacementRatio.toFixed(2)} \u2014 overproducing. Production far exceeds consumption. Reduce yield to prevent glut.`
|
|
@@ -1931,7 +1986,7 @@ var P49_IdleAssetTax = {
|
|
|
1931
1986
|
severity: 5,
|
|
1932
1987
|
evidence: { giniCoefficient, top10PctShare, velocity },
|
|
1933
1988
|
suggestedAction: {
|
|
1934
|
-
parameter: "
|
|
1989
|
+
parameter: "transactionFee",
|
|
1935
1990
|
direction: "increase",
|
|
1936
1991
|
magnitude: 0.15,
|
|
1937
1992
|
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.`
|
|
@@ -1963,7 +2018,7 @@ var P33_FairNotEqual = {
|
|
|
1963
2018
|
severity: 3,
|
|
1964
2019
|
evidence: { giniCoefficient },
|
|
1965
2020
|
suggestedAction: {
|
|
1966
|
-
parameter: "
|
|
2021
|
+
parameter: "rewardRate",
|
|
1967
2022
|
direction: "increase",
|
|
1968
2023
|
magnitude: 0.1,
|
|
1969
2024
|
reasoning: `Gini ${giniCoefficient.toFixed(2)} \u2014 near-perfect equality. Economy lacks stakes. Increase winner rewards to create meaningful spread.`
|
|
@@ -1978,7 +2033,7 @@ var P33_FairNotEqual = {
|
|
|
1978
2033
|
severity: 7,
|
|
1979
2034
|
evidence: { giniCoefficient },
|
|
1980
2035
|
suggestedAction: {
|
|
1981
|
-
parameter: "
|
|
2036
|
+
parameter: "transactionFee",
|
|
1982
2037
|
direction: "increase",
|
|
1983
2038
|
magnitude: 0.2,
|
|
1984
2039
|
reasoning: `Gini ${giniCoefficient.toFixed(2)} \u2014 oligarchy level. Toxic inequality. Raise transaction fees to redistribute wealth from rich to pool.`
|
|
@@ -1993,7 +2048,7 @@ var P33_FairNotEqual = {
|
|
|
1993
2048
|
severity: 4,
|
|
1994
2049
|
evidence: { giniCoefficient },
|
|
1995
2050
|
suggestedAction: {
|
|
1996
|
-
parameter: "
|
|
2051
|
+
parameter: "transactionFee",
|
|
1997
2052
|
direction: "increase",
|
|
1998
2053
|
magnitude: 0.1,
|
|
1999
2054
|
reasoning: `Gini ${giniCoefficient.toFixed(2)} \u2014 high inequality warning. Gently raise fees to slow wealth concentration.`
|
|
@@ -2018,7 +2073,7 @@ var P36_MechanicFrictionDetector = {
|
|
|
2018
2073
|
severity: 5,
|
|
2019
2074
|
evidence: { churnRate, avgSatisfaction, velocity },
|
|
2020
2075
|
suggestedAction: {
|
|
2021
|
-
parameter: "
|
|
2076
|
+
parameter: "rewardRate",
|
|
2022
2077
|
direction: "increase",
|
|
2023
2078
|
magnitude: 0.15,
|
|
2024
2079
|
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."
|
|
@@ -2043,7 +2098,7 @@ var P37_LatecommerProblem = {
|
|
|
2043
2098
|
severity: 6,
|
|
2044
2099
|
evidence: { timeToValue, avgSatisfaction, churnRate },
|
|
2045
2100
|
suggestedAction: {
|
|
2046
|
-
parameter: "
|
|
2101
|
+
parameter: "productionCost",
|
|
2047
2102
|
direction: "decrease",
|
|
2048
2103
|
magnitude: 0.15,
|
|
2049
2104
|
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.`
|
|
@@ -2070,7 +2125,7 @@ var P45_TimeBudget = {
|
|
|
2070
2125
|
severity: 5,
|
|
2071
2126
|
evidence: { timeToValue, avgSatisfaction, timeBudgetRatio: thresholds.timeBudgetRatio },
|
|
2072
2127
|
suggestedAction: {
|
|
2073
|
-
parameter: "
|
|
2128
|
+
parameter: "entryFee",
|
|
2074
2129
|
direction: "decrease",
|
|
2075
2130
|
magnitude: 0.15,
|
|
2076
2131
|
reasoning: `Time-to-value ${timeToValue} ticks with ${avgSatisfaction.toFixed(0)} satisfaction. Economy requires too much time investment. Lower barriers to participation.`
|
|
@@ -2100,7 +2155,7 @@ var P50_PayPowerRatio = {
|
|
|
2100
2155
|
threshold: thresholds.payPowerRatioMax
|
|
2101
2156
|
},
|
|
2102
2157
|
suggestedAction: {
|
|
2103
|
-
parameter: "
|
|
2158
|
+
parameter: "transactionFee",
|
|
2104
2159
|
direction: "increase",
|
|
2105
2160
|
magnitude: 0.2,
|
|
2106
2161
|
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.`
|
|
@@ -2135,7 +2190,7 @@ var P34_ExtractionRatio = {
|
|
|
2135
2190
|
severity: 8,
|
|
2136
2191
|
evidence: { extractionRatio, threshold: thresholds.extractionRatioRed },
|
|
2137
2192
|
suggestedAction: {
|
|
2138
|
-
parameter: "
|
|
2193
|
+
parameter: "transactionFee",
|
|
2139
2194
|
direction: "increase",
|
|
2140
2195
|
magnitude: 0.25,
|
|
2141
2196
|
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.`
|
|
@@ -2150,7 +2205,7 @@ var P34_ExtractionRatio = {
|
|
|
2150
2205
|
severity: 5,
|
|
2151
2206
|
evidence: { extractionRatio, threshold: thresholds.extractionRatioYellow },
|
|
2152
2207
|
suggestedAction: {
|
|
2153
|
-
parameter: "
|
|
2208
|
+
parameter: "transactionFee",
|
|
2154
2209
|
direction: "increase",
|
|
2155
2210
|
magnitude: 0.1,
|
|
2156
2211
|
reasoning: `Extraction ratio ${(extractionRatio * 100).toFixed(0)}% (warning: ${(thresholds.extractionRatioYellow * 100).toFixed(0)}%). Economy trending toward extraction-heavy. Apply early pressure.`
|
|
@@ -2166,7 +2221,7 @@ var P47_SmokeTest = {
|
|
|
2166
2221
|
id: "P47",
|
|
2167
2222
|
name: "Smoke Test",
|
|
2168
2223
|
category: "open_economy",
|
|
2169
|
-
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 (
|
|
2224
|
+
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.",
|
|
2170
2225
|
check(metrics, thresholds) {
|
|
2171
2226
|
const { smokeTestRatio } = metrics;
|
|
2172
2227
|
if (isNaN(smokeTestRatio)) return { violated: false };
|
|
@@ -2176,7 +2231,7 @@ var P47_SmokeTest = {
|
|
|
2176
2231
|
severity: 9,
|
|
2177
2232
|
evidence: { smokeTestRatio, threshold: thresholds.smokeTestCritical },
|
|
2178
2233
|
suggestedAction: {
|
|
2179
|
-
parameter: "
|
|
2234
|
+
parameter: "rewardRate",
|
|
2180
2235
|
direction: "increase",
|
|
2181
2236
|
magnitude: 0.2,
|
|
2182
2237
|
reasoning: `Utility/market ratio ${(smokeTestRatio * 100).toFixed(0)}% (critical). Economy is >90% speculative. Collapse risk is extreme. Increase utility rewards to anchor real value.`
|
|
@@ -2191,7 +2246,7 @@ var P47_SmokeTest = {
|
|
|
2191
2246
|
severity: 6,
|
|
2192
2247
|
evidence: { smokeTestRatio, threshold: thresholds.smokeTestWarning },
|
|
2193
2248
|
suggestedAction: {
|
|
2194
|
-
parameter: "
|
|
2249
|
+
parameter: "rewardRate",
|
|
2195
2250
|
direction: "increase",
|
|
2196
2251
|
magnitude: 0.1,
|
|
2197
2252
|
reasoning: `Utility/market ratio ${(smokeTestRatio * 100).toFixed(0)}% (warning). Economy is >70% speculative. Boost utility rewards to restore intrinsic value anchor.`
|
|
@@ -2207,7 +2262,7 @@ var P48_CurrencyInsulation = {
|
|
|
2207
2262
|
id: "P48",
|
|
2208
2263
|
name: "Currency Insulation",
|
|
2209
2264
|
category: "open_economy",
|
|
2210
|
-
description: "Gameplay economy correlation with external markets > 0.5 = insulation failure. When your
|
|
2265
|
+
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.",
|
|
2211
2266
|
check(metrics, thresholds) {
|
|
2212
2267
|
const { currencyInsulation } = metrics;
|
|
2213
2268
|
if (isNaN(currencyInsulation)) return { violated: false };
|
|
@@ -2217,7 +2272,7 @@ var P48_CurrencyInsulation = {
|
|
|
2217
2272
|
severity: 6,
|
|
2218
2273
|
evidence: { currencyInsulation, threshold: thresholds.currencyInsulationMax },
|
|
2219
2274
|
suggestedAction: {
|
|
2220
|
-
parameter: "
|
|
2275
|
+
parameter: "transactionFee",
|
|
2221
2276
|
direction: "increase",
|
|
2222
2277
|
magnitude: 0.1,
|
|
2223
2278
|
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.`
|
|
@@ -2257,7 +2312,7 @@ var P51_SharkTooth = {
|
|
|
2257
2312
|
threshold: thresholds.sharkToothPeakDecay
|
|
2258
2313
|
},
|
|
2259
2314
|
suggestedAction: {
|
|
2260
|
-
parameter: "
|
|
2315
|
+
parameter: "rewardRate",
|
|
2261
2316
|
direction: "increase",
|
|
2262
2317
|
magnitude: 0.1,
|
|
2263
2318
|
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.`
|
|
@@ -2275,7 +2330,7 @@ var P51_SharkTooth = {
|
|
|
2275
2330
|
severity: 4,
|
|
2276
2331
|
evidence: { lastValley, prevValley, ratio: lastValley / prevValley },
|
|
2277
2332
|
suggestedAction: {
|
|
2278
|
-
parameter: "
|
|
2333
|
+
parameter: "productionCost",
|
|
2279
2334
|
direction: "decrease",
|
|
2280
2335
|
magnitude: 0.1,
|
|
2281
2336
|
reasoning: "Between-event engagement declining (deepening valleys). Base economy not sustaining participants between events. Lower production costs to improve off-event value."
|
|
@@ -2292,7 +2347,7 @@ var P52_EndowmentEffect = {
|
|
|
2292
2347
|
id: "P52",
|
|
2293
2348
|
name: "Endowment Effect",
|
|
2294
2349
|
category: "liveops",
|
|
2295
|
-
description: "
|
|
2350
|
+
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).",
|
|
2296
2351
|
check(metrics, _thresholds) {
|
|
2297
2352
|
const { avgSatisfaction, churnRate } = metrics;
|
|
2298
2353
|
const { eventCompletionRate } = metrics;
|
|
@@ -2303,7 +2358,7 @@ var P52_EndowmentEffect = {
|
|
|
2303
2358
|
severity: 4,
|
|
2304
2359
|
evidence: { eventCompletionRate, avgSatisfaction, churnRate },
|
|
2305
2360
|
suggestedAction: {
|
|
2306
|
-
parameter: "
|
|
2361
|
+
parameter: "rewardRate",
|
|
2307
2362
|
direction: "increase",
|
|
2308
2363
|
magnitude: 0.15,
|
|
2309
2364
|
reasoning: `${(eventCompletionRate * 100).toFixed(0)}% event completion but satisfaction only ${avgSatisfaction.toFixed(0)}. Events not creating perceived value. Increase reward quality/quantity.`
|
|
@@ -2333,10 +2388,10 @@ var P53_EventCompletionRate = {
|
|
|
2333
2388
|
max: thresholds.eventCompletionMax
|
|
2334
2389
|
},
|
|
2335
2390
|
suggestedAction: {
|
|
2336
|
-
parameter: "
|
|
2391
|
+
parameter: "productionCost",
|
|
2337
2392
|
direction: "decrease",
|
|
2338
2393
|
magnitude: 0.15,
|
|
2339
|
-
reasoning: `Event completion rate ${(eventCompletionRate * 100).toFixed(0)}% \u2014 predatory territory (min: ${(thresholds.eventCompletionMin * 100).toFixed(0)}%). Too hard for free
|
|
2394
|
+
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.`
|
|
2340
2395
|
},
|
|
2341
2396
|
confidence: 0.8,
|
|
2342
2397
|
estimatedLag: 10
|
|
@@ -2348,7 +2403,7 @@ var P53_EventCompletionRate = {
|
|
|
2348
2403
|
severity: 3,
|
|
2349
2404
|
evidence: { eventCompletionRate, max: thresholds.eventCompletionMax },
|
|
2350
2405
|
suggestedAction: {
|
|
2351
|
-
parameter: "
|
|
2406
|
+
parameter: "entryFee",
|
|
2352
2407
|
direction: "increase",
|
|
2353
2408
|
magnitude: 0.05,
|
|
2354
2409
|
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.`
|
|
@@ -2373,7 +2428,7 @@ var P54_LiveOpsCadence = {
|
|
|
2373
2428
|
severity: 3,
|
|
2374
2429
|
evidence: { velocity, avgSatisfaction, tick: metrics.tick },
|
|
2375
2430
|
suggestedAction: {
|
|
2376
|
-
parameter: "
|
|
2431
|
+
parameter: "rewardRate",
|
|
2377
2432
|
direction: "increase",
|
|
2378
2433
|
magnitude: 0.1,
|
|
2379
2434
|
reasoning: "Low velocity and satisfaction after long runtime. Possible content staleness. Increase rewards as bridge while new content is developed (developer action required)."
|
|
@@ -2404,7 +2459,7 @@ var P56_ContentDropShock = {
|
|
|
2404
2459
|
postDropMax: thresholds.postDropArbitrageMax
|
|
2405
2460
|
},
|
|
2406
2461
|
suggestedAction: {
|
|
2407
|
-
parameter: "
|
|
2462
|
+
parameter: "transactionFee",
|
|
2408
2463
|
direction: "decrease",
|
|
2409
2464
|
magnitude: 0.1,
|
|
2410
2465
|
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.`
|
|
@@ -2570,19 +2625,21 @@ var Simulator = class {
|
|
|
2570
2625
|
flowEffect(action, metrics) {
|
|
2571
2626
|
const { parameter, direction } = action;
|
|
2572
2627
|
const sign = direction === "increase" ? -1 : 1;
|
|
2573
|
-
|
|
2628
|
+
const roleEntries = Object.entries(metrics.populationByRole).sort((a, b) => b[1] - a[1]);
|
|
2629
|
+
const dominantRoleCount = roleEntries[0]?.[1] ?? 0;
|
|
2630
|
+
if (parameter === "productionCost") {
|
|
2574
2631
|
return sign * metrics.netFlow * 0.2;
|
|
2575
2632
|
}
|
|
2576
|
-
if (parameter === "
|
|
2633
|
+
if (parameter === "transactionFee") {
|
|
2577
2634
|
return sign * metrics.velocity * 10 * 0.1;
|
|
2578
2635
|
}
|
|
2579
|
-
if (parameter === "
|
|
2580
|
-
return sign *
|
|
2636
|
+
if (parameter === "entryFee") {
|
|
2637
|
+
return sign * dominantRoleCount * 0.5;
|
|
2581
2638
|
}
|
|
2582
|
-
if (parameter === "
|
|
2583
|
-
return -sign *
|
|
2639
|
+
if (parameter === "rewardRate") {
|
|
2640
|
+
return -sign * dominantRoleCount * 0.3;
|
|
2584
2641
|
}
|
|
2585
|
-
if (parameter === "
|
|
2642
|
+
if (parameter === "yieldRate") {
|
|
2586
2643
|
return sign * metrics.faucetVolume * 0.15;
|
|
2587
2644
|
}
|
|
2588
2645
|
return sign * metrics.netFlow * 0.1;
|
|
@@ -2895,30 +2952,33 @@ var RingBuffer = class {
|
|
|
2895
2952
|
}
|
|
2896
2953
|
};
|
|
2897
2954
|
var MetricStore = class {
|
|
2898
|
-
constructor() {
|
|
2955
|
+
constructor(tickConfig) {
|
|
2899
2956
|
/** Fine: last 200 ticks, one entry per tick */
|
|
2900
2957
|
this.fine = new RingBuffer(200);
|
|
2901
|
-
/** Medium: last 200 windows
|
|
2958
|
+
/** Medium: last 200 windows */
|
|
2902
2959
|
this.medium = new RingBuffer(200);
|
|
2903
|
-
/** Coarse: last 200 epochs
|
|
2960
|
+
/** Coarse: last 200 epochs */
|
|
2904
2961
|
this.coarse = new RingBuffer(200);
|
|
2905
2962
|
this.ticksSinceLastMedium = 0;
|
|
2906
2963
|
this.ticksSinceLastCoarse = 0;
|
|
2907
2964
|
this.mediumAccumulator = [];
|
|
2908
2965
|
this.coarseAccumulator = [];
|
|
2966
|
+
const config = { ...DEFAULT_TICK_CONFIG, ...tickConfig };
|
|
2967
|
+
this.mediumWindow = config.mediumWindow;
|
|
2968
|
+
this.coarseWindow = config.coarseWindow;
|
|
2909
2969
|
}
|
|
2910
2970
|
record(metrics) {
|
|
2911
2971
|
this.fine.push(metrics);
|
|
2912
2972
|
this.mediumAccumulator.push(metrics);
|
|
2913
2973
|
this.ticksSinceLastMedium++;
|
|
2914
|
-
if (this.ticksSinceLastMedium >=
|
|
2974
|
+
if (this.ticksSinceLastMedium >= this.mediumWindow) {
|
|
2915
2975
|
this.medium.push(this.aggregate(this.mediumAccumulator));
|
|
2916
2976
|
this.mediumAccumulator = [];
|
|
2917
2977
|
this.ticksSinceLastMedium = 0;
|
|
2918
2978
|
}
|
|
2919
2979
|
this.coarseAccumulator.push(metrics);
|
|
2920
2980
|
this.ticksSinceLastCoarse++;
|
|
2921
|
-
if (this.ticksSinceLastCoarse >=
|
|
2981
|
+
if (this.ticksSinceLastCoarse >= this.coarseWindow) {
|
|
2922
2982
|
this.coarse.push(this.aggregate(this.coarseAccumulator));
|
|
2923
2983
|
this.coarseAccumulator = [];
|
|
2924
2984
|
this.ticksSinceLastCoarse = 0;
|
|
@@ -3018,7 +3078,7 @@ var PersonaTracker = class {
|
|
|
3018
3078
|
/** Classify all agents and return persona distribution */
|
|
3019
3079
|
getDistribution() {
|
|
3020
3080
|
const counts = {
|
|
3021
|
-
|
|
3081
|
+
Active: 0,
|
|
3022
3082
|
Trader: 0,
|
|
3023
3083
|
Collector: 0,
|
|
3024
3084
|
Speculator: 0,
|
|
@@ -3042,7 +3102,7 @@ var PersonaTracker = class {
|
|
|
3042
3102
|
return distribution;
|
|
3043
3103
|
}
|
|
3044
3104
|
classify(history) {
|
|
3045
|
-
if (history.length === 0) return "
|
|
3105
|
+
if (history.length === 0) return "Active";
|
|
3046
3106
|
const avg = (key) => {
|
|
3047
3107
|
const vals = history.map((h) => h[key]);
|
|
3048
3108
|
return vals.reduce((s, v) => s + v, 0) / vals.length;
|
|
@@ -3056,21 +3116,18 @@ var PersonaTracker = class {
|
|
|
3056
3116
|
if (uniqueItems > 5 && extraction < 0) return "Collector";
|
|
3057
3117
|
if (extraction > 100) return "Earner";
|
|
3058
3118
|
if (extraction > 50) return "Speculator";
|
|
3059
|
-
return "
|
|
3119
|
+
return "Active";
|
|
3060
3120
|
}
|
|
3061
3121
|
};
|
|
3062
3122
|
|
|
3063
3123
|
// src/AgentE.ts
|
|
3064
3124
|
var AgentE = class {
|
|
3065
3125
|
constructor(config) {
|
|
3066
|
-
// ── Pipeline ──
|
|
3067
|
-
this.observer = new Observer();
|
|
3068
3126
|
this.simulator = new Simulator();
|
|
3069
3127
|
this.planner = new Planner();
|
|
3070
3128
|
this.executor = new Executor();
|
|
3071
3129
|
// ── State ──
|
|
3072
3130
|
this.log = new DecisionLog();
|
|
3073
|
-
this.store = new MetricStore();
|
|
3074
3131
|
this.personaTracker = new PersonaTracker();
|
|
3075
3132
|
this.params = {};
|
|
3076
3133
|
this.eventBuffer = [];
|
|
@@ -3089,6 +3146,7 @@ var AgentE = class {
|
|
|
3089
3146
|
mode: this.mode,
|
|
3090
3147
|
dominantRoles: config.dominantRoles ?? [],
|
|
3091
3148
|
idealDistribution: config.idealDistribution ?? {},
|
|
3149
|
+
tickConfig: config.tickConfig ?? { duration: 1, unit: "tick" },
|
|
3092
3150
|
gracePeriod: config.gracePeriod ?? 50,
|
|
3093
3151
|
checkInterval: config.checkInterval ?? 5,
|
|
3094
3152
|
maxAdjustmentPercent: config.maxAdjustmentPercent ?? 0.15,
|
|
@@ -3100,6 +3158,9 @@ var AgentE = class {
|
|
|
3100
3158
|
maxAdjustmentPercent: config.maxAdjustmentPercent ?? DEFAULT_THRESHOLDS.maxAdjustmentPercent,
|
|
3101
3159
|
cooldownTicks: config.cooldownTicks ?? DEFAULT_THRESHOLDS.cooldownTicks
|
|
3102
3160
|
};
|
|
3161
|
+
const tickConfig = { ...DEFAULT_TICK_CONFIG, ...config.tickConfig };
|
|
3162
|
+
this.observer = new Observer(tickConfig);
|
|
3163
|
+
this.store = new MetricStore(tickConfig);
|
|
3103
3164
|
this.diagnoser = new Diagnoser(ALL_PRINCIPLES);
|
|
3104
3165
|
if (config.onDecision) this.on("decision", config.onDecision);
|
|
3105
3166
|
if (config.onAlert) this.on("alert", config.onAlert);
|
|
@@ -3131,7 +3192,7 @@ var AgentE = class {
|
|
|
3131
3192
|
this.isRunning = false;
|
|
3132
3193
|
this.isPaused = false;
|
|
3133
3194
|
}
|
|
3134
|
-
// ── Main cycle (call once per tick from your
|
|
3195
|
+
// ── Main cycle (call once per tick from your economy loop) ─────────────────
|
|
3135
3196
|
async tick(state) {
|
|
3136
3197
|
if (!this.isRunning || this.isPaused) return;
|
|
3137
3198
|
const currentState = state ?? await Promise.resolve(this.adapter.getState());
|