@velum-labs/routekit-eval-setup 1.3.2 → 1.5.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/adapters/authoring-responses-request.d.ts +5 -0
- package/dist/adapters/authoring-responses-request.js +38 -0
- package/dist/adapters/evaluation-evidence-freshness.d.ts +7 -0
- package/dist/adapters/evaluation-evidence-freshness.js +76 -0
- package/dist/adapters/git-task-history.d.ts +67 -0
- package/dist/adapters/git-task-history.js +171 -0
- package/dist/adapters/integrated-repository-history.d.ts +21 -0
- package/dist/adapters/integrated-repository-history.js +175 -0
- package/dist/adapters/repository-command-diagnostic.d.ts +8 -0
- package/dist/adapters/repository-command-diagnostic.js +46 -0
- package/dist/adapters/repository-command-evidence.d.ts +13 -0
- package/dist/adapters/repository-command-evidence.js +102 -0
- package/dist/adapters/repository-command-runner.d.ts +238 -0
- package/dist/adapters/repository-command-runner.js +1483 -0
- package/dist/adapters/repository-import-context.d.ts +47 -0
- package/dist/adapters/repository-import-context.js +469 -0
- package/dist/adapters/repository-node-test-reporter.d.ts +3 -0
- package/dist/adapters/repository-node-test-reporter.js +27 -0
- package/dist/adapters/repository-review-evidence.d.ts +39 -0
- package/dist/adapters/repository-review-evidence.js +632 -0
- package/dist/adapters/repository-seed-selection.d.ts +7 -0
- package/dist/adapters/repository-seed-selection.js +79 -0
- package/dist/adapters/repository-solution-edits.d.ts +49 -0
- package/dist/adapters/repository-solution-edits.js +136 -0
- package/dist/adapters/repository-vitest-phase-adapter.d.ts +8 -0
- package/dist/adapters/repository-vitest-phase-adapter.js +310 -0
- package/dist/adapters/repository-vitest-reporter.d.ts +24 -0
- package/dist/adapters/repository-vitest-reporter.js +314 -0
- package/dist/adapters/strict-authoring-schema.d.ts +5 -0
- package/dist/adapters/strict-authoring-schema.js +158 -0
- package/dist/adapters/test-discovery.d.ts +30 -0
- package/dist/adapters/test-discovery.js +124 -0
- package/dist/adapters/typescript-repository-index.d.ts +51 -0
- package/dist/adapters/typescript-repository-index.js +226 -0
- package/dist/agentic-capabilities-protocol.d.ts +1373 -0
- package/dist/agentic-capabilities-protocol.js +786 -0
- package/dist/case-checkpoint-store.d.ts +29 -0
- package/dist/case-checkpoint-store.js +133 -0
- package/dist/case-pipeline-protocol-v2.d.ts +184 -0
- package/dist/case-pipeline-protocol-v2.js +193 -0
- package/dist/case-pipeline-protocol.d.ts +2626 -0
- package/dist/case-pipeline-protocol.js +371 -0
- package/dist/effect-api.d.ts +74 -10
- package/dist/effect-api.js +56 -6
- package/dist/errors.d.ts +31 -0
- package/dist/errors.js +10 -0
- package/dist/eval-capability-execution-envelope.d.ts +64 -0
- package/dist/eval-capability-execution-envelope.js +98 -0
- package/dist/eval-capability-policy.d.ts +90 -0
- package/dist/eval-capability-policy.js +107 -0
- package/dist/eval-event-log.d.ts +140 -0
- package/dist/eval-event-log.js +220 -0
- package/dist/evaluation-authoring-policy.d.ts +18 -0
- package/dist/evaluation-authoring-policy.js +19 -0
- package/dist/evaluation-authoring-validation.d.ts +22 -0
- package/dist/evaluation-authoring-validation.js +72 -0
- package/dist/evaluation-evidence.d.ts +20 -0
- package/dist/evaluation-evidence.js +319 -0
- package/dist/evaluation-grader-calibration-protocol.d.ts +108 -0
- package/dist/evaluation-grader-calibration-protocol.js +80 -0
- package/dist/evaluation-grader-calibration.d.ts +18 -0
- package/dist/evaluation-grader-calibration.js +334 -0
- package/dist/evaluation-grading-policy.d.ts +24 -0
- package/dist/evaluation-grading-policy.js +54 -0
- package/dist/evaluation-proposal-policy.d.ts +4 -0
- package/dist/evaluation-proposal-policy.js +91 -0
- package/dist/evaluation-source-retrieval.d.ts +68 -0
- package/dist/evaluation-source-retrieval.js +513 -0
- package/dist/evaluation-structure-policy.d.ts +29 -0
- package/dist/evaluation-structure-policy.js +138 -0
- package/dist/index.d.ts +124 -17
- package/dist/index.js +69 -11
- package/dist/inspection.js +2 -3
- package/dist/project-artifacts.d.ts +7 -2
- package/dist/project-artifacts.js +49 -136
- package/dist/project-authoring.d.ts +66 -5
- package/dist/project-authoring.js +783 -109
- package/dist/project-contracts.d.ts +419 -84
- package/dist/project-contracts.js +160 -52
- package/dist/project-store.js +2 -1
- package/dist/project-workflow.d.ts +5 -4
- package/dist/project-workflow.js +154 -35
- package/dist/repository-adversary-protocol.d.ts +64 -0
- package/dist/repository-adversary-protocol.js +105 -0
- package/dist/repository-behavior-protocol.d.ts +188 -0
- package/dist/repository-behavior-protocol.js +202 -0
- package/dist/repository-benchmark-protocol.d.ts +487 -0
- package/dist/repository-benchmark-protocol.js +96 -0
- package/dist/repository-execution-protocol.d.ts +150 -0
- package/dist/repository-execution-protocol.js +38 -0
- package/dist/repository-fixture-instructions.d.ts +3 -0
- package/dist/repository-fixture-instructions.js +91 -0
- package/dist/repository-fixture-protocol.d.ts +79 -0
- package/dist/repository-fixture-protocol.js +79 -0
- package/dist/repository-foundry-plan-protocol.d.ts +118 -0
- package/dist/repository-foundry-plan-protocol.js +296 -0
- package/dist/repository-foundry-progress-protocol.d.ts +52 -0
- package/dist/repository-foundry-progress-protocol.js +52 -0
- package/dist/repository-improvement-protocol.d.ts +100 -0
- package/dist/repository-improvement-protocol.js +106 -0
- package/dist/repository-language-model-protocol.d.ts +43 -0
- package/dist/repository-language-model-protocol.js +146 -0
- package/dist/repository-oracle-coverage-protocol.d.ts +18 -0
- package/dist/repository-oracle-coverage-protocol.js +39 -0
- package/dist/repository-oracle-execution-binding.d.ts +27 -0
- package/dist/repository-oracle-execution-binding.js +59 -0
- package/dist/repository-oracle-protocol.d.ts +230 -0
- package/dist/repository-oracle-protocol.js +156 -0
- package/dist/repository-oracle-scope-policy.d.ts +22 -0
- package/dist/repository-oracle-scope-policy.js +92 -0
- package/dist/repository-quality-policy.d.ts +15 -0
- package/dist/repository-quality-policy.js +357 -0
- package/dist/repository-routing-benchmark-protocol.d.ts +176 -0
- package/dist/repository-routing-benchmark-protocol.js +103 -0
- package/dist/repository-routing-model-protocol.d.ts +36 -0
- package/dist/repository-routing-model-protocol.js +89 -0
- package/dist/repository-routing-plan-protocol.d.ts +112 -0
- package/dist/repository-routing-plan-protocol.js +58 -0
- package/dist/repository-routing-quality-policy.d.ts +9 -0
- package/dist/repository-routing-quality-policy.js +191 -0
- package/dist/repository-seed-qualification-progress-protocol.d.ts +205 -0
- package/dist/repository-seed-qualification-progress-protocol.js +28 -0
- package/dist/repository-semantic-calibration-protocol.d.ts +768 -0
- package/dist/repository-semantic-calibration-protocol.js +276 -0
- package/dist/repository-semantic-calibration.d.ts +163 -0
- package/dist/repository-semantic-calibration.js +581 -0
- package/dist/repository-specification-contract-facts-protocol.d.ts +224 -0
- package/dist/repository-specification-contract-facts-protocol.js +276 -0
- package/dist/repository-specification-critique-protocol.d.ts +189 -0
- package/dist/repository-specification-critique-protocol.js +103 -0
- package/dist/repository-task-family-protocol.d.ts +24 -0
- package/dist/repository-task-family-protocol.js +37 -0
- package/dist/repository-task-seed-protocol.d.ts +384 -0
- package/dist/repository-task-seed-protocol.js +236 -0
- package/dist/repository-trajectory-protocol.d.ts +20 -0
- package/dist/repository-trajectory-protocol.js +42 -0
- package/dist/service.js +1 -1
- package/dist/services/adversary/service.d.ts +64 -0
- package/dist/services/adversary/service.js +330 -0
- package/dist/services/benchmark-compiler/service.d.ts +450 -0
- package/dist/services/benchmark-compiler/service.js +9 -0
- package/dist/services/budgeted-model/service.d.ts +118 -0
- package/dist/services/budgeted-model/service.js +460 -0
- package/dist/services/case-authoring/service.d.ts +163 -0
- package/dist/services/case-authoring/service.js +1456 -0
- package/dist/services/case-finalization/service.d.ts +283 -0
- package/dist/services/case-finalization/service.js +370 -0
- package/dist/services/case-generation/service.d.ts +619 -0
- package/dist/services/case-generation/service.js +2628 -0
- package/dist/services/case-pipeline/service.d.ts +31 -0
- package/dist/services/case-pipeline/service.js +485 -0
- package/dist/services/case-pipeline-v2/service.d.ts +70 -0
- package/dist/services/case-pipeline-v2/service.js +477 -0
- package/dist/services/command-observability/service.d.ts +13 -0
- package/dist/services/command-observability/service.js +3 -0
- package/dist/services/dimension-labeling/service.d.ts +77 -0
- package/dist/services/dimension-labeling/service.js +188 -0
- package/dist/services/eval-candidate/service.d.ts +208 -0
- package/dist/services/eval-candidate/service.js +64 -0
- package/dist/services/eval-capabilities/service.d.ts +183 -0
- package/dist/services/eval-capabilities/service.js +1433 -0
- package/dist/services/eval-environment/service.d.ts +173 -0
- package/dist/services/eval-environment/service.js +127 -0
- package/dist/services/evidence-reconstruction/service.d.ts +36 -0
- package/dist/services/evidence-reconstruction/service.js +145 -0
- package/dist/services/fixture-builder/service.d.ts +62 -0
- package/dist/services/fixture-builder/service.js +36 -0
- package/dist/services/fixture-validation/service.d.ts +75 -0
- package/dist/services/fixture-validation/service.js +295 -0
- package/dist/services/foundry/service.d.ts +831 -0
- package/dist/services/foundry/service.js +442 -0
- package/dist/services/foundry-progress/service.d.ts +62 -0
- package/dist/services/foundry-progress/service.js +149 -0
- package/dist/services/foundry-v2/service.d.ts +54 -0
- package/dist/services/foundry-v2/service.js +28 -0
- package/dist/services/grounded-authoring/service.d.ts +126 -0
- package/dist/services/grounded-authoring/service.js +822 -0
- package/dist/services/historical-case/service.d.ts +722 -0
- package/dist/services/historical-case/service.js +177 -0
- package/dist/services/improvement-loop/service.d.ts +59 -0
- package/dist/services/improvement-loop/service.js +176 -0
- package/dist/services/language-model/service.d.ts +52 -0
- package/dist/services/language-model/service.js +194 -0
- package/dist/services/oracle-builder/service.d.ts +146 -0
- package/dist/services/oracle-builder/service.js +513 -0
- package/dist/services/oracle-coverage/service.d.ts +28 -0
- package/dist/services/oracle-coverage/service.js +50 -0
- package/dist/services/oracle-coverage-witness/service.d.ts +130 -0
- package/dist/services/oracle-coverage-witness/service.js +538 -0
- package/dist/services/pipeline-challenge/service.d.ts +551 -0
- package/dist/services/pipeline-challenge/service.js +427 -0
- package/dist/services/pipeline-controls/service.d.ts +130 -0
- package/dist/services/pipeline-controls/service.js +483 -0
- package/dist/services/pipeline-oracle/service.d.ts +8 -0
- package/dist/services/pipeline-oracle/service.js +256 -0
- package/dist/services/pipeline-seed/service.d.ts +298 -0
- package/dist/services/pipeline-seed/service.js +428 -0
- package/dist/services/pipeline-spec/service.d.ts +103 -0
- package/dist/services/pipeline-spec/service.js +619 -0
- package/dist/services/pipeline-tournament/service.d.ts +258 -0
- package/dist/services/pipeline-tournament/service.js +476 -0
- package/dist/services/quality-gate/service.d.ts +233 -0
- package/dist/services/quality-gate/service.js +136 -0
- package/dist/services/repository-bundle/service.d.ts +33 -0
- package/dist/services/repository-bundle/service.js +114 -0
- package/dist/services/repository-model/service.d.ts +105 -0
- package/dist/services/repository-model/service.js +250 -0
- package/dist/services/repository-public-artifact/service.d.ts +133 -0
- package/dist/services/repository-public-artifact/service.js +330 -0
- package/dist/services/routing-benchmark/service.d.ts +362 -0
- package/dist/services/routing-benchmark/service.js +96 -0
- package/dist/services/specification-critic/service.d.ts +92 -0
- package/dist/services/specification-critic/service.js +172 -0
- package/dist/services/task-family/service.d.ts +40 -0
- package/dist/services/task-family/service.js +55 -0
- package/dist/services/task-seed/service.d.ts +906 -0
- package/dist/services/task-seed/service.js +1406 -0
- package/dist/services/task-specification/service.d.ts +27 -0
- package/dist/services/task-specification/service.js +40 -0
- package/dist/services/trajectory-policy/service.d.ts +110 -0
- package/dist/services/trajectory-policy/service.js +216 -0
- package/dist/test/agentic-capabilities-protocol.test.d.ts +1 -0
- package/dist/test/agentic-capabilities-protocol.test.js +570 -0
- package/dist/test/agentic-capabilities.test.d.ts +1 -0
- package/dist/test/agentic-capabilities.test.js +1461 -0
- package/dist/test/agentic-environment.test.d.ts +1 -0
- package/dist/test/agentic-environment.test.js +213 -0
- package/dist/test/case-pipeline-foundation.test.d.ts +1 -0
- package/dist/test/case-pipeline-foundation.test.js +535 -0
- package/dist/test/case-pipeline-protocol-v2.test.d.ts +1 -0
- package/dist/test/case-pipeline-protocol-v2.test.js +124 -0
- package/dist/test/case-pipeline-v2.test.d.ts +1 -0
- package/dist/test/case-pipeline-v2.test.js +286 -0
- package/dist/test/case-pipeline.test.d.ts +1 -0
- package/dist/test/case-pipeline.test.js +851 -0
- package/dist/test/eval-capability-policy.test.d.ts +1 -0
- package/dist/test/eval-capability-policy.test.js +50 -0
- package/dist/test/eval-event-log.test.d.ts +1 -0
- package/dist/test/eval-event-log.test.js +125 -0
- package/dist/test/evaluation-evidence-freshness.test.d.ts +1 -0
- package/dist/test/evaluation-evidence-freshness.test.js +44 -0
- package/dist/test/evaluation-evidence.test.d.ts +1 -0
- package/dist/test/evaluation-evidence.test.js +230 -0
- package/dist/test/evaluation-grader-calibration.test.d.ts +1 -0
- package/dist/test/evaluation-grader-calibration.test.js +373 -0
- package/dist/test/evaluation-proposal-digest.test.d.ts +1 -0
- package/dist/test/evaluation-proposal-digest.test.js +187 -0
- package/dist/test/evaluation-source-retrieval.test.d.ts +1 -0
- package/dist/test/evaluation-source-retrieval.test.js +237 -0
- package/dist/test/evaluation-structure-policy.test.d.ts +1 -0
- package/dist/test/evaluation-structure-policy.test.js +196 -0
- package/dist/test/fixtures/repository-resource-panel.d.ts +39 -0
- package/dist/test/fixtures/repository-resource-panel.js +111 -0
- package/dist/test/fixtures/vitest-boundary-panel.d.ts +84 -0
- package/dist/test/fixtures/vitest-boundary-panel.js +120 -0
- package/dist/test/fixtures/vitest-phase-panel.d.ts +135 -0
- package/dist/test/fixtures/vitest-phase-panel.js +213 -0
- package/dist/test/fixtures/vitest-reporter-results.d.ts +76 -0
- package/dist/test/fixtures/vitest-reporter-results.js +94 -0
- package/dist/test/grounded-authoring.test.d.ts +1 -0
- package/dist/test/grounded-authoring.test.js +565 -0
- package/dist/test/integrated-repository-history.test.d.ts +1 -0
- package/dist/test/integrated-repository-history.test.js +227 -0
- package/dist/test/project-authoring.test.js +593 -43
- package/dist/test/project-workflow.test.js +419 -40
- package/dist/test/repository-authoring-artifacts.test.d.ts +1 -0
- package/dist/test/repository-authoring-artifacts.test.js +185 -0
- package/dist/test/repository-bundle.test.d.ts +1 -0
- package/dist/test/repository-bundle.test.js +52 -0
- package/dist/test/repository-case-generation.test.d.ts +1 -0
- package/dist/test/repository-case-generation.test.js +3465 -0
- package/dist/test/repository-command-diagnostic.test.d.ts +1 -0
- package/dist/test/repository-command-diagnostic.test.js +55 -0
- package/dist/test/repository-command-signals.test.d.ts +1 -0
- package/dist/test/repository-command-signals.test.js +124 -0
- package/dist/test/repository-fixture-scope-coverage.test.d.ts +1 -0
- package/dist/test/repository-fixture-scope-coverage.test.js +127 -0
- package/dist/test/repository-fixture-validation.test.d.ts +1 -0
- package/dist/test/repository-fixture-validation.test.js +362 -0
- package/dist/test/repository-foundry-progress.test.d.ts +1 -0
- package/dist/test/repository-foundry-progress.test.js +110 -0
- package/dist/test/repository-foundry-quality.test.d.ts +1 -0
- package/dist/test/repository-foundry-quality.test.js +1138 -0
- package/dist/test/repository-import-context.test.d.ts +1 -0
- package/dist/test/repository-import-context.test.js +354 -0
- package/dist/test/repository-model-authoring.test.d.ts +1 -0
- package/dist/test/repository-model-authoring.test.js +544 -0
- package/dist/test/repository-model.test.d.ts +1 -0
- package/dist/test/repository-model.test.js +2195 -0
- package/dist/test/repository-node-test-reporter.test.d.ts +1 -0
- package/dist/test/repository-node-test-reporter.test.js +104 -0
- package/dist/test/repository-oracle-concurrency.test.d.ts +1 -0
- package/dist/test/repository-oracle-concurrency.test.js +542 -0
- package/dist/test/repository-oracle-coverage-witness.test.d.ts +1 -0
- package/dist/test/repository-oracle-coverage-witness.test.js +511 -0
- package/dist/test/repository-oracle-coverage.test.d.ts +1 -0
- package/dist/test/repository-oracle-coverage.test.js +168 -0
- package/dist/test/repository-oracle-evidence.test.d.ts +1 -0
- package/dist/test/repository-oracle-evidence.test.js +185 -0
- package/dist/test/repository-oracle-plan.test.d.ts +1 -0
- package/dist/test/repository-oracle-plan.test.js +176 -0
- package/dist/test/repository-overlay-isolation.test.d.ts +1 -0
- package/dist/test/repository-overlay-isolation.test.js +85 -0
- package/dist/test/repository-preparation-cache.test.d.ts +1 -0
- package/dist/test/repository-preparation-cache.test.js +414 -0
- package/dist/test/repository-public-artifact.test.d.ts +1 -0
- package/dist/test/repository-public-artifact.test.js +273 -0
- package/dist/test/repository-qualification-diagnostics.test.d.ts +1 -0
- package/dist/test/repository-qualification-diagnostics.test.js +524 -0
- package/dist/test/repository-reference-authoring.test.d.ts +1 -0
- package/dist/test/repository-reference-authoring.test.js +1633 -0
- package/dist/test/repository-review-evidence-v2.test.d.ts +1 -0
- package/dist/test/repository-review-evidence-v2.test.js +183 -0
- package/dist/test/repository-review-evidence.test.d.ts +1 -0
- package/dist/test/repository-review-evidence.test.js +124 -0
- package/dist/test/repository-seed-exclusions.test.d.ts +1 -0
- package/dist/test/repository-seed-exclusions.test.js +96 -0
- package/dist/test/repository-seed-selection.test.d.ts +1 -0
- package/dist/test/repository-seed-selection.test.js +504 -0
- package/dist/test/repository-semantic-calibration.test.d.ts +1 -0
- package/dist/test/repository-semantic-calibration.test.js +688 -0
- package/dist/test/repository-solution-edits.test.d.ts +1 -0
- package/dist/test/repository-solution-edits.test.js +377 -0
- package/dist/test/repository-specification-budget.test.d.ts +1 -0
- package/dist/test/repository-specification-budget.test.js +171 -0
- package/dist/test/repository-specification-contract-checkpoint.test.d.ts +1 -0
- package/dist/test/repository-specification-contract-checkpoint.test.js +228 -0
- package/dist/test/repository-specification-contract-facts.test.d.ts +1 -0
- package/dist/test/repository-specification-contract-facts.test.js +177 -0
- package/dist/test/repository-trajectory-authoring.test.d.ts +1 -0
- package/dist/test/repository-trajectory-authoring.test.js +176 -0
- package/dist/test/repository-valid-control-plan.test.d.ts +1 -0
- package/dist/test/repository-valid-control-plan.test.js +45 -0
- package/dist/test/repository-vitest-phase.test.d.ts +1 -0
- package/dist/test/repository-vitest-phase.test.js +848 -0
- package/dist/test/repository-vitest-reporter.test.d.ts +1 -0
- package/dist/test/repository-vitest-reporter.test.js +158 -0
- package/dist/test/repository-workspace-build.test.d.ts +1 -0
- package/dist/test/repository-workspace-build.test.js +160 -0
- package/dist/test/strict-authoring-schema.test.d.ts +1 -0
- package/dist/test/strict-authoring-schema.test.js +169 -0
- package/package.json +48 -6
package/dist/project-workflow.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { assertDecompositionResult, assertPublishedRoutingActivation, assertRoutingObjectivePolicy, isForbiddenEvalModel } from "@velum-labs/routekit-eval-contracts";
|
|
2
2
|
import { RoutingActivationConstraints, RoutingObjectivePolicy } from "@velum-labs/routekit-eval-contracts";
|
|
3
|
+
import { CostService } from "@velum-labs/routekit-registry";
|
|
3
4
|
import { Clock, Context, Effect, Layer, Path, Schema } from "effect";
|
|
5
|
+
import { assertCurrentEvaluationEvidence } from "./adapters/evaluation-evidence-freshness.js";
|
|
4
6
|
import { EvalDimensionContrastError, EvalProjectTransitionError } from "./errors.js";
|
|
7
|
+
import { EVAL_STRUCTURE_POLICY_VERSION, assertEvaluationStructure, evaluationStructureReportDigest } from "./evaluation-structure-policy.js";
|
|
5
8
|
import { EvalRepositoryInspector } from "./inspection.js";
|
|
6
9
|
import { candidateReasoningEffortFromAnswer } from "./model-selection.js";
|
|
7
10
|
import { EvalProjectArtifacts, evaluationProposalDigest, routingBasisDigest } from "./project-artifacts.js";
|
|
8
|
-
import { EVAL_PROJECT_VERSION, scopedExpectedCalls, summarizeEvalRunLedger } from "./project-contracts.js";
|
|
11
|
+
import { EVAL_PROJECT_VERSION, estimateEvalPlanCost, scopedExpectedCalls, summarizeEvalRunLedger } from "./project-contracts.js";
|
|
9
12
|
import { EvalProjectStore } from "./project-store.js";
|
|
10
13
|
import { EvalModelCatalog } from "./services/model-catalog/service.js";
|
|
14
|
+
import { assertEvalRunCanFail } from "./eval-event-log.js";
|
|
11
15
|
const isoNow = Effect.map(Clock.currentTimeMillis, (millis) => new Date(millis).toISOString());
|
|
12
16
|
const questionForProgress = (progress) => {
|
|
13
17
|
switch (progress._tag) {
|
|
@@ -92,7 +96,7 @@ const nextAction = (state, artifacts) => {
|
|
|
92
96
|
? "propose-evaluations"
|
|
93
97
|
: "approve-evaluations";
|
|
94
98
|
case "ready":
|
|
95
|
-
return "run";
|
|
99
|
+
return artifacts.evaluationsApproved ? "run" : "approve-evaluations";
|
|
96
100
|
case "running":
|
|
97
101
|
return "none";
|
|
98
102
|
case "qualified":
|
|
@@ -157,15 +161,18 @@ const sameLedger = (left, right) => left.expectedCalls === right.expectedCalls &
|
|
|
157
161
|
left.knownOutputTokens === right.knownOutputTokens &&
|
|
158
162
|
left.unknownTokenMeasurements === right.unknownTokenMeasurements &&
|
|
159
163
|
left.knownPricedSubtotalUsd === right.knownPricedSubtotalUsd &&
|
|
160
|
-
left.unpricedCalls === right.unpricedCalls
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
left.unpricedCalls === right.unpricedCalls &&
|
|
165
|
+
left.subscriptionUnitCalls === right.subscriptionUnitCalls;
|
|
166
|
+
const validateQualifiedReport = (state, plan, proposal, report, costService) => Effect.gen(function* () {
|
|
167
|
+
if (report.status === "passed") {
|
|
168
|
+
assertPublishedRoutingActivation(report.activation, {
|
|
169
|
+
dimensionIds: plan.selectedCaseIds.map((entry) => entry.dimensionId)
|
|
170
|
+
});
|
|
171
|
+
if (report.activation.basisDigest !== state.basisDigest ||
|
|
172
|
+
report.activation.classifierModel !== state.configuration.classifierModel ||
|
|
173
|
+
!sameStrings(report.activation.candidateModels, plan.candidateModels)) {
|
|
174
|
+
throw new Error("published activation does not match the immutable execution plan");
|
|
175
|
+
}
|
|
169
176
|
}
|
|
170
177
|
const expectedDimensions = new Map(plan.selectedCaseIds.map((entry) => [entry.dimensionId, new Set(entry.caseIds)]));
|
|
171
178
|
const comparisons = new Map();
|
|
@@ -285,30 +292,60 @@ const validateQualifiedReport = (state, plan, proposal, report) => {
|
|
|
285
292
|
observedCompositionCases.size !== 0 ||
|
|
286
293
|
qualification.composition.comparableCases !== 0 ||
|
|
287
294
|
qualification.composition.agreeingCases !== 0 ||
|
|
295
|
+
qualification.composition.winnerAgreement !== undefined ||
|
|
296
|
+
qualification.composition.conclusion !== "inconclusive" ||
|
|
297
|
+
qualification.composition.publishable ||
|
|
288
298
|
qualification.composition.cases.length !== 0) {
|
|
289
299
|
throw new Error("composition qualification summary does not meet the reviewed threshold");
|
|
290
300
|
}
|
|
291
301
|
}
|
|
292
302
|
else if (qualification.composition.expectedCases !== expectedCompositionCases.size ||
|
|
293
303
|
observedCompositionCases.size !== expectedCompositionCases.size ||
|
|
294
|
-
qualification.composition.comparableCases < 1 ||
|
|
295
304
|
qualification.composition.agreeingCases !==
|
|
296
305
|
qualification.composition.cases.filter((result) => result.passed).length ||
|
|
297
|
-
|
|
298
|
-
qualification.composition.
|
|
299
|
-
qualification.composition.
|
|
300
|
-
|
|
306
|
+
qualification.composition.comparableCases !==
|
|
307
|
+
qualification.composition.cases.filter((result) => result.comparable).length ||
|
|
308
|
+
qualification.composition.cases.some((result) => result.comparable !==
|
|
309
|
+
(result.predictedWinner !== null &&
|
|
310
|
+
result.observedWinner !== null &&
|
|
311
|
+
result.predictedScoreGap >= proposal.compositionSuite.minimumWinnerScoreGap &&
|
|
312
|
+
result.observedScoreGap >= proposal.compositionSuite.minimumWinnerScoreGap) ||
|
|
313
|
+
result.passed !==
|
|
314
|
+
(result.comparable && result.predictedWinner === result.observedWinner))) {
|
|
301
315
|
throw new Error("composition qualification summary does not meet the reviewed threshold");
|
|
302
316
|
}
|
|
317
|
+
if (expectedCompositionCases.size > 0) {
|
|
318
|
+
const comparableCases = qualification.composition.comparableCases;
|
|
319
|
+
const expectedAgreement = comparableCases === 0
|
|
320
|
+
? undefined
|
|
321
|
+
: qualification.composition.agreeingCases / comparableCases;
|
|
322
|
+
const meetsThreshold = expectedAgreement !== undefined &&
|
|
323
|
+
expectedAgreement >= proposal.compositionSuite.minimumWinnerAgreement;
|
|
324
|
+
if ((expectedAgreement === undefined
|
|
325
|
+
? qualification.composition.winnerAgreement !== undefined
|
|
326
|
+
: qualification.composition.winnerAgreement === undefined ||
|
|
327
|
+
Math.abs(qualification.composition.winnerAgreement - expectedAgreement) > 1e-6) ||
|
|
328
|
+
qualification.composition.conclusion !==
|
|
329
|
+
(expectedAgreement === undefined
|
|
330
|
+
? "inconclusive"
|
|
331
|
+
: meetsThreshold
|
|
332
|
+
? "passed"
|
|
333
|
+
: "failed") ||
|
|
334
|
+
qualification.composition.publishable !==
|
|
335
|
+
(plan.scope === "full" && meetsThreshold) ||
|
|
336
|
+
(plan.scope === "full" && !meetsThreshold)) {
|
|
337
|
+
throw new Error("composition qualification summary does not meet the reviewed threshold");
|
|
338
|
+
}
|
|
339
|
+
}
|
|
303
340
|
}
|
|
304
341
|
const expected = scopedExpectedCalls(plan);
|
|
305
|
-
const ledger = summarizeEvalRunLedger(report.comparisons, expected.expectedCallCount, qualification?.decomposition.observations ?? []);
|
|
342
|
+
const ledger = yield* summarizeEvalRunLedger(report.comparisons, expected.expectedCallCount, costService, qualification?.decomposition.observations ?? [], plan.classifierModel);
|
|
306
343
|
if (ledger.observedCalls !== expected.expectedCallCount ||
|
|
307
344
|
ledger.observedCandidateRows !== expected.expectedCandidateCalls ||
|
|
308
345
|
!sameLedger(ledger, report.ledger)) {
|
|
309
346
|
throw new Error("qualification ledger does not match the completed evidence");
|
|
310
347
|
}
|
|
311
|
-
};
|
|
348
|
+
});
|
|
312
349
|
const parseObjective = (state, answer) => Effect.gen(function* () {
|
|
313
350
|
const text = yield* nonEmptyAnswer(state, answer);
|
|
314
351
|
const json = yield* Effect.try({
|
|
@@ -512,8 +549,26 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
512
549
|
const artifacts = yield* EvalProjectArtifacts;
|
|
513
550
|
const inspector = yield* EvalRepositoryInspector;
|
|
514
551
|
const modelCatalog = yield* EvalModelCatalog;
|
|
552
|
+
const costService = yield* CostService;
|
|
515
553
|
const paths = yield* Path.Path;
|
|
554
|
+
const platform = yield* Effect.context();
|
|
516
555
|
const resolveRoot = (repositoryRoot) => paths.resolve(repositoryRoot);
|
|
556
|
+
const evaluationStructureFor = (root, state, proposal) => Effect.gen(function* () {
|
|
557
|
+
const report = yield* Effect.try({
|
|
558
|
+
try: () => assertEvaluationStructure({
|
|
559
|
+
proposal,
|
|
560
|
+
sourceInventory: state.sourceInventory
|
|
561
|
+
}),
|
|
562
|
+
catch: (cause) => transitionError(state.stage, cause instanceof Error
|
|
563
|
+
? cause.message
|
|
564
|
+
: "evaluation proposal failed structure validation")
|
|
565
|
+
});
|
|
566
|
+
yield* assertCurrentEvaluationEvidence({
|
|
567
|
+
repositoryRoot: root,
|
|
568
|
+
evidenceSources: proposal.evidenceSources ?? []
|
|
569
|
+
}).pipe(Effect.provide(platform), Effect.mapError((cause) => transitionError(state.stage, cause.message)));
|
|
570
|
+
return report;
|
|
571
|
+
});
|
|
517
572
|
const statusOf = (root, state) => Effect.gen(function* () {
|
|
518
573
|
const [basis, basisApproval, evaluations, evaluationsApproval, plans] = yield* Effect.all([
|
|
519
574
|
artifacts.loadBasisProposal(root),
|
|
@@ -522,6 +577,15 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
522
577
|
artifacts.loadEvaluationsApproval(root),
|
|
523
578
|
artifacts.listPlans(root)
|
|
524
579
|
]);
|
|
580
|
+
const structureReport = evaluations === undefined
|
|
581
|
+
? undefined
|
|
582
|
+
: yield* evaluationStructureFor(root, state, evaluations).pipe(Effect.match({
|
|
583
|
+
onFailure: () => undefined,
|
|
584
|
+
onSuccess: (report) => report
|
|
585
|
+
}));
|
|
586
|
+
const structureReportDigest = structureReport === undefined
|
|
587
|
+
? undefined
|
|
588
|
+
: evaluationStructureReportDigest(structureReport);
|
|
525
589
|
const artifactStatus = {
|
|
526
590
|
...(basis === undefined ? {} : { basisProposalDigest: basis.basisDigest }),
|
|
527
591
|
basisApproved: basis !== undefined &&
|
|
@@ -532,7 +596,10 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
532
596
|
: { evaluationProposalDigest: evaluations.evaluationDigest }),
|
|
533
597
|
evaluationsApproved: evaluations !== undefined &&
|
|
534
598
|
evaluationsApproval?.kind === "evaluations" &&
|
|
535
|
-
evaluationsApproval.digest === evaluations.evaluationDigest
|
|
599
|
+
evaluationsApproval.digest === evaluations.evaluationDigest &&
|
|
600
|
+
evaluationsApproval.structurePolicyVersion ===
|
|
601
|
+
EVAL_STRUCTURE_POLICY_VERSION &&
|
|
602
|
+
evaluationsApproval.structureReportDigest === structureReportDigest,
|
|
536
603
|
plans
|
|
537
604
|
};
|
|
538
605
|
return {
|
|
@@ -697,7 +764,9 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
697
764
|
const proposeEvaluations = (repositoryRoot, input) => Effect.gen(function* () {
|
|
698
765
|
const root = resolveRoot(repositoryRoot);
|
|
699
766
|
const state = yield* loadRequired(root);
|
|
700
|
-
if (state.stage !== "evaluations-review"
|
|
767
|
+
if (state.stage !== "evaluations-review" &&
|
|
768
|
+
state.stage !== "ready" &&
|
|
769
|
+
state.stage !== "qualified") {
|
|
701
770
|
return yield* transitionError(state.stage, "dimension evaluations can only be proposed after routing-basis approval");
|
|
702
771
|
}
|
|
703
772
|
const basis = yield* artifacts.loadBasisProposal(root);
|
|
@@ -743,6 +812,9 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
743
812
|
candidateReasoningEfforts: state.configuration.candidateReasoningEfforts
|
|
744
813
|
}),
|
|
745
814
|
judgeModel: state.configuration.judgeModel,
|
|
815
|
+
...(input.evidenceSources === undefined
|
|
816
|
+
? {}
|
|
817
|
+
: { evidenceSources: input.evidenceSources }),
|
|
746
818
|
suites: input.suites,
|
|
747
819
|
decompositionBenchmark: input.decompositionBenchmark,
|
|
748
820
|
compositionSuite: input.compositionSuite
|
|
@@ -757,7 +829,9 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
757
829
|
const approveEvaluations = (repositoryRoot, expectedDigest) => Effect.gen(function* () {
|
|
758
830
|
const root = resolveRoot(repositoryRoot);
|
|
759
831
|
const state = yield* loadRequired(root);
|
|
760
|
-
if (state.stage !== "evaluations-review"
|
|
832
|
+
if (state.stage !== "evaluations-review" &&
|
|
833
|
+
state.stage !== "ready" &&
|
|
834
|
+
state.stage !== "qualified") {
|
|
761
835
|
return yield* transitionError(state.stage, "dimension evaluations are not awaiting approval");
|
|
762
836
|
}
|
|
763
837
|
const proposal = yield* artifacts.loadEvaluationProposal(root);
|
|
@@ -768,13 +842,19 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
768
842
|
proposal.basisDigest !== state.basisDigest) {
|
|
769
843
|
return yield* transitionError(state.stage, "evaluation proposal changed after review; approve its current digest");
|
|
770
844
|
}
|
|
845
|
+
const structureReport = yield* evaluationStructureFor(root, state, proposal);
|
|
771
846
|
const now = yield* isoNow;
|
|
772
847
|
yield* artifacts.saveEvaluationsApproval(root, {
|
|
773
848
|
version: EVAL_PROJECT_VERSION,
|
|
774
849
|
kind: "evaluations",
|
|
775
850
|
digest: proposal.evaluationDigest,
|
|
776
|
-
approvedAt: now
|
|
851
|
+
approvedAt: now,
|
|
852
|
+
structurePolicyVersion: EVAL_STRUCTURE_POLICY_VERSION,
|
|
853
|
+
structureReportDigest: evaluationStructureReportDigest(structureReport)
|
|
777
854
|
});
|
|
855
|
+
if (state.stage !== "evaluations-review") {
|
|
856
|
+
return yield* statusOf(root, state);
|
|
857
|
+
}
|
|
778
858
|
const next = {
|
|
779
859
|
version: state.version,
|
|
780
860
|
projectId: state.projectId,
|
|
@@ -790,7 +870,7 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
790
870
|
yield* store.save(root, next);
|
|
791
871
|
return yield* statusOf(root, next);
|
|
792
872
|
});
|
|
793
|
-
const createPlan = (repositoryRoot, scope) => Effect.gen(function* () {
|
|
873
|
+
const createPlan = (repositoryRoot, scope, repetitions = 1) => Effect.gen(function* () {
|
|
794
874
|
const root = resolveRoot(repositoryRoot);
|
|
795
875
|
const state = yield* loadRequired(root);
|
|
796
876
|
if (state.stage !== "ready" && state.stage !== "qualified") {
|
|
@@ -798,13 +878,24 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
798
878
|
}
|
|
799
879
|
const proposal = yield* artifacts.loadEvaluationProposal(root);
|
|
800
880
|
const approval = yield* artifacts.loadEvaluationsApproval(root);
|
|
881
|
+
const structureReport = proposal === undefined
|
|
882
|
+
? undefined
|
|
883
|
+
: yield* evaluationStructureFor(root, state, proposal);
|
|
801
884
|
if (proposal === undefined ||
|
|
802
885
|
approval?.kind !== "evaluations" ||
|
|
803
886
|
approval.digest !== proposal.evaluationDigest ||
|
|
887
|
+
approval.structurePolicyVersion !== EVAL_STRUCTURE_POLICY_VERSION ||
|
|
888
|
+
approval.structureReportDigest !==
|
|
889
|
+
(structureReport === undefined
|
|
890
|
+
? undefined
|
|
891
|
+
: evaluationStructureReportDigest(structureReport)) ||
|
|
804
892
|
proposal.evaluationDigest !== state.evaluationDigest ||
|
|
805
893
|
proposal.basisDigest !== state.basisDigest) {
|
|
806
894
|
return yield* transitionError(state.stage, "approved evaluation artifacts are stale");
|
|
807
895
|
}
|
|
896
|
+
if (!Number.isSafeInteger(repetitions) || repetitions < 1) {
|
|
897
|
+
return yield* transitionError(state.stage, "eval repetitions N must be at least 1");
|
|
898
|
+
}
|
|
808
899
|
if (scope === "full") {
|
|
809
900
|
const shortSuite = proposal.suites.find((suite) => suite.cases.length < 20);
|
|
810
901
|
if (shortSuite !== undefined ||
|
|
@@ -817,16 +908,22 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
817
908
|
}
|
|
818
909
|
const selectedCaseIds = proposal.suites.map((suite) => ({
|
|
819
910
|
dimensionId: suite.dimensionId,
|
|
820
|
-
caseIds: suite.cases
|
|
911
|
+
caseIds: Array.from({ length: repetitions }, (_, repetition) => suite.cases
|
|
821
912
|
.slice(0, scope === "pilot" ? 5 : undefined)
|
|
822
|
-
.map((testCase) =>
|
|
913
|
+
.map((testCase) => repetitions === 1
|
|
914
|
+
? testCase.id
|
|
915
|
+
: `${testCase.id}#${String(repetition + 1)}`)).flat()
|
|
823
916
|
}));
|
|
824
|
-
const selectedDecompositionCaseIds = proposal.decompositionBenchmark.cases
|
|
917
|
+
const selectedDecompositionCaseIds = Array.from({ length: repetitions }, (_, repetition) => proposal.decompositionBenchmark.cases
|
|
825
918
|
.slice(0, scope === "pilot" ? 5 : undefined)
|
|
826
|
-
.map((testCase) =>
|
|
827
|
-
|
|
919
|
+
.map((testCase) => repetitions === 1
|
|
920
|
+
? testCase.id
|
|
921
|
+
: `${testCase.id}#${String(repetition + 1)}`)).flat();
|
|
922
|
+
const selectedCompositionCaseIds = Array.from({ length: repetitions }, (_, repetition) => proposal.compositionSuite.cases
|
|
828
923
|
.slice(0, scope === "pilot" ? 5 : undefined)
|
|
829
|
-
.map((testCase) =>
|
|
924
|
+
.map((testCase) => repetitions === 1
|
|
925
|
+
? testCase.id
|
|
926
|
+
: `${testCase.id}#${String(repetition + 1)}`)).flat();
|
|
830
927
|
const expected = scopedExpectedCalls({
|
|
831
928
|
candidateModels: proposal.candidateModels,
|
|
832
929
|
selectedCaseIds,
|
|
@@ -840,6 +937,7 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
840
937
|
projectRevision: state.revision,
|
|
841
938
|
createdAt: yield* isoNow,
|
|
842
939
|
scope,
|
|
940
|
+
repetitions,
|
|
843
941
|
basisDigest: state.basisDigest,
|
|
844
942
|
evaluationDigest: state.evaluationDigest,
|
|
845
943
|
candidateModels: state.configuration.candidateModels,
|
|
@@ -855,7 +953,15 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
855
953
|
selectedDecompositionCaseIds,
|
|
856
954
|
selectedCompositionCaseIds,
|
|
857
955
|
maximumOutputTokens: Math.max(proposal.compositionSuite.maximumOutputTokens, ...proposal.suites.map((suite) => suite.maximumOutputTokens)),
|
|
858
|
-
...expected
|
|
956
|
+
...expected,
|
|
957
|
+
costEstimate: yield* estimateEvalPlanCost({
|
|
958
|
+
candidateModels: state.configuration.candidateModels,
|
|
959
|
+
candidateReasoningEfforts: state.configuration.candidateReasoningEfforts,
|
|
960
|
+
classifierModel: state.configuration.classifierModel,
|
|
961
|
+
judgeModel: state.configuration.judgeModel,
|
|
962
|
+
maximumOutputTokens: Math.max(proposal.compositionSuite.maximumOutputTokens, ...proposal.suites.map((suite) => suite.maximumOutputTokens)),
|
|
963
|
+
...expected
|
|
964
|
+
}, costService)
|
|
859
965
|
};
|
|
860
966
|
yield* artifacts.materializePlanSuites(root, plan, proposal);
|
|
861
967
|
yield* artifacts.savePlan(root, plan);
|
|
@@ -877,6 +983,9 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
877
983
|
plan.evaluationDigest !== state.evaluationDigest ||
|
|
878
984
|
!sameStrings(plan.candidateModels, state.configuration.candidateModels) ||
|
|
879
985
|
!sameReasoningEfforts(plan.candidateReasoningEfforts, state.configuration.candidateReasoningEfforts) ||
|
|
986
|
+
(plan.costEstimate !== undefined &&
|
|
987
|
+
JSON.stringify(plan.costEstimate) !==
|
|
988
|
+
JSON.stringify(yield* estimateEvalPlanCost(plan, costService))) ||
|
|
880
989
|
plan.classifierModel !== state.configuration.classifierModel ||
|
|
881
990
|
plan.authorModel !== state.configuration.authorModel ||
|
|
882
991
|
plan.judgeModel !== state.configuration.judgeModel) {
|
|
@@ -888,6 +997,15 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
888
997
|
proposal.basisDigest !== plan.basisDigest) {
|
|
889
998
|
return yield* transitionError(state.stage, "the approved evaluation proposal for the execution plan is missing or stale");
|
|
890
999
|
}
|
|
1000
|
+
const approval = yield* artifacts.loadEvaluationsApproval(root);
|
|
1001
|
+
const structureReport = yield* evaluationStructureFor(root, state, proposal);
|
|
1002
|
+
if (approval?.kind !== "evaluations" ||
|
|
1003
|
+
approval.digest !== proposal.evaluationDigest ||
|
|
1004
|
+
approval.structurePolicyVersion !== EVAL_STRUCTURE_POLICY_VERSION ||
|
|
1005
|
+
approval.structureReportDigest !==
|
|
1006
|
+
evaluationStructureReportDigest(structureReport)) {
|
|
1007
|
+
return yield* transitionError(state.stage, "the evaluation approval is stale under the current structure policy");
|
|
1008
|
+
}
|
|
891
1009
|
yield* artifacts.materializePlanSuites(root, plan, proposal, "rematerialize");
|
|
892
1010
|
const now = yield* isoNow;
|
|
893
1011
|
const runId = crypto.randomUUID();
|
|
@@ -923,7 +1041,7 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
923
1041
|
if ((report.target.kind === "configured"
|
|
924
1042
|
? !report.cleanup.sessionOpened || !report.cleanup.sessionClosed
|
|
925
1043
|
: report.cleanup.sessionOpened || report.cleanup.sessionClosed) ||
|
|
926
|
-
report.activation.basisDigest !== state.basisDigest) {
|
|
1044
|
+
(report.status === "passed" && report.activation.basisDigest !== state.basisDigest)) {
|
|
927
1045
|
return yield* transitionError(state.stage, "a run cannot qualify before session cleanup and activation validation complete");
|
|
928
1046
|
}
|
|
929
1047
|
const plan = yield* artifacts.loadPlan(root, state.planId);
|
|
@@ -940,10 +1058,7 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
940
1058
|
(plan.scope === "pilot" && report.status !== "completed")) {
|
|
941
1059
|
return yield* transitionError(state.stage, "only full plans may qualify routing activation; pilot plans are completed diagnostics");
|
|
942
1060
|
}
|
|
943
|
-
yield* Effect.
|
|
944
|
-
try: () => validateQualifiedReport(state, plan, proposal, report),
|
|
945
|
-
catch: (cause) => transitionError(state.stage, cause instanceof Error ? cause.message : "qualification report is invalid")
|
|
946
|
-
});
|
|
1061
|
+
yield* validateQualifiedReport(state, plan, proposal, report, costService).pipe(Effect.catchDefect((cause) => Effect.fail(transitionError(state.stage, cause instanceof Error ? cause.message : "qualification report is invalid"))));
|
|
947
1062
|
const reportPath = yield* artifacts.saveRunReport(root, report);
|
|
948
1063
|
const common = {
|
|
949
1064
|
version: state.version,
|
|
@@ -982,6 +1097,10 @@ export const makeEvalProjectWorkflow = Effect.gen(function* () {
|
|
|
982
1097
|
report.evaluationDigest !== state.evaluationDigest) {
|
|
983
1098
|
return yield* transitionError(state.stage, "failure report does not match the active run");
|
|
984
1099
|
}
|
|
1100
|
+
yield* Effect.try({
|
|
1101
|
+
try: () => assertEvalRunCanFail(report.events ?? []),
|
|
1102
|
+
catch: (cause) => transitionError(state.stage, cause instanceof Error ? cause.message : "failure report has no terminal event")
|
|
1103
|
+
});
|
|
985
1104
|
yield* artifacts.saveRunReport(root, report);
|
|
986
1105
|
const next = {
|
|
987
1106
|
version: state.version,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export declare const RepositoryAdversaryMutationOperatorV1: Schema.Literals<readonly ["condition-negation", "boundary-operator", "partial-output-drop", "cross-file-omission"]>;
|
|
3
|
+
export type RepositoryAdversaryMutationOperatorV1 = typeof RepositoryAdversaryMutationOperatorV1.Type;
|
|
4
|
+
export declare const RepositoryAdversaryValidationObservationV1: Schema.Struct<{
|
|
5
|
+
readonly repetition: Schema.Finite;
|
|
6
|
+
readonly outcome: Schema.Literals<readonly ["pass", "fail"]>;
|
|
7
|
+
readonly detail: Schema.String;
|
|
8
|
+
}>;
|
|
9
|
+
export type RepositoryAdversaryValidationObservationV1 = typeof RepositoryAdversaryValidationObservationV1.Type;
|
|
10
|
+
export declare const RepositoryAdversaryCandidateV1: Schema.Struct<{
|
|
11
|
+
readonly version: Schema.Literal<1>;
|
|
12
|
+
readonly id: Schema.String;
|
|
13
|
+
readonly solutionId: Schema.String;
|
|
14
|
+
readonly family: Schema.String;
|
|
15
|
+
readonly operator: Schema.Literals<readonly ["condition-negation", "boundary-operator", "partial-output-drop", "cross-file-omission"]>;
|
|
16
|
+
readonly sourcePath: Schema.String;
|
|
17
|
+
readonly relatedPaths: Schema.$Array<Schema.String>;
|
|
18
|
+
readonly sourceCommit: Schema.String;
|
|
19
|
+
readonly originalSnippet: Schema.String;
|
|
20
|
+
readonly mutatedSnippet: Schema.String;
|
|
21
|
+
readonly validationRecipeId: Schema.String;
|
|
22
|
+
readonly compilationStatus: Schema.Literals<readonly ["passed", "failed"]>;
|
|
23
|
+
readonly validationObservations: Schema.$Array<Schema.Struct<{
|
|
24
|
+
readonly repetition: Schema.Finite;
|
|
25
|
+
readonly outcome: Schema.Literals<readonly ["pass", "fail"]>;
|
|
26
|
+
readonly detail: Schema.String;
|
|
27
|
+
}>>;
|
|
28
|
+
readonly rejectionReasons: Schema.$Array<Schema.String>;
|
|
29
|
+
}>;
|
|
30
|
+
export type RepositoryAdversaryCandidateV1 = typeof RepositoryAdversaryCandidateV1.Type;
|
|
31
|
+
export declare const RepositoryAdversaryGenerationReportV1: Schema.Struct<{
|
|
32
|
+
readonly version: Schema.Literal<1>;
|
|
33
|
+
readonly seedId: Schema.String;
|
|
34
|
+
readonly generationCoverage: Schema.Struct<{
|
|
35
|
+
readonly implementationPathCount: Schema.Finite;
|
|
36
|
+
readonly changedPathCount: Schema.Finite;
|
|
37
|
+
readonly generatedCrossFileCandidateCount: Schema.Finite;
|
|
38
|
+
readonly omittedCrossFileCandidateCount: Schema.Finite;
|
|
39
|
+
}>;
|
|
40
|
+
readonly candidates: Schema.$Array<Schema.Struct<{
|
|
41
|
+
readonly version: Schema.Literal<1>;
|
|
42
|
+
readonly id: Schema.String;
|
|
43
|
+
readonly solutionId: Schema.String;
|
|
44
|
+
readonly family: Schema.String;
|
|
45
|
+
readonly operator: Schema.Literals<readonly ["condition-negation", "boundary-operator", "partial-output-drop", "cross-file-omission"]>;
|
|
46
|
+
readonly sourcePath: Schema.String;
|
|
47
|
+
readonly relatedPaths: Schema.$Array<Schema.String>;
|
|
48
|
+
readonly sourceCommit: Schema.String;
|
|
49
|
+
readonly originalSnippet: Schema.String;
|
|
50
|
+
readonly mutatedSnippet: Schema.String;
|
|
51
|
+
readonly validationRecipeId: Schema.String;
|
|
52
|
+
readonly compilationStatus: Schema.Literals<readonly ["passed", "failed"]>;
|
|
53
|
+
readonly validationObservations: Schema.$Array<Schema.Struct<{
|
|
54
|
+
readonly repetition: Schema.Finite;
|
|
55
|
+
readonly outcome: Schema.Literals<readonly ["pass", "fail"]>;
|
|
56
|
+
readonly detail: Schema.String;
|
|
57
|
+
}>>;
|
|
58
|
+
readonly rejectionReasons: Schema.$Array<Schema.String>;
|
|
59
|
+
}>>;
|
|
60
|
+
readonly admittedCandidateIds: Schema.$Array<Schema.String>;
|
|
61
|
+
readonly rejectedCandidateIds: Schema.$Array<Schema.String>;
|
|
62
|
+
}>;
|
|
63
|
+
export type RepositoryAdversaryGenerationReportV1 = typeof RepositoryAdversaryGenerationReportV1.Type;
|
|
64
|
+
export declare function assertRepositoryAdversaryGenerationReportV1(value: unknown): asserts value is RepositoryAdversaryGenerationReportV1;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export const RepositoryAdversaryMutationOperatorV1 = Schema.Literals([
|
|
3
|
+
"condition-negation",
|
|
4
|
+
"boundary-operator",
|
|
5
|
+
"partial-output-drop",
|
|
6
|
+
"cross-file-omission"
|
|
7
|
+
]);
|
|
8
|
+
export const RepositoryAdversaryValidationObservationV1 = Schema.Struct({
|
|
9
|
+
repetition: Schema.Finite,
|
|
10
|
+
outcome: Schema.Literals(["pass", "fail"]),
|
|
11
|
+
detail: Schema.String
|
|
12
|
+
});
|
|
13
|
+
export const RepositoryAdversaryCandidateV1 = Schema.Struct({
|
|
14
|
+
version: Schema.Literal(1),
|
|
15
|
+
id: Schema.String,
|
|
16
|
+
solutionId: Schema.String,
|
|
17
|
+
family: Schema.String,
|
|
18
|
+
operator: RepositoryAdversaryMutationOperatorV1,
|
|
19
|
+
sourcePath: Schema.String,
|
|
20
|
+
relatedPaths: Schema.Array(Schema.String),
|
|
21
|
+
sourceCommit: Schema.String,
|
|
22
|
+
originalSnippet: Schema.String,
|
|
23
|
+
mutatedSnippet: Schema.String,
|
|
24
|
+
validationRecipeId: Schema.String,
|
|
25
|
+
compilationStatus: Schema.Literals(["passed", "failed"]),
|
|
26
|
+
validationObservations: Schema.Array(RepositoryAdversaryValidationObservationV1),
|
|
27
|
+
rejectionReasons: Schema.Array(Schema.String)
|
|
28
|
+
});
|
|
29
|
+
export const RepositoryAdversaryGenerationReportV1 = Schema.Struct({
|
|
30
|
+
version: Schema.Literal(1),
|
|
31
|
+
seedId: Schema.String,
|
|
32
|
+
generationCoverage: Schema.Struct({
|
|
33
|
+
implementationPathCount: Schema.Finite,
|
|
34
|
+
changedPathCount: Schema.Finite,
|
|
35
|
+
generatedCrossFileCandidateCount: Schema.Finite,
|
|
36
|
+
omittedCrossFileCandidateCount: Schema.Finite
|
|
37
|
+
}),
|
|
38
|
+
candidates: Schema.Array(RepositoryAdversaryCandidateV1),
|
|
39
|
+
admittedCandidateIds: Schema.Array(Schema.String),
|
|
40
|
+
rejectedCandidateIds: Schema.Array(Schema.String)
|
|
41
|
+
});
|
|
42
|
+
export function assertRepositoryAdversaryGenerationReportV1(value) {
|
|
43
|
+
const report = Schema.decodeUnknownSync(RepositoryAdversaryGenerationReportV1)(value);
|
|
44
|
+
const candidateIds = new Set(report.candidates.map((candidate) => candidate.id));
|
|
45
|
+
const solutionIds = new Set(report.candidates.map((candidate) => candidate.solutionId));
|
|
46
|
+
const crossFileCandidateCount = report.candidates.filter((candidate) => candidate.operator === "cross-file-omission").length;
|
|
47
|
+
if (candidateIds.size !== report.candidates.length ||
|
|
48
|
+
solutionIds.size !== report.candidates.length) {
|
|
49
|
+
throw new Error("repository adversary candidate ids must be unique");
|
|
50
|
+
}
|
|
51
|
+
if (!Number.isInteger(report.generationCoverage.implementationPathCount) ||
|
|
52
|
+
!Number.isInteger(report.generationCoverage.changedPathCount) ||
|
|
53
|
+
!Number.isInteger(report.generationCoverage.generatedCrossFileCandidateCount) ||
|
|
54
|
+
!Number.isInteger(report.generationCoverage.omittedCrossFileCandidateCount) ||
|
|
55
|
+
report.generationCoverage.implementationPathCount < 0 ||
|
|
56
|
+
report.generationCoverage.changedPathCount < 0 ||
|
|
57
|
+
report.generationCoverage.generatedCrossFileCandidateCount < 0 ||
|
|
58
|
+
report.generationCoverage.omittedCrossFileCandidateCount < 0 ||
|
|
59
|
+
report.generationCoverage.changedPathCount >
|
|
60
|
+
report.generationCoverage.implementationPathCount ||
|
|
61
|
+
report.generationCoverage.generatedCrossFileCandidateCount !==
|
|
62
|
+
crossFileCandidateCount ||
|
|
63
|
+
(report.generationCoverage.changedPathCount >= 2
|
|
64
|
+
? report.generationCoverage.generatedCrossFileCandidateCount +
|
|
65
|
+
report.generationCoverage.omittedCrossFileCandidateCount !==
|
|
66
|
+
report.generationCoverage.changedPathCount
|
|
67
|
+
: report.generationCoverage.generatedCrossFileCandidateCount !== 0 ||
|
|
68
|
+
report.generationCoverage.omittedCrossFileCandidateCount !== 0)) {
|
|
69
|
+
throw new Error("repository adversary generation coverage must account for every eligible cross-file path");
|
|
70
|
+
}
|
|
71
|
+
const classified = new Set([
|
|
72
|
+
...report.admittedCandidateIds,
|
|
73
|
+
...report.rejectedCandidateIds
|
|
74
|
+
]);
|
|
75
|
+
if (classified.size !== report.candidates.length ||
|
|
76
|
+
[...classified].some((id) => !candidateIds.has(id))) {
|
|
77
|
+
throw new Error("every repository adversary candidate must be classified exactly once");
|
|
78
|
+
}
|
|
79
|
+
for (const candidate of report.candidates) {
|
|
80
|
+
if (new Set(candidate.relatedPaths).size !== candidate.relatedPaths.length ||
|
|
81
|
+
candidate.relatedPaths.includes(candidate.sourcePath) ||
|
|
82
|
+
(candidate.operator === "cross-file-omission"
|
|
83
|
+
? candidate.relatedPaths.length === 0
|
|
84
|
+
: candidate.relatedPaths.length !== 0)) {
|
|
85
|
+
throw new Error("repository adversary related paths must identify only the coupled files for cross-file mutations");
|
|
86
|
+
}
|
|
87
|
+
if (candidate.validationObservations.length < 2 ||
|
|
88
|
+
candidate.validationObservations.some((observation) => !Number.isInteger(observation.repetition) ||
|
|
89
|
+
observation.repetition < 1)) {
|
|
90
|
+
throw new Error("repository adversary candidates require repeated validation observations");
|
|
91
|
+
}
|
|
92
|
+
const passed = candidate.validationObservations.every((observation) => observation.outcome === "pass");
|
|
93
|
+
if ((candidate.compilationStatus === "passed") !== passed ||
|
|
94
|
+
(candidate.compilationStatus === "passed") !==
|
|
95
|
+
report.admittedCandidateIds.includes(candidate.id) ||
|
|
96
|
+
(candidate.compilationStatus === "failed") !==
|
|
97
|
+
report.rejectedCandidateIds.includes(candidate.id)) {
|
|
98
|
+
throw new Error("repository adversary classification must match compilation observations");
|
|
99
|
+
}
|
|
100
|
+
if (candidate.compilationStatus === "passed" &&
|
|
101
|
+
candidate.rejectionReasons.length > 0) {
|
|
102
|
+
throw new Error("admitted repository adversaries cannot have rejection reasons");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|