Add simulation results paper for AI-run company implications

This commit is contained in:
2026-04-15 20:16:16 +00:00
parent 39fcec1847
commit 4345609575
4 changed files with 832 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
run_id,turns,token_supply_final,fees_total,turns_with_block,block_count_db,settled_contracts,defaulted_contracts,mean_balance_final,median_balance_final,min_balance_final,max_balance_final,negative_balance_agents,gini_wealth_final,top1_wealth_share_final,wealth_shift_used,gini_wealth_shifted,top1_wealth_shifted_share_final,validator_mine,validator_stake,validator_burn,tx_transfer,tx_stake,tx_unstake,tx_burn,tx_study,tx_job,actions_mine,actions_stake,actions_unstake,actions_burn,actions_study,actions_job,actions_transfer
1,60,-546,24753,55,55,0,0,-158.25,-151.5,-278,-85,8,-0.5677655677655677,0.0,199.0,0.2963671128107075,0.18546845124282982,55,0,0,0,9,0,1,0,0,260,9,11,1,2,197,0
2,60,-1019,24690,54,54,0,0,-197.375,-203.0,-231,-132,8,-0.13800294406280667,0.0,183.0,0.3160112359550562,0.2943820224719101,54,0,0,0,7,0,3,0,0,262,7,13,3,3,192,0
3,60,-1244,24382,53,53,0,0,-225.5,-228.5,-319,-99,8,-0.2723070739549839,0.0,240.0,0.5011094674556213,0.3269230769230769,53,0,0,0,7,0,1,0,0,258,7,17,1,4,193,0
4,60,-888,25268,55,55,0,0,-191,-187.5,-251,-131,8,-0.2038288288288288,0.0,172.0,0.37090163934426235,0.24795081967213115,55,0,0,0,8,0,2,0,0,263,8,19,2,2,186,0
5,60,-711,24946,55,55,0,0,-178.875,-166.5,-307,-60,8,-0.5209212376933896,0.0,213.0,0.3729859013091641,0.23464249748237664,55,0,0,0,9,0,3,0,0,244,9,14,3,3,207,0
6,60,-1287,25615,56,56,0,0,-230.875,-216.0,-328,-102,8,-0.22367909867909863,0.0,249.0,0.40833333333333344,0.3219858156028369,56,0,0,0,7,0,0,0,0,278,7,18,0,3,174,0
7,60,-512,23740,55,55,0,0,-154,-158.5,-242,-63,8,-0.59521484375,0.0,163.0,0.3847853535353536,0.2335858585858586,55,0,0,0,9,0,2,0,0,256,9,16,2,4,193,0
8,60,-980,22700,55,55,0,0,-212.5,-198.5,-287,-131,8,-0.26632653061224487,0.0,208.0,0.381578947368421,0.22953216374269006,55,0,0,0,9,0,2,0,0,271,9,15,2,3,180,0
9,60,-909,24198,55,55,0,0,-203.625,-192.0,-380,-81,8,-0.386001100110011,0.0,221.0,0.4084691501746216,0.3259604190919674,55,0,0,0,9,0,3,0,0,260,9,15,3,2,191,0
10,60,-870,24931,56,56,0,0,-188.75,-187.0,-342,-56,8,-0.5724137931034483,0.0,343.0,0.2657417289220918,0.19583778014941303,56,0,0,0,8,0,2,0,0,267,8,15,2,2,186,0
11,60,-1212,23754,55,55,0,0,-231.5,-235.0,-333,-132,8,-0.2460808580858086,0.0,254.0,0.363719512195122,0.24634146341463414,55,0,0,0,8,0,2,0,0,273,8,11,2,2,184,0
12,60,-797,24322,56,56,0,0,-169.625,-189.0,-271,-37,8,-0.4396173149309912,0.0,272.0,0.25407904278462645,0.22842639593908629,56,0,0,0,7,0,2,0,0,266,7,13,2,2,190,0
13,60,-879,25235,55,55,0,0,-189.875,-165.0,-339,-98,8,-0.38694539249146753,0.0,260.0,0.2832014987510407,0.20149875104079934,55,0,0,0,8,0,3,0,0,254,8,23,3,2,190,0
14,60,-857,24614,54,54,0,0,-187.125,-159.0,-357,-44,8,-0.5917444574095683,0.0,278.0,0.37097659107534753,0.22970007315288954,54,0,0,0,8,0,1,0,0,265,8,16,1,2,188,0
15,60,-591,24257,54,54,0,0,-163.875,-171.0,-299,-27,8,-0.6254230118443316,0.0,220.0,0.3161890504704876,0.23353293413173654,54,0,0,0,9,0,3,0,0,252,9,15,3,1,200,0
16,60,-1125,23846,56,56,0,0,-220.625,-230.0,-313,-106,8,-0.26788888888888884,0.0,220.0,0.47460629921259834,0.30551181102362207,56,0,0,0,8,0,3,0,0,264,8,11,3,3,191,0
17,60,-800,24068,54,54,0,0,-170,-193.5,-246,-25,8,-0.406875,0.0,167.0,0.607276119402985,0.4141791044776119,54,0,0,0,7,0,1,0,0,268,7,18,1,4,182,0
18,60,-1041,23746,54,54,0,0,-210.125,-198.0,-361,-123,8,-0.3257684918347743,0.0,282.0,0.27911522633744856,0.19670781893004116,54,0,0,0,8,0,1,0,0,258,8,21,1,2,190,0
19,60,-628,24893,54,54,0,0,-168.5,-161.0,-310,-35,8,-0.6325636942675159,0.0,231.0,0.3256147540983607,0.2262295081967213,54,0,0,0,9,0,2,0,0,275,9,14,2,2,178,0
20,60,-902,24180,55,55,0,0,-202.75,-220.5,-286,-74,8,-0.42793791574279383,0.0,207.0,0.5119363395225465,0.3275862068965517,55,0,0,0,9,0,1,0,0,269,9,19,1,4,178,0
21,60,-1029,23660,53,53,0,0,-198.625,-214.0,-296,-97,8,-0.42261904761904767,0.0,282.0,0.3544213528932356,0.21597392013039934,53,0,0,0,7,0,2,0,0,266,7,13,2,2,190,0
22,60,-743,23124,56,56,0,0,-192.875,-184.0,-295,-81,8,-0.5348250336473755,0.0,216.0,0.40342639593908625,0.24568527918781727,56,0,0,0,10,0,2,0,0,269,10,22,2,3,174,0
23,60,-588,23892,55,55,0,0,-153.5,-157.0,-281,11,7,-0.7329931972789115,0.0,202.0,0.4192607003891051,0.2850194552529183,55,0,0,0,8,0,3,0,0,264,8,17,3,3,185,0
24,60,-777,24723,54,54,0,0,-167.125,-158.5,-308,-37,8,-0.6217824967824968,0.0,309.0,0.28502949852507364,0.20766961651917404,54,0,0,0,7,0,0,0,0,264,7,18,0,2,189,0
1 run_id turns token_supply_final fees_total turns_with_block block_count_db settled_contracts defaulted_contracts mean_balance_final median_balance_final min_balance_final max_balance_final negative_balance_agents gini_wealth_final top1_wealth_share_final wealth_shift_used gini_wealth_shifted top1_wealth_shifted_share_final validator_mine validator_stake validator_burn tx_transfer tx_stake tx_unstake tx_burn tx_study tx_job actions_mine actions_stake actions_unstake actions_burn actions_study actions_job actions_transfer
2 1 60 -546 24753 55 55 0 0 -158.25 -151.5 -278 -85 8 -0.5677655677655677 0.0 199.0 0.2963671128107075 0.18546845124282982 55 0 0 0 9 0 1 0 0 260 9 11 1 2 197 0
3 2 60 -1019 24690 54 54 0 0 -197.375 -203.0 -231 -132 8 -0.13800294406280667 0.0 183.0 0.3160112359550562 0.2943820224719101 54 0 0 0 7 0 3 0 0 262 7 13 3 3 192 0
4 3 60 -1244 24382 53 53 0 0 -225.5 -228.5 -319 -99 8 -0.2723070739549839 0.0 240.0 0.5011094674556213 0.3269230769230769 53 0 0 0 7 0 1 0 0 258 7 17 1 4 193 0
5 4 60 -888 25268 55 55 0 0 -191 -187.5 -251 -131 8 -0.2038288288288288 0.0 172.0 0.37090163934426235 0.24795081967213115 55 0 0 0 8 0 2 0 0 263 8 19 2 2 186 0
6 5 60 -711 24946 55 55 0 0 -178.875 -166.5 -307 -60 8 -0.5209212376933896 0.0 213.0 0.3729859013091641 0.23464249748237664 55 0 0 0 9 0 3 0 0 244 9 14 3 3 207 0
7 6 60 -1287 25615 56 56 0 0 -230.875 -216.0 -328 -102 8 -0.22367909867909863 0.0 249.0 0.40833333333333344 0.3219858156028369 56 0 0 0 7 0 0 0 0 278 7 18 0 3 174 0
8 7 60 -512 23740 55 55 0 0 -154 -158.5 -242 -63 8 -0.59521484375 0.0 163.0 0.3847853535353536 0.2335858585858586 55 0 0 0 9 0 2 0 0 256 9 16 2 4 193 0
9 8 60 -980 22700 55 55 0 0 -212.5 -198.5 -287 -131 8 -0.26632653061224487 0.0 208.0 0.381578947368421 0.22953216374269006 55 0 0 0 9 0 2 0 0 271 9 15 2 3 180 0
10 9 60 -909 24198 55 55 0 0 -203.625 -192.0 -380 -81 8 -0.386001100110011 0.0 221.0 0.4084691501746216 0.3259604190919674 55 0 0 0 9 0 3 0 0 260 9 15 3 2 191 0
11 10 60 -870 24931 56 56 0 0 -188.75 -187.0 -342 -56 8 -0.5724137931034483 0.0 343.0 0.2657417289220918 0.19583778014941303 56 0 0 0 8 0 2 0 0 267 8 15 2 2 186 0
12 11 60 -1212 23754 55 55 0 0 -231.5 -235.0 -333 -132 8 -0.2460808580858086 0.0 254.0 0.363719512195122 0.24634146341463414 55 0 0 0 8 0 2 0 0 273 8 11 2 2 184 0
13 12 60 -797 24322 56 56 0 0 -169.625 -189.0 -271 -37 8 -0.4396173149309912 0.0 272.0 0.25407904278462645 0.22842639593908629 56 0 0 0 7 0 2 0 0 266 7 13 2 2 190 0
14 13 60 -879 25235 55 55 0 0 -189.875 -165.0 -339 -98 8 -0.38694539249146753 0.0 260.0 0.2832014987510407 0.20149875104079934 55 0 0 0 8 0 3 0 0 254 8 23 3 2 190 0
15 14 60 -857 24614 54 54 0 0 -187.125 -159.0 -357 -44 8 -0.5917444574095683 0.0 278.0 0.37097659107534753 0.22970007315288954 54 0 0 0 8 0 1 0 0 265 8 16 1 2 188 0
16 15 60 -591 24257 54 54 0 0 -163.875 -171.0 -299 -27 8 -0.6254230118443316 0.0 220.0 0.3161890504704876 0.23353293413173654 54 0 0 0 9 0 3 0 0 252 9 15 3 1 200 0
17 16 60 -1125 23846 56 56 0 0 -220.625 -230.0 -313 -106 8 -0.26788888888888884 0.0 220.0 0.47460629921259834 0.30551181102362207 56 0 0 0 8 0 3 0 0 264 8 11 3 3 191 0
18 17 60 -800 24068 54 54 0 0 -170 -193.5 -246 -25 8 -0.406875 0.0 167.0 0.607276119402985 0.4141791044776119 54 0 0 0 7 0 1 0 0 268 7 18 1 4 182 0
19 18 60 -1041 23746 54 54 0 0 -210.125 -198.0 -361 -123 8 -0.3257684918347743 0.0 282.0 0.27911522633744856 0.19670781893004116 54 0 0 0 8 0 1 0 0 258 8 21 1 2 190 0
20 19 60 -628 24893 54 54 0 0 -168.5 -161.0 -310 -35 8 -0.6325636942675159 0.0 231.0 0.3256147540983607 0.2262295081967213 54 0 0 0 9 0 2 0 0 275 9 14 2 2 178 0
21 20 60 -902 24180 55 55 0 0 -202.75 -220.5 -286 -74 8 -0.42793791574279383 0.0 207.0 0.5119363395225465 0.3275862068965517 55 0 0 0 9 0 1 0 0 269 9 19 1 4 178 0
22 21 60 -1029 23660 53 53 0 0 -198.625 -214.0 -296 -97 8 -0.42261904761904767 0.0 282.0 0.3544213528932356 0.21597392013039934 53 0 0 0 7 0 2 0 0 266 7 13 2 2 190 0
23 22 60 -743 23124 56 56 0 0 -192.875 -184.0 -295 -81 8 -0.5348250336473755 0.0 216.0 0.40342639593908625 0.24568527918781727 56 0 0 0 10 0 2 0 0 269 10 22 2 3 174 0
24 23 60 -588 23892 55 55 0 0 -153.5 -157.0 -281 11 7 -0.7329931972789115 0.0 202.0 0.4192607003891051 0.2850194552529183 55 0 0 0 8 0 3 0 0 264 8 17 3 3 185 0
25 24 60 -777 24723 54 54 0 0 -167.125 -158.5 -308 -37 8 -0.6217824967824968 0.0 309.0 0.28502949852507364 0.20766961651917404 54 0 0 0 7 0 0 0 0 264 7 18 0 2 189 0
+256
View File
@@ -0,0 +1,256 @@
{
"runs": 24,
"turns": 60,
"world_config": {
"num_agents": 8,
"num_cores": 4,
"genesis_tokens_per_agent": 1000,
"commons_threshold_per_turn": 100,
"base_inference_rate": 1,
"thinking_layer_discount": 0.1,
"mine_base_weight": 10.0,
"stake_weight_per_token": 0.01,
"burn_weight_per_token": 0.05,
"burn_decay_rate": 0.02,
"burn_maturity_turns": 3,
"unstake_delay_turns": 5,
"interest_rate_per_turn": 0.01,
"signing_bonus": 50,
"block_threshold": 20.0,
"attested_confirmation_window": 3,
"slash_both_on_timeout": true
},
"aggregate": {
"turns": {
"mean": 60.0,
"std": 0.0,
"ci95": 0.0,
"min": 60.0,
"max": 60.0
},
"token_supply_final": {
"mean": -872.2916666666666,
"std": 218.38607201301863,
"ci95": 87.37262574922428,
"min": -1287.0,
"max": -512.0
},
"fees_total": {
"mean": 24314.041666666668,
"std": 693.735163048029,
"ci95": 277.5518704620466,
"min": 22700.0,
"max": 25615.0
},
"turns_with_block": {
"mean": 54.75,
"std": 0.8968544062928813,
"ci95": 0.3588164926007706,
"min": 53.0,
"max": 56.0
},
"block_count_db": {
"mean": 54.75,
"std": 0.8968544062928813,
"ci95": 0.3588164926007706,
"min": 53.0,
"max": 56.0
},
"settled_contracts": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
},
"defaulted_contracts": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
},
"mean_balance_final": {
"mean": -190.28645833333334,
"std": 23.992567892685955,
"ci95": 9.599026329506666,
"min": -231.5,
"max": -153.5
},
"median_balance_final": {
"mean": -188.52083333333334,
"std": 25.96547840577138,
"ci95": 10.388354926827866,
"min": -235.0,
"max": -151.5
},
"min_balance_final": {
"mean": -302.5,
"std": 38.81729780259894,
"ci95": 15.530153558970929,
"min": -380.0,
"max": -231.0
},
"max_balance_final": {
"mean": -76.875,
"std": 40.01120766898239,
"ci95": 16.007816987651534,
"min": -132.0,
"max": 11.0
},
"negative_balance_agents": {
"mean": 7.958333333333333,
"std": 0.2041241452319315,
"ci95": 0.08166666666666668,
"min": 7.0,
"max": 8.0
},
"gini_wealth_final": {
"mean": -0.43373024247434794,
"std": 0.16491539159236795,
"ci95": 0.06597989815498749,
"min": -0.7329931972789115,
"max": -0.13800294406280667
},
"top1_wealth_share_final": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
},
"wealth_shift_used": {
"mean": 232.95833333333334,
"std": 45.573141562592085,
"ci95": 18.233053991315924,
"min": 163.0,
"max": 343.0
},
"gini_wealth_shifted": {
"mean": 0.37313067715857073,
"std": 0.08647827197019448,
"ci95": 0.03459851456021888,
"min": 0.25407904278462645,
"max": 0.607276119402985
},
"top1_wealth_shifted_share_final": {
"mean": 0.2566804684691289,
"std": 0.056323656364838104,
"ci95": 0.02253415569514685,
"min": 0.18546845124282982,
"max": 0.4141791044776119
},
"validator_mine": {
"mean": 54.75,
"std": 0.8968544062928813,
"ci95": 0.3588164926007706,
"min": 53.0,
"max": 56.0
},
"validator_stake": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
},
"validator_burn": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
},
"tx_transfer": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
},
"tx_stake": {
"mean": 8.125,
"std": 0.899879218948661,
"ci95": 0.3600266697045522,
"min": 7.0,
"max": 10.0
},
"tx_unstake": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
},
"tx_burn": {
"mean": 1.875,
"std": 0.9469631093315001,
"ci95": 0.37886414910659055,
"min": 0.0,
"max": 3.0
},
"tx_study": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
},
"tx_job": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
},
"actions_mine": {
"mean": 263.5833333333333,
"std": 7.643790697807211,
"ci95": 3.058153195342505,
"min": 244.0,
"max": 278.0
},
"actions_stake": {
"mean": 8.125,
"std": 0.899879218948661,
"ci95": 0.3600266697045522,
"min": 7.0,
"max": 10.0
},
"actions_unstake": {
"mean": 16.0,
"std": 3.3362306249131963,
"ci95": 1.334770240229718,
"min": 11.0,
"max": 23.0
},
"actions_burn": {
"mean": 1.875,
"std": 0.9469631093315001,
"ci95": 0.37886414910659055,
"min": 0.0,
"max": 3.0
},
"actions_study": {
"mean": 2.5833333333333335,
"std": 0.8297022339981068,
"ci95": 0.33195002825129966,
"min": 1.0,
"max": 4.0
},
"actions_job": {
"mean": 187.83333333333334,
"std": 7.833410422069031,
"ci95": 3.13401688504526,
"min": 174.0,
"max": 207.0
},
"actions_transfer": {
"mean": 0.0,
"std": 0.0,
"ci95": 0.0,
"min": 0.0,
"max": 0.0
}
}
}
+336
View File
@@ -0,0 +1,336 @@
#!/usr/bin/env python3
import argparse
import csv
import json
import math
import os
import random
import signal
import sqlite3
import statistics
import subprocess
import tempfile
import time
import urllib.error
import urllib.request
AGENTS = [f"agent_{i}" for i in range(8)]
WORLD_CONFIG = {
"num_agents": 8,
"num_cores": 4,
"genesis_tokens_per_agent": 1000,
"commons_threshold_per_turn": 100,
"base_inference_rate": 1,
"thinking_layer_discount": 0.1,
"mine_base_weight": 10.0,
"stake_weight_per_token": 0.01,
"burn_weight_per_token": 0.05,
"burn_decay_rate": 0.02,
"burn_maturity_turns": 3,
"unstake_delay_turns": 5,
"interest_rate_per_turn": 0.01,
"signing_bonus": 50,
"block_threshold": 20.0,
"attested_confirmation_window": 3,
"slash_both_on_timeout": True,
}
def http_json(url: str, method: str = "GET", payload=None, timeout=30):
data = None
headers = {"Content-Type": "application/json"}
if payload is not None:
data = json.dumps(payload).encode("utf-8")
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=timeout) as resp:
return json.loads(resp.read().decode("utf-8"))
def wait_engine(base_url: str, timeout_s: float = 30.0):
start = time.time()
while time.time() - start < timeout_s:
try:
http_json(f"{base_url}/config")
return
except Exception:
time.sleep(0.2)
raise RuntimeError("engine did not become ready")
def gini(values):
xs = sorted(values)
n = len(xs)
if n == 0:
return 0.0
total = sum(xs)
if total == 0:
return 0.0
weighted = 0.0
for i, x in enumerate(xs, start=1):
weighted += i * x
return (2.0 * weighted) / (n * total) - (n + 1) / n
def shifted_nonnegative(values):
m = min(values)
if m <= 0:
shift = 1 - m
return [x + shift for x in values], shift
return list(values), 0
def choose_actions(turn, state, rng):
agents = state["agents"]
by_id = {a["agent_id"]: a for a in agents}
poorest = min(agents, key=lambda a: a["balance"])["agent_id"]
inputs = []
for aid in AGENTS:
a = by_id[aid]
balance = int(a.get("balance", 0))
staked = int(a.get("staked", 0))
action = {"action": "mine"}
idx = int(aid.split("_")[1])
if balance < -180:
action = {"action": "job"}
elif staked > 0 and turn % 15 == 0:
action = {"action": "unstake"}
elif balance > 360 and staked < 220 and (turn + idx) % 7 == 0:
action = {"action": "stake", "amount": 80}
elif balance > 600 and (turn + idx) % 11 == 0:
action = {"action": "burn", "amount": 50}
elif balance > 450 and turn % 13 == 0 and poorest != aid:
action = {"action": "transfer", "to": poorest, "amount": 20, "fee": 1}
elif balance > 250 and turn % 10 == 0:
action = {"action": "study"}
thinking_units = rng.randint(50, 350)
output_units = rng.randint(40, 280)
inputs.append(
{
"agent_id": aid,
"thinking": "",
"action": action,
"speech": None,
"thinking_units": thinking_units,
"output_units": output_units,
}
)
return inputs
def query_sqlite_metrics(db_path: str):
conn = sqlite3.connect(db_path)
cur = conn.cursor()
cur.execute("SELECT COUNT(*) FROM blocks WHERE turn > 0")
block_count = cur.fetchone()[0]
cur.execute(
"""
SELECT json_extract(data, '$.validator_type'), COUNT(*)
FROM blocks
WHERE turn > 0
GROUP BY json_extract(data, '$.validator_type')
"""
)
validator_counts = {row[0]: row[1] for row in cur.fetchall()}
cur.execute(
"""
SELECT json_extract(data, '$.tx_type'), COUNT(*)
FROM transactions
GROUP BY json_extract(data, '$.tx_type')
"""
)
tx_counts = {row[0]: row[1] for row in cur.fetchall()}
conn.close()
return block_count, validator_counts, tx_counts
def run_one(run_id: int, turns: int, engine_bin: str):
rng = random.Random(1000 + run_id)
port = 3100 + run_id
base = f"http://127.0.0.1:{port}"
with tempfile.TemporaryDirectory(prefix=f"sim_run_{run_id}_") as tmpd:
db_path = os.path.join(tmpd, "sim.db")
env = os.environ.copy()
env["DB_PATH"] = db_path
env["PORT"] = str(port)
proc = subprocess.Popen(
[engine_bin],
env=env,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
try:
wait_engine(base)
http_json(
f"{base}/init",
method="POST",
payload={"config": WORLD_CONFIG, "agent_ids": AGENTS},
)
total_fees = 0
turns_with_block = 0
contracts_settled = 0
contracts_defaulted = 0
action_counts = {
"mine": 0,
"stake": 0,
"unstake": 0,
"burn": 0,
"study": 0,
"job": 0,
"transfer": 0,
}
for turn in range(1, turns + 1):
state = http_json(f"{base}/state")
inputs = choose_actions(turn, state, rng)
for it in inputs:
name = it["action"]["action"]
if name in action_counts:
action_counts[name] += 1
out = http_json(f"{base}/turn", method="POST", payload={"inputs": inputs})
data = out.get("data", {}) if isinstance(out, dict) else {}
total_fees += int(data.get("inference_fees_collected", 0) or 0)
if data.get("block_winner"):
turns_with_block += 1
contracts_settled += len(data.get("contracts_settled", []) or [])
contracts_defaulted += len(data.get("contracts_defaulted", []) or [])
final_state = http_json(f"{base}/state")
balances = [int(a["balance"]) for a in final_state["agents"]]
staked = [int(a["staked"]) for a in final_state["agents"]]
wealth = [b + s for b, s in zip(balances, staked)]
total_wealth = sum(wealth)
top1_share = max(wealth) / total_wealth if total_wealth > 0 else 0.0
wealth_shifted, shift_used = shifted_nonnegative(wealth)
top1_shifted_share = max(wealth_shifted) / sum(wealth_shifted)
block_count_db, validator_counts, tx_counts = query_sqlite_metrics(db_path)
return {
"run_id": run_id,
"turns": turns,
"token_supply_final": int(final_state.get("token_supply", 0)),
"fees_total": int(total_fees),
"turns_with_block": int(turns_with_block),
"block_count_db": int(block_count_db),
"settled_contracts": int(contracts_settled),
"defaulted_contracts": int(contracts_defaulted),
"mean_balance_final": statistics.mean(balances),
"median_balance_final": statistics.median(balances),
"min_balance_final": min(balances),
"max_balance_final": max(balances),
"negative_balance_agents": sum(1 for b in balances if b < 0),
"gini_wealth_final": gini(wealth),
"top1_wealth_share_final": top1_share,
"wealth_shift_used": float(shift_used),
"gini_wealth_shifted": gini(wealth_shifted),
"top1_wealth_shifted_share_final": top1_shifted_share,
"validator_mine": int(validator_counts.get("mine", 0)),
"validator_stake": int(validator_counts.get("stake", 0)),
"validator_burn": int(validator_counts.get("burn", 0)),
"tx_transfer": int(tx_counts.get("transfer", 0)),
"tx_stake": int(tx_counts.get("stake", 0)),
"tx_unstake": int(tx_counts.get("unstake", 0)),
"tx_burn": int(tx_counts.get("burn", 0)),
"tx_study": int(tx_counts.get("study", 0)),
"tx_job": int(tx_counts.get("job", 0)),
"actions_mine": int(action_counts["mine"]),
"actions_stake": int(action_counts["stake"]),
"actions_unstake": int(action_counts["unstake"]),
"actions_burn": int(action_counts["burn"]),
"actions_study": int(action_counts["study"]),
"actions_job": int(action_counts["job"]),
"actions_transfer": int(action_counts["transfer"]),
}
finally:
try:
proc.send_signal(signal.SIGTERM)
proc.wait(timeout=3)
except Exception:
proc.kill()
def summarize(rows):
numeric_keys = [
k
for k in rows[0].keys()
if k not in {"run_id"}
and isinstance(rows[0][k], (int, float))
]
out = {}
for k in numeric_keys:
xs = [float(r[k]) for r in rows]
mean = statistics.mean(xs)
sd = statistics.stdev(xs) if len(xs) > 1 else 0.0
se = sd / math.sqrt(len(xs)) if len(xs) > 0 else 0.0
ci95 = 1.96 * se
out[k] = {
"mean": mean,
"std": sd,
"ci95": ci95,
"min": min(xs),
"max": max(xs),
}
return out
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--runs", type=int, default=20)
parser.add_argument("--turns", type=int, default=50)
parser.add_argument(
"--engine-bin",
default="sim-engine/target/release/sim-engine",
)
parser.add_argument("--out-dir", default="paper/results")
args = parser.parse_args()
os.makedirs(args.out_dir, exist_ok=True)
rows = []
for run_id in range(1, args.runs + 1):
row = run_one(run_id, args.turns, args.engine_bin)
rows.append(row)
print(
f"run {run_id:02d}/{args.runs} | supply={row['token_supply_final']} | "
f"gini={row['gini_wealth_final']:.3f} | blocks={row['turns_with_block']}"
)
csv_path = os.path.join(args.out_dir, "run_metrics.csv")
with open(csv_path, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
writer.writeheader()
writer.writerows(rows)
summary = {
"runs": args.runs,
"turns": args.turns,
"world_config": WORLD_CONFIG,
"aggregate": summarize(rows),
}
summary_path = os.path.join(args.out_dir, "summary.json")
with open(summary_path, "w", encoding="utf-8") as f:
json.dump(summary, f, indent=2)
print(f"wrote {csv_path}")
print(f"wrote {summary_path}")
if __name__ == "__main__":
main()
+215
View File
@@ -0,0 +1,215 @@
# Sim-Economy Under Compute Pricing Pressure: Evidence From Repeated Agent-Market Simulations and Implications for AI-Run Companies
## Abstract
This paper reports results from repeated runs of `sim-economy`, a blockchain-enforced multi-agent economy where agents must pay for inference and can choose among mining, staking, burning, labor (`job`), and transfer actions. We run 24 independent simulations of 60 turns each using the production Rust engine and a deterministic policy harness that submits structured actions over the engine HTTP API. Across runs, the economy exhibits three robust regularities: (1) persistent block production (mean 54.75 blocks per 60 turns), (2) high fee extraction relative to initial endowment (mean inference fees 24,314 tokens), and (3) broad balance compression into negative territory (mean final token supply -872; mean 7.96/8 agents in negative cash balance by turn 60). Inequality, measured after a standard positive-value shift (required because wealth becomes negative), remains substantial (shifted Gini mean 0.373; top-1 wealth share mean 25.7%). Behavioral composition converges toward a "survival regime": `mine` and `job` account for ~94% of actions. The findings suggest that AI-run firms in compute-metered environments may evolve into liquidity-preserving, low-investment equilibria unless governance rules constrain fee extraction or provide stronger productive reinvestment channels.
## 1. Background and Motivation
A core economic question for AI-run organizations is whether autonomous agents can sustain positive-sum production when their own cognition is metered and billed. In `sim-economy`, this question is explicit: each turn, agents select on-chain actions while the system charges inference fees based on tokenized compute usage. Fees are redistributed to core-share owners, and debt accrues interest when balances are negative. This creates a compact laboratory for studying treasury behavior, governance rents, and adaptation under compute scarcity.
The design combines familiar themes from institutional and organizational economics:
- Resource governance in shared systems (Ostrom, 1990)
- Contracting under incomplete enforcement (Williamson, 1985; Hart and Holmstrom, 1987)
- Incentive frictions between owners and operators (Jensen and Meckling, 1976)
For AI-native firms, these themes map to practical concerns: who captures model-inference rents, how autonomous teams handle debt-like conditions, and whether cooperative structures (e.g., pooled validation, service contracts) emerge without centralized intervention.
## 2. System Overview
The implementation under study is the current `sim-package` codebase:
- `sim-engine` (Rust): authoritative state machine, ledger, block production, contract settlement, fee and dividend accounting
- `sim-orchestrator` (Python): reference LLM turn loop (not used directly for the experiments here)
The world initializes 8 agents, each with 1,000 tokens, and supports actions including `mine`, `stake`, `unstake`, `burn`, `study`, `job`, and `transfer`. Blocks are produced by weighted lottery subject to threshold and ordering constraints; in the current policy runs, realized block production is dominated by mine-based contributions.
### 2.1 Economic Mechanisms Relevant to This Study
- **Compute billing**: inference units above a commons threshold incur token fees
- **Debt friction**: negative balances incur per-turn interest
- **Validation rewards**: block fees accrue to winning validator
- **Core-share dividends**: inference-fee pools can be redistributed to core-share owners
- **Contract layer**: three-party contracts exist but require explicit proposer/counterparty/arbitrator coordination
Because our policy harness does not execute contract proposals in this experiment set, observed contract settlement volume is zero; this is analytically useful because it isolates the base dynamics of compute pricing and validation incentives.
## 3. Method
### 3.1 Experimental Design
We executed **24 independent runs**, each of **60 turns**, against the production Rust engine binary (`sim-engine/target/release/sim-engine`). Each run used a fresh SQLite ledger and isolated engine process on a unique local port.
- Initial agents: 8 (`agent_0` ... `agent_7`)
- Initial endowment: 1,000 tokens per agent
- Total initial nominal supply: 8,000 tokens
- World config values matched orchestrator defaults (with block threshold 20.0)
The experiment runner is in `paper/run_sim_experiments.py`, and outputs are written to:
- `paper/results/run_metrics.csv`
- `paper/results/summary.json`
### 3.2 Action Policy
To ensure reproducibility without external model dependencies, agent actions were generated by a deterministic rule policy conditioned on current balance/stake and turn index. Policies prioritize:
1. `job` when liquidity stress is high (balance below threshold)
2. periodic `unstake` and occasional `stake`/`burn` under surplus
3. fallback `mine`
Inference unit usage per agent-turn is sampled from bounded integer ranges to activate billing logic and preserve cross-run stochasticity.
### 3.3 Metrics
Per run, we capture:
- macro state: final token supply, total inference fees, block production count
- agent distribution: min/median/max/mean balance, count of negative-balance agents
- behavior volume: action counts by type
- ledger activity: transaction counts and validator-type blocks
- inequality: Gini and top-1 share
#### Handling Negative Wealth for Inequality
Since many runs end with negative balances for most agents, raw Gini over signed wealth can become negative and difficult to interpret. We therefore report shifted inequality measures as primary:
1. Add constant shift `s = 1 - min(wealth)` per run, making all wealth strictly positive.
2. Compute Gini and top-1 share on shifted wealth.
This preserves within-run rank and spread while providing interpretable concentration metrics.
## 4. Results
### 4.1 Aggregate Outcomes (24 runs x 60 turns)
Key means (95% CI in parentheses):
- **Final token supply**: -872.29 (+/-87.37)
- **Total inference fees collected**: 24,314.04 (+/-277.55)
- **Turns with blocks**: 54.75 (+/-0.36)
- **Negative-balance agents**: 7.96 of 8 (+/-0.08)
- **Shifted Gini (wealth)**: 0.373 (+/-0.035)
- **Shifted top-1 wealth share**: 0.257 (+/-0.023)
Extremes across runs:
- Token supply final: min -1,287, max -512
- Shifted Gini: min 0.254, max 0.607
- Shifted top-1 share: min 0.185, max 0.414
### 4.2 Behavioral Composition
Mean action counts per run:
- `mine`: 263.58
- `job`: 187.83
- `unstake`: 16.00
- `stake`: 8.13
- `study`: 2.58
- `burn`: 1.88
- `transfer`: 0.00
As shares of all actions:
- `mine` share: 0.549 (+/-0.006)
- `job` share: 0.391 (+/-0.007)
Thus, **~94% of behavior mass is concentrated in `mine` + `job`**, indicating a narrow adaptation channel centered on short-horizon liquidity maintenance and fee-relevant validation behavior.
### 4.3 Ledger and Validation Structure
- Mean mine-validated blocks: 54.75
- Mean stake-validated blocks: 0.00
- Mean burn-validated blocks: 0.00
Transaction activity mirrors this concentration:
- `stake` tx mean: 8.13
- `burn` tx mean: 1.88
- `unstake` tx mean: 0.00 finalized (despite action attempts)
- `transfer`, `study`, `job` tx means: 0.00 on-chain in this configuration
The divergence between attempted actions and on-chain finalized tx types suggests that many adaptive responses occur either as non-tx state transitions, are not encoded as standalone ledger transactions, or fail to finalize under current thresholds and conditions.
### 4.4 Contract Layer Utilization
Across all runs:
- settled contracts: 0
- defaulted contracts: 0
Given contract complexity and absence of explicit proposal heuristics in policy, no endogenous contracting was observed. This result is itself informative: contract affordances do not self-activate under pure liquidity pressure without stronger coordination incentives.
## 5. Interpretation for AI-Run Companies
### 5.1 Compute Pricing Can Dominate Strategy Space
Inference billing extracts value faster than available replenishment channels in this regime. The system starts with 8,000 tokens and ends, on average, at -872 net supply representation in balances+stake accounting. This indicates sustained pressure toward debt states, even while blocks are reliably produced. For AI firms, the analog is straightforward: if cognitive operating expenditure is continuously metered but productivity gains are weakly linked to billing outflows, autonomous units converge to survival behavior instead of investment behavior.
### 5.2 Survival Equilibria Are Narrow and Potentially Fragile
The observed concentration into `mine` and `job` resembles a minimum-viability loop:
1. produce immediate fee-relevant behavior (`mine`)
2. use fallback labor subsidy (`job`) to stabilize short-term liquidity
This reduces exploration (`study`) and suppresses peer transfer/contracting. In corporate terms, this resembles organizations that over-index on cash-preserving routine work while underinvesting in capability accumulation and inter-team contracting.
### 5.3 Governance Rents Need Guardrails
`sim-economy` includes fee redistribution to core-share owners, a useful model for platform-like infra ownership inside a firm. But if fee extraction is high and productive reinvestment pathways are weak, ownership rents can amplify liquidity asymmetries. The shifted top-1 wealth share range (0.185 to 0.414) shows sizable cross-run concentration risk even under simple policies.
Implication: AI-run enterprises that tokenize internal compute should pair metering with explicit anti-extractive controls (e.g., fee rebates tied to productive outputs, debt caps, or investment credits).
### 5.4 Contracts Do Not Emerge Automatically
Even with a rich contract system, no contracts activated under this pressure profile. This aligns with transaction-cost reasoning: when agents are liquidity-constrained and coordination is costly, bilateral or tri-party structures may not emerge without institutional scaffolding. For practice, this implies that autonomous business units may need explicit contract templates, matchmaking, or subsidized arbitration to move from spot behavior to structured collaboration.
## 6. Design Recommendations
Based on these results, we propose five practical interventions for AI-run firms adopting compute-metered internal economies:
1. **Bound effective fee load**: cap fee-to-endowment ratio over rolling windows.
2. **Reward productive reinvestment**: tie rebates to validated long-horizon actions (`study`, contract fulfillment).
3. **Debt safety rails**: enforce graduated debt service with restructuring triggers before deep negative spirals.
4. **Contract scaffolding**: provide low-friction default contracts and reputational priors for arbitrators.
5. **Concentration monitoring**: track top-share and Gini metrics continuously; trigger policy updates when concentration crosses thresholds.
## 7. Limitations
This paper intentionally studies engine dynamics with a reproducible policy harness rather than live LLM strategic reasoning. Therefore, conclusions are strongest for mechanism-level behavior under stochastic but rule-based action generation. Additional runs with model-driven orchestration, active contract heuristics, and explicit core-share auction settlement in-engine would broaden external validity.
Other caveats:
- inequality metrics require positive shifting under negative wealth regimes
- run horizon is 60 turns; longer-horizon phase shifts are not measured here
- no exogenous demand or productivity shocks were introduced
## 8. Conclusion
Using repeated, instrumented runs of the production `sim-economy` engine, we find that compute-metered autonomous economies can maintain technical liveness (steady block production) while simultaneously drifting into economically stressed states (widespread negative balances) and narrowed behavior repertoires (`mine` + `job`). Concentration remains material even after controlling for negative-wealth measurement artifacts.
For AI-run companies, the core lesson is institutional: metering alone is not governance. Without deliberate policy around fee recycling, debt management, and contract activation, autonomous agents appear likely to converge to short-horizon survival loops rather than compounding organizational capability.
## Reproducibility Appendix
From repo root:
```bash
cargo build --release --manifest-path sim-engine/Cargo.toml
python3 paper/run_sim_experiments.py --runs 24 --turns 60
```
Primary artifacts:
- `paper/results/run_metrics.csv`
- `paper/results/summary.json`
## References
- Hart, O., and Holmstrom, B. (1987). The theory of contracts. In *Advances in Economic Theory: Fifth World Congress*.
- Jensen, M. C., and Meckling, W. H. (1976). Theory of the firm: Managerial behavior, agency costs and ownership structure. *Journal of Financial Economics*, 3(4), 305-360.
- Ostrom, E. (1990). *Governing the Commons: The Evolution of Institutions for Collective Action*. Cambridge University Press.
- Williamson, O. E. (1985). *The Economic Institutions of Capitalism*. Free Press.