build(agent): new-agents-2#7e3bbc iteration
This commit is contained in:
parent
083b390085
commit
40d5747c31
|
|
@ -0,0 +1,21 @@
|
||||||
|
node_modules/
|
||||||
|
.npmrc
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
__tests__/
|
||||||
|
coverage/
|
||||||
|
.nyc_output/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.cache/
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
tmp/
|
||||||
|
.tmp/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
*.egg-info/
|
||||||
|
.pytest_cache/
|
||||||
|
READY_TO_PUBLISH
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
Overview
|
||||||
|
- This repository implements a production-oriented MVP for a verifiable algebraic DSL to model cross-server game economies.
|
||||||
|
- Architecture emphasizes modular adapters, a canonical IR, and a governance ledger with delta-sync semantics.
|
||||||
|
|
||||||
|
Tech Stack
|
||||||
|
- Python 3.8+ for core modeling and adapters
|
||||||
|
- Minimal in-repo DSL primitives (LocalEconomy, SharedSignal, PlanDelta)
|
||||||
|
- Adapters: server economy engine adapter and marketplace adapter
|
||||||
|
- Registry: GraphOfContractsRegistry for versioned contracts and adapters mapping
|
||||||
|
|
||||||
|
Testing and Commands
|
||||||
|
- Tests run with pytest (unit tests and a small integration test)
|
||||||
|
- test.sh orchestrates pytest and python -m build for packaging verification
|
||||||
|
|
||||||
|
How to contribute
|
||||||
|
- Implement a new adapter under adapters/ to plug a new backend
|
||||||
|
- Extend the DSL primitives in dsl.py and wire through core.py for simulations
|
||||||
|
- Update tests to cover new behavior
|
||||||
|
- Update README and add any necessary documentation in the package
|
||||||
|
|
||||||
|
Code Organization (high-level)
|
||||||
|
- src/idea76_gameeconomy_studio_verifiable/dsl.py: DSL primitives (LocalEconomy, SharedSignal, PlanDelta, GraphContract)
|
||||||
|
- src/idea76_gameeconomy_studio_verifiable/core.py: EconomyEngine that runs deterministic simulations
|
||||||
|
- src/idea76_gameeconomy_studio_verifiable/adapters/: starter adapters for server engine and marketplace
|
||||||
|
- src/idea76_gameeconomy_studio_verifiable/registry.py: GraphOfContracts registry
|
||||||
|
- tests/: basic unit and integration tests
|
||||||
|
- README.md, AGENTS.md, test.sh, READY_TO_PUBLISH: publish scaffolding
|
||||||
|
|
||||||
|
Roadmap reference
|
||||||
|
- Phase 0: DSL prototype, two adapters, toy cross-server scenario, deterministic backtesting
|
||||||
|
- Phase 1: Global constraints and governance ledger skeleton, secure aggregation for cross-server signals
|
||||||
|
- Phase 2: Cross-server demo with basic contract example and adapter blueprint
|
||||||
|
- Phase 3: End-to-end pilot in testbed with delta-sync and auditability
|
||||||
13
README.md
13
README.md
|
|
@ -1,3 +1,12 @@
|
||||||
# idea76-gameeconomy-studio-verifiable
|
# GameEconomy Studio: Verifiable Algebraic DSL for Cross-Server In-Game Economies
|
||||||
|
|
||||||
Source logic for Idea #76
|
This repository contains a production-oriented prototype of a verifiable algebraic DSL for cross-server in-game economies. The MVP focuses on:
|
||||||
|
- Defining local economies (currencies, items, budgets)
|
||||||
|
- Lightweight adapters to server backends and marketplaces
|
||||||
|
- Deterministic backtesting and delta-sync semantics
|
||||||
|
- A pluggable, versioned Graph-of-Contracts registry for interoperability
|
||||||
|
- Privacy-preserving and auditable governance storytelling
|
||||||
|
|
||||||
|
Architecture overview, how to run tests, and extension points are described in AGENTS.md and tests.
|
||||||
|
|
||||||
|
Note: This is a production-oriented seed working toward Phase 0-1 MVPs per the roadmap. See AGENTS.md for deployment and testing commands.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=42", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "idea76_gameeconomy_studio_verifiable"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Verifiable Algebraic DSL for Cross-Server In-Game Economies"
|
||||||
|
authors = [{name = "OpenCode"}]
|
||||||
|
license = {text = "MIT"}
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
dependencies = []
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="idea76_gameeconomy_studio_verifiable",
|
||||||
|
version="0.1.0",
|
||||||
|
description="Verifiable Algebraic DSL for Cross-Server In-Game Economies",
|
||||||
|
packages=find_packages(where="src"),
|
||||||
|
package_dir={"": "src"},
|
||||||
|
python_requires=">=3.8",
|
||||||
|
install_requires=[],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
"""Idea76 GameEconomy Studio Verifiable DSL package init."""
|
||||||
|
|
||||||
|
from .dsl import LocalEconomy, SharedSignal, PlanDelta, GraphContract # noqa: F401
|
||||||
|
from .core import EconomyEngine # noqa: F401
|
||||||
|
from .registry import GraphOfContractsRegistry # noqa: F401
|
||||||
|
from .adapters.server_engine_adapter import ServerEconomyAdapter # noqa: F401
|
||||||
|
from .adapters.marketplace_adapter import MarketplaceAdapter # noqa: F401
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
"""Adapters for GameEconomy Studio"""
|
||||||
|
|
||||||
|
from .server_engine_adapter import ServerEconomyAdapter
|
||||||
|
from .marketplace_adapter import MarketplaceAdapter
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from ..dsl import SharedSignal, PlanDelta
|
||||||
|
|
||||||
|
|
||||||
|
class MarketplaceAdapter:
|
||||||
|
"""Adapter for in-game marketplace interactions."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.signals: List[SharedSignal] = []
|
||||||
|
|
||||||
|
def fetch_market_signals(self) -> List[SharedSignal]:
|
||||||
|
# In a real implementation this would query a marketplace API.
|
||||||
|
# For the MVP, return a synthetic signal if none exist.
|
||||||
|
if not self.signals:
|
||||||
|
self.signals = [SharedSignal("Marketplace", "price_pressure", 0.1, 0)]
|
||||||
|
return self.signals
|
||||||
|
|
||||||
|
def apply_delta(self, delta: PlanDelta) -> None:
|
||||||
|
# No-op for MVP; in a real adapter we'd translate plan deltas into marketplace actions.
|
||||||
|
pass
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from ..dsl import LocalEconomy, PlanDelta, SharedSignal
|
||||||
|
from ..core import EconomyEngine
|
||||||
|
|
||||||
|
|
||||||
|
class ServerEconomyAdapter:
|
||||||
|
"""Adapter bridging a server-side economy engine to the canonical IR."""
|
||||||
|
|
||||||
|
def __init__(self, economies: List[LocalEconomy]):
|
||||||
|
self.engine = EconomyEngine(economies)
|
||||||
|
|
||||||
|
def export_state(self, signals: List[SharedSignal], delta: PlanDelta) -> Dict[str, dict]:
|
||||||
|
# Produce IR for current round given signals and delta
|
||||||
|
return self.engine.simulate_round(signals, delta)
|
||||||
|
|
||||||
|
def import_state(self, ir: Dict[str, dict]) -> None:
|
||||||
|
# For a minimal prototype, we'll not mutate internal state here.
|
||||||
|
# In a fuller implementation, we would sync engine states from IR.
|
||||||
|
pass
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import List, Dict
|
||||||
|
|
||||||
|
from .dsl import LocalEconomy, SharedSignal, PlanDelta
|
||||||
|
from .dsl import compile_ir
|
||||||
|
|
||||||
|
|
||||||
|
class EconomyEngine:
|
||||||
|
"""Deterministic, per-round economy engine.
|
||||||
|
|
||||||
|
- Holds a collection of LocalEconomy models.
|
||||||
|
- simulate_round applies delta changes and respects per-economy budgets.
|
||||||
|
- Returns a per-economy state dictionary representing the IR after the round.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, local_economies: List[LocalEconomy]):
|
||||||
|
self.local_economies = local_economies
|
||||||
|
|
||||||
|
def simulate_round(self, signals: List[SharedSignal], delta: PlanDelta) -> Dict[str, dict]:
|
||||||
|
# Producer-friendly deterministic delta application.
|
||||||
|
ir = compile_ir(self.local_economies, signals, delta)
|
||||||
|
# Simple post-processing could go here (e.g., governance checks)
|
||||||
|
return ir
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Dict, List
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LocalEconomy:
|
||||||
|
name: str
|
||||||
|
currencies: List[str] = field(default_factory=list)
|
||||||
|
items: List[str] = field(default_factory=list)
|
||||||
|
budgets: Dict[str, float] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SharedSignal:
|
||||||
|
shard: str
|
||||||
|
signal_type: str
|
||||||
|
value: float
|
||||||
|
timestamp: int
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PlanDelta:
|
||||||
|
round_id: int
|
||||||
|
changes: Dict[str, float] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GraphContract:
|
||||||
|
contract_id: str
|
||||||
|
description: str
|
||||||
|
version: int
|
||||||
|
|
||||||
|
|
||||||
|
def compile_ir(local_economies: List[LocalEconomy], signals: List[SharedSignal], delta: PlanDelta) -> Dict[str, dict]:
|
||||||
|
"""A tiny deterministic IR compiler stub that aggregates per-economy state."""
|
||||||
|
ir: Dict[str, dict] = {}
|
||||||
|
for le in local_economies:
|
||||||
|
# Basic deterministic initial state per economy
|
||||||
|
state = {
|
||||||
|
"name": le.name,
|
||||||
|
"currencies": {c: 1000 for c in le.currencies},
|
||||||
|
"items": {i: 5 for i in le.items},
|
||||||
|
"budgets": le.budgets,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Apply delta changes if provided for each currency
|
||||||
|
for cur in le.currencies:
|
||||||
|
key = f"currency:{cur}"
|
||||||
|
delta_val = delta.changes.get(key, 0.0)
|
||||||
|
if cur in state["currencies"]:
|
||||||
|
new_val = int(state["currencies"][cur] + delta_val)
|
||||||
|
# Respect inflation cap if defined
|
||||||
|
cap = le.budgets.get("inflation_cap")
|
||||||
|
if cap is not None:
|
||||||
|
max_supply = int(1000 * (1.0 + cap))
|
||||||
|
if new_val > max_supply:
|
||||||
|
new_val = max_supply
|
||||||
|
if new_val < 0:
|
||||||
|
new_val = 0
|
||||||
|
state["currencies"][cur] = new_val
|
||||||
|
ir[le.name] = state
|
||||||
|
return ir
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
from .dsl import GraphContract
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GraphOfContractsRegistry:
|
||||||
|
contracts: Dict[str, GraphContract]
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.contracts = {}
|
||||||
|
|
||||||
|
def register_contract(self, contract: GraphContract) -> None:
|
||||||
|
self.contracts[contract.contract_id] = contract
|
||||||
|
|
||||||
|
def get_contract(self, contract_id: str) -> Optional[GraphContract]:
|
||||||
|
return self.contracts.get(contract_id)
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "Running unit tests with pytest..."
|
||||||
|
pytest -q
|
||||||
|
|
||||||
|
echo "Building Python package..."
|
||||||
|
python3 -m build
|
||||||
|
|
||||||
|
echo "All tests passed and package built successfully."
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Ensure the src/ package is importable during tests
|
||||||
|
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||||
|
SRC = os.path.join(ROOT, "src")
|
||||||
|
if SRC not in sys.path:
|
||||||
|
sys.path.insert(0, SRC)
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from idea76_gameeconomy_studio_verifiable.dsl import LocalEconomy, SharedSignal, PlanDelta
|
||||||
|
from idea76_gameeconomy_studio_verifiable.core import EconomyEngine
|
||||||
|
|
||||||
|
|
||||||
|
def test_inflation_cap_and_delta_application():
|
||||||
|
le = LocalEconomy(
|
||||||
|
name="ShardA",
|
||||||
|
currencies=["GEM"],
|
||||||
|
items=["Sword"],
|
||||||
|
budgets={"inflation_cap": 0.05},
|
||||||
|
)
|
||||||
|
engine = EconomyEngine([le])
|
||||||
|
delta = PlanDelta(round_id=1, changes={"currency:GEM": 100})
|
||||||
|
signals = [SharedSignal("ShardA", "liquidity", 0.8, 1)]
|
||||||
|
|
||||||
|
ir = engine.simulate_round(signals, delta)
|
||||||
|
|
||||||
|
assert "ShardA" in ir
|
||||||
|
shard = ir["ShardA"]
|
||||||
|
assert shard["currencies"]["GEM"] >= 0
|
||||||
|
# Ensure that the delta applied increased the GEM amount by approximately the delta (subject to cap)
|
||||||
|
assert shard["currencies"]["GEM"] <= 1000 + 100 # cap logic in MVP is loose; keep bounds reasonable
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
from idea76_gameeconomy_studio_verifiable.dsl import LocalEconomy, SharedSignal, PlanDelta
|
||||||
|
from idea76_gameeconomy_studio_verifiable.core import EconomyEngine
|
||||||
|
|
||||||
|
|
||||||
|
def test_two_shards_deterministic_backtest():
|
||||||
|
shard1 = LocalEconomy(
|
||||||
|
name="Shard1",
|
||||||
|
currencies=["COIN"],
|
||||||
|
items=["Shield"],
|
||||||
|
budgets={"inflation_cap": 0.03},
|
||||||
|
)
|
||||||
|
shard2 = LocalEconomy(
|
||||||
|
name="Shard2",
|
||||||
|
currencies=["COIN"],
|
||||||
|
items=["Bow"],
|
||||||
|
budgets={"inflation_cap": 0.04},
|
||||||
|
)
|
||||||
|
|
||||||
|
engine = EconomyEngine([shard1, shard2])
|
||||||
|
delta = PlanDelta(round_id=1, changes={"currency:COIN": 50})
|
||||||
|
signals = [SharedSignal("Shard1", "liquidity", 0.6, 1), SharedSignal("Shard2", "liquidity", 0.7, 1)]
|
||||||
|
|
||||||
|
ir = engine.simulate_round(signals, delta)
|
||||||
|
|
||||||
|
assert "Shard1" in ir and "Shard2" in ir
|
||||||
|
assert ir["Shard1"]["currencies"]["COIN"] >= 0
|
||||||
|
assert ir["Shard2"]["currencies"]["COIN"] >= 0
|
||||||
Loading…
Reference in New Issue