CrisisWorldCortex / tests /test_baseline_b3.py
Angshuman28's picture
Upload folder using huggingface_hub
952db85 verified
Raw
History Blame Contribute Delete
4.93 kB
"""Session 13 - B3CortexFixedRouter baseline smoke tests.
Per Phase A docs/CORTEX_ARCHITECTURE.md Decisions 51-55 + the user's
Session 13 proposal acceptance. T11 verifies B3 runs one full episode
on outbreak_easy in-process; T12 verifies the step_callback fires once
per tick (matching B1/B2's contract per Decision 54).
"""
from __future__ import annotations
import json
from typing import List
from baselines.cortex_fixed_router import B3CortexFixedRouter
from baselines.flat_agent import B1StepEvent
from CrisisWorldCortex.models import CrisisworldcortexAction
from CrisisWorldCortex.server.CrisisWorldCortex_environment import (
CrisisworldcortexEnvironment,
)
from tests._helpers.llm_stub import StubLLMClient
def _belief_json(brain: str) -> str:
return json.dumps(
{
"brain": brain,
"latent_estimates": {
"R1": {
"estimated_infection_rate": 0.05,
"estimated_r_effective": 1.2,
"estimated_compliance": 0.85,
"confidence_intervals": {},
}
},
"hypotheses": [{"label": "h1", "weight": 0.6, "explanation": "rising"}],
"uncertainty": 0.4,
"reducible_by_more_thought": 0.3,
"evidence": [{"source": "telemetry", "ref": "R1.cases", "excerpt": "5"}],
}
)
def _plan_json() -> str:
return json.dumps(
{
"action_sketch": "Deploy 100 test_kits to R1",
"expected_outer_action": {
"kind": "deploy_resource",
"region": "R1",
"resource_type": "test_kits",
"quantity": 100,
},
"expected_value": 0.6,
"cost": 200.0,
"assumptions": [],
"falsifiers": ["R1 cases drop"],
"confidence": 0.75,
}
)
def _critic_json(brain: str) -> str:
return json.dumps(
{
"brain": brain,
"target_plan_id": "plan-0",
"attacks": [],
"missing_considerations": [],
"would_change_mind_if": [],
"severity": 0.3,
}
)
def _round_responses() -> List[str]:
"""9 valid JSON responses for one round."""
out: List[str] = []
for brain in ("epidemiology", "logistics", "governance"):
out.append(_belief_json(brain))
out.append(_plan_json())
out.append(_critic_json(brain))
return out
class _InProcessEnvAdapter:
"""Mirrors tests/test_baseline_b1.py:83-99. Tests use in-process env;
production B3 uses HTTP CrisisworldcortexEnv per baselines/CLAUDE.md."""
def __init__(self, env: CrisisworldcortexEnvironment) -> None:
self._env = env
def reset(self):
return self._env.reset(task_name="outbreak_easy", seed=0)
def step(self, action: CrisisworldcortexAction):
return self._env.step(action)
# T11 - B3 runs one full episode on outbreak_easy
def test_b3_runs_one_full_episode_outbreak_easy() -> None:
env = CrisisworldcortexEnvironment()
env_adapter = _InProcessEnvAdapter(env)
# Pre-populate enough responses for 3 ticks worth of round-1 calls.
# DeterministicRouter emits after round 1 if agreement is high (all 3
# brains return deploy_resource here -> agreement == 1.0 -> emit).
# 3 ticks x 9 calls/tick = 27 responses.
responses: List[str] = []
for _ in range(3):
responses.extend(_round_responses())
stub = StubLLMClient(scripted_responses=responses)
b3 = B3CortexFixedRouter(env=env_adapter, llm=stub)
result = b3.run_episode(task="outbreak_easy", seed=0, max_ticks=3)
# Trajectory dict shape (matches B1's run_episode return)
assert "rewards" in result
assert "action_history" in result
assert "steps_taken" in result
assert result["steps_taken"] >= 1
assert all("kind" in a for a in result["action_history"])
# At least 9 LLM calls fired (one tick's worth of round-1)
assert stub.call_count >= 9
# T12 - step_callback fires once per tick (Decision 54)
def test_b3_step_callback_invoked_per_tick() -> None:
env = CrisisworldcortexEnvironment()
env_adapter = _InProcessEnvAdapter(env)
responses: List[str] = []
for _ in range(3):
responses.extend(_round_responses())
stub = StubLLMClient(scripted_responses=responses)
events_out: List[B1StepEvent] = []
def _capture(event: B1StepEvent) -> None:
events_out.append(event)
b3 = B3CortexFixedRouter(env=env_adapter, llm=stub)
result = b3.run_episode(
task="outbreak_easy",
seed=0,
max_ticks=3,
step_callback=_capture,
)
# Callback fires exactly once per tick taken
assert len(events_out) == result["steps_taken"]
assert all(isinstance(e, B1StepEvent) for e in events_out)
assert all(hasattr(e.action, "kind") for e in events_out)