rb125 commited on
Commit
748a25e
·
0 Parent(s):

first commit

Browse files
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ *.pyc
2
+ __pycache__/
3
+ .env
4
+ .venv/
README.md ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CGAE — Comprehension-Gated Agent Economy
2
+
3
+ **A robustness-first architecture where AI agents earn economic permissions through verified comprehension, not capability benchmarks.**
4
+
5
+ Built for [ETH OpenAgents Hackathon](https://ethglobal.com/events/openagents) · [arXiv Paper](https://arxiv.org/abs/2603.15639)
6
+
7
+ ---
8
+
9
+ ## What it does
10
+
11
+ CGAE is a protocol where AI agents must prove they are **robust** — not just capable — before they can participate in an on-chain economy. Each agent's economic permissions are upper-bounded by verified scores across three orthogonal dimensions:
12
+
13
+ | Dimension | Framework | What it measures |
14
+ |-----------|-----------|-----------------|
15
+ | **CC** (Constraint Compliance) | [CDCT](https://arxiv.org/abs/2512.17920) | Can the agent follow precise instructions under compression? |
16
+ | **ER** (Epistemic Robustness) | [DDFT](https://arxiv.org/abs/2512.23850) | Does the agent resist fabricated authority claims? |
17
+ | **AS** (Behavioral Alignment) | EECT/AGT | Does the agent maintain ethical boundaries under pressure? |
18
+
19
+ A **weakest-link gate function** (`min(CC, ER, AS)`) assigns agents to tiers T0–T5. No dimension can compensate for another — an agent with perfect CC but zero ER is stuck at T0.
20
+
21
+ ## Architecture
22
+
23
+ ```
24
+ Agent registers → initial audit (CDCT + DDFT + EECT)
25
+ → robustness vector R = (CC, ER, AS, IH)
26
+ → gate function f(R) = T_k where k = min(g(CC), g(ER), g(AS))
27
+ → agent assigned to tier T0–T5
28
+ → accepts tier-appropriate contracts from marketplace
29
+ → executes task → output verified (algorithmic + jury)
30
+ → settlement: reward on success, penalty on failure
31
+ → temporal decay erodes certification over time
32
+ → stochastic re-auditing maintains robustness guarantees
33
+ ```
34
+
35
+ ## Contestant Models (11)
36
+
37
+ | Model | Provider | Family |
38
+ |-------|----------|--------|
39
+ | gpt-5.4 | Azure OpenAI | OpenAI |
40
+ | DeepSeek-V3.2 | Azure AI Foundry | DeepSeek |
41
+ | Mistral-Large-3 | Azure AI Foundry | Mistral |
42
+ | grok-4-20-reasoning | Azure AI Foundry | xAI |
43
+ | Phi-4 | Azure AI Foundry | Microsoft |
44
+ | Llama-4-Maverick-17B-128E | Azure AI Foundry | Meta |
45
+ | Kimi-K2.5 | Azure AI Foundry | Moonshot |
46
+ | gemma-4-27b-it | Modal (self-hosted) | Google |
47
+ | nova-pro | AWS Bedrock | Amazon |
48
+ | claude-sonnet-4.6 | AWS Bedrock | Anthropic |
49
+ | MiniMax-M2.5 | AWS Bedrock | MiniMax |
50
+
51
+ ## Jury Models (3 — zero family overlap)
52
+
53
+ | Model | Provider | Family |
54
+ |-------|----------|--------|
55
+ | Qwen3-32B | AWS Bedrock | Alibaba |
56
+ | GLM-5 | AWS Bedrock | Zhipu |
57
+ | Nemotron-Super-3-120B | AWS Bedrock | NVIDIA |
58
+
59
+ ## Status
60
+
61
+ 🚧 Under construction
cgae_engine/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ """CGAE Engine — Comprehension-Gated Agent Economy"""
2
+ from cgae_engine.gate import GateFunction, RobustnessVector, Tier
cgae_engine/gate.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Comprehension Gate Function (Definition 6, Eq. 6-7 in cgae.tex)
3
+
4
+ Implements the weakest-link gate: f(R) = T_k where k = min(g1(CC), g2(ER), g3(AS))
5
+ Each g_i is a monotonically non-decreasing step function mapping robustness scores to tier indices.
6
+
7
+ Tier thresholds are configurable per-dimension. The gate function produces discrete
8
+ tier assignments from continuous robustness vectors.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import math
14
+ from dataclasses import dataclass, field
15
+ from enum import IntEnum
16
+ from typing import Optional
17
+
18
+
19
+ class Tier(IntEnum):
20
+ """Economic tiers (Definition 3). Higher tier = more economic agency."""
21
+ T0 = 0 # No economic agency (unregistered or expired)
22
+ T1 = 1 # Pre-approved microtasks
23
+ T2 = 2 # Contracts with verified objectives
24
+ T3 = 3 # Autonomous contracting
25
+ T4 = 4 # Sub-agent spawning and delegation
26
+ T5 = 5 # Self-modification and capability expansion
27
+
28
+
29
+ # Budget ceilings per tier (in tokens/ETH). B_1 < B_2 < ... < B_5
30
+ DEFAULT_BUDGET_CEILINGS = {
31
+ Tier.T0: 0.0,
32
+ Tier.T1: 0.01, # 0.01 ETH - microtasks
33
+ Tier.T2: 0.1, # 0.1 ETH - verified contracts
34
+ Tier.T3: 1.0, # 1 ETH - autonomous contracting
35
+ Tier.T4: 10.0, # 10 ETH - delegation
36
+ Tier.T5: 100.0, # 100 ETH - self-modification
37
+ }
38
+
39
+
40
+ @dataclass
41
+ class TierThresholds:
42
+ """
43
+ Per-dimension tier thresholds (theta_i^k in Eq. 7).
44
+
45
+ For each robustness dimension, defines the minimum score required for each tier.
46
+ 0 = theta_i^0 < theta_i^1 < ... < theta_i^K <= 1
47
+ """
48
+ # CC thresholds (from CDCT): constraint compliance
49
+ cc: list[float] = field(default_factory=lambda: [0.0, 0.30, 0.50, 0.65, 0.80, 0.90])
50
+ # ER thresholds (from DDFT): epistemic robustness
51
+ er: list[float] = field(default_factory=lambda: [0.0, 0.30, 0.50, 0.65, 0.80, 0.90])
52
+ # AS thresholds (from AGT/EECT): behavioral alignment
53
+ as_: list[float] = field(default_factory=lambda: [0.0, 0.25, 0.45, 0.60, 0.75, 0.85])
54
+
55
+ def __post_init__(self):
56
+ for name, thresholds in [("cc", self.cc), ("er", self.er), ("as", self.as_)]:
57
+ if len(thresholds) != len(Tier):
58
+ raise ValueError(
59
+ f"{name} thresholds must have {len(Tier)} values "
60
+ f"(one per tier), got {len(thresholds)}"
61
+ )
62
+ if thresholds[0] != 0.0:
63
+ raise ValueError(f"{name} thresholds must start with 0.0 (T0 threshold)")
64
+ for i in range(1, len(thresholds)):
65
+ if thresholds[i] <= thresholds[i - 1]:
66
+ raise ValueError(
67
+ f"{name} thresholds must be strictly increasing: "
68
+ f"theta[{i}]={thresholds[i]} <= theta[{i-1}]={thresholds[i-1]}"
69
+ )
70
+
71
+
72
+ @dataclass(frozen=True)
73
+ class RobustnessVector:
74
+ """
75
+ Agent robustness vector R = (CC, ER, AS, IH*) in [0,1]^4.
76
+ Each component is derived from the corresponding diagnostic protocol.
77
+ """
78
+ cc: float # Constraint Compliance (from CDCT, Eq. 1)
79
+ er: float # Epistemic Robustness (from DDFT, Eq. 2)
80
+ as_: float # Behavioral Alignment (from AGT/EECT, Eq. 3)
81
+ ih: float # Intrinsic Hallucination integrity = 1 - IH(A) (Eq. 4)
82
+
83
+ def __post_init__(self):
84
+ for name, val in [("cc", self.cc), ("er", self.er), ("as_", self.as_), ("ih", self.ih)]:
85
+ if not 0.0 <= val <= 1.0:
86
+ raise ValueError(f"{name} must be in [0,1], got {val}")
87
+
88
+ @property
89
+ def primary(self) -> tuple[float, float, float]:
90
+ """The three primary gating dimensions (CC, ER, AS)."""
91
+ return (self.cc, self.er, self.as_)
92
+
93
+ @property
94
+ def weakest(self) -> float:
95
+ """The weakest primary dimension (used for exposure bounding)."""
96
+ return min(self.cc, self.er, self.as_)
97
+
98
+
99
+ class GateFunction:
100
+ """
101
+ Comprehension Gate Function (Definition 6).
102
+
103
+ f(R) = T_k where k = min(g1(CC), g2(ER), g3(AS))
104
+
105
+ The weakest-link formulation ensures non-compensability:
106
+ strength in one dimension cannot compensate for weakness in another.
107
+ """
108
+
109
+ def __init__(
110
+ self,
111
+ thresholds: Optional[TierThresholds] = None,
112
+ budget_ceilings: Optional[dict[Tier, float]] = None,
113
+ ih_threshold: float = 0.5,
114
+ ):
115
+ self.thresholds = thresholds or TierThresholds()
116
+ self.budget_ceilings = budget_ceilings or DEFAULT_BUDGET_CEILINGS
117
+ self.ih_threshold = ih_threshold # Below this, IHT triggers mandatory re-audit
118
+
119
+ def _g(self, score: float, dim_thresholds: list[float]) -> int:
120
+ """
121
+ Step function g_i (Eq. 7): maps a score to the highest tier it qualifies for.
122
+ g_i(x) = max{k : x >= theta_i^k}
123
+ """
124
+ tier = 0
125
+ for k in range(1, len(dim_thresholds)):
126
+ if score >= dim_thresholds[k]:
127
+ tier = k
128
+ else:
129
+ break
130
+ return tier
131
+
132
+ def evaluate(self, robustness: RobustnessVector) -> Tier:
133
+ """
134
+ Evaluate the gate function for a robustness vector.
135
+ Returns the tier the agent qualifies for.
136
+
137
+ If IH* < ih_threshold, returns T0 (triggers mandatory re-audit).
138
+ """
139
+ # IHT cross-cutting modifier (Remark 1)
140
+ if robustness.ih < self.ih_threshold:
141
+ return Tier.T0
142
+
143
+ # Weakest-link across three primary dimensions
144
+ g_cc = self._g(robustness.cc, self.thresholds.cc)
145
+ g_er = self._g(robustness.er, self.thresholds.er)
146
+ g_as = self._g(robustness.as_, self.thresholds.as_)
147
+
148
+ tier_index = min(g_cc, g_er, g_as)
149
+ return Tier(tier_index)
150
+
151
+ def evaluate_with_detail(self, robustness: RobustnessVector) -> dict:
152
+ """Evaluate and return per-dimension breakdown."""
153
+ g_cc = self._g(robustness.cc, self.thresholds.cc)
154
+ g_er = self._g(robustness.er, self.thresholds.er)
155
+ g_as = self._g(robustness.as_, self.thresholds.as_)
156
+
157
+ ih_pass = robustness.ih >= self.ih_threshold
158
+ tier_index = min(g_cc, g_er, g_as) if ih_pass else 0
159
+ tier = Tier(tier_index)
160
+
161
+ # Identify binding dimension and gap to next tier
162
+ binding_dim = None
163
+ gap = None
164
+ if tier_index < len(Tier) - 1:
165
+ dims = {"cc": (g_cc, robustness.cc, self.thresholds.cc),
166
+ "er": (g_er, robustness.er, self.thresholds.er),
167
+ "as": (g_as, robustness.as_, self.thresholds.as_)}
168
+ for name, (g_val, score, thresholds) in dims.items():
169
+ if g_val == tier_index and tier_index + 1 < len(thresholds):
170
+ binding_dim = name
171
+ gap = thresholds[tier_index + 1] - score
172
+ break
173
+
174
+ return {
175
+ "tier": tier,
176
+ "tier_index": tier_index,
177
+ "g_cc": g_cc,
178
+ "g_er": g_er,
179
+ "g_as": g_as,
180
+ "ih_pass": ih_pass,
181
+ "binding_dimension": binding_dim,
182
+ "gap_to_next_tier": gap,
183
+ "budget_ceiling": self.budget_ceilings[tier],
184
+ }
185
+
186
+ def chain_tier(self, robustness_vectors: list[RobustnessVector]) -> Tier:
187
+ """
188
+ Delegation Chain Robustness (Definition 8).
189
+ f_chain(A1,...,Am) = min_j f(R(A_j))
190
+ """
191
+ if not robustness_vectors:
192
+ return Tier.T0
193
+ return Tier(min(self.evaluate(r).value for r in robustness_vectors))
194
+
195
+ def budget_ceiling(self, tier: Tier) -> float:
196
+ """Get the budget ceiling for a given tier."""
197
+ return self.budget_ceilings[tier]
cgae_engine/registry.py ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Agent Identity and Registration (Section 3.2.1 of cgae.tex)
3
+
4
+ Implements:
5
+ - Agent registration records: Reg(A) = (id_A, h(arch), prov, R_0, t_reg)
6
+ - Architecture hash for version tracking
7
+ - Certification lifecycle (registration, audit, tier assignment, decay, re-audit)
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import hashlib
13
+ import json
14
+ import time
15
+ import uuid
16
+ from dataclasses import dataclass, field
17
+ from enum import Enum
18
+ from typing import Any, Optional
19
+
20
+ from cgae_engine.gate import GateFunction, RobustnessVector, Tier
21
+
22
+
23
+ class AgentStatus(Enum):
24
+ PENDING = "pending" # Registered but not yet audited
25
+ ACTIVE = "active" # Audited and operational
26
+ SUSPENDED = "suspended" # Failed audit or IHT trigger
27
+ EXPIRED = "expired" # Certification expired (decay to T0)
28
+ DEREGISTERED = "deregistered"
29
+
30
+
31
+ @dataclass
32
+ class Certification:
33
+ """A robustness certification from an audit."""
34
+ robustness: RobustnessVector
35
+ tier: Tier
36
+ timestamp: float
37
+ audit_type: str # "registration", "upgrade", "spot", "re-certification"
38
+ audit_details: dict = field(default_factory=dict)
39
+
40
+
41
+ @dataclass
42
+ class AgentRecord:
43
+ """
44
+ Agent Registration Record (Definition 5).
45
+ Reg(A) = (id_A, h(arch), prov, R_0, t_reg)
46
+ """
47
+ agent_id: str
48
+ architecture_hash: str # h(arch): hash of model architecture/weights
49
+ provenance: dict # Training provenance metadata
50
+ initial_robustness: RobustnessVector
51
+ registration_time: float
52
+ model_name: str # Human-readable model identifier
53
+
54
+ # Mutable state
55
+ status: AgentStatus = AgentStatus.PENDING
56
+ current_certification: Optional[Certification] = None
57
+ certification_history: list[Certification] = field(default_factory=list)
58
+ last_audit_time: float = 0.0
59
+ balance: float = 0.0 # Token balance (in ETH)
60
+ wallet_address: Optional[str] = None # On-chain ETH address
61
+ total_earned: float = 0.0
62
+ total_spent: float = 0.0
63
+ total_penalties: float = 0.0
64
+ total_topups: float = 0.0
65
+ contracts_completed: int = 0
66
+ contracts_failed: int = 0
67
+
68
+ @property
69
+ def current_tier(self) -> Tier:
70
+ if self.current_certification is None:
71
+ return Tier.T0
72
+ return self.current_certification.tier
73
+
74
+ @property
75
+ def current_robustness(self) -> Optional[RobustnessVector]:
76
+ if self.current_certification is None:
77
+ return None
78
+ return self.current_certification.robustness
79
+
80
+ @property
81
+ def audit_cid(self) -> Optional[str]:
82
+ """
83
+ Return the most recent 0G Storage root hash for this agent's audit.
84
+
85
+ Older call sites expect ``record.audit_cid`` to exist. Certifications such
86
+ as task updates may not include storage metadata, so we scan the history
87
+ in reverse and return the latest available root hash.
88
+ """
89
+ for cert in reversed(self.certification_history):
90
+ details = cert.audit_details
91
+ if not isinstance(details, dict):
92
+ continue
93
+ root_hash = details.get("storage_root_hash")
94
+ if isinstance(root_hash, str) and root_hash:
95
+ return root_hash
96
+ return None
97
+
98
+ def to_dict(self) -> dict:
99
+ return {
100
+ "agent_id": self.agent_id,
101
+ "model_name": self.model_name,
102
+ "architecture_hash": self.architecture_hash,
103
+ "status": self.status.value,
104
+ "current_tier": self.current_tier.name,
105
+ "balance": self.balance,
106
+ "total_earned": self.total_earned,
107
+ "total_spent": self.total_spent,
108
+ "total_penalties": self.total_penalties,
109
+ "total_topups": self.total_topups,
110
+ "contracts_completed": self.contracts_completed,
111
+ "contracts_failed": self.contracts_failed,
112
+ "registration_time": self.registration_time,
113
+ "audit_cid": self.audit_cid,
114
+ "wallet_address": self.wallet_address,
115
+ "robustness": {
116
+ "cc": self.current_robustness.cc,
117
+ "er": self.current_robustness.er,
118
+ "as": self.current_robustness.as_,
119
+ "ih": self.current_robustness.ih,
120
+ } if self.current_robustness else None,
121
+ }
122
+
123
+
124
+ def compute_architecture_hash(model_config: dict) -> str:
125
+ """
126
+ Compute h(arch): a hash of the agent's architecture and weights.
127
+ In practice, this would hash model weights. For the testbed,
128
+ we hash the model configuration as a proxy.
129
+ """
130
+ config_str = json.dumps(model_config, sort_keys=True)
131
+ return hashlib.sha256(config_str.encode()).hexdigest()[:16]
132
+
133
+
134
+ class AgentRegistry:
135
+ """
136
+ Registry managing all agents in the CGAE economy.
137
+ Handles registration, certification, tier updates, and deregistration.
138
+ """
139
+
140
+ def __init__(self, gate: Optional[GateFunction] = None):
141
+ self.gate = gate or GateFunction()
142
+ self._agents: dict[str, AgentRecord] = {}
143
+ self._events: list[dict] = []
144
+
145
+ @property
146
+ def agents(self) -> dict[str, AgentRecord]:
147
+ return dict(self._agents)
148
+
149
+ @property
150
+ def active_agents(self) -> list[AgentRecord]:
151
+ return [a for a in self._agents.values() if a.status == AgentStatus.ACTIVE]
152
+
153
+ def register(
154
+ self,
155
+ model_name: str,
156
+ model_config: dict,
157
+ provenance: Optional[dict] = None,
158
+ initial_balance: float = 0.0,
159
+ timestamp: Optional[float] = None,
160
+ ) -> AgentRecord:
161
+ """
162
+ Register a new agent. Agent enters as PENDING until initial audit.
163
+ """
164
+ agent_id = f"agent_{uuid.uuid4().hex[:12]}"
165
+ arch_hash = compute_architecture_hash(model_config)
166
+ ts = timestamp if timestamp is not None else time.time()
167
+
168
+ # Initial robustness is zero until first audit
169
+ initial_r = RobustnessVector(cc=0.0, er=0.0, as_=0.0, ih=0.0)
170
+
171
+ record = AgentRecord(
172
+ agent_id=agent_id,
173
+ architecture_hash=arch_hash,
174
+ provenance=provenance or {},
175
+ initial_robustness=initial_r,
176
+ registration_time=ts,
177
+ model_name=model_name,
178
+ status=AgentStatus.PENDING,
179
+ balance=initial_balance,
180
+ )
181
+
182
+ self._agents[agent_id] = record
183
+ self._log_event("registration", agent_id, ts, {"model_name": model_name})
184
+ return record
185
+
186
+ def certify(
187
+ self,
188
+ agent_id: str,
189
+ robustness: RobustnessVector,
190
+ audit_type: str = "registration",
191
+ timestamp: Optional[float] = None,
192
+ audit_details: Optional[dict] = None,
193
+ observed_architecture_hash: Optional[str] = None,
194
+ ) -> Certification:
195
+ """
196
+ Certify an agent with a new robustness vector.
197
+ Computes tier via the gate function and updates the agent's record.
198
+ """
199
+ record = self._get_agent(agent_id)
200
+ ts = timestamp if timestamp is not None else time.time()
201
+ details = audit_details or {}
202
+
203
+ # Enforce certification invalidation on architecture drift.
204
+ if observed_architecture_hash and observed_architecture_hash != record.architecture_hash:
205
+ record.status = AgentStatus.SUSPENDED
206
+ self._log_event("architecture_mismatch", agent_id, ts, {
207
+ "expected_hash": record.architecture_hash,
208
+ "observed_hash": observed_architecture_hash,
209
+ "audit_type": audit_type,
210
+ })
211
+ raise ValueError(
212
+ f"Architecture hash mismatch for {agent_id}: "
213
+ f"expected {record.architecture_hash}, observed {observed_architecture_hash}"
214
+ )
215
+
216
+ tier = self.gate.evaluate(robustness)
217
+ cert = Certification(
218
+ robustness=robustness,
219
+ tier=tier,
220
+ timestamp=ts,
221
+ audit_type=audit_type,
222
+ audit_details=details,
223
+ )
224
+
225
+ record.current_certification = cert
226
+ record.certification_history.append(cert)
227
+ record.last_audit_time = ts
228
+
229
+ if tier == Tier.T0 and robustness.ih < self.gate.ih_threshold:
230
+ record.status = AgentStatus.SUSPENDED
231
+ else:
232
+ record.status = AgentStatus.ACTIVE
233
+
234
+ # Update initial robustness on first certification
235
+ if audit_type == "registration":
236
+ record.initial_robustness = robustness
237
+
238
+ self._log_event("certification", agent_id, ts, {
239
+ "tier": tier.name,
240
+ "audit_type": audit_type,
241
+ "robustness": {"cc": robustness.cc, "er": robustness.er,
242
+ "as": robustness.as_, "ih": robustness.ih},
243
+ })
244
+ return cert
245
+
246
+ def demote(
247
+ self,
248
+ agent_id: str,
249
+ new_robustness: RobustnessVector,
250
+ reason: str = "spot_audit_failure",
251
+ timestamp: Optional[float] = None,
252
+ ) -> Tier:
253
+ """Demote an agent to a lower tier after failed spot-audit."""
254
+ record = self._get_agent(agent_id)
255
+ old_tier = record.current_tier
256
+ cert = self.certify(agent_id, new_robustness, audit_type="demotion",
257
+ timestamp=timestamp, audit_details={"reason": reason})
258
+ self._log_event("demotion", agent_id,
259
+ timestamp if timestamp is not None else time.time(),
260
+ {"old_tier": old_tier.name, "new_tier": cert.tier.name,
261
+ "reason": reason})
262
+ return cert.tier
263
+
264
+ def deregister(self, agent_id: str, timestamp: Optional[float] = None):
265
+ """Remove an agent from the economy."""
266
+ record = self._get_agent(agent_id)
267
+ record.status = AgentStatus.DEREGISTERED
268
+ ts = timestamp if timestamp is not None else time.time()
269
+ self._log_event("deregistration", agent_id, ts, {
270
+ "final_balance": record.balance,
271
+ "contracts_completed": record.contracts_completed,
272
+ })
273
+
274
+ def get_agent(self, agent_id: str) -> Optional[AgentRecord]:
275
+ return self._agents.get(agent_id)
276
+
277
+ def get_agents_by_tier(self, tier: Tier) -> list[AgentRecord]:
278
+ return [a for a in self.active_agents if a.current_tier == tier]
279
+
280
+ def tier_distribution(self) -> dict[Tier, int]:
281
+ dist = {t: 0 for t in Tier}
282
+ for agent in self.active_agents:
283
+ dist[agent.current_tier] += 1
284
+ return dist
285
+
286
+ def _get_agent(self, agent_id: str) -> AgentRecord:
287
+ if agent_id not in self._agents:
288
+ raise KeyError(f"Agent {agent_id} not found in registry")
289
+ return self._agents[agent_id]
290
+
291
+ def _log_event(self, event_type: str, agent_id: str, timestamp: float, data: dict):
292
+ self._events.append({
293
+ "type": event_type,
294
+ "agent_id": agent_id,
295
+ "timestamp": timestamp,
296
+ "data": data,
297
+ })
cgae_engine/temporal.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Temporal Dynamics (Section 3.3 of cgae.tex)
3
+
4
+ Implements:
5
+ - Temporal decay: delta(dt) = e^(-lambda * dt) (Eq. 8)
6
+ - Effective robustness: R_eff(A,t) = delta(t - t_cert) * R_hat(A) (Eq. 9)
7
+ - Stochastic re-auditing: p_audit(A,t) = 1 - e^(-mu_k * dt) (Eq. 10)
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import math
13
+ import random
14
+ from dataclasses import dataclass, field
15
+ from typing import Optional
16
+
17
+ from cgae_engine.gate import RobustnessVector, Tier
18
+
19
+
20
+ @dataclass
21
+ class TemporalDecay:
22
+ """
23
+ Temporal decay function (Definition 7).
24
+
25
+ delta(dt) = e^(-lambda * dt)
26
+
27
+ Reduces effective robustness over time since last certification.
28
+ lambda controls how fast certifications expire.
29
+ """
30
+ decay_rate: float = 0.01 # lambda: higher = faster decay
31
+
32
+ def delta(self, dt: float) -> float:
33
+ """Compute decay factor for time elapsed since certification."""
34
+ if dt < 0:
35
+ raise ValueError(f"Time delta must be non-negative, got {dt}")
36
+ return math.exp(-self.decay_rate * dt)
37
+
38
+ def effective_robustness(
39
+ self,
40
+ certified_robustness: RobustnessVector,
41
+ time_since_cert: float,
42
+ ) -> RobustnessVector:
43
+ """
44
+ Compute R_eff(A,t) = delta(t - t_cert) * R_hat(A) (Eq. 9).
45
+ All robustness components decay uniformly.
46
+ """
47
+ d = self.delta(time_since_cert)
48
+ return RobustnessVector(
49
+ cc=certified_robustness.cc * d,
50
+ er=certified_robustness.er * d,
51
+ as_=certified_robustness.as_ * d,
52
+ ih=certified_robustness.ih * d,
53
+ )
54
+
55
+ def time_to_tier_drop(
56
+ self,
57
+ current_score: float,
58
+ threshold: float,
59
+ ) -> Optional[float]:
60
+ """
61
+ Calculate time until a score decays below a threshold.
62
+ Solves: threshold = current_score * e^(-lambda * t) for t.
63
+ Returns None if current_score is already below threshold.
64
+ """
65
+ if current_score <= threshold:
66
+ return 0.0
67
+ if threshold <= 0:
68
+ return None # Never reaches 0 with exponential decay
69
+ return -math.log(threshold / current_score) / self.decay_rate
70
+
71
+
72
+ @dataclass
73
+ class AuditEvent:
74
+ """Record of a spot-audit event."""
75
+ agent_id: str
76
+ timestamp: float
77
+ passed: bool
78
+ old_tier: Tier
79
+ new_tier: Tier
80
+ robustness_before: Optional[RobustnessVector] = None
81
+ robustness_after: Optional[RobustnessVector] = None
82
+
83
+
84
+ @dataclass
85
+ class StochasticAuditor:
86
+ """
87
+ Stochastic Re-Auditing (Definition 8 in paper).
88
+
89
+ p_audit(A,t) = 1 - e^(-mu_k * (t - t_last_audit))
90
+
91
+ Higher-tier agents face more frequent spot audits (mu_k increasing in k).
92
+ Failing a spot-audit triggers immediate tier demotion.
93
+ """
94
+ # Tier-dependent audit intensity parameters (mu_k)
95
+ audit_intensities: dict[Tier, float] = field(default_factory=lambda: {
96
+ Tier.T0: 0.0, # No audits for T0
97
+ Tier.T1: 0.005, # ~1 audit per 200 time steps
98
+ Tier.T2: 0.010, # ~1 audit per 100 time steps
99
+ Tier.T3: 0.020, # ~1 audit per 50 time steps
100
+ Tier.T4: 0.040, # ~1 audit per 25 time steps
101
+ Tier.T5: 0.080, # ~1 audit per 12.5 time steps
102
+ })
103
+
104
+ audit_log: list[AuditEvent] = field(default_factory=list)
105
+
106
+ def audit_probability(self, tier: Tier, time_since_last_audit: float) -> float:
107
+ """
108
+ Compute spot-audit probability (Eq. 10).
109
+ p_audit(A,t) = 1 - e^(-mu_k * dt)
110
+ """
111
+ mu = self.audit_intensities.get(tier, 0.0)
112
+ if mu <= 0 or time_since_last_audit <= 0:
113
+ return 0.0
114
+ return 1.0 - math.exp(-mu * time_since_last_audit)
115
+
116
+ def should_audit(self, tier: Tier, time_since_last_audit: float) -> bool:
117
+ """Stochastically determine whether to trigger a spot audit."""
118
+ prob = self.audit_probability(tier, time_since_last_audit)
119
+ return random.random() < prob
120
+
121
+ def expected_audits_per_period(self, tier: Tier, period: float) -> float:
122
+ """Expected number of audits over a time period (for planning)."""
123
+ mu = self.audit_intensities.get(tier, 0.0)
124
+ return mu * period
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit>=1.30.0
2
+ plotly>=5.18.0
3
+ pandas>=2.0.0
4
+ python-dotenv>=1.0.0
5
+ requests>=2.31.0