Source code for aeat.agent.eval._flywheel
"""The data flywheel: promote a live failure into a golden regression scenario.
ADR R7's operating cadence: a live subagent-persona failure is not just a red
run — it becomes a NEW golden scenario so the same failure cannot recur
unnoticed. Promotion is deliberately conservative: the promoted scenario pins
the ORIGINAL scenario's declared expectations (the correct path), while the
observed failing behaviour is preserved verbatim in the scenario's comment
header as the annotation-queue evidence a tax-professional reviews. Names are
content-addressed (a hash of scenario + failure signature) so re-promoting
the same failure is idempotent — the flywheel dedups by construction, never
by clock.
"""
from __future__ import annotations
import hashlib
from pathlib import Path
from ...core.external_constants import UTF_8_ENCODING as _UTF_8
from ._live_scoring import LiveScenarioScore
from ._models import GoldenScenario, LiveTrajectory
[docs]
def failure_signature(score: LiveScenarioScore) -> str:
"""A stable content address for one failure shape (scenario + failed dimensions)."""
basis = "|".join(
(
score.scenario,
str(score.keys_resolve),
str(score.lifecycle_ordered),
str(score.expected_covered),
",".join(sorted(score.invariants.live_submit_attempts)),
",".join(sorted(score.invariants.handoff_faithfulness_blocks)),
),
)
return hashlib.sha256(basis.encode(_UTF_8)).hexdigest()[:12]
[docs]
def promote_failure(
*,
score: LiveScenarioScore,
trajectory: LiveTrajectory,
scenario: GoldenScenario,
) -> str:
"""Render the promoted golden-scenario TOML for one live failure.
The promoted scenario re-declares the ORIGINAL correct expectations; the
observed failing trajectory and the failure reasons ride in the comment
header as evidence, never as expectations (a failure must not become the
new normal).
Raises:
ValueError: When the score did not actually fail — a passing run has
nothing to promote.
"""
if score.passed:
raise ValueError(f"live run for scenario '{score.scenario}' passed; nothing to promote")
observed = ", ".join(trajectory.observed_command_keys) or "(none)"
reasons = "\n".join(f"# - {reason}" for reason in score.failures) or "# - (no reason recorded)"
trajectory_lines = ",\n".join(f' "{key}"' for key in scenario.expected_trajectory)
casillas = ", ".join(f'"{c}"' for c in scenario.expected_computed_casillas)
return (
f"# Golden regression scenario promoted from live failure {failure_signature(score)}.\n"
f"# Origin: scenario '{score.scenario}', persona '{score.persona}', session '{score.session_id}'.\n"
f"# Observed (failing) trajectory: {observed}\n"
f"# Failure reasons:\n{reasons}\n"
f"# The expectations below re-declare the ORIGINAL correct path; the observed\n"
f"# behaviour above is evidence for the annotation queue, not an expectation.\n"
f"\n"
f'name = "{scenario.name}-regression-{failure_signature(score)}"\n'
f'modelo = "{scenario.modelo}"\n'
f"filing_year = {scenario.filing_year}\n"
f'period = "{scenario.period}"\n'
f'skill_name = "{scenario.skill_name}"\n'
f"provenance_required = {str(scenario.provenance_required).lower()}\n"
f"expected_computed_casillas = [{casillas}]\n"
f"\n"
f"expected_trajectory = [\n{trajectory_lines},\n]\n"
)
[docs]
def write_promoted_scenario(
*,
score: LiveScenarioScore,
trajectory: LiveTrajectory,
scenario: GoldenScenario,
scenarios_dir: Path,
) -> Path:
"""Write the promoted scenario into ``scenarios_dir``, idempotently.
Returns:
The path written (or the existing identical file on re-promotion).
"""
text = promote_failure(score=score, trajectory=trajectory, scenario=scenario)
stem = f"{scenario.name.replace('-', '_')}_regression_{failure_signature(score)}"
path = scenarios_dir / f"{stem}.toml"
if path.exists() and path.read_text(encoding=_UTF_8) == text:
return path
scenarios_dir.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding=_UTF_8)
return path
__all__ = [
"failure_signature",
"promote_failure",
"write_promoted_scenario",
]