@rulvar/evals 1.240.0 → 1.241.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.
Files changed (2) hide show
  1. package/dist/index.js +104 -1
  2. package/package.json +7 -6
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRequire } from "node:module";
2
- import { ConfigError, InMemoryStore, JsonlFileStore, KnowledgeCasError, LeaseHeldError, SettlementError, SupersededError, citedValueValidator, claimCoverageOf, claimExpiry, compareRates, compileVerifiedLayer, createEngine, defineWorkflow, evidenceGradeValidator, hashRunOutput, invoiceFromJournal, journalPricingSnapshot, lastRunSettle, makeOrchestratorWorkflow, memoryQuotaLimiter, pairDraftClaims, pairRunFactClaims, preflightEstimate, priceComponentsOf } from "@rulvar/core";
2
+ import { ConfigError, InMemoryStore, JsonlFileStore, KnowledgeCasError, LeaseHeldError, SettlementError, SupersededError, citedValueValidator, claimCoverageOf, claimExpiry, compareRates, compileVerifiedLayer, createEngine, defineWorkflow, evidenceGradeValidator, hashRunOutput, invoiceFromJournal, journalPricingSnapshot, lastRunSettle, makeOrchestratorWorkflow, memoryQuotaLimiter, minMatchesValidator, pairDraftClaims, pairRunFactClaims, preflightEstimate, priceComponentsOf } from "@rulvar/core";
3
3
  import { createHash } from "node:crypto";
4
4
  import { appendFileSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
@@ -3492,6 +3492,8 @@ const TAIL_DRAFT_INVERTED = "draft: an audit-write failure does not turn success
3492
3492
  const TAIL_FINAL_INVERTED = "final: an audit-write failure does not turn success into failure [src/exec.ts:256-296].";
3493
3493
  const TAIL_FINAL_STILL_INVERTED = "final: the repaired text still flips the recorded outcome [src/exec.ts:256-296].";
3494
3494
  const TAIL_FINAL_CLEAN = "final: a failed audit write does not mask success [src/exec.ts:256-296].";
3495
+ const TAIL_FINAL_UNGROUNDED = "final: repaired wording with the provenance stripped.";
3496
+ const TAIL_FINAL_UNGROUNDED_INITIAL = "final: the initial wording arrived without any anchor.";
3495
3497
  const TAIL_FINDS = { contradictions: [{
3496
3498
  pair: 0,
3497
3499
  reason: "the draft inverts the recorded reading"
@@ -3671,6 +3673,107 @@ const SCENARIOS = [
3671
3673
  };
3672
3674
  }
3673
3675
  },
3676
+ {
3677
+ name: "repair-round-host-rejection",
3678
+ doctrine: "a repair round that dispatched and lost its candidate to the finish contract fails typed as a host rejection (RV3601): the message names the dispatch, never 'could not dispatch'; data carries roundDispatched true, repairsUsed 1, the judge meta beside the findings, and the finish verdict verbatim (failed validators, candidateHash, candidateChars); the outcome lifts the findings beside the meta",
3679
+ async run() {
3680
+ const { engine, store } = tailEngine(tailAdapter({
3681
+ judge: () => TAIL_FINDS,
3682
+ finals: [
3683
+ TAIL_FINAL_INVERTED,
3684
+ TAIL_FINAL_UNGROUNDED,
3685
+ TAIL_FINAL_UNGROUNDED
3686
+ ]
3687
+ }));
3688
+ const outcome = await engine.run(makeOrchestratorWorkflow("audit the executor", {
3689
+ ...TAIL_OPTS,
3690
+ claimConsistency: {
3691
+ stage: "final",
3692
+ onFound: "repair"
3693
+ },
3694
+ finishValidation: {
3695
+ validators: [minMatchesValidator({
3696
+ pattern: "src/[a-z]+\\.ts:\\d+",
3697
+ min: 1,
3698
+ name: "provenance-anchor"
3699
+ })],
3700
+ maxRepairs: 1
3701
+ }
3702
+ }), void 0, {
3703
+ runId: "fault-repair-host-rejection",
3704
+ budgetUsd: 10
3705
+ }).result;
3706
+ const data = outcome.error?.data ?? {};
3707
+ const entries = await store.load("fault-repair-host-rejection");
3708
+ const { compositions, judges } = tailSpans(entries);
3709
+ const liftedFindings = outcome.claimContradictions;
3710
+ const message = outcome.error?.message ?? "";
3711
+ return {
3712
+ observation: {
3713
+ matched: outcome.status === "error" && message.includes("dispatched and its repaired candidate failed host validation") && !message.includes("could not dispatch") && data.source === "orchestrator_claim_consistency" && data.roundDispatched === true && data.repairsUsed === 1 && data.claimConsistencyMeta?.findings === 1 && Array.isArray(data.claimContradictions) && data.claimContradictions.length === 1 && typeof data.finishValidation?.callId === "string" && data.finishValidation.repairsUsed === 1 && data.finishValidation.maxRepairs === 1 && typeof data.finishValidation.candidateHash === "string" && typeof data.finishValidation.candidateChars === "number" && JSON.stringify(data.finishValidation.failed ?? null).includes("provenance-anchor") && Array.isArray(liftedFindings) && liftedFindings.length === 1 && compositions.length === 2 && judges.length === 1,
3714
+ detail: `run '${outcome.status}': roundDispatched=${String(data.roundDispatched)}, repairsUsed=${String(data.repairsUsed)}, meta findings=${String(data.claimConsistencyMeta?.findings)}, finish verdict carries hash=${String(typeof data.finishValidation?.candidateHash === "string")} chars=${String(data.finishValidation?.candidateChars)}, outcome lifts findings=${String(Array.isArray(liftedFindings))}; ${String(compositions.length)} composition(s), ${String(judges.length)} final judge pass(es)`
3715
+ },
3716
+ artifacts: [jsonArtifact("outcome.json", {
3717
+ status: outcome.status,
3718
+ error: outcome.error ?? null
3719
+ }), jsonArtifact("journal.json", entries)]
3720
+ };
3721
+ }
3722
+ },
3723
+ {
3724
+ name: "repair-round-own-pool",
3725
+ doctrine: "the mechanical repair pool belongs to one composition invocation (RV3602): the bounded claim repair round enters with the full maxRepairs even after the initial composition spent its own, so the frozen third comparison sequence converges to ok/complete with verdicts repair/accepted twice and repairsUsed restarting at the invocation boundary, never a host rejection born of an inherited spent pool; the round's prompt also carries the HOST VALIDATION LESSONS block naming the failure the run already paid for (RV3603), while the initial composition carries none",
3726
+ async run() {
3727
+ let judgeCalls = 0;
3728
+ const adapter = tailAdapter({
3729
+ judge: () => (judgeCalls += 1) === 1 ? TAIL_FINDS : TAIL_AGREES,
3730
+ finals: [
3731
+ TAIL_FINAL_UNGROUNDED_INITIAL,
3732
+ TAIL_FINAL_INVERTED,
3733
+ TAIL_FINAL_UNGROUNDED,
3734
+ TAIL_FINAL_CLEAN
3735
+ ]
3736
+ });
3737
+ const { engine, store } = tailEngine(adapter);
3738
+ const outcome = await engine.run(makeOrchestratorWorkflow("audit the executor", {
3739
+ ...TAIL_OPTS,
3740
+ claimConsistency: {
3741
+ stage: "final",
3742
+ onFound: "repair"
3743
+ },
3744
+ finishValidation: {
3745
+ validators: [minMatchesValidator({
3746
+ pattern: "src/[a-z]+\\.ts:\\d+",
3747
+ min: 1,
3748
+ name: "provenance-anchor"
3749
+ })],
3750
+ maxRepairs: 1
3751
+ }
3752
+ }), void 0, {
3753
+ runId: "fault-repair-own-pool",
3754
+ budgetUsd: 10
3755
+ }).result;
3756
+ const value = outcome.value;
3757
+ const entries = await store.load("fault-repair-own-pool");
3758
+ const { compositions, judges } = tailSpans(entries);
3759
+ const verdictRows = entries.filter((entry) => entry.kind === "decision" && entry.value?.decisionType === "orchestrator_finish_validation").map((entry) => entry.value);
3760
+ const verdicts = verdictRows.map((row) => row.verdict).join(",");
3761
+ const pools = verdictRows.map((row) => String(row.repairsUsed)).join(",");
3762
+ const compositionPrompts = adapter.calls.filter((call) => call.label === "final-composition").map((call) => call.prompt);
3763
+ const lessonCarried = compositionPrompts.length === 4 && compositionPrompts[0]?.includes("HOST VALIDATION LESSONS") === false && compositionPrompts[2]?.includes("HOST VALIDATION LESSONS") === true && compositionPrompts[2]?.includes("provenance-anchor") === true;
3764
+ return {
3765
+ observation: {
3766
+ matched: outcome.status === "ok" && value?.result === TAIL_FINAL_CLEAN && value.claimConsistencyMeta?.findings === 0 && verdicts === "repair,accepted,repair,accepted" && pools === "0,1,0,1" && (value.rejectedFinishCandidates?.length ?? 0) === 2 && value.rejectedFinishCandidates?.every((row) => row.verdict === "repair") === true && lessonCarried && compositions.length === 2 && judges.length === 2,
3767
+ detail: `run '${outcome.status}' shipped ${value?.result === TAIL_FINAL_CLEAN ? "the repaired document" : "an unexpected document"}; verdicts [${verdicts}], repairsUsed [${pools}] (fresh pool at the invocation boundary); lesson carried=${String(lessonCarried)}; meta findings=${String(value?.claimConsistencyMeta?.findings)}; ${String(compositions.length)} composition(s), ${String(judges.length)} final judge pass(es)`
3768
+ },
3769
+ artifacts: [jsonArtifact("outcome.json", {
3770
+ status: outcome.status,
3771
+ value: outcome.value ?? null,
3772
+ envelope: outcome.envelope
3773
+ }), jsonArtifact("journal.json", entries)]
3774
+ };
3775
+ }
3776
+ },
3674
3777
  {
3675
3778
  name: "claim-judge-dead-armed-refusal",
3676
3779
  doctrine: "a final stage judge that dies on the wire under an armed posture fails the run typed for both 'fail' and 'repair' (RV3307), each message naming its armed posture, with exactly one composition paid and no repair round dispatched, never a silent settle over findings nobody ruled on",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/evals",
3
- "version": "1.240.0",
3
+ "version": "1.241.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,11 +22,11 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@rulvar/anthropic": "1.240.0",
26
- "@rulvar/openai": "1.240.0",
27
- "@rulvar/core": "1.240.0",
28
- "@rulvar/plan": "1.240.0",
29
- "@rulvar/testing": "1.240.0"
25
+ "@rulvar/anthropic": "1.241.0",
26
+ "@rulvar/plan": "1.241.0",
27
+ "@rulvar/core": "1.241.0",
28
+ "@rulvar/testing": "1.241.0",
29
+ "@rulvar/openai": "1.241.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^22.20.1",
@@ -46,6 +46,7 @@
46
46
  "build": "tsdown",
47
47
  "typecheck": "tsc --noEmit",
48
48
  "lint": "eslint .",
49
+ "test": "pnpm -w exec vitest run --project @rulvar/evals",
49
50
  "pack-check": "publint --pack pnpm && attw --pack . --profile esm-only"
50
51
  }
51
52
  }