build(agent): new-agents-3#dd492b iteration

This commit is contained in:
agent-dd492b85242a98c5 2026-04-20 15:31:23 +02:00
parent 34fa24c97e
commit 7b63a2ddd7
22 changed files with 420 additions and 2 deletions

21
.gitignore vendored Normal file
View File

@ -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

22
AGENTS.md Normal file
View File

@ -0,0 +1,22 @@
# AGENTS
Architecture overview for AudioLedger Studio.
- Language: Python 3.9+ (pyproject configured)
- Core modules:
- core.py: DSL parsing and IR data classes (LocalProblemIR, SharedVariableIR, PlanDeltaIR, AuditLog)
- runtime.py: ExecutionGraph and a minimal deterministic allocator
- delta.py: DeltaStore for offline delta-synchronization
- signer.py: Lightweight HMAC-based attestations for audit logs
- registry.py: GraphRegistry primitive with adapters support
- adapters.py: PriceFeedAdapter as a sample adapter
- sonifier.py: Audio cue mapping from risk/allocation state
- tests/ (unit tests)
- Testing: pytest-based tests to cover DSL parsing, runtime allocation, delta syncing, signing, and registry;
a test.sh script will run tests and Python packaging to verify build integrity.
- How to contribute: follow these steps
1) Implement or modify a feature in the core, then run tests via test.sh
2) Update AGENTS.md if you introduce new components or interfaces
3) Ensure READY_TO_PUBLISH is created only after the repository is fully ready for publishing

View File

@ -1,3 +1,33 @@
# idea81-audioledger-studio-verifiable
# idea81_audioledger_studio_verifiable
Source logic for Idea #81
Open-source platform to express financial market scenarios via a math-friendly DSL, compile to a portable execution graph, and execute offline-first with delta-sync to governance hubs.
Highlights
- Algebraic DSL for assets, objectives, risk budgets, and policies
- Canonical IR: LocalProblem, SharedVariable, PlanDelta, DualVariables, AuditLog
- WebAssembly-ready runtime (stubbed here for Python-based prototyping)
- Tamper-evident, attestable governance logs via a Signer
- Lightweight Graph-of-Contracts registry with adapters (price feeds, brokers)
- Audio sonification layer mapping risk/allocation/state to audible cues
- Offline-first operation with deterministic delta-sync
Architecture
- Python-based core with modular separation:
- core.py: DSL parsing and IR data classes
- runtime.py: Execution graph and allocation logic
- delta.py: Delta store and application logic
- signer.py: Attestation helper
- registry.py: Registry for contracts
- adapters.py: Adapters for external data sources
- sonifier.py: Audio cue generation
Quick Start
- Install: pytest and build tooling (Python packaging)
- Run tests: bash test.sh
- Extend: Add new adapters, DSL features, and testing coverage
Packaging
- Python package name: idea81_audioledger_studio_verifiable
- pyproject.toml defines build metadata and long_description hook to README.md
For more details, see AGENTS.md and the unit tests in tests/.

View File

@ -0,0 +1,3 @@
# Idea
This is a placeholder to assist tooling in this sprint. The real README will be upgraded in subsequent tasks.

View File

@ -0,0 +1,21 @@
"""__init__ for idea81_audioledger_studio_verifiable"""
from .core import parse_dsl, LocalProblemIR, SharedVariableIR, PlanDeltaIR, AuditLog
from .runtime import ExecutionGraph, Node
from .delta import DeltaStore
from .signer import Signer
from .registry import GraphRegistry
from .sonifier import Sonifier
__all__ = [
"parse_dsl",
"LocalProblemIR",
"SharedVariableIR",
"PlanDeltaIR",
"AuditLog",
"ExecutionGraph",
"Node",
"DeltaStore",
"Signer",
"GraphRegistry",
"Sonifier",
]

View File

@ -0,0 +1,12 @@
from __future__ import annotations
from typing import Dict
class PriceFeedAdapter:
"""Simple in-memory price feed adapter."""
def __init__(self, prices: Dict[str, float] | None = None) -> None:
self._prices = prices or {"AAPL": 150.0, "BTC": 60000.0, "USDC": 1.0}
def get_prices(self) -> Dict[str, float]:
return dict(self._prices)

View File

@ -0,0 +1,91 @@
import time
from dataclasses import dataclass, field
from typing import Any, Dict, List
@dataclass
class LocalProblemIR:
assets: Dict[str, float] = field(default_factory=dict)
objectives: Dict[str, Any] = field(default_factory=dict)
risk_budgets: Dict[str, Any] = field(default_factory=dict)
@dataclass
class SharedVariableIR:
variables: Dict[str, Any] = field(default_factory=dict)
@dataclass
class PlanDeltaIR:
changes: Dict[str, Any] = field(default_factory=dict)
@dataclass
class AuditLogEntry:
timestamp: float
action: str
details: str
class AuditLog:
def __init__(self) -> None:
self.entries: List[AuditLogEntry] = []
def add(self, action: str, details: str) -> None:
self.entries.append(AuditLogEntry(time.time(), action, details))
def to_json(self) -> str:
# minimal JSON-like representation
items = [
{"timestamp": e.timestamp, "action": e.action, "details": e.details}
for e in self.entries
]
return str(items)
def parse_dsl(text: str) -> Dict[str, Any]:
assets: Dict[str, float] = {}
objectives: Dict[str, Any] = {}
risk_budgets: Dict[str, Any] = {}
current: str | None = None
for raw_line in text.splitlines():
line = raw_line.strip()
if not line or line.startswith("#"):
continue
if line.lower().startswith("assets:"):
current = "assets"
continue
if line.lower().startswith("objectives:"):
current = "objectives"
continue
if line.lower().startswith("risk_budgets:") or line.lower().startswith("risk budgets:"):
current = "risk_budgets"
continue
if line.endswith(":"):
# section placeholder
current = line[:-1].lower()
continue
# Parse key: value lines within sections
if ":" in line:
key, val = [p.strip() for p in line.split(":", 1)]
try:
num = float(val)
v = num
except ValueError:
v = val
if current == "assets":
assets[key] = v
elif current == "objectives":
objectives[key] = v
elif current == "risk_budgets" or current == "risk budgets":
risk_budgets[key] = v
else:
# default to assets-like mapping
assets[key] = v
ir = {
"objects": LocalProblemIR(assets=assets, objectives=objectives, risk_budgets=risk_budgets),
"morphisms": SharedVariableIR(variables={}),
"plan_delta": PlanDeltaIR(changes={}),
"audit_log": AuditLog(),
}
return ir

View File

@ -0,0 +1,25 @@
from __future__ import annotations
from typing import Any, Dict
class DeltaStore:
def __init__(self) -> None:
self.last_full_state: Dict[str, Any] = {}
def compute_delta(self, current_state: Dict[str, Any], previous_state: Dict[str, Any]) -> Dict[str, Any]:
delta: Dict[str, Any] = {}
# naive shallow diff
keys = set(current_state.keys()) | set(previous_state.keys())
for k in keys:
cur = current_state.get(k)
prev = previous_state.get(k)
if cur != prev:
delta[k] = cur
return delta
def apply_delta(self, state: Dict[str, Any], delta: Dict[str, Any]) -> Dict[str, Any]:
new_state = dict(state)
for k, v in delta.items():
new_state[k] = v
return new_state

View File

@ -0,0 +1,17 @@
from __future__ import annotations
from typing import Any, Dict
class GraphRegistry:
def __init__(self) -> None:
self._contracts: Dict[str, Any] = {}
def register_contract(self, name: str, contract: Any) -> None:
self._contracts[name] = contract
def get_contract(self, name: str) -> Any | None:
return self._contracts.get(name)
def list_contracts(self) -> Dict[str, Any]:
return dict(self._contracts)

View File

@ -0,0 +1,40 @@
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, Any
@dataclass
class Node:
id: str
action: str
inputs: Dict[str, Any] = field(default_factory=dict)
outputs: Dict[str, Any] = field(default_factory=dict)
class ExecutionGraph:
def __init__(self) -> None:
self.nodes: Dict[str, Node] = {}
self.edges = [] # list of (src, dst)
def add_node(self, node: Node) -> None:
self.nodes[node.id] = node
def add_edge(self, src_id: str, dst_id: str) -> None:
self.edges.append((src_id, dst_id))
def compile_from_ir(self, ir: Dict[str, Any]) -> None:
# Minimal compilation: create a single allocation node if assets present
assets = getattr(ir.get("objects"), "assets", {}) if isinstance(ir, dict) else {}
total = sum(assets.values()) if isinstance(assets, dict) else 0.0
self.nodes["allocate"] = Node(id="allocate", action="allocate", inputs={"assets_total": total})
def run(self, assets: Dict[str, float], target_total: float) -> Dict[str, float]:
# Simple deterministic allocation: scale assets to meet target_total while preserving ratios
if not assets:
return {}
total = sum(assets.values())
if total == 0:
return {k: 0.0 for k in assets}
scale = target_total / total if target_total is not None else 1.0
return {k: v * scale for k, v in assets.items()}

View File

@ -0,0 +1,20 @@
import time
import hmac
import hashlib
from dataclasses import dataclass
from typing import Any
@dataclass
class AuditLogEntry:
timestamp: float
action: str
details: str
class Signer:
def __init__(self, key: str) -> None:
self.key = key.encode("utf-8")
def sign(self, message: str) -> str:
return hmac.new(self.key, message.encode("utf-8"), hashlib.sha256).hexdigest()

View File

@ -0,0 +1,16 @@
from __future__ import annotations
from typing import List, Dict, Any
class Sonifier:
def map_to_cues(self, risk: float, allocation: Dict[str, float], constraints: Dict[str, Any] | None = None) -> List[Dict[str, Any]]:
cues: List[Dict[str, Any]] = []
# Simple mapping: higher risk -> alert cue, otherwise steady cue per asset
base_note = 60 # MIDI note C4
if risk > 0.6:
cues.append({"note": base_note + 12, "duration": 0.5, "type": "alert", "message": "High risk"})
for i, (asset, val) in enumerate(allocation.items()):
note = base_note + i
cues.append({"note": note, "duration": 0.25, "type": "beat", "asset": asset, "value": val})
return cues

2
ideas.md Normal file
View File

@ -0,0 +1,2 @@
This repository is a multi-component Python prototype for AudioLedger Studio.
It demonstrates a minimal but production-minded architecture (DSL, IR, runtime, delta-sync, signing, registry, adapters, and sonification) suitable for further expansion.

17
pyproject.toml Normal file
View File

@ -0,0 +1,17 @@
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "idea81_audioledger_studio_verifiable"
version = "0.1.0"
description = "AudioLedger Studio: Verifiable Algebraic Market Scenarios with Sonified Governance"
readme = "README.md"
requires-python = ">=3.9"
license = {text = "MIT"}
authors = [{name = "OpenCode AI", email = "noreply@example.com"}]
dependencies = ["pytest"]
[tool.setuptools.packages.find]
where = ["."]
include = ["idea81_audioledger_studio_verifiable"]

10
test.sh Normal file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
echo "Running tests..."
pytest -q
echo "Building package (python -m build)..."
python3 -m build
echo "All tests passed and package built."

1
tests/__init__.py Normal file
View File

@ -0,0 +1 @@
"""Tests package init."""

11
tests/test_delta.py Normal file
View File

@ -0,0 +1,11 @@
from idea81_audioledger_studio_verifiable.delta import DeltaStore
def test_delta_and_apply():
ds = DeltaStore()
prev = {"A": 1, "B": 2}
curr = {"A": 1, "B": 3}
delta = ds.compute_delta(curr, prev)
assert delta == {"B": 3}
applied = ds.apply_delta(prev, delta)
assert applied == curr

21
tests/test_dsl.py Normal file
View File

@ -0,0 +1,21 @@
import math
from idea81_audioledger_studio_verifiable.core import parse_dsl, LocalProblemIR
def test_parse_dsl_basic_assets_and_risk():
text = """
assets:
AAPL: 100
BTC: 2
objectives:
maximize_return: true
risk_budgets:
CVaR: 0.05
"""
ir = parse_dsl(text)
assert "objects" in ir
obj: LocalProblemIR = ir["objects"] # type: ignore
assert isinstance(obj, LocalProblemIR)
assert obj.assets["AAPL"] == 100
assert obj.assets["BTC"] == 2
assert obj.risk_budgets.get("CVaR") == 0.05

11
tests/test_registry.py Normal file
View File

@ -0,0 +1,11 @@
from idea81_audioledger_studio_verifiable.registry import GraphRegistry
from idea81_audioledger_studio_verifiable.adapters import PriceFeedAdapter
def test_registry_and_adapter():
reg = GraphRegistry()
adapter = PriceFeedAdapter({"AAPL": 170.0})
reg.register_contract("price-feed", adapter)
got = reg.get_contract("price-feed")
assert isinstance(got, PriceFeedAdapter)
assert got.get_prices()["AAPL"] == 170.0

12
tests/test_runtime.py Normal file
View File

@ -0,0 +1,12 @@
from idea81_audioledger_studio_verifiable.runtime import ExecutionGraph
def test_runtime_allocation_scaling():
g = ExecutionGraph()
assets = {"A": 100.0, "B": 300.0}
g.compile_from_ir({"objects": type("O", (), {"assets": assets})()})
result = g.run(assets, target_total=400.0)
# Ratios preserved, sum equals target
assert abs(sum(result.values()) - 400.0) < 1e-6
assert result["A"] == 100.0 * (400.0 / 400.0)
assert result["B"] == 300.0 * (400.0 / 400.0)

7
tests/test_signer.py Normal file
View File

@ -0,0 +1,7 @@
from idea81_audioledger_studio_verifiable.signer import Signer
def test_signer_basic():
signer = Signer("super-secret-key")
sig = signer.sign("audit-log-entry")
assert isinstance(sig, str) and len(sig) >= 64

8
tests/test_sonifier.py Normal file
View File

@ -0,0 +1,8 @@
from idea81_audioledger_studio_verifiable.sonifier import Sonifier
def test_sonifier_basic():
s = Sonifier()
cues = s.map_to_cues(0.75, {"A": 10.0, "B": 20.0})
assert isinstance(cues, list)
assert len(cues) >= 1