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