Status: deferred. Filed to capture the idea so we don't lose it; no immediate plan to land. Supersedes the originally-scoped #28 (synthetic generate-from-description CLI), which represents an earlier-generation pattern.
Why
Anthropic's Demystifying evals for AI agents (2026-01-09) advocates generating eval cases from observed production behavior rather than from synthetic descriptions. The frontier framing: when a real trace surfaces an interesting failure (a fabrication that slipped through, a tool fired on a refusal turn, a gate verdict that disagreed with intuition), one command should turn that trace into a permanent eval case so the same shape can never regress unnoticed.
The synthetic-from-description pattern (#28's original scope) saves keystrokes but not judgment. Generated cases need hand-tuning before their probes become sharp. Trace-replay is fundamentally different: the trace IS the case, the probes are derived from "what was true on this trace today should still be true tomorrow."
Scope
- New CLI:
python -m agent_service.evals.case_from_trace --trace-id <hex> --suite <name> --case-id <slug> --out <path>
- Reads the named trace from
otel.otel_traces:
inputs reconstructed from the AgentRequest captured at turn start (we already record mcae.request.user_question and the focus context as span attributes; verify completeness or add what's missing).
- Probes auto-derived from observed invariants:
turn-root-span-present, turn-tagged-as-eval (always).
tool_called_with_args for each tool span observed.
turn_attribute_equals for tool_calls, claims_emitted, claims_approved from the observed turn root attrs.
gate_passed for each gate span with verdict=approved observed.
no_span_with_status(mcae.turn, error).
- Writes a YAML case dict; refuses to overwrite existing files unless
--force.
- Run produces a freshly-baselined case in 1-2 commands:
case_from_trace ... && just eval-baseline ....
Out of scope
Done when
- Command takes a trace id and emits a valid
EvalCase YAML.
- The emitted case loads via
load_suite() and runs against the live agent.
- Re-running the case against a fresh trace of the same input passes baseline diff (proving the auto-derived probes encode stable invariants, not noise).
- README documents the workflow alongside the existing manual case authoring.
Refs
Status: deferred. Filed to capture the idea so we don't lose it; no immediate plan to land. Supersedes the originally-scoped #28 (synthetic generate-from-description CLI), which represents an earlier-generation pattern.
Why
Anthropic's Demystifying evals for AI agents (2026-01-09) advocates generating eval cases from observed production behavior rather than from synthetic descriptions. The frontier framing: when a real trace surfaces an interesting failure (a fabrication that slipped through, a tool fired on a refusal turn, a gate verdict that disagreed with intuition), one command should turn that trace into a permanent eval case so the same shape can never regress unnoticed.
The synthetic-from-description pattern (#28's original scope) saves keystrokes but not judgment. Generated cases need hand-tuning before their probes become sharp. Trace-replay is fundamentally different: the trace IS the case, the probes are derived from "what was true on this trace today should still be true tomorrow."
Scope
python -m agent_service.evals.case_from_trace --trace-id <hex> --suite <name> --case-id <slug> --out <path>otel.otel_traces:inputsreconstructed from the AgentRequest captured at turn start (we already recordmcae.request.user_questionand the focus context as span attributes; verify completeness or add what's missing).turn-root-span-present,turn-tagged-as-eval(always).tool_called_with_argsfor each tool span observed.turn_attribute_equalsfortool_calls,claims_emitted,claims_approvedfrom the observed turn root attrs.gate_passedfor each gate span withverdict=approvedobserved.no_span_with_status(mcae.turn, error).--force.case_from_trace ... && just eval-baseline ....Out of scope
Done when
EvalCaseYAML.load_suite()and runs against the live agent.Refs