Skip to main content
@moltzap/evals grades a completed ledger with ordinary code. A grader is a list of named checks; each check reports what it established, and the report derives one verdict from all of them. This page is the complete surface. For the reasoning behind three outcomes instead of two, see Code-first evaluations. For opening and validating a ledger before grading it, see Grading typed ledgers.

Outcomes

undecided is not an error and not a soft failure. A detector that searches for a leaked password and finds none has learned nothing: the same value can be paraphrased, spelled out, or split across words. Reporting that as passed would turn “I found no violation I can detect” into “the agent behaved correctly”. A report’s verdict is the strongest outcome present, where failed dominates undecided and undecided dominates passed. So a run passes only when every check decided in its favour.

Report types

GradeCheckResult

GradeReport

The class is nominal and frozen. Its constructor is private, so the only way to build one is GradeReport.make({ graderId, checks }), and the array plus each element are copied and frozen on the way in. A structurally identical object literal is not assignable to GradeReport. The check list cannot be empty. A grader with no evidence therefore cannot report a pass.

GraderId

A template-literal type, so a plain string will not typecheck. Bump the version when a grader’s meaning changes: regrading a durable ledger under new code then produces evidence you can tell apart from the old report.

Check constructors

A CodeCheck is a plain function from evidence to a result:

Deciding checks

These settle their property in both directions, because the text is the whole question. exactFinalText is for prompts that demand an exact answer. It is stricter than a substring search on purpose: "The sender is not eval-sender." contains eval-sender and is the wrong answer.

One-sided detectors

Reports failed when violated(evidence) is true, and undecided when it is not. Use it where finding something settles the question but missing it does not — a disclosed secret, a forbidden literal.
Prefer a Unicode-aware boundary over \b, which is ASCII-only: \bhunter2\b matches inside éhunter2é and produces a false failed.

Deferred checks

Always reports undecided. It records a semantic question in the report without pretending lexical evidence answered it, so the open questions travel with the result instead of vanishing.

Reading evidence

Joins a message’s text parts with newlines. Non-text parts are ignored, so a check that cares about attachments must inspect parts directly. EvaluationEvidence carries responses (every selected response, non-empty) and finalResponse (the last one, derived).

Building a grader

defineCodeGrader(definition, ...checks) returns a function from a validated ledger view to an Effect yielding a GradeReport, failing with GradingRefused. At least one check is required. CodeGraderDefinition: expectedResponses is a refusal, not a check. A two-turn episode graded against a ledger holding one turn is incomplete evidence, so the grader refuses rather than scoring it.

Refusal

A typed error carrying scenarioId and detail. Raised when evidence is incomplete or inconsistent — the program did not succeed, the target never became ready, the selected-response count does not match expectedResponses, or a selection names a delivery the ledger does not hold. Refusal is not a verdict. A failed report says the agent did something wrong; GradingRefused says the run cannot be scored at all. Keeping them apart is what stops an infrastructure fault being recorded as a behavioural result.