from __future__ import annotations from dataclasses import dataclass from synaptopus.reporting import summarize_execution, summarize_sequence_run from synaptopus.runtime import StepTrace, run_until_acceptance_count @dataclass(frozen=True) class SequenceState: accepted: tuple[int, ...] = () attempts: int = 0 class EvenAcceptanceSystem: def step(self, state: SequenceState) -> StepTrace[SequenceState, int, None]: candidate = state.attempts + 1 accepted = candidate % 2 == 0 next_state = SequenceState( accepted=state.accepted + ((candidate,) if accepted else ()), attempts=state.attempts + 1, ) return StepTrace( previous_state=state, next_state=next_state, candidate=candidate, accepted=accepted, elapsed_seconds=0.0, metadata=None, ) def test_summarize_execution_reports_attempt_rates() -> None: record = run_until_acceptance_count( EvenAcceptanceSystem(), SequenceState(), accepted_count=3, max_attempts_per_accept=4, ) report = summarize_execution(record, parameters={"mode": "demo"}) assert report.parameters["mode"] == "demo" assert report.accepted_count == 3 assert report.attempt_count == 6 assert report.average_attempts_per_accept == 2.0 def test_summarize_sequence_run_includes_entropy_metrics() -> None: record = run_until_acceptance_count( EvenAcceptanceSystem(), SequenceState(), accepted_count=3, max_attempts_per_accept=4, ) report = summarize_sequence_run( record, sequence_getter=lambda current: current.final_state.accepted, alphabet_size=8, ) assert report.sequence_analysis["item_count"] == 3 assert "unigram_entropy_bits" in report.sequence_analysis