Files
FusionAGI/tests/test_consequence_engine.py
Devin AI 9a8affae9a
Some checks failed
Tests / test (3.10) (pull_request) Failing after 35s
Tests / test (3.11) (pull_request) Failing after 34s
Tests / test (3.12) (pull_request) Successful in 39s
Tests / lint (pull_request) Successful in 36s
Tests / docker (pull_request) Successful in 1m42s
feat: consequence engine, causal world model, metacognition, interpretability, claim verification
Choice → Consequence → Learning:
- ConsequenceEngine tracks every decision point with alternatives,
  risk/reward estimates, and actual outcomes
- Consequences feed into AdaptiveEthics for experience-based learning
- FusionAGILoop now wires ethics + consequences into task lifecycle

Causal World Model:
- CausalWorldModel learns state-transition patterns from execution history
- Predicts outcomes based on observed action→effect patterns
- Uncertainty estimates decrease as more evidence accumulates

Metacognition:
- assess_head_outputs() evaluates reasoning quality from head outputs
- Detects knowledge gaps, measures head agreement, identifies uncertainty
- Actively recommends whether to seek more information

Interpretability:
- ReasoningTracer captures full prompt→answer reasoning traces
- Each step records stage, component, input/output, timing
- explain() generates human-readable reasoning explanations

Claim Verification:
- ClaimVerifier cross-checks claims for evidence, consistency, grounding
- Flags high-confidence claims lacking evidence support
- Detects contradictions between claims from different heads

325 tests passing, 0 ruff errors, 0 mypy errors.

Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
2026-04-28 06:25:35 +00:00

119 lines
4.3 KiB
Python

"""Tests for the consequence engine and choice→consequence→learning loop."""
from fusionagi.governance import Alternative, ConsequenceEngine
from fusionagi.governance.audit_log import AuditLog
from fusionagi.schemas.audit import AuditEventType
class TestConsequenceEngine:
"""Test consequence tracking and risk/reward estimation."""
def test_record_choice(self) -> None:
ce = ConsequenceEngine()
choice = ce.record_choice(
choice_id="c1",
actor="planner",
action_taken="use_tool_x",
estimated_risk=0.3,
estimated_reward=0.7,
rationale="Tool X is the best fit",
)
assert choice.choice_id == "c1"
assert choice.estimated_risk == 0.3
assert ce.total_choices == 1
def test_record_consequence(self) -> None:
ce = ConsequenceEngine()
ce.record_choice(choice_id="c1", actor="planner", action_taken="act")
consequence = ce.record_consequence(
choice_id="c1",
outcome_positive=True,
actual_risk_realized=0.1,
actual_reward_gained=0.9,
description="Action succeeded",
)
assert consequence is not None
assert consequence.outcome_positive is True
assert ce.total_consequences == 1
def test_consequence_not_found(self) -> None:
ce = ConsequenceEngine()
result = ce.record_consequence(choice_id="nonexistent", outcome_positive=True)
assert result is None
def test_surprise_factor(self) -> None:
ce = ConsequenceEngine()
ce.record_choice(
choice_id="c1",
actor="exec",
action_taken="risky_op",
estimated_risk=0.1,
estimated_reward=0.9,
)
consequence = ce.record_consequence(
choice_id="c1",
outcome_positive=False,
actual_risk_realized=0.9,
actual_reward_gained=0.1,
)
assert consequence is not None
assert consequence.surprise_factor > 0.5
def test_estimate_risk_reward_no_history(self) -> None:
ce = ConsequenceEngine()
estimate = ce.estimate_risk_reward("unknown_action")
assert estimate["observations"] == 0
assert estimate["confidence"] == 0.1
def test_estimate_risk_reward_with_history(self) -> None:
ce = ConsequenceEngine()
for i in range(5):
ce.record_choice(f"c{i}", "exec", "tool_call")
ce.record_consequence(
f"c{i}",
outcome_positive=True,
actual_risk_realized=0.2,
actual_reward_gained=0.8,
)
estimate = ce.estimate_risk_reward("tool_call")
assert estimate["observations"] == 5
assert abs(estimate["expected_risk"] - 0.2) < 0.01
assert abs(estimate["expected_reward"] - 0.8) < 0.01
def test_alternatives_recorded(self) -> None:
ce = ConsequenceEngine()
alts = [
Alternative(action="alt_a", estimated_risk=0.6, reason_not_chosen="Too risky"),
Alternative(action="alt_b", estimated_risk=0.2, reason_not_chosen="Lower reward"),
]
choice = ce.record_choice(
choice_id="c1",
actor="planner",
action_taken="chosen_action",
alternatives=alts,
)
assert len(choice.alternatives) == 2
assert choice.alternatives[0].reason_not_chosen == "Too risky"
def test_get_summary(self) -> None:
ce = ConsequenceEngine()
ce.record_choice("c1", "exec", "action_a")
ce.record_consequence("c1", True, 0.1, 0.9)
ce.record_choice("c2", "exec", "action_a")
ce.record_consequence("c2", False, 0.8, 0.1)
summary = ce.get_summary()
assert summary["total_choices"] == 2
assert summary["total_consequences"] == 2
assert summary["positive_outcomes"] == 1
assert summary["negative_outcomes"] == 1
def test_audit_log_integration(self) -> None:
audit = AuditLog()
ce = ConsequenceEngine(audit_log=audit)
ce.record_choice("c1", "exec", "action")
ce.record_consequence("c1", True)
choices = audit.get_by_type(AuditEventType.CHOICE)
consequences = audit.get_by_type(AuditEventType.CONSEQUENCE)
assert len(choices) == 1
assert len(consequences) == 1