from dataclasses import dataclass from app.schemas.conclusion import ConclusionSummary, RankedFinding from app.schemas.evidence import EvidenceSummary from app.schemas.experiment import ExperimentSummary, ScoreCard from app.schemas.observation import ObservationSummary from app.schemas.orchestration import OrchestratorPlan @dataclass(slots=True) class StubRunnerResult: probe_evidence: list[EvidenceSummary] experiments: list[ExperimentSummary] conclusion: ConclusionSummary status: str class StubRunnerService: def run_initial_plan( self, *, session_id: str, observation: ObservationSummary, plan: OrchestratorPlan, ) -> StubRunnerResult: periodic_hint = 0.79 if "periodic" in observation.tags else 0.68 tonal_hint = 0.74 if observation.duration_ms >= 4500 else 0.61 classifier_top_score = 0.64 if "periodic" in observation.tags else 0.55 probe_evidence = [ EvidenceSummary( id=f"{session_id}-e1", producer_module_id="energy_probe", category="feature", values={ "rms": 0.41, "peak_count": 7, "duration_ms": observation.duration_ms, }, confidence=0.86, ), EvidenceSummary( id=f"{session_id}-e2", producer_module_id="periodicity_probe", category="pattern", values={ "repeat_interval_ms": 620, "stability": periodic_hint, }, confidence=0.82, ), EvidenceSummary( id=f"{session_id}-e3", producer_module_id="baseline_sound_classifier", category="classification", values={ "top_k": [ { "label": "periodic_alert_tone", "score": classifier_top_score, }, { "label": "mechanical_click_sequence", "score": 0.27, }, ] }, confidence=classifier_top_score, ), ] experiments: list[ExperimentSummary] = [] parent_id: str | None = None for index, planned_experiment in enumerate(plan.experiments, start=1): experiment_id = f"{session_id}-x{index}" title = planned_experiment.goal score_total = 0.72 + (index * 0.06) notes = [ f"Executed planned chain '{planned_experiment.preferred_chain_id or 'ad-hoc'}'." ] if planned_experiment.preferred_chain_id == "periodic_validation_chain": components = { "repeat_consistency": 0.89, "pattern_clarity": periodic_hint, "resource_cost": 0.18, } penalties = {"mixed_source_risk": 0.05} notes.append("Autocorrelation and cepstrum align on repeat interval.") failure_reasons: list[str] = [] elif planned_experiment.preferred_chain_id == "harmonic_validation_chain": components = { "tonal_stability": tonal_hint, "harmonic_ratio": 0.71, "resource_cost": 0.22, } penalties = {"short_clip_penalty": 0.04} notes.append("Harmonic structure is present but not fully dominant.") failure_reasons = [] else: components = { "mixed_source_probability": 0.43, "post_separation_gain": 0.18, "resource_cost": 0.31, } penalties = {"separation_uncertainty": 0.08} notes.append( "Source separation did not improve confidence enough to overtake the periodic hypothesis." ) failure_reasons = [] experiments.append( ExperimentSummary( id=experiment_id, parent_id=parent_id, hypothesis_id=planned_experiment.hypothesis_id, title=title, status="done", pipeline_summary=[ node.module_id for node in planned_experiment.pipeline ], score=ScoreCard( total=round(score_total, 2), components=components, penalties=penalties, notes=notes, ), failure_reasons=failure_reasons, ) ) parent_id = experiment_id conclusion = ConclusionSummary( summary=( "The sample most likely contains a periodic alert-like tone rather " "than an unstructured environmental event." ), findings=[ RankedFinding( label="Periodic alert tone", confidence=0.84 if "periodic" in observation.tags else 0.76, supporting_evidence=[ "Repeat interval remains stable near 620 ms.", "Probe chain shows clear onset grouping.", "Validation chains favor periodic structure over diffuse events.", ], contradicting_evidence=[ "Mixed-source contamination is not fully ruled out.", ], ) ], uncertainty=[ "The current stub runner does not yet incorporate source separation output.", "A longer clip may improve confidence around tonal stability.", ], suggested_next_actions=[ "Run harmonic validation against a longer sample window.", "Add a mixed-source validation branch if future captures include overlap tags.", ], ) return StubRunnerResult( probe_evidence=probe_evidence, experiments=experiments, conclusion=conclusion, status="reviewing", )