@rulvar/evals 1.50.0 → 1.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CompiledWorkflow, DeclaredLadder, Effort, Engine, EvidenceRef, Json, JsonSchema, KnowledgeSnapshot, ModelClaim, ModelKnowledgeStore, ModelRef, ModelSpec, RunOutcome, SchemaSpec, TaskClass, Usage, WireError, Workflow } from "@rulvar/core";
1
+ import { CompiledWorkflow, DeclaredLadder, Effort, Engine, EvidenceRef, Json, JsonSchema, KnowledgeSnapshot, ModelClaim, ModelKnowledgeStore, ModelRef, ModelSpec, RunOutcome, SchemaSpec, TaskClass, Usage, WireError, Workflow, WorkflowEvent } from "@rulvar/core";
2
2
 
3
3
  //#region src/envelope.d.ts
4
4
  /** Thrown when authorizing a run's ceiling would exceed the envelope. */
@@ -391,6 +391,145 @@ declare function flipStaleOnCanaryDrift(store: ModelKnowledgeStore, model: Model
391
391
  attempts?: number;
392
392
  }): Promise<CanaryDriftReport>;
393
393
  //#endregion
394
+ //#region src/benchmark.d.ts
395
+ /** One benchmark: a workflow measured over a series of repeats. */
396
+ interface BenchmarkSpec {
397
+ name: string;
398
+ workflow: Workflow | CompiledWorkflow;
399
+ args: Json;
400
+ /**
401
+ * Scored repeats to attempt; a positive integer. The regression
402
+ * protocol this kit serves calls for at least 5 before a series is
403
+ * citable; the kit does not enforce that floor, it reports what ran.
404
+ */
405
+ repeats: number;
406
+ /**
407
+ * Per-run graders over the settled outcome, the same contract the
408
+ * eval runners use (golden, rubric, and LLM-judge graders compose
409
+ * unchanged). A failing grader rejects the run from scoring; a
410
+ * throwing grader is a defect of the spec and propagates.
411
+ */
412
+ graders?: Grader[];
413
+ }
414
+ /** A per-run metric extractor over the run's full event stream. */
415
+ type BenchmarkMetricExtractor = (events: readonly WorkflowEvent[], outcome: RunOutcome<Json>) => number;
416
+ interface RunBenchmarkOptions {
417
+ /** Run ceiling for each target run. */
418
+ budgetUsd?: number;
419
+ /** Run ceiling for each judge run a grader performs. */
420
+ judgeBudgetUsd?: number;
421
+ /**
422
+ * Aggregate debit-only envelope: every target and judge run
423
+ * authorizes its ceiling here BEFORE starting, exactly like the eval
424
+ * runners. A target-run refusal throws SweepBudgetError; a judge-run
425
+ * refusal rejects that run from scoring as 'judge:refused'.
426
+ */
427
+ envelope?: SpendEnvelope;
428
+ /**
429
+ * Host-supplied fingerprint labels: the commit, the pricing snapshot
430
+ * id, the corpus hash, the series name (cold/warm). The kit never
431
+ * shells out or guesses; identity the host does not supply is not
432
+ * recorded.
433
+ */
434
+ labels?: Record<string, string>;
435
+ /** Named per-run metric extractors; each scored series gets percentiles. */
436
+ metrics?: Record<string, BenchmarkMetricExtractor>;
437
+ }
438
+ /** Nearest-rank percentile summary of one scored series. */
439
+ interface BenchmarkPercentiles {
440
+ min: number;
441
+ p50: number;
442
+ p90: number;
443
+ max: number;
444
+ mean: number;
445
+ }
446
+ /** The replay-strict verification verdict of one run. */
447
+ interface BenchmarkVerification {
448
+ /** Every clause below held. */
449
+ verified: boolean;
450
+ /** The dry-run resume had zero misses and zero reruns. */
451
+ pureReplay: boolean;
452
+ /** The replayed settle status equals the journaled one. */
453
+ statusReproduced: boolean;
454
+ /** The journaled output digest, when the settle recorded one. */
455
+ outputHash?: string;
456
+ /** The digest of the replayed result, when hashable. */
457
+ replayedOutputHash?: string;
458
+ /**
459
+ * Digest equality where comparable. A run that settled ok with a
460
+ * value but no journaled digest (a non-JCS-serializable result)
461
+ * fails this clause explicitly: a benchmark demands comparable
462
+ * outputs. A run with no output value passes it vacuously.
463
+ */
464
+ outputReproduced: boolean;
465
+ /** Workflow-provenance determinism warnings across live and replay. */
466
+ determinismWarnings: number;
467
+ /** Machine-readable failure reasons; empty when verified. */
468
+ reasons: string[];
469
+ }
470
+ /** The full record of one benchmark run, scored or not. */
471
+ interface BenchmarkRunRecord {
472
+ /** 1-based ordinal in execution order. */
473
+ ordinal: number;
474
+ runId: string;
475
+ status: RunOutcome<Json>["status"];
476
+ /** Counted into the percentile series. */
477
+ scored: boolean;
478
+ /** Why the run was excluded; empty when scored. */
479
+ rejectedReasons: string[];
480
+ /** run:start to run:end, from event timestamps. */
481
+ wallMs: number;
482
+ /** The target run's cost (judge runs are separate). */
483
+ costUsd: number;
484
+ /** The judge-run share this run's grading spent. */
485
+ judgeCostUsd: number;
486
+ usage: Usage;
487
+ /** agent:end events on the live stream (logical dispatches). */
488
+ agentDispatches: number;
489
+ /** agent:phase:end events on the live stream (model activations). */
490
+ invocations: number;
491
+ verdicts: GraderVerdict[];
492
+ verification: BenchmarkVerification;
493
+ /** Extractor values for this run. */
494
+ metrics: Record<string, number>;
495
+ error?: WireError;
496
+ }
497
+ /** Where the numbers came from; percentiles without this are hearsay. */
498
+ interface BenchmarkFingerprint {
499
+ node: string;
500
+ platform: string;
501
+ arch: string;
502
+ /** Resolved versions of the rulvar packages doing the measuring. */
503
+ packages: Record<string, string>;
504
+ /** The first run's run:start timestamp (event time, no clock read). */
505
+ startedAt?: string;
506
+ labels?: Record<string, string>;
507
+ }
508
+ interface BenchmarkReport {
509
+ name: string;
510
+ /** Repeats attempted (equals runs.length). */
511
+ repeats: number;
512
+ /** Runs that entered the percentile series. */
513
+ scored: number;
514
+ runs: BenchmarkRunRecord[];
515
+ /** Absent when no run scored: the kit never fabricates a series. */
516
+ wallMs?: BenchmarkPercentiles;
517
+ costUsd?: BenchmarkPercentiles;
518
+ /** Percentiles per named extractor, over scored runs. */
519
+ metrics: Record<string, BenchmarkPercentiles>;
520
+ /** Every target and judge run, scored or rejected (honest spend). */
521
+ totalCostUsd: number;
522
+ judgeCostUsd: number;
523
+ fingerprint: BenchmarkFingerprint;
524
+ }
525
+ /**
526
+ * Runs the spec's repeats sequentially and reports the verified series.
527
+ * Throws only for spec defects (invalid repeats, a throwing grader or
528
+ * extractor) and for a target-run envelope refusal; everything a run
529
+ * does wrong lands in its record instead.
530
+ */
531
+ declare function runBenchmark(engine: Engine, spec: BenchmarkSpec, options?: RunBenchmarkOptions): Promise<BenchmarkReport>;
532
+ //#endregion
394
533
  //#region src/sweeps.d.ts
395
534
  /** One fixed pool member; effort is part of the claim subject identity. */
396
535
  interface SweepModel {
@@ -610,4 +749,4 @@ declare function runValueCheckpoint(checkpointPool: CheckpointPool, options: Run
610
749
  /** The deterministic render for the M12 gate docs amendment. */
611
750
  declare function renderCheckpointReport(report: CheckpointReport): string;
612
751
  //#endregion
613
- export { type CanaryDriftReport, type CanaryProbeSet, type CanaryReport, type CanaryRunOptions, type CheckpointArm, type CheckpointCell, type CheckpointLadder, type CheckpointPool, type CheckpointReport, type CriterionOneReport, type CriterionTwoReport, type EvalCase, type EvalCaseResult, type EvalCommitterOptions, EvalJudgeError, type EvalMatrixReport, type EvalSuiteResult, type GoldenGraderOptions, type Grader, type GraderContext, type GraderVerdict, JUDGE_VERDICT_SCHEMA, type JudgeGraderOptions, type JudgeSpec, type MatrixCell, type MatrixCellReport, type MeasuredClaimInput, type OrchestratedCase, type RubricCriterion, type RubricGraderOptions, type RunCheckpointOptions, type RunEvalCaseOptions, type RunEvalSuiteOptions, type RunSweepOptions, SWEEP_THRESHOLD_DEFAULTS, SpendEnvelope, SweepBudgetError, type SweepCase, type SweepCellReport, type SweepModel, type SweepPool, type SweepReport, type SweepThresholds, agentTypeRuleHolds, canaryFingerprint, commitEvalMeasured, evalMeasuredClaim, flipStaleOnCanaryDrift, goldenGrader, judgeGrader, normalizeCanaryOutput, renderCheckpointReport, rubricGrader, runCanary, runEvalCase, runEvalMatrix, runEvalSuite, runSweepMatrix, runValueCheckpoint, rungRuleHolds };
752
+ export { type BenchmarkFingerprint, type BenchmarkMetricExtractor, type BenchmarkPercentiles, type BenchmarkReport, type BenchmarkRunRecord, type BenchmarkSpec, type BenchmarkVerification, type CanaryDriftReport, type CanaryProbeSet, type CanaryReport, type CanaryRunOptions, type CheckpointArm, type CheckpointCell, type CheckpointLadder, type CheckpointPool, type CheckpointReport, type CriterionOneReport, type CriterionTwoReport, type EvalCase, type EvalCaseResult, type EvalCommitterOptions, EvalJudgeError, type EvalMatrixReport, type EvalSuiteResult, type GoldenGraderOptions, type Grader, type GraderContext, type GraderVerdict, JUDGE_VERDICT_SCHEMA, type JudgeGraderOptions, type JudgeSpec, type MatrixCell, type MatrixCellReport, type MeasuredClaimInput, type OrchestratedCase, type RubricCriterion, type RubricGraderOptions, type RunBenchmarkOptions, type RunCheckpointOptions, type RunEvalCaseOptions, type RunEvalSuiteOptions, type RunSweepOptions, SWEEP_THRESHOLD_DEFAULTS, SpendEnvelope, SweepBudgetError, type SweepCase, type SweepCellReport, type SweepModel, type SweepPool, type SweepReport, type SweepThresholds, agentTypeRuleHolds, canaryFingerprint, commitEvalMeasured, evalMeasuredClaim, flipStaleOnCanaryDrift, goldenGrader, judgeGrader, normalizeCanaryOutput, renderCheckpointReport, rubricGrader, runBenchmark, runCanary, runEvalCase, runEvalMatrix, runEvalSuite, runSweepMatrix, runValueCheckpoint, rungRuleHolds };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- import { ConfigError, KnowledgeCasError, claimExpiry, compileVerifiedLayer, defineWorkflow } from "@rulvar/core";
1
+ import { createRequire } from "node:module";
2
+ import { ConfigError, KnowledgeCasError, claimExpiry, compileVerifiedLayer, defineWorkflow, hashRunOutput, lastRunSettle } from "@rulvar/core";
2
3
  import { createHash } from "node:crypto";
3
4
  //#region src/envelope.ts
4
5
  /**
@@ -234,6 +235,12 @@ async function runEvalCase(engine, evalCase, options = {}) {
234
235
  ...incomplete === void 0 ? {} : { incomplete }
235
236
  };
236
237
  }
238
+ /**
239
+ * Runs one judge invocation through the engine. Package-internal: the
240
+ * benchmark kit reuses it so benchmark judge runs are journaled,
241
+ * budgeted, and VCR-recordable exactly like eval judge runs; not part
242
+ * of the public index.
243
+ */
237
244
  async function runJudge(engine, judgeName, spec, budgetUsd) {
238
245
  const workflowName = `eval-judge:${judgeName}`;
239
246
  const judgeWorkflow = defineWorkflow({ name: workflowName }, async (ctx) => {
@@ -627,6 +634,269 @@ async function flipStaleOnCanaryDrift(store, model, freshFingerprint, options) {
627
634
  throw lastCas ?? /* @__PURE__ */ new Error("flipStaleOnCanaryDrift: unreachable");
628
635
  }
629
636
  //#endregion
637
+ //#region src/benchmark.ts
638
+ /**
639
+ * The reproducible benchmark kit (RV-213): repeated, verified, and
640
+ * fingerprinted measurement of one workflow on one engine, built
641
+ * strictly on the public core APIs.
642
+ *
643
+ * What makes a run SCORED rather than merely finished: it settles 'ok',
644
+ * every grader passes, and the replay-strict verification holds: a
645
+ * dry-run resume replays it with zero would-be-live calls, reproduces
646
+ * the recorded settle status and the journaled output digest, and the
647
+ * re-executed body raises zero workflow-provenance determinism
648
+ * warnings. A hand-rolled benchmark loop reports clean numbers for a
649
+ * workflow whose result replay cannot reproduce; this kit rejects that
650
+ * run from the series and says why, so the percentiles only ever
651
+ * summarize runs that are evidence.
652
+ *
653
+ * Percentiles use the nearest-rank method (1-based, ascending): the
654
+ * p-th percentile of n values is the element at index ceil(p/100 * n)
655
+ * in the sorted series. No interpolation, so a reported p50/p90 is
656
+ * always a value that actually occurred.
657
+ *
658
+ * Judging stays blind by construction: graders (including LLM judges
659
+ * via the shared judge channel) see the run's output and their own
660
+ * rubric, never a system label, a run ordinal, or a candidate
661
+ * identity, so comparing two systems is running the same spec twice
662
+ * and comparing reports. Repeats run SEQUENTIALLY in ordinal order;
663
+ * cold-versus-warm cache series are a host concern (run the benchmark
664
+ * once per series). Wall time is measured from the run's own
665
+ * run:start/run:end event timestamps; the kit reads no clock of its
666
+ * own.
667
+ */
668
+ const require = createRequire(import.meta.url);
669
+ function packageVersion(name) {
670
+ try {
671
+ return require(`${name}/package.json`).version;
672
+ } catch {
673
+ return;
674
+ }
675
+ }
676
+ function percentilesOf(values) {
677
+ const sorted = [...values].sort((a, b) => a - b);
678
+ const at = (index) => sorted[Math.min(Math.max(index, 0), sorted.length - 1)] ?? 0;
679
+ const rank = (p) => at(Math.ceil(p / 100 * sorted.length) - 1);
680
+ return {
681
+ min: at(0),
682
+ p50: rank(50),
683
+ p90: rank(90),
684
+ max: at(sorted.length - 1),
685
+ mean: sorted.reduce((sum, value) => sum + value, 0) / sorted.length
686
+ };
687
+ }
688
+ /**
689
+ * The documented event catalog, enumerated: capture subscribes through
690
+ * the typed `handle.on` surface instead of consuming the handle's
691
+ * single `events` iterable, so the kit never competes with a host (or
692
+ * a test harness) that already consumes the stream. An event type the
693
+ * catalog gains later is invisible to extractors until this list
694
+ * learns it; lifecycle, cost, and determinism events are all here.
695
+ */
696
+ const EVENT_VOCABULARY = [
697
+ "run:start",
698
+ "run:end",
699
+ "phase:start",
700
+ "log",
701
+ "budget:update",
702
+ "external:waiting",
703
+ "approval:pending",
704
+ "child:start",
705
+ "child:end",
706
+ "agent:queued",
707
+ "agent:start",
708
+ "agent:phase:start",
709
+ "agent:phase:end",
710
+ "agent:end",
711
+ "agent:error",
712
+ "agent:schema-retry",
713
+ "agent:stream",
714
+ "tool:start",
715
+ "tool:end",
716
+ "determinism:warning",
717
+ "plan:revised",
718
+ "node:parked",
719
+ "node:cancelled",
720
+ "node:linked",
721
+ "orchestrator:woke",
722
+ "orchestrator:budget",
723
+ "escalation:raised",
724
+ "escalation:decided",
725
+ "spawn:admitted",
726
+ "spawn:rejected",
727
+ "verify:failed",
728
+ "ledger:op",
729
+ "stall:detected",
730
+ "guard:oscillation",
731
+ "resolution:applied",
732
+ "resolution:superseded",
733
+ "termination:debit",
734
+ "termination:denied",
735
+ "termination:config-drift",
736
+ "journal:compat"
737
+ ];
738
+ async function collectRun(handle) {
739
+ const events = [];
740
+ const record = (event) => {
741
+ events.push(event);
742
+ };
743
+ const detachers = EVENT_VOCABULARY.map((type) => handle.on(type, record));
744
+ const outcome = await handle.result;
745
+ for (const detach of detachers) detach();
746
+ return {
747
+ events,
748
+ outcome,
749
+ runId: handle.runId
750
+ };
751
+ }
752
+ function wallMsOf(events) {
753
+ const start = events.find((event) => event.type === "run:start")?.ts;
754
+ const end = events.find((event) => event.type === "run:end")?.ts;
755
+ return start !== void 0 && end !== void 0 ? Math.max(0, Date.parse(end) - Date.parse(start)) : 0;
756
+ }
757
+ function workflowWarningsOf(events) {
758
+ return events.filter((event) => event.type === "determinism:warning" && event.provenance === "workflow").length;
759
+ }
760
+ /**
761
+ * Runs the spec's repeats sequentially and reports the verified series.
762
+ * Throws only for spec defects (invalid repeats, a throwing grader or
763
+ * extractor) and for a target-run envelope refusal; everything a run
764
+ * does wrong lands in its record instead.
765
+ */
766
+ async function runBenchmark(engine, spec, options = {}) {
767
+ if (!Number.isInteger(spec.repeats) || spec.repeats < 1) throw new TypeError(`BenchmarkSpec.repeats must be a positive integer, got ${String(spec.repeats)}`);
768
+ const runs = [];
769
+ let startedAt;
770
+ let totalCostUsd = 0;
771
+ let totalJudgeCostUsd = 0;
772
+ for (let ordinal = 1; ordinal <= spec.repeats; ordinal += 1) {
773
+ options.envelope?.authorize(options.budgetUsd, `benchmark '${spec.name}' run ${String(ordinal)}`);
774
+ const live = await collectRun(engine.run(spec.workflow, spec.args, {
775
+ name: `benchmark:${spec.name}:${String(ordinal)}`,
776
+ ...options.budgetUsd === void 0 ? {} : { budgetUsd: options.budgetUsd }
777
+ }));
778
+ startedAt ??= live.events.find((event) => event.type === "run:start")?.ts;
779
+ totalCostUsd += live.outcome.cost.totalUsd;
780
+ const rejectedReasons = [];
781
+ if (live.outcome.status !== "ok") rejectedReasons.push(`status:${live.outcome.status}`);
782
+ const replayHandle = engine.resume(live.runId, spec.workflow, {
783
+ args: spec.args,
784
+ dryRun: true
785
+ });
786
+ const replay = await collectRun(replayHandle);
787
+ const preview = await replayHandle.preview;
788
+ const recorded = lastRunSettle(await engine.stores.journal.load(live.runId));
789
+ const outputHash = recorded?.outputHash;
790
+ const replayedOutputHash = hashRunOutput(replay.outcome.value);
791
+ const pureReplay = preview.misses === 0 && preview.reruns === 0;
792
+ const statusReproduced = recorded !== void 0 && replay.outcome.status === recorded.runStatus;
793
+ const outputReproduced = live.outcome.value === void 0 ? true : outputHash !== void 0 && replayedOutputHash === outputHash;
794
+ const determinismWarnings = workflowWarningsOf(live.events) + workflowWarningsOf(replay.events);
795
+ const reasons = [];
796
+ if (!pureReplay) reasons.push("verification:not-pure-replay");
797
+ if (recorded === void 0) reasons.push("verification:no-recorded-settle");
798
+ else if (!statusReproduced) reasons.push("verification:status-diverged");
799
+ if (!outputReproduced) reasons.push(outputHash === void 0 ? "verification:output-not-hashable" : "verification:output-diverged");
800
+ if (determinismWarnings > 0) reasons.push("verification:determinism-warning");
801
+ const verification = {
802
+ verified: reasons.length === 0,
803
+ pureReplay,
804
+ statusReproduced,
805
+ ...outputHash === void 0 ? {} : { outputHash },
806
+ ...replayedOutputHash === void 0 ? {} : { replayedOutputHash },
807
+ outputReproduced,
808
+ determinismWarnings,
809
+ reasons
810
+ };
811
+ rejectedReasons.push(...reasons);
812
+ let judgeCostUsd = 0;
813
+ let judgeOrdinal = 0;
814
+ const context = {
815
+ value: live.outcome.value,
816
+ outcome: live.outcome,
817
+ async judge(judgeSpec) {
818
+ const which = judgeOrdinal;
819
+ judgeOrdinal += 1;
820
+ options.envelope?.authorize(options.judgeBudgetUsd, `benchmark judge '${spec.name}:${String(ordinal)}:${String(which)}'`);
821
+ const judged = await runJudge(engine, `${spec.name}:${String(ordinal)}:${String(which)}`, judgeSpec, options.judgeBudgetUsd);
822
+ judgeCostUsd += judged.costUsd;
823
+ return judged.output;
824
+ }
825
+ };
826
+ const verdicts = [];
827
+ for (const grader of spec.graders ?? []) try {
828
+ const verdict = await grader.grade(context);
829
+ verdicts.push(verdict);
830
+ if (!verdict.passed) rejectedReasons.push(`grader:${verdict.grader}`);
831
+ } catch (error) {
832
+ if (error instanceof SweepBudgetError) {
833
+ rejectedReasons.push("judge:refused");
834
+ break;
835
+ }
836
+ if (error instanceof EvalJudgeError && error.status === "exhausted") {
837
+ judgeCostUsd += error.costUsd;
838
+ rejectedReasons.push("judge:exhausted");
839
+ break;
840
+ }
841
+ throw error;
842
+ }
843
+ totalJudgeCostUsd += judgeCostUsd;
844
+ totalCostUsd += judgeCostUsd;
845
+ const metricValues = {};
846
+ for (const [metricName, extract] of Object.entries(options.metrics ?? {})) metricValues[metricName] = extract(live.events, live.outcome);
847
+ runs.push({
848
+ ordinal,
849
+ runId: live.runId,
850
+ status: live.outcome.status,
851
+ scored: rejectedReasons.length === 0,
852
+ rejectedReasons,
853
+ wallMs: wallMsOf(live.events),
854
+ costUsd: live.outcome.cost.totalUsd,
855
+ judgeCostUsd,
856
+ usage: live.outcome.usage,
857
+ agentDispatches: live.events.filter((event) => event.type === "agent:end").length,
858
+ invocations: live.events.filter((event) => event.type === "agent:phase:end").length,
859
+ verdicts,
860
+ verification,
861
+ metrics: metricValues,
862
+ ...live.outcome.error === void 0 ? {} : { error: live.outcome.error }
863
+ });
864
+ }
865
+ const scoredRuns = runs.filter((run) => run.scored);
866
+ const seriesOf = (pick) => scoredRuns.length === 0 ? void 0 : percentilesOf(scoredRuns.map(pick));
867
+ const metricSeries = {};
868
+ for (const metricName of Object.keys(options.metrics ?? {})) {
869
+ const series = seriesOf((run) => run.metrics[metricName] ?? 0);
870
+ if (series !== void 0) metricSeries[metricName] = series;
871
+ }
872
+ const wallMs = seriesOf((run) => run.wallMs);
873
+ const costUsd = seriesOf((run) => run.costUsd);
874
+ const packages = {};
875
+ for (const name of ["@rulvar/core", "@rulvar/evals"]) {
876
+ const version = packageVersion(name);
877
+ if (version !== void 0) packages[name] = version;
878
+ }
879
+ return {
880
+ name: spec.name,
881
+ repeats: runs.length,
882
+ scored: scoredRuns.length,
883
+ runs,
884
+ ...wallMs === void 0 ? {} : { wallMs },
885
+ ...costUsd === void 0 ? {} : { costUsd },
886
+ metrics: metricSeries,
887
+ totalCostUsd,
888
+ judgeCostUsd: totalJudgeCostUsd,
889
+ fingerprint: {
890
+ node: process.version,
891
+ platform: process.platform,
892
+ arch: process.arch,
893
+ packages,
894
+ ...startedAt === void 0 ? {} : { startedAt },
895
+ ...options.labels === void 0 ? {} : { labels: options.labels }
896
+ }
897
+ };
898
+ }
899
+ //#endregion
630
900
  //#region src/checkpoint.ts
631
901
  /**
632
902
  * The phases 1-2 measured-value checkpoint (M12-T01; the quantitative
@@ -901,4 +1171,4 @@ async function runSweepMatrix(pool, options) {
901
1171
  return report;
902
1172
  }
903
1173
  //#endregion
904
- export { EvalJudgeError, JUDGE_VERDICT_SCHEMA, SWEEP_THRESHOLD_DEFAULTS, SpendEnvelope, SweepBudgetError, agentTypeRuleHolds, canaryFingerprint, commitEvalMeasured, evalMeasuredClaim, flipStaleOnCanaryDrift, goldenGrader, judgeGrader, normalizeCanaryOutput, renderCheckpointReport, rubricGrader, runCanary, runEvalCase, runEvalMatrix, runEvalSuite, runSweepMatrix, runValueCheckpoint, rungRuleHolds };
1174
+ export { EvalJudgeError, JUDGE_VERDICT_SCHEMA, SWEEP_THRESHOLD_DEFAULTS, SpendEnvelope, SweepBudgetError, agentTypeRuleHolds, canaryFingerprint, commitEvalMeasured, evalMeasuredClaim, flipStaleOnCanaryDrift, goldenGrader, judgeGrader, normalizeCanaryOutput, renderCheckpointReport, rubricGrader, runBenchmark, runCanary, runEvalCase, runEvalMatrix, runEvalSuite, runSweepMatrix, runValueCheckpoint, rungRuleHolds };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/evals",
3
- "version": "1.50.0",
3
+ "version": "1.52.0",
4
4
  "description": "Rulvar evals: eval cases, golden outputs, rubric and judge graders, matrix sweeps, canary fingerprint.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -22,8 +22,8 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@rulvar/core": "1.50.0",
26
- "@rulvar/testing": "1.50.0"
25
+ "@rulvar/core": "1.52.0",
26
+ "@rulvar/testing": "1.52.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^22.20.0",