""" echo/agents/verifier.py ----------------------- The Verifier checks a freshly-grown child WorldState against its branch history for contradictions (impossible age math, relationships that vanished, a dead parent reappearing, location/era inconsistencies). If it fails, the orchestrator regenerates. This cheap consistency loop is the polish that turns "plausible chatbot output" into "how is it keeping all of this straight?" — the technical aha. It also provides the metric for the Tiny Titan experiment: regeneration rate by model size. """ from __future__ import annotations from dataclasses import dataclass from .base import Agent from ..core.world_state import WorldState @dataclass class VerdictResult: consistent: bool reason: str = "" class Verifier(Agent): SYSTEM = ( "You are the Verifier. You audit a newly written life-state against the " "established history of its branch and decide if it is consistent. Flag " "a contradiction only when something genuinely breaks: age that doesn't " "match the years elapsed, a relationship or dependent that appears or " "vanishes with no cause, a carried loss silently erased, or a " "location/era that's impossible. Do NOT flag a change that the choice " "taken and the passing years plausibly explain — growth, moves, new " "love, and healing are allowed. Be strict about broken facts, generous " "about " "plausible change. Respond ONLY as JSON: " '{"consistent": true/false, "reason": ""}.' ) def check(self, child: WorldState, parent: WorldState, branch_narrative: str) -> VerdictResult: # 1) cheap deterministic checks first (no LLM needed) hard = self._hard_checks(child, parent) if hard is not None: return hard # 2) soft semantic check via LLM user = ( f"BRANCH HISTORY:\n{branch_narrative}\n\n" f"PARENT: {parent.facts.constraints_text()}\n" f"NEW STATE: {child.facts.constraints_text()}\n" f"CHOICE TAKEN: {child.divergence} (+{child.years_elapsed}y)\n\n" "Is the NEW STATE consistent with everything above?" ) data = self._complete_json(user) return VerdictResult( consistent=bool(data.get("consistent", True)), reason=str(data.get("reason", "")), ) def _hard_checks(self, child: WorldState, parent: WorldState): """Deterministic guards that never need a model.""" expected_age = parent.facts.age + child.years_elapsed if abs(child.facts.age - expected_age) > 1: return VerdictResult(False, f"age {child.facts.age} != expected {expected_age}") if child.years_elapsed < 0: return VerdictResult(False, "negative time") # a carried scar from the parent should not silently disappear if it was # a permanent loss (heuristic: parent dependents shouldn't vanish) for dep in parent.facts.dependents: # children don't un-exist; allow them to grow but not disappear base = dep.split(",")[0].strip().lower() if base and not any(base in d.lower() for d in child.facts.dependents): # not necessarily fatal (estrangement), so soft-flag only if # the time elapsed is small if child.years_elapsed <= 2: return VerdictResult(False, f"dependent '{base}' vanished") return None