SUT stands for System Under Test.
@merit.sut is optional. It exists to make your agent/workflow callable injectable and traceable.@merit.sut registers a SUT factory function as an injectable resource and wraps each resolved invocation in an OpenTelemetry span. This gives you two things:
- A clean dependency injection (DI) boundary in your merits (you call the injected parameter, not a global).
- Trace spans you can query inside a test via
trace_context(when tracing is enabled).
Basic Usage
The most common use case for@merit.sut is asserting on the SUT call span(s).
trace_context is only available when tracing is enabled. From the CLI, run merit test --trace.What @merit.sut actually does
Injection semantics
@merit.sut registers a resource factory so the Merit runner can inject it into tests by parameter name (by default, a case-scoped resource).
If constructing your SUT is expensive, you can widen its lifecycle using scope (the same values as @merit.resource):
chatbot parameter inside merit_chatbot_works(chatbot), not the decorated global name.
Naming rules (important for DI and get_sut_spans)
- SUT name: the factory function name (
def weather_agent(): ...→"weather_agent").- Pick your factory name intentionally, since it’s used for dependency injection and the
sut.<sut_name>span name.
- Pick your factory name intentionally, since it’s used for dependency injection and the
Instance-based SUTs (trace a method)
If your factory returns a non-callable instance, Merit will trace a method on that instance. By default it traces__call__, but you can set method="run" (or any method name your object provides):
SUT span attributes
Each SUT call creates a span namedsut.<sut_name> and sets:
merit.sut=truemerit.sut.name=<sut_name>
MERIT_TRACE_CONTENT=true (default), Merit also records:
sut.input.args/sut.input.kwargs(truncated repr)sut.output(truncated repr)
MERIT_TRACE_CONTENT=false, Merit records only coarse metadata:
sut.input.countsut.output.type
Recommendations
1. Create isolated helpers; don’t touch your production code
Many evaluation frameworks require developers to modify their production codebase to instrument traces. Merit avoids this pattern. The best way to introduce SUTs to your suite is to create isolated wrapper functions within yourmerit_ files.
Don’t do this:
2. Pass using Dependency Injection; don’t call directly
@merit.sut registers a resource factory for injection. Calling the decorated global directly is the wrong pattern (and may not work the way you expect). Always call the injected parameter.
Don’t do this: