Evals
Subspace grades its own LLM seams two ways. The recorded-run harness pins the prompt-to-behavior contract in CI by replaying recorded model responses through the real machinery and asserting on the resulting database. The eval sweep compares two versions of one agent definition head to head, graded by judges, under a hard budget ceiling. Both grade prompts, never the open network.
The recorded-run harness
Section titled “The recorded-run harness”The harness covers the three LLM seams where a wrong model output would silently corrupt state:
| Seam | What it grades |
|---|---|
| Event triage | Severity routing through the classifier and triage. |
| Mail-rule labeling | Label decisions through the rule classifier and mail rules. |
| CRM enrichment | A full agent run through the real runner and toolkit, enriching CRM. |
A case is {name, input, recorded, expected}, checked into a per-seam fixture JSON and
validated on load. The recorded field is the model’s canned response for that input.
Replay mode (CI, default)
Section titled “Replay mode (CI, default)”Replay runs as part of pnpm test. For each case, the recorded response is injected at the
seam (a classifier stub, or a scripted AgentModel transcript) while the real
producer, routing, labeling, and run machinery executes against a mock-world database clone.
The expected assertions are then evaluated on the resulting DB state, so the harness pins
not just the prompt but everything around it.
Assertions are per-seam and every field is optional:
severity, route, decidedBy (rule / llm / fallback), provisional,
taskCreated, notified.
matched, labels, notLabels, skippedInbox, stamped.
runStatus, pageHasBullet / pageLacksBullet ({page, contains}), memoryItem
({kind, contains}), toolOutputContains ({tool, contains}).
A failing case prints its name and a per-assertion expected-versus-actual, so a regression points straight at the broken behavior.
Live mode
Section titled “Live mode”Live mode runs the same cases and assertions against the real model:
EVALS_LIVE=1 ANTHROPIC_API_KEY=… corepack pnpm --filter @subspace/server evals:liveIt grades the production providers (SUBSPACE_MODEL, default claude-sonnet-5), prints a
per-case scorecard, and exits 1 on any failure. Tools still run under PROVIDERS=fake (so
web.fetch serves only registered fixtures): live evals grade prompts, never the open
network. Cases marked live: false are synthetic failures (a classifier error, a
hallucinated level, wrong-shape tool args) and are replay-only, skipped live.
The eval sweep
Section titled “The eval sweep”The eval-sweep workflow is a judge-scored A/B comparison of two immutable versions of
one agents/ definition. It is registered and manual-only. Invoke the seeded
agents/eval-sweep definition through the ordinary agent command, or call
agents.evalSweep {agentPageId, evalSet, armA, armB, judges}.
-
Cases from an evals/ page
Cases come from a versioned page under
evals/: each top-level node is one case, using its text as the default prompt orprops.eval.promptfor an explicit or multiline prompt. -
Plan and budget
The plan step resolves both historical definition snapshots, captures the exact eval-set version, and resolves the selected
judges/pages. It rejects the entire sweep before its first child ifcases × 2 arms × judgesexceedsEVAL_SWEEP_MAX_GRADES(default 24). Paid execution also requiresEVALS_LIVE=1, the same explicit posture as live evals. The eight-child fan-out cap bounds one sweep to four cases. -
Run both arms
It spawns each arm from its stored definition hash, gathers children in durable batches of at most six, disables their global auto-judge path, and explicitly grades only the budgeted judges (irrespective of ordinary judge gates).
-
Report
The final page under
evals/is advisory: per-judge pass rate for A and B, verdict counts, case and child-run links, the two definition hashes, the eval-set snapshot, and the budget provenance. It never promotes or edits the live definition.