@rulvar/evals 1.28.0 → 1.29.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
@@ -227,7 +227,10 @@ interface RubricGraderOptions {
227
227
  name?: string;
228
228
  /**
229
229
  * Minimum fraction of criteria that must pass; default 1 (all).
230
- * The fraction is also reported as the verdict score.
230
+ * The fraction is also reported as the verdict score. Must be a
231
+ * finite fraction in [0, 1]: anything else throws a ConfigError at
232
+ * construction, because an out of range threshold silently passes
233
+ * or fails every verdict (v1.28.0 review P2).
231
234
  */
232
235
  passThreshold?: number;
233
236
  }
@@ -400,6 +403,13 @@ interface SweepPool {
400
403
  models: SweepModel[];
401
404
  cases: SweepCase[];
402
405
  }
406
+ /**
407
+ * The claim bands. Both effective values must be finite fractions in
408
+ * [0, 1] with weakness strictly below strength (so the bands are
409
+ * ordered and an uninformative mid band exists); runSweepMatrix
410
+ * rejects anything else with a ConfigError before any engine, store,
411
+ * or envelope activity.
412
+ */
403
413
  interface SweepThresholds {
404
414
  /** passRate at or above emits a strength claim; default 0.9. */
405
415
  strength: number;
package/dist/index.js CHANGED
@@ -352,9 +352,15 @@ function goldenGrader(expected, options = {}) {
352
352
  }
353
353
  //#endregion
354
354
  //#region src/graders/rubric.ts
355
+ /**
356
+ * Rubric grader: scores the output against
357
+ * declared, named criteria with per-criterion verdicts. Criteria are pure
358
+ * predicates; the grader is host-side and involves no engine calls.
359
+ */
355
360
  function rubricGrader(criteria, options = {}) {
356
361
  const name = options.name ?? "rubric";
357
362
  const threshold = options.passThreshold ?? 1;
363
+ if (!Number.isFinite(threshold) || threshold < 0 || threshold > 1) throw new ConfigError(`rubricGrader: passThreshold must be a finite fraction between 0 and 1 inclusive; got ${String(threshold)}`);
358
364
  return {
359
365
  name,
360
366
  grade(context) {
@@ -801,6 +807,8 @@ async function runSweepMatrix(pool, options) {
801
807
  ...SWEEP_THRESHOLD_DEFAULTS,
802
808
  ...options.thresholds
803
809
  };
810
+ for (const [field, value] of [["strength", thresholds.strength], ["weakness", thresholds.weakness]]) if (!Number.isFinite(value) || value < 0 || value > 1) throw new ConfigError(`runSweepMatrix: thresholds.${field} must be a finite fraction between 0 and 1 inclusive; got ${String(value)}`);
811
+ if (!(thresholds.weakness < thresholds.strength)) throw new ConfigError(`runSweepMatrix: thresholds.weakness (${String(thresholds.weakness)}) must be strictly below thresholds.strength (${String(thresholds.strength)}) so the bands are ordered and an uninformative mid band exists`);
804
812
  if (options.envelope !== void 0 && options.suite?.budgetUsd === void 0) throw new ConfigError("runSweepMatrix: an aggregate envelope requires suite.budgetUsd (the per-target ceiling); unbounded targets under an envelope would be unaccountable");
805
813
  const byTaskClass = /* @__PURE__ */ new Map();
806
814
  for (const entry of pool.cases) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/evals",
3
- "version": "1.28.0",
3
+ "version": "1.29.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.28.0",
26
- "@rulvar/testing": "1.28.0"
25
+ "@rulvar/core": "1.29.0",
26
+ "@rulvar/testing": "1.29.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^22.20.0",