Skip to content

Generate eval cases from observed production traces (trace-replay-to-yaml) #30

Description

@nabinpkl

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestship:eval-substrateShip 2: framework-on-foundation eval substrate per ADR 14

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions