@rulvar/evals 1.34.0 → 1.36.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
@@ -291,7 +291,10 @@ interface EvalCommitterOptions {
291
291
  committerId: string;
292
292
  /** The emitting sweep report; every claim's gate references it. */
293
293
  reportId: string;
294
- /** CAS-rebase attempts; default 3. */
294
+ /**
295
+ * CAS rebase attempts; default 3. A positive integer, refused as a
296
+ * ConfigError before the first store read.
297
+ */
295
298
  attempts?: number;
296
299
  }
297
300
  /** One measured claim; claimExpiry applies the TTL from the decay table. */
package/dist/index.js CHANGED
@@ -443,6 +443,16 @@ function judgeGrader(options) {
443
443
  * documented CAS-rebase recipe. Humans never call this; their path is
444
444
  * the human gate and it structurally cannot carry metrics.
445
445
  */
446
+ /**
447
+ * Local mirror of the core numeric intake idiom (v1.35.0 review P2-5):
448
+ * the CAS loop bound is compared with `<`, and every comparison with NaN
449
+ * is false, so an unvalidated NaN or nonpositive count skipped the loop
450
+ * entirely and surfaced the generic 'unreachable' Error instead of a
451
+ * typed refusal, while a fraction over ran by an attempt.
452
+ */
453
+ function requireCasAttempts(value, site) {
454
+ if (!Number.isInteger(value) || value < 1) throw new ConfigError(`${site} must be a positive integer; got ${String(value)}`);
455
+ }
446
456
  /** One measured claim; claimExpiry applies the TTL from the decay table. */
447
457
  function evalMeasuredClaim(input, committerId) {
448
458
  return {
@@ -482,6 +492,7 @@ async function commitEvalMeasured(store, claims, options) {
482
492
  gate
483
493
  }));
484
494
  const attempts = options.attempts ?? 3;
495
+ requireCasAttempts(attempts, "EvalCommitterOptions.attempts");
485
496
  let lastCas;
486
497
  for (let attempt = 0; attempt < attempts; attempt += 1) {
487
498
  const snapshot = await store.current();
@@ -582,6 +593,7 @@ async function canaryFingerprint(engine, probes, options = {}) {
582
593
  */
583
594
  async function flipStaleOnCanaryDrift(store, model, freshFingerprint, options) {
584
595
  const attempts = options?.attempts ?? 3;
596
+ requireCasAttempts(attempts, "flipStaleOnCanaryDrift attempts");
585
597
  let lastCas;
586
598
  for (let attempt = 0; attempt < attempts; attempt += 1) {
587
599
  const snapshot = await store.current();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/evals",
3
- "version": "1.34.0",
3
+ "version": "1.36.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.34.0",
26
- "@rulvar/testing": "1.34.0"
25
+ "@rulvar/core": "1.36.0",
26
+ "@rulvar/testing": "1.36.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^22.20.0",