@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
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { mkdtemp, readFile, realpath, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { test } from "node:test";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
import { Effect } from "effect";
|
|
9
|
+
import { RepositoryCommandExecutionPort } from "../adapters/repository-command-runner.js";
|
|
10
|
+
import { makeCaseCheckpointStoreV1 } from "../case-checkpoint-store.js";
|
|
11
|
+
import { RepositoryFoundryError } from "../errors.js";
|
|
12
|
+
import { EvalAuthoringTransport } from "../project-authoring.js";
|
|
13
|
+
import { repositoryFoundryModelPlanV1 } from "../repository-language-model-protocol.js";
|
|
14
|
+
import { repositoryFixturePreflightFeedbackV1, validateRepositoryFixturesV1 } from "../services/fixture-validation/service.js";
|
|
15
|
+
import { RepositoryFoundryProgressLive } from "../services/foundry-progress/service.js";
|
|
16
|
+
import { RepositoryFoundryLanguageModelLive } from "../services/language-model/service.js";
|
|
17
|
+
const execute = promisify(execFile);
|
|
18
|
+
const modelPlan = repositoryFoundryModelPlanV1({ primaryModel: "openai/gpt-6-astra" });
|
|
19
|
+
const goodCode = `import assert from "node:assert/strict";
|
|
20
|
+
import test from "node:test";
|
|
21
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
22
|
+
import { value } from "./subject.mjs";
|
|
23
|
+
test("frozen public behavior", () => {
|
|
24
|
+
assert.equal(existsSync("candidate-ran.txt"), false);
|
|
25
|
+
writeFileSync("candidate-ran.txt", "fresh candidate only");
|
|
26
|
+
assert.equal(readFileSync("control.json", "utf8"), "reference");
|
|
27
|
+
assert.equal(value, 1);
|
|
28
|
+
});
|
|
29
|
+
`;
|
|
30
|
+
const brokenCode = `${goodCode}\nconst syntaxError = ;\n`;
|
|
31
|
+
async function fixture(t) {
|
|
32
|
+
const root = await realpath(await mkdtemp(join(tmpdir(), "fixture-validation-test-")));
|
|
33
|
+
t.after(() => rm(root, { recursive: true, force: true }));
|
|
34
|
+
const git = (...args) => execute("git", ["-C", root, ...args]);
|
|
35
|
+
await git("init", "-q");
|
|
36
|
+
await writeFile(join(root, "case.test.mjs"), goodCode);
|
|
37
|
+
const commit = async (value, control) => {
|
|
38
|
+
await writeFile(join(root, "subject.mjs"), `export const value = ${value};\n`);
|
|
39
|
+
await writeFile(join(root, "control.json"), control);
|
|
40
|
+
await git("add", ".");
|
|
41
|
+
await git("-c", "core.hooksPath=/dev/null", "-c", "commit.gpgSign=false", "-c", "user.name=Fixture Validation", "-c", "user.email=fixture@example.test", "commit", "-qm", "fixture");
|
|
42
|
+
return (await git("rev-parse", "HEAD")).stdout.trim();
|
|
43
|
+
};
|
|
44
|
+
const initialCommit = await commit(0, "initial");
|
|
45
|
+
const referenceCommit = await commit(1, "reference");
|
|
46
|
+
// Ambient dirty source must not influence the pinned reference replay.
|
|
47
|
+
await writeFile(join(root, "control.json"), "untrusted working tree");
|
|
48
|
+
const grade = {
|
|
49
|
+
id: "grade",
|
|
50
|
+
kind: "test",
|
|
51
|
+
cwd: ".",
|
|
52
|
+
executable: "node",
|
|
53
|
+
args: ["--test", "case.test.mjs"],
|
|
54
|
+
timeoutMs: 5000
|
|
55
|
+
};
|
|
56
|
+
const observation = (id, subjectId, outcome) => ({
|
|
57
|
+
id,
|
|
58
|
+
kind: "test-command",
|
|
59
|
+
subjectId,
|
|
60
|
+
outcome,
|
|
61
|
+
detail: "Synthetic qualified seed evidence."
|
|
62
|
+
});
|
|
63
|
+
const seed = {
|
|
64
|
+
version: 1,
|
|
65
|
+
id: "synthetic-seed",
|
|
66
|
+
status: "qualified",
|
|
67
|
+
source: { kind: "historical-fix", changeEpisodeId: "synthetic-change" },
|
|
68
|
+
summary: "Synthetic public behavior.",
|
|
69
|
+
capabilityEvidence: [{ kind: "test", id: "case", path: "case.test.mjs" }],
|
|
70
|
+
initialState: { commit: initialCommit },
|
|
71
|
+
referenceCommit,
|
|
72
|
+
targetBehavior: [{ id: "behavior", description: "Return one.", critical: true, evidence: [] }],
|
|
73
|
+
baselineObservations: [observation("baseline", "baseline", "pass")],
|
|
74
|
+
preChangeObservations: [observation("pre", "grade", "fail")],
|
|
75
|
+
postChangeObservations: [observation("post", "grade", "pass")],
|
|
76
|
+
candidateTestIds: ["case"],
|
|
77
|
+
environment: {
|
|
78
|
+
protectedControlPaths: ["control.json"],
|
|
79
|
+
trustedPreparationRecipes: [],
|
|
80
|
+
candidateValidationRecipes: [
|
|
81
|
+
{
|
|
82
|
+
id: "syntax",
|
|
83
|
+
kind: "check",
|
|
84
|
+
cwd: ".",
|
|
85
|
+
executable: "node",
|
|
86
|
+
args: ["--check", "case.test.mjs"],
|
|
87
|
+
timeoutMs: 5000
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
baselineGradeRecipes: [{ ...grade, id: "baseline" }],
|
|
91
|
+
gradeRecipes: [grade]
|
|
92
|
+
},
|
|
93
|
+
confidence: "high",
|
|
94
|
+
risks: [],
|
|
95
|
+
rejectionReasons: []
|
|
96
|
+
};
|
|
97
|
+
const suite = {
|
|
98
|
+
version: 1,
|
|
99
|
+
caseId: "synthetic-case",
|
|
100
|
+
fixtures: ["good", "broken"].map((id) => ({
|
|
101
|
+
id,
|
|
102
|
+
description: `Frozen ${id} fixture.`,
|
|
103
|
+
expectedBehavior: "Return one.",
|
|
104
|
+
source: "generated",
|
|
105
|
+
testPath: "case.test.mjs",
|
|
106
|
+
kind: "metamorphic",
|
|
107
|
+
expectationMode: "preserved"
|
|
108
|
+
})),
|
|
109
|
+
overlays: [
|
|
110
|
+
{ path: "case.test.mjs", content: goodCode, fixtureIds: ["good"] },
|
|
111
|
+
{ path: "case.test.mjs", content: brokenCode, fixtureIds: ["broken"] }
|
|
112
|
+
]
|
|
113
|
+
};
|
|
114
|
+
return { root, seed, suite };
|
|
115
|
+
}
|
|
116
|
+
function runner(data, options = {}) {
|
|
117
|
+
const calls = [];
|
|
118
|
+
const artifacts = [];
|
|
119
|
+
const events = [];
|
|
120
|
+
const repairAccounting = { attempts: 0, validatedCalls: 0 };
|
|
121
|
+
const effect = validateRepositoryFixturesV1({
|
|
122
|
+
repositoryRoot: data.root,
|
|
123
|
+
operationId: "fixture-test",
|
|
124
|
+
seed: options.seed ?? data.seed,
|
|
125
|
+
suite: options.suite ?? data.suite,
|
|
126
|
+
allowedTestPaths: new Set(["case.test.mjs"]),
|
|
127
|
+
context: {
|
|
128
|
+
visible: { title: "Frozen visible task" },
|
|
129
|
+
pinnedManifest: { apiVersion: "synthetic" }
|
|
130
|
+
},
|
|
131
|
+
modelPlan,
|
|
132
|
+
maximumRepairAttempts: options.maximumRepairAttempts ?? 1,
|
|
133
|
+
checkpointStore: options.checkpointStore,
|
|
134
|
+
onRepairAttempt: () => Effect.sync(() => {
|
|
135
|
+
repairAccounting.attempts += 1;
|
|
136
|
+
}),
|
|
137
|
+
onRepairCall: () => Effect.sync(() => {
|
|
138
|
+
repairAccounting.validatedCalls += 1;
|
|
139
|
+
})
|
|
140
|
+
}).pipe(Effect.provide(RepositoryFoundryLanguageModelLive), Effect.provideService(EvalAuthoringTransport, {
|
|
141
|
+
complete: (request) => Effect.sync(() => {
|
|
142
|
+
calls.push(request);
|
|
143
|
+
return JSON.stringify(options.reply?.(request) ?? {
|
|
144
|
+
overlays: [{ path: "case.test.mjs", content: goodCode, fixtureIds: ["broken"] }]
|
|
145
|
+
});
|
|
146
|
+
})
|
|
147
|
+
}), Effect.provide(RepositoryFoundryProgressLive((event) => Effect.sync(() => {
|
|
148
|
+
events.push(event);
|
|
149
|
+
}), (artifact) => Effect.sync(() => {
|
|
150
|
+
artifacts.push(artifact);
|
|
151
|
+
}))));
|
|
152
|
+
return { effect, calls, artifacts, events, repairAccounting };
|
|
153
|
+
}
|
|
154
|
+
test("fixture preflight repairs only failed code, replays the pinned reference, and retains private evidence without counting host model calls", async (t) => {
|
|
155
|
+
const data = await fixture(t);
|
|
156
|
+
const original = JSON.stringify(data.suite);
|
|
157
|
+
const run = runner(data);
|
|
158
|
+
const result = await Effect.runPromise(run.effect);
|
|
159
|
+
assert.equal(result.modelCalls.length, 1);
|
|
160
|
+
assert.equal(run.calls.length, 1);
|
|
161
|
+
assert.equal(run.calls[0].foundryRole, "hill-climb-planner");
|
|
162
|
+
assert.equal(run.calls[0].operationId, "fixture-test:fixture-repair:1");
|
|
163
|
+
const packet = JSON.parse(run.calls[0].input);
|
|
164
|
+
assert.deepEqual(packet.failedFixtures.map((entry) => entry.fixture.id), ["broken"]);
|
|
165
|
+
assert.equal(packet.failedFixtures[0].evidence.outcome, "unknown");
|
|
166
|
+
assert.equal(packet.failedFixtures[0].diagnostics[0].stage, "candidate-validation");
|
|
167
|
+
assert.match(packet.failedFixtures[0].diagnostics[0].stderr, /SyntaxError/u);
|
|
168
|
+
assert.equal(packet.context.pinnedManifest.apiVersion, "synthetic");
|
|
169
|
+
assert.deepEqual(result.suite.fixtures, data.suite.fixtures);
|
|
170
|
+
assert.deepEqual(result.suite.overlays[0], data.suite.overlays[0]);
|
|
171
|
+
assert.equal(result.suite.overlays[1].content, goodCode);
|
|
172
|
+
assert.equal(JSON.stringify(data.suite), original);
|
|
173
|
+
const host = run.artifacts.filter((artifact) => artifact.role === "fixture-validator");
|
|
174
|
+
assert.equal(host.length, 3, "the already-passing overlay is not replayed or rewritten by repair");
|
|
175
|
+
for (const artifact of host) {
|
|
176
|
+
const request = artifact.request.input;
|
|
177
|
+
assert.equal(request.replayInput.commit, data.seed.referenceCommit);
|
|
178
|
+
assert.equal(request.replayInput.contentOverlays.length, 1);
|
|
179
|
+
assert.equal(request.replayInput.repetitions, 1);
|
|
180
|
+
assert.equal(artifact.model, "local-replay");
|
|
181
|
+
const value = artifact.value;
|
|
182
|
+
assert.equal(value.admissionEvidence, false);
|
|
183
|
+
assert.ok(value.results.length > 0);
|
|
184
|
+
}
|
|
185
|
+
assert.equal(run.events.filter((event) => event.kind === "model-call" && event.phase === "complete").length, 1);
|
|
186
|
+
assert.ok(run.events
|
|
187
|
+
.filter((event) => event.role === "fixture-validator")
|
|
188
|
+
.every((event) => event.kind === "heartbeat"));
|
|
189
|
+
assert.ok(run.events.every((event) => !JSON.stringify(event).includes("SyntaxError")));
|
|
190
|
+
assert.equal(await readFile(join(data.root, "control.json"), "utf8"), "untrusted working tree");
|
|
191
|
+
});
|
|
192
|
+
test("passing reference fixtures require no repair or model calls", async (t) => {
|
|
193
|
+
const data = await fixture(t);
|
|
194
|
+
const suite = {
|
|
195
|
+
...data.suite,
|
|
196
|
+
overlays: data.suite.overlays.map((overlay) => ({ ...overlay, content: goodCode }))
|
|
197
|
+
};
|
|
198
|
+
const run = runner(data, { suite, maximumRepairAttempts: 0 });
|
|
199
|
+
const result = await Effect.runPromise(run.effect);
|
|
200
|
+
assert.deepEqual(result.suite, suite);
|
|
201
|
+
assert.deepEqual(result.modelCalls, []);
|
|
202
|
+
assert.equal(run.calls.length, 0);
|
|
203
|
+
assert.equal(run.events.filter((event) => event.kind === "model-call").length, 0);
|
|
204
|
+
});
|
|
205
|
+
test("reference preflight does not overlap independent fixture command trees", async (t) => {
|
|
206
|
+
const data = await fixture(t);
|
|
207
|
+
const suite = {
|
|
208
|
+
...data.suite,
|
|
209
|
+
overlays: data.suite.overlays.map((overlay) => ({ ...overlay, content: goodCode }))
|
|
210
|
+
};
|
|
211
|
+
let active = 0;
|
|
212
|
+
let peak = 0;
|
|
213
|
+
let executed = 0;
|
|
214
|
+
const run = runner(data, { suite, maximumRepairAttempts: 0 });
|
|
215
|
+
const result = await Effect.runPromise(run.effect.pipe(Effect.provideService(RepositoryCommandExecutionPort, {
|
|
216
|
+
run: (input) => Effect.tryPromise({
|
|
217
|
+
try: async () => {
|
|
218
|
+
active += 1;
|
|
219
|
+
peak = Math.max(peak, active);
|
|
220
|
+
executed += 1;
|
|
221
|
+
try {
|
|
222
|
+
// Allow a sibling replay to reach its first command if the
|
|
223
|
+
// preflight accidentally becomes parallel again.
|
|
224
|
+
await new Promise((resolve) => setTimeout(resolve, 1_000));
|
|
225
|
+
const { stdout, stderr } = await execute(input.executable, [...input.args], { cwd: input.cwd, env: input.environment, timeout: input.timeoutMs });
|
|
226
|
+
return { exitCode: 0, stdout, stderr, timedOut: false };
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
active -= 1;
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
catch: (cause) => new RepositoryFoundryError({
|
|
233
|
+
operation: "run-command",
|
|
234
|
+
detail: "reference preflight command failed",
|
|
235
|
+
cause
|
|
236
|
+
})
|
|
237
|
+
})
|
|
238
|
+
})));
|
|
239
|
+
assert.equal(result.modelCalls.length, 0);
|
|
240
|
+
assert.equal(executed, 4, "both fixtures must run validation and grading");
|
|
241
|
+
assert.equal(peak, 1, "one fixture's build and grade must finish before the next starts");
|
|
242
|
+
});
|
|
243
|
+
test("failed reference preflight returns concrete compiler evidence to the same author without copying overlay bodies", async (t) => {
|
|
244
|
+
const data = await fixture(t);
|
|
245
|
+
const run = runner(data, { maximumRepairAttempts: 0 });
|
|
246
|
+
const result = await Effect.runPromise(run.effect.pipe(Effect.result));
|
|
247
|
+
assert.equal(result._tag, "Failure");
|
|
248
|
+
if (result._tag !== "Failure")
|
|
249
|
+
return;
|
|
250
|
+
const feedback = repositoryFixturePreflightFeedbackV1(result.failure);
|
|
251
|
+
assert.match(feedback, /SyntaxError/);
|
|
252
|
+
assert.match(feedback, /candidate-validation/);
|
|
253
|
+
assert.match(feedback, /"gradeExecuted":false/);
|
|
254
|
+
assert.match(feedback, /case\.test\.mjs/);
|
|
255
|
+
assert.doesNotMatch(feedback, /\[object Object\]/);
|
|
256
|
+
assert.ok(!feedback.includes(goodCode));
|
|
257
|
+
assert.ok(feedback.length < 20_000);
|
|
258
|
+
});
|
|
259
|
+
test("fixture preflight retains completed overlays and invalidates only changed executable inputs", async (t) => {
|
|
260
|
+
const data = await fixture(t);
|
|
261
|
+
const checkpointStore = makeCaseCheckpointStoreV1({ caseDirectory: join(data.root, "preflight-work") });
|
|
262
|
+
const suite = {
|
|
263
|
+
...data.suite,
|
|
264
|
+
overlays: data.suite.overlays.map((overlay) => ({ ...overlay, content: goodCode }))
|
|
265
|
+
};
|
|
266
|
+
await Effect.runPromise(runner(data, { suite, checkpointStore, maximumRepairAttempts: 0 }).effect);
|
|
267
|
+
const restored = runner(data, { suite, checkpointStore, maximumRepairAttempts: 0 });
|
|
268
|
+
await Effect.runPromise(restored.effect.pipe(Effect.provideService(RepositoryCommandExecutionPort, {
|
|
269
|
+
run: () => Effect.fail(new RepositoryFoundryError({
|
|
270
|
+
operation: "run-command", detail: "completed preflight must not execute again"
|
|
271
|
+
}))
|
|
272
|
+
})));
|
|
273
|
+
assert.ok(restored.artifacts.filter((artifact) => artifact.role === "fixture-validator")
|
|
274
|
+
.every((artifact) => artifact.value.restored));
|
|
275
|
+
const changed = runner(data, {
|
|
276
|
+
suite: { ...suite, overlays: suite.overlays.map((overlay, index) => index === 0 ? { ...overlay, content: `${goodCode}\n// distinct executable input\n` } : overlay) },
|
|
277
|
+
checkpointStore, maximumRepairAttempts: 0
|
|
278
|
+
});
|
|
279
|
+
await Effect.runPromise(changed.effect);
|
|
280
|
+
const flags = changed.artifacts.filter((artifact) => artifact.role === "fixture-validator")
|
|
281
|
+
.map((artifact) => artifact.value.restored).sort();
|
|
282
|
+
assert.deepEqual(flags, [false, true]);
|
|
283
|
+
});
|
|
284
|
+
test("failed reference preflight stops at its bounded repair allowance before downstream generation", async (t) => {
|
|
285
|
+
const data = await fixture(t);
|
|
286
|
+
for (const maximumRepairAttempts of [0, 2]) {
|
|
287
|
+
const run = runner(data, {
|
|
288
|
+
maximumRepairAttempts,
|
|
289
|
+
reply: () => ({ overlays: [data.suite.overlays[1]] })
|
|
290
|
+
});
|
|
291
|
+
await assert.rejects(Effect.runPromise(run.effect), /fixture preflight failed after/u);
|
|
292
|
+
assert.equal(run.calls.length, maximumRepairAttempts);
|
|
293
|
+
assert.ok(run.calls.every((call) => call.foundryRole === "hill-climb-planner"));
|
|
294
|
+
assert.equal(run.artifacts.filter((artifact) => artifact.role === "fixture-validator").length, 2 + maximumRepairAttempts);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
test("repair cannot remove a failed fixture, alter its path or identity, or rewrite a passing overlay", async (t) => {
|
|
298
|
+
const data = await fixture(t);
|
|
299
|
+
for (const overlays of [
|
|
300
|
+
[],
|
|
301
|
+
[{ path: "other.test.mjs", content: goodCode, fixtureIds: ["broken"] }],
|
|
302
|
+
[{ path: "case.test.mjs", content: goodCode, fixtureIds: ["renamed"] }],
|
|
303
|
+
[{ path: "case.test.mjs", content: goodCode, fixtureIds: ["good"] }],
|
|
304
|
+
[{ path: "case.test.mjs", content: goodCode, fixtureIds: ["broken", "good"] }]
|
|
305
|
+
]) {
|
|
306
|
+
const run = runner(data, { reply: () => ({ overlays }) });
|
|
307
|
+
await assert.rejects(Effect.runPromise(run.effect), /fixture repair changed frozen identity/u);
|
|
308
|
+
assert.equal(run.calls.length, 1);
|
|
309
|
+
assert.equal(run.artifacts.filter((artifact) => artifact.role === "fixture-validator").length, 2);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
test("invalid fixture metadata and paths fail before any replay or model request", async (t) => {
|
|
313
|
+
const data = await fixture(t);
|
|
314
|
+
for (const suite of [
|
|
315
|
+
{ ...data.suite, fixtures: [data.suite.fixtures[0], data.suite.fixtures[0]] },
|
|
316
|
+
{ ...data.suite, overlays: [] },
|
|
317
|
+
{
|
|
318
|
+
...data.suite,
|
|
319
|
+
fixtures: data.suite.fixtures.map((fixture) => ({
|
|
320
|
+
...fixture,
|
|
321
|
+
testPath: "../case.test.mjs"
|
|
322
|
+
})),
|
|
323
|
+
overlays: data.suite.overlays.map((overlay) => ({ ...overlay, path: "../case.test.mjs" }))
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
...data.suite,
|
|
327
|
+
fixtures: data.suite.fixtures.map((fixture) => ({ ...fixture, expectedBehavior: "" }))
|
|
328
|
+
}
|
|
329
|
+
]) {
|
|
330
|
+
const run = runner(data, { suite });
|
|
331
|
+
await assert.rejects(Effect.runPromise(run.effect), /fixture preflight input failed validation/u);
|
|
332
|
+
assert.equal(run.calls.length, 0);
|
|
333
|
+
assert.equal(run.artifacts.length, 0);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
test("a malformed model response still consumes its reserved fixture repair attempt", async (t) => {
|
|
337
|
+
const data = await fixture(t);
|
|
338
|
+
const run = runner(data, { reply: () => ({ unexpected: true }) });
|
|
339
|
+
await assert.rejects(Effect.runPromise(run.effect), /violated routekit_repository_fixture_overlay_repair_v1/u);
|
|
340
|
+
assert.equal(run.calls.length, 1);
|
|
341
|
+
assert.deepEqual(run.repairAccounting, { attempts: 1, validatedCalls: 0 });
|
|
342
|
+
assert.equal(run.events.filter((event) => event.phase === "complete").at(-1)?.modelCalls, 1);
|
|
343
|
+
});
|
|
344
|
+
test("runtime errors, failing setup hooks, and empty test discovery remain unknown and block preflight", async (t) => {
|
|
345
|
+
const data = await fixture(t);
|
|
346
|
+
for (const code of [
|
|
347
|
+
'import test from "node:test"; test("contract", () => { throw new TypeError("runtime"); });',
|
|
348
|
+
'import test,{beforeEach} from "node:test"; import assert from "node:assert/strict"; beforeEach(() => assert.fail("setup")); test("contract", () => {});',
|
|
349
|
+
"export const noTests = true;"
|
|
350
|
+
]) {
|
|
351
|
+
const run = runner(data, {
|
|
352
|
+
maximumRepairAttempts: 0,
|
|
353
|
+
suite: {
|
|
354
|
+
...data.suite,
|
|
355
|
+
overlays: data.suite.overlays.map((overlay) => ({ ...overlay, content: code }))
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
await assert.rejects(Effect.runPromise(run.effect), /fixture preflight failed after/u);
|
|
359
|
+
assert.equal(run.calls.length, 0);
|
|
360
|
+
assert.ok(run.artifacts.every((artifact) => artifact.value.evidence.outcome === "unknown"));
|
|
361
|
+
}
|
|
362
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { Effect, Layer } from "effect";
|
|
4
|
+
import { boundRepositoryFoundryIdleStallMsV1, formatRepositoryFoundryProgressLineV1, makeRepositoryFoundryProgress, REPOSITORY_FOUNDRY_DEFAULT_IDLE_STALL_MS, reportFoundryModelCallV1, reportFoundryStageV1, RepositoryFoundryIdleStallError, RepositoryFoundryProgress, withRepositoryFoundryIdleStall } from "../index.js";
|
|
5
|
+
test("foundry progress emits stage and model-call events", async () => {
|
|
6
|
+
const events = [];
|
|
7
|
+
const progress = await Effect.runPromise(makeRepositoryFoundryProgress((event) => Effect.sync(() => {
|
|
8
|
+
events.push(event);
|
|
9
|
+
})));
|
|
10
|
+
await Effect.runPromise(Effect.gen(function* () {
|
|
11
|
+
yield* reportFoundryStageV1("author-specification");
|
|
12
|
+
yield* reportFoundryModelCallV1({ role: "repository-analyst", phase: "start" });
|
|
13
|
+
yield* reportFoundryModelCallV1({
|
|
14
|
+
role: "repository-analyst",
|
|
15
|
+
phase: "complete",
|
|
16
|
+
callId: "call_1"
|
|
17
|
+
});
|
|
18
|
+
yield* reportFoundryStageV1("tournament");
|
|
19
|
+
const snap = yield* progress.snapshot;
|
|
20
|
+
assert.equal(snap.stage, "tournament");
|
|
21
|
+
assert.equal(snap.modelCalls, 1);
|
|
22
|
+
}).pipe(Effect.provideService(RepositoryFoundryProgress, progress)));
|
|
23
|
+
assert.equal(events.length, 4);
|
|
24
|
+
assert.equal(events[0]?.kind, "stage");
|
|
25
|
+
assert.equal(events[0]?.stage, "author-specification");
|
|
26
|
+
assert.equal(events[1]?.kind, "model-call");
|
|
27
|
+
assert.equal(events[1]?.phase, "start");
|
|
28
|
+
assert.equal(events[2]?.phase, "complete");
|
|
29
|
+
assert.equal(events[2]?.modelCalls, 1);
|
|
30
|
+
assert.match(formatRepositoryFoundryProgressLineV1(events[2]), /foundry progress kind=model-call stage=author-specification modelCalls=1 role=repository-analyst phase=complete callId=call_1/u);
|
|
31
|
+
});
|
|
32
|
+
test("idle stall fails closed before first model call when progress stays flat", async () => {
|
|
33
|
+
const progress = await Effect.runPromise(makeRepositoryFoundryProgress());
|
|
34
|
+
const startedAt = Date.now();
|
|
35
|
+
const error = await Effect.runPromise(withRepositoryFoundryIdleStall(Effect.gen(function* () {
|
|
36
|
+
yield* reportFoundryStageV1("execute-start");
|
|
37
|
+
// Silent post-turbo authoring: no further stage/modelCalls emissions.
|
|
38
|
+
yield* Effect.sleep(5_000);
|
|
39
|
+
return "should-not-reach";
|
|
40
|
+
}), {
|
|
41
|
+
idleStallMs: 80,
|
|
42
|
+
wallTimeMs: 10_000
|
|
43
|
+
}).pipe(Effect.provideService(RepositoryFoundryProgress, progress), Effect.flip));
|
|
44
|
+
assert.ok(error instanceof RepositoryFoundryIdleStallError);
|
|
45
|
+
assert.equal(error.stage, "execute-start");
|
|
46
|
+
assert.equal(error.modelCalls, 0);
|
|
47
|
+
assert.match(error.message, /stalled/u);
|
|
48
|
+
assert.match(error.message, /idleStallMs=80/u);
|
|
49
|
+
assert.ok(Date.now() - startedAt < 2_000);
|
|
50
|
+
});
|
|
51
|
+
test("idle stall fails closed after a hung model-call start with no completion", async () => {
|
|
52
|
+
const progress = await Effect.runPromise(makeRepositoryFoundryProgress());
|
|
53
|
+
const startedAt = Date.now();
|
|
54
|
+
const error = await Effect.runPromise(withRepositoryFoundryIdleStall(Effect.gen(function* () {
|
|
55
|
+
yield* reportFoundryStageV1("author-specification");
|
|
56
|
+
yield* reportFoundryModelCallV1({
|
|
57
|
+
role: "repository-analyst",
|
|
58
|
+
phase: "start"
|
|
59
|
+
});
|
|
60
|
+
// Hung provider call or stalled transport: start emitted, nothing else.
|
|
61
|
+
yield* Effect.sleep(5_000);
|
|
62
|
+
return "should-not-reach";
|
|
63
|
+
}), {
|
|
64
|
+
idleStallMs: 80,
|
|
65
|
+
wallTimeMs: 10_000
|
|
66
|
+
}).pipe(Effect.provideService(RepositoryFoundryProgress, progress), Effect.flip));
|
|
67
|
+
assert.ok(error instanceof RepositoryFoundryIdleStallError);
|
|
68
|
+
assert.equal(error.stage, "author-specification");
|
|
69
|
+
assert.equal(error.modelCalls, 0);
|
|
70
|
+
assert.match(error.message, /stalled/u);
|
|
71
|
+
assert.ok(Date.now() - startedAt < 2_000);
|
|
72
|
+
});
|
|
73
|
+
test("normal progress does not false-trigger idle stall", async () => {
|
|
74
|
+
const progress = await Effect.runPromise(makeRepositoryFoundryProgress());
|
|
75
|
+
const result = await Effect.runPromise(withRepositoryFoundryIdleStall(Effect.gen(function* () {
|
|
76
|
+
for (let index = 0; index < 5; index += 1) {
|
|
77
|
+
yield* Effect.sleep(40);
|
|
78
|
+
yield* reportFoundryModelCallV1({
|
|
79
|
+
role: "oracle-designer",
|
|
80
|
+
phase: index % 2 === 0 ? "start" : "complete"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return "ok";
|
|
84
|
+
}), {
|
|
85
|
+
idleStallMs: 120,
|
|
86
|
+
wallTimeMs: 10_000
|
|
87
|
+
}).pipe(Effect.provideService(RepositoryFoundryProgress, progress)));
|
|
88
|
+
assert.equal(result, "ok");
|
|
89
|
+
const snap = await Effect.runPromise(progress.snapshot);
|
|
90
|
+
assert.equal(snap.modelCalls, 2);
|
|
91
|
+
});
|
|
92
|
+
test("idle stall is capped by wall and defaults to twenty minutes", () => {
|
|
93
|
+
assert.equal(REPOSITORY_FOUNDRY_DEFAULT_IDLE_STALL_MS, 20 * 60_000);
|
|
94
|
+
assert.equal(boundRepositoryFoundryIdleStallMsV1(undefined, 4 * 60 * 60_000), 20 * 60_000);
|
|
95
|
+
assert.equal(boundRepositoryFoundryIdleStallMsV1(60_000, 30_000), 30_000);
|
|
96
|
+
});
|
|
97
|
+
test("progress helpers no-op without a progress service", async () => {
|
|
98
|
+
await Effect.runPromise(Effect.gen(function* () {
|
|
99
|
+
yield* reportFoundryStageV1("execute-start");
|
|
100
|
+
yield* reportFoundryModelCallV1({ role: "adversary", phase: "start" });
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
test("RepositoryFoundryProgressLive layer wires emit", async () => {
|
|
104
|
+
const events = [];
|
|
105
|
+
const layer = Layer.effect(RepositoryFoundryProgress, makeRepositoryFoundryProgress((event) => Effect.sync(() => {
|
|
106
|
+
events.push(event.stage);
|
|
107
|
+
})));
|
|
108
|
+
await Effect.runPromise(reportFoundryStageV1("admit").pipe(Effect.provide(layer)));
|
|
109
|
+
assert.deepEqual(events, ["admit"]);
|
|
110
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|