@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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
import { Effect } from "effect";
|
|
9
|
+
import { repositoryCommandTestEvidenceV1 } from "../adapters/repository-command-evidence.js";
|
|
10
|
+
import { replayRepositoryCommandsV1 } from "../adapters/repository-command-runner.js";
|
|
11
|
+
import { repositoryNodeTestArgumentsV1 } from "../adapters/repository-node-test-reporter.js";
|
|
12
|
+
const recipe = {
|
|
13
|
+
id: "node-contract",
|
|
14
|
+
kind: "test",
|
|
15
|
+
executable: "node",
|
|
16
|
+
cwd: ".",
|
|
17
|
+
timeoutMs: 5_000,
|
|
18
|
+
args: [
|
|
19
|
+
"--test",
|
|
20
|
+
"--test-reporter",
|
|
21
|
+
"spec",
|
|
22
|
+
"--test-reporter-destination",
|
|
23
|
+
"old-report.txt",
|
|
24
|
+
"case.test.mjs"
|
|
25
|
+
]
|
|
26
|
+
};
|
|
27
|
+
test("controlled Node reporter preserves test selection and overrides reporter redirection for direct and pnpm execution", () => {
|
|
28
|
+
const expected = ["--test-reporter=tap", "--test", "case.test.mjs"];
|
|
29
|
+
assert.deepEqual(repositoryNodeTestArgumentsV1(recipe), expected);
|
|
30
|
+
for (const wrapper of [
|
|
31
|
+
{ executable: "corepack", prefix: ["pnpm@11.15.1", "exec", "node"] },
|
|
32
|
+
{ executable: "pnpm", prefix: ["exec", "node"] },
|
|
33
|
+
{ executable: "corepack", prefix: ["pnpm@11.15.1", "exec", "tsx"] },
|
|
34
|
+
{ executable: "pnpm", prefix: ["exec", "tsx"] },
|
|
35
|
+
{ executable: "tsx", prefix: [] }
|
|
36
|
+
]) {
|
|
37
|
+
assert.deepEqual(repositoryNodeTestArgumentsV1({
|
|
38
|
+
...recipe,
|
|
39
|
+
executable: wrapper.executable,
|
|
40
|
+
args: [...wrapper.prefix, ...recipe.args]
|
|
41
|
+
}), [...wrapper.prefix, ...expected]);
|
|
42
|
+
}
|
|
43
|
+
const script = { ...recipe, args: ["-e", "process.exit(0)"] };
|
|
44
|
+
assert.deepEqual(repositoryNodeTestArgumentsV1(script), script.args);
|
|
45
|
+
});
|
|
46
|
+
test("isolated Node replay forces TAP and rejects setup assertions while accepting test-body assertion evidence", async () => {
|
|
47
|
+
const root = await mkdtemp(path.join(tmpdir(), "routekit-node-reporter-"));
|
|
48
|
+
const execute = promisify(execFile);
|
|
49
|
+
const git = (args) => execute("git", ["-C", root, ...args]);
|
|
50
|
+
try {
|
|
51
|
+
await git(["init", "-q"]);
|
|
52
|
+
await git(["config", "user.name", "Repository Fixture"]);
|
|
53
|
+
await git(["config", "user.email", "fixture@example.test"]);
|
|
54
|
+
await writeFile(path.join(root, "case.test.mjs"), "import test from 'node:test';test('contract',()=>{});\n");
|
|
55
|
+
await git(["add", "."]);
|
|
56
|
+
await git(["commit", "-qm", "independent Node fixture", "--no-gpg-sign"]);
|
|
57
|
+
for (const scenario of [
|
|
58
|
+
{ source: "test('contract',()=>assert.equal(1,2));", expected: "fail" },
|
|
59
|
+
{
|
|
60
|
+
source: "test('contract',async()=>{await Promise.reject(new Error('buffered Responses SSE ended without a terminal response object'));});",
|
|
61
|
+
expected: "unknown"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
source: "test('contract',async()=>{await assert.doesNotReject(async()=>{await Promise.reject(new Error('buffered Responses SSE ended without a terminal response object'));});});",
|
|
65
|
+
expected: "fail"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
source: "test('contract',async()=>{let result;await assert.doesNotReject(async()=>{result=await Promise.resolve({output:[]});});assert.deepEqual(result,{output:[]});});",
|
|
69
|
+
expected: "pass"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
source: "beforeEach(()=>assert.equal(1,2));test('contract',()=>assert.equal(2,2));",
|
|
73
|
+
expected: "unknown"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
source: "afterEach(()=>assert.equal(1,2));test('contract',()=>assert.equal(2,2));",
|
|
77
|
+
expected: "unknown"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
source: "beforeEach(()=>assert.equal(2,2));test('contract',()=>assert.equal(2,2));",
|
|
81
|
+
expected: "pass"
|
|
82
|
+
}
|
|
83
|
+
]) {
|
|
84
|
+
const [result] = await Effect.runPromise(replayRepositoryCommandsV1({
|
|
85
|
+
repositoryRoot: root,
|
|
86
|
+
commit: "HEAD",
|
|
87
|
+
recipes: [recipe],
|
|
88
|
+
repetitions: 1,
|
|
89
|
+
fileOverrides: [
|
|
90
|
+
{
|
|
91
|
+
path: "case.test.mjs",
|
|
92
|
+
content: `import test,{beforeEach,afterEach} from 'node:test';import assert from 'node:assert/strict';\n${scenario.source}\n`
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}));
|
|
96
|
+
assert.ok(result);
|
|
97
|
+
assert.match(result.stdout, /^TAP version 13$/mu);
|
|
98
|
+
assert.equal(repositoryCommandTestEvidenceV1(result, recipe.id).outcome, scenario.expected);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
await rm(root, { recursive: true, force: true });
|
|
103
|
+
}
|
|
104
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { access, mkdtemp, readdir, readFile, realpath, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { test } from "node:test";
|
|
8
|
+
import { promisify } from "node:util";
|
|
9
|
+
import { Effect, Fiber, Schema } from "effect";
|
|
10
|
+
import { RepositoryFoundryError } from "../errors.js";
|
|
11
|
+
import { RepositoryHiddenOracleV1 } from "../repository-oracle-protocol.js";
|
|
12
|
+
import { evaluateRepositoryOracleAdequacyV1, repositoryOracleSolutionObservationsCompleteV1 } from "../repository-quality-policy.js";
|
|
13
|
+
import { RepositoryFoundryProgressLive, reportFoundryStageV1 } from "../services/foundry-progress/service.js";
|
|
14
|
+
import { buildHistoricalHiddenOracleV1 } from "../services/oracle-builder/service.js";
|
|
15
|
+
const exec = promisify(execFile);
|
|
16
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
17
|
+
const oracleTestOptions = { timeout: 60_000 };
|
|
18
|
+
function observeOracleCompletion(fiber) {
|
|
19
|
+
// With the pinned Effect runtime, joining an interrupted fiber can remove its
|
|
20
|
+
// observer during notification and skip the concurrent interruption waiter.
|
|
21
|
+
// Observe the Exit as a success, then unwrap it outside the notification stack.
|
|
22
|
+
return Effect.runPromise(Fiber.await(fiber)).then((exit) => Effect.runPromise(exit));
|
|
23
|
+
}
|
|
24
|
+
async function fixture(t) {
|
|
25
|
+
const root = await realpath(await mkdtemp(join(tmpdir(), "oracle-concurrency-test-")));
|
|
26
|
+
t.after(() => rm(root, { recursive: true, force: true }));
|
|
27
|
+
const marker = `oracle-unit-${randomUUID()}.json`;
|
|
28
|
+
const ready = `ready-${marker}`;
|
|
29
|
+
const release = `release-${marker}`;
|
|
30
|
+
const finished = `finished-${marker}`;
|
|
31
|
+
// These gates exist only in this synthetic test's isolated checkouts. They let the test
|
|
32
|
+
// observe real concurrent children and cancellation without relying on elapsed speed.
|
|
33
|
+
const testSource = (assertion) => `
|
|
34
|
+
import assert from "node:assert/strict";
|
|
35
|
+
import { existsSync, writeFileSync } from "node:fs";
|
|
36
|
+
import { test } from "node:test";
|
|
37
|
+
import { value } from "./subject.mjs";
|
|
38
|
+
test("synthetic public behavior", async () => {
|
|
39
|
+
assert.equal(existsSync("single-use.json"), false);
|
|
40
|
+
writeFileSync("single-use.json", "fresh checkout");
|
|
41
|
+
writeFileSync(${JSON.stringify(ready)}, JSON.stringify({
|
|
42
|
+
checkout: process.cwd(), pid: process.pid, home: process.env.HOME, temporary: process.env.TMPDIR
|
|
43
|
+
}));
|
|
44
|
+
while (!existsSync(${JSON.stringify(release)})) await new Promise(resolve => setTimeout(resolve, 10));
|
|
45
|
+
writeFileSync(${JSON.stringify(finished)}, "finished");
|
|
46
|
+
${assertion}
|
|
47
|
+
});
|
|
48
|
+
`;
|
|
49
|
+
const git = (...args) => exec("git", ["-C", root, ...args], { encoding: "utf8" });
|
|
50
|
+
await git("init", "-q");
|
|
51
|
+
await writeFile(join(root, marker), "synthetic fixture only");
|
|
52
|
+
await writeFile(join(root, "control.json"), "{}");
|
|
53
|
+
await writeFile(join(root, "case.test.mjs"), testSource("assert.equal(value, 1);"));
|
|
54
|
+
const commit = async (value) => {
|
|
55
|
+
await writeFile(join(root, "subject.mjs"), `export const value = ${value};\n`);
|
|
56
|
+
await git("add", ".");
|
|
57
|
+
await git("-c", "core.hooksPath=/dev/null", "-c", "commit.gpgSign=false", "-c", "user.name=Oracle Unit Test", "-c", "user.email=oracle@example.test", "commit", "-qm", "fixture");
|
|
58
|
+
return (await git("rev-parse", "HEAD")).stdout.trim();
|
|
59
|
+
};
|
|
60
|
+
const initialCommit = await commit(0);
|
|
61
|
+
const referenceCommit = await commit(1);
|
|
62
|
+
const recipe = {
|
|
63
|
+
id: "behavior",
|
|
64
|
+
kind: "test",
|
|
65
|
+
cwd: ".",
|
|
66
|
+
executable: "node",
|
|
67
|
+
args: ["--test", "--test-reporter=tap", "case.test.mjs"],
|
|
68
|
+
timeoutMs: 30000
|
|
69
|
+
};
|
|
70
|
+
const seed = {
|
|
71
|
+
version: 1,
|
|
72
|
+
id: "synthetic-seed",
|
|
73
|
+
status: "qualified",
|
|
74
|
+
source: { kind: "historical-fix", changeEpisodeId: "synthetic-change" },
|
|
75
|
+
summary: "Synthetic public behavior.",
|
|
76
|
+
capabilityEvidence: [{ kind: "test", id: "synthetic-behavior", path: "case.test.mjs" }],
|
|
77
|
+
initialState: { commit: initialCommit },
|
|
78
|
+
referenceCommit,
|
|
79
|
+
targetBehavior: [
|
|
80
|
+
{ id: "behavior", description: "Return the expected value.", critical: true, evidence: [] }
|
|
81
|
+
],
|
|
82
|
+
baselineObservations: [],
|
|
83
|
+
preChangeObservations: [],
|
|
84
|
+
postChangeObservations: [],
|
|
85
|
+
candidateTestIds: [],
|
|
86
|
+
environment: {
|
|
87
|
+
protectedControlPaths: ["control.json"],
|
|
88
|
+
trustedPreparationRecipes: [],
|
|
89
|
+
candidateValidationRecipes: [
|
|
90
|
+
{
|
|
91
|
+
id: "syntax",
|
|
92
|
+
kind: "check",
|
|
93
|
+
cwd: ".",
|
|
94
|
+
executable: "node",
|
|
95
|
+
args: ["--check", "subject.mjs"],
|
|
96
|
+
timeoutMs: 10000
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
baselineGradeRecipes: [recipe],
|
|
100
|
+
gradeRecipes: [recipe]
|
|
101
|
+
},
|
|
102
|
+
confidence: "high",
|
|
103
|
+
risks: [],
|
|
104
|
+
rejectionReasons: []
|
|
105
|
+
};
|
|
106
|
+
const hiddenFixtureSuite = {
|
|
107
|
+
version: 1,
|
|
108
|
+
caseId: "synthetic-case",
|
|
109
|
+
fixtures: [
|
|
110
|
+
{
|
|
111
|
+
id: "boundary",
|
|
112
|
+
kind: "boundary",
|
|
113
|
+
description: "Boundary behavior.",
|
|
114
|
+
expectedBehavior: "Expected value.",
|
|
115
|
+
source: "generated",
|
|
116
|
+
testPath: "case.test.mjs",
|
|
117
|
+
expectationMode: "changes"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "metamorphic",
|
|
121
|
+
kind: "metamorphic",
|
|
122
|
+
description: "Transformed value.",
|
|
123
|
+
expectedBehavior: "Scaling preserves the behavior.",
|
|
124
|
+
source: "generated",
|
|
125
|
+
testPath: "case.test.mjs",
|
|
126
|
+
expectationMode: "preserved"
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
overlays: [
|
|
130
|
+
{
|
|
131
|
+
path: "case.test.mjs",
|
|
132
|
+
content: testSource("assert.equal(value, 1);"),
|
|
133
|
+
fixtureIds: ["boundary"]
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
path: "case.test.mjs",
|
|
137
|
+
content: testSource("assert.equal(value * 2, 2);"),
|
|
138
|
+
fixtureIds: ["metamorphic"]
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
};
|
|
142
|
+
const additionalSolutions = [
|
|
143
|
+
{
|
|
144
|
+
id: "alternate",
|
|
145
|
+
kind: "independent-valid",
|
|
146
|
+
family: "alternate",
|
|
147
|
+
expectedClass: "valid",
|
|
148
|
+
commit: initialCommit,
|
|
149
|
+
fileOverrides: [{ path: "subject.mjs", content: "export const value = 2 - 1;\n" }]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: "wrong",
|
|
153
|
+
kind: "mutation",
|
|
154
|
+
family: "wrong",
|
|
155
|
+
expectedClass: "wrong",
|
|
156
|
+
commit: referenceCommit,
|
|
157
|
+
fileOverrides: [{ path: "subject.mjs", content: "export const value = 2;\n" }]
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: "policy-rejected",
|
|
161
|
+
kind: "reward-hacking",
|
|
162
|
+
family: "policy",
|
|
163
|
+
expectedClass: "wrong",
|
|
164
|
+
commit: referenceCommit,
|
|
165
|
+
fileOverrides: [{ path: "control.json", content: '{"tampered":true}' }]
|
|
166
|
+
}
|
|
167
|
+
];
|
|
168
|
+
const running = async () => {
|
|
169
|
+
const rows = await Promise.all((await readdir(tmpdir()))
|
|
170
|
+
.filter((name) => name.startsWith("routekit-foundry-isolated-"))
|
|
171
|
+
.map(async (name) => {
|
|
172
|
+
const checkout = join(tmpdir(), name, "repository");
|
|
173
|
+
try {
|
|
174
|
+
await access(join(checkout, marker));
|
|
175
|
+
try {
|
|
176
|
+
await access(join(checkout, finished));
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
catch { }
|
|
180
|
+
const row = JSON.parse(await readFile(join(checkout, ready), "utf8"));
|
|
181
|
+
return { ...row, root: dirname(row.checkout) };
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
if (error.code === "ENOENT" || error instanceof SyntaxError)
|
|
185
|
+
return undefined;
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}));
|
|
189
|
+
return rows.filter((row) => row !== undefined);
|
|
190
|
+
};
|
|
191
|
+
return {
|
|
192
|
+
root,
|
|
193
|
+
running,
|
|
194
|
+
release,
|
|
195
|
+
input: {
|
|
196
|
+
repositoryRoot: root,
|
|
197
|
+
caseId: "synthetic-case",
|
|
198
|
+
seed,
|
|
199
|
+
hiddenFixtureSuite,
|
|
200
|
+
additionalSolutions,
|
|
201
|
+
repetitions: 2
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
async function firstConcurrentGroup(context, concurrency = 2) {
|
|
206
|
+
const deadline = Date.now() + 10000;
|
|
207
|
+
while (Date.now() < deadline) {
|
|
208
|
+
const rows = await context.running();
|
|
209
|
+
assert.ok(rows.length <= concurrency, "the oracle exceeded its isolated-solution concurrency");
|
|
210
|
+
if (rows.length === concurrency)
|
|
211
|
+
return rows;
|
|
212
|
+
await delay(10);
|
|
213
|
+
}
|
|
214
|
+
throw new Error(`${concurrency} independent oracle solutions never reached their gates`);
|
|
215
|
+
}
|
|
216
|
+
async function releaseUntilSettled(context, fiber, concurrency, seen) {
|
|
217
|
+
const completion = observeOracleCompletion(fiber);
|
|
218
|
+
let done = false;
|
|
219
|
+
void completion.then(() => {
|
|
220
|
+
done = true;
|
|
221
|
+
}, () => {
|
|
222
|
+
done = true;
|
|
223
|
+
});
|
|
224
|
+
const deadline = Date.now() + 45_000;
|
|
225
|
+
while (!done && Date.now() < deadline) {
|
|
226
|
+
const rows = await context.running();
|
|
227
|
+
assert.ok(rows.length <= concurrency, "replay children exceeded the configured concurrency");
|
|
228
|
+
for (const row of rows) {
|
|
229
|
+
seen.set(row.root, row);
|
|
230
|
+
try {
|
|
231
|
+
await writeFile(join(row.checkout, context.release), "release synthetic test gate");
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
if (error.code !== "ENOENT")
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
await delay(10);
|
|
239
|
+
}
|
|
240
|
+
assert.equal(done, true, "the bounded oracle replay did not finish");
|
|
241
|
+
return completion;
|
|
242
|
+
}
|
|
243
|
+
test("completed solution evidence resumes after interruption without replaying accepted solutions", oracleTestOptions, async (t) => {
|
|
244
|
+
const context = await fixture(t);
|
|
245
|
+
let partial;
|
|
246
|
+
const firstSeen = new Map();
|
|
247
|
+
const first = Effect.runFork(buildHistoricalHiddenOracleV1({
|
|
248
|
+
...context.input,
|
|
249
|
+
oracleConcurrency: 1,
|
|
250
|
+
onSolutionCompleted: (oracle) => Effect.sync(() => {
|
|
251
|
+
partial = oracle;
|
|
252
|
+
}).pipe(Effect.andThen(Effect.interrupt))
|
|
253
|
+
}));
|
|
254
|
+
await assert.rejects(releaseUntilSettled(context, first, 1, firstSeen));
|
|
255
|
+
assert.ok(partial);
|
|
256
|
+
assert.deepEqual([...new Set(partial.observations.map((row) => row.solutionId))], ["historical-reference"]);
|
|
257
|
+
assert.equal(firstSeen.size, 6);
|
|
258
|
+
// Real checkpoints pass through the persisted oracle schema, unlike an
|
|
259
|
+
// in-memory resume. This must preserve the executable identity.
|
|
260
|
+
partial = Schema.decodeUnknownSync(RepositoryHiddenOracleV1)(JSON.parse(JSON.stringify(partial)));
|
|
261
|
+
assert.match(partial.executionBindingDigest ?? "", /^[a-f0-9]{64}$/u);
|
|
262
|
+
await assert.rejects(Effect.runPromise(buildHistoricalHiddenOracleV1({
|
|
263
|
+
...context.input,
|
|
264
|
+
repetitions: (context.input.repetitions ?? 2) + 1,
|
|
265
|
+
resumeOracle: partial
|
|
266
|
+
})), /does not bind the current executable inputs/u);
|
|
267
|
+
const resumedSeen = new Map();
|
|
268
|
+
const resumed = Effect.runFork(buildHistoricalHiddenOracleV1({
|
|
269
|
+
...context.input,
|
|
270
|
+
oracleConcurrency: 1,
|
|
271
|
+
resumeOracle: partial
|
|
272
|
+
}));
|
|
273
|
+
const oracle = await releaseUntilSettled(context, resumed, 1, resumedSeen);
|
|
274
|
+
assert.deepEqual([...new Set(oracle.observations.map((row) => row.solutionId))], [
|
|
275
|
+
"historical-reference",
|
|
276
|
+
"historical-defect",
|
|
277
|
+
"alternate",
|
|
278
|
+
"wrong",
|
|
279
|
+
"policy-rejected"
|
|
280
|
+
]);
|
|
281
|
+
assert.equal(resumedSeen.size, 18, "resumption must execute only the three remaining non-policy solutions");
|
|
282
|
+
});
|
|
283
|
+
test("oracle resumes complete replay units inside a solution without rerunning accepted repetitions", oracleTestOptions, async (t) => {
|
|
284
|
+
const context = await fixture(t);
|
|
285
|
+
let partial;
|
|
286
|
+
const checkpointAndInterrupt = (oracle) => Effect.sync(() => {
|
|
287
|
+
partial = Schema.decodeUnknownSync(RepositoryHiddenOracleV1)(JSON.parse(JSON.stringify(oracle)));
|
|
288
|
+
}).pipe(Effect.andThen(Effect.interrupt));
|
|
289
|
+
const firstSeen = new Map();
|
|
290
|
+
const first = Effect.runFork(buildHistoricalHiddenOracleV1({
|
|
291
|
+
...context.input,
|
|
292
|
+
oracleConcurrency: 1,
|
|
293
|
+
onReplayCompleted: checkpointAndInterrupt
|
|
294
|
+
}));
|
|
295
|
+
await assert.rejects(releaseUntilSettled(context, first, 1, firstSeen));
|
|
296
|
+
assert.ok(partial);
|
|
297
|
+
assert.equal(firstSeen.size, 1, "checkpoint precedes the next isolated repetition");
|
|
298
|
+
assert.equal(partial.executionRepetitions, 2, "the serialized checkpoint retains the full plan");
|
|
299
|
+
assert.equal(repositoryOracleSolutionObservationsCompleteV1(partial, "historical-reference"), false);
|
|
300
|
+
assert.equal(evaluateRepositoryOracleAdequacyV1(partial).admitted, false);
|
|
301
|
+
assert.equal(partial.observations.filter((row) => row.clauseId === "test-behavior").length, 1);
|
|
302
|
+
assert.equal(partial.observations.filter((row) => row.clauseId.startsWith("fixture-")).length, 0);
|
|
303
|
+
await assert.rejects(Effect.runPromise(buildHistoricalHiddenOracleV1({
|
|
304
|
+
...context.input,
|
|
305
|
+
resumeOracle: {
|
|
306
|
+
...partial,
|
|
307
|
+
observations: partial.observations.filter((row) => row.clauseId !== "validation-syntax")
|
|
308
|
+
}
|
|
309
|
+
})), /incomplete replay unit/u, "a partial baseline result is not trusted as a completed replay");
|
|
310
|
+
const secondSeen = new Map();
|
|
311
|
+
const second = Effect.runFork(buildHistoricalHiddenOracleV1({
|
|
312
|
+
...context.input,
|
|
313
|
+
oracleConcurrency: 1,
|
|
314
|
+
resumeOracle: partial,
|
|
315
|
+
onReplayCompleted: checkpointAndInterrupt
|
|
316
|
+
}));
|
|
317
|
+
await assert.rejects(releaseUntilSettled(context, second, 1, secondSeen));
|
|
318
|
+
assert.equal(secondSeen.size, 1, "resume executes repetition two, not repetition one again");
|
|
319
|
+
assert.deepEqual(partial.observations
|
|
320
|
+
.filter((row) => row.clauseId === "test-behavior")
|
|
321
|
+
.map((row) => row.repetition), [1, 2]);
|
|
322
|
+
const counts = [];
|
|
323
|
+
const resumedSeen = new Map();
|
|
324
|
+
const resumed = Effect.runFork(buildHistoricalHiddenOracleV1({
|
|
325
|
+
...context.input,
|
|
326
|
+
oracleConcurrency: 3,
|
|
327
|
+
resumeOracle: partial,
|
|
328
|
+
onReplayCompleted: (oracle) => Effect.sync(() => {
|
|
329
|
+
const keys = oracle.observations.map((row) => `${row.solutionId}:${row.clauseId}:${row.repetition}`);
|
|
330
|
+
assert.equal(new Set(keys).size, keys.length, "concurrent checkpoint rows never duplicate");
|
|
331
|
+
assert.ok(oracle.observations.length > (counts.at(-1) ?? 0), "concurrent progress never regresses");
|
|
332
|
+
counts.push(oracle.observations.length);
|
|
333
|
+
if (oracle.observations.length < 42) {
|
|
334
|
+
assert.equal(evaluateRepositoryOracleAdequacyV1(oracle).admitted, false, "incomplete replay evidence cannot advance the completed scientific gate");
|
|
335
|
+
}
|
|
336
|
+
})
|
|
337
|
+
}));
|
|
338
|
+
const oracle = await releaseUntilSettled(context, resumed, 3, resumedSeen);
|
|
339
|
+
assert.equal(resumedSeen.size, 22, "only the twenty-two uncommitted replay units execute");
|
|
340
|
+
assert.equal(oracle.observations.length, 42);
|
|
341
|
+
assert.ok(oracle.solutions.every((solution) => repositoryOracleSolutionObservationsCompleteV1(oracle, solution.id)));
|
|
342
|
+
const largerPlan = { ...oracle, executionRepetitions: 3 };
|
|
343
|
+
assert.equal(evaluateRepositoryOracleAdequacyV1(largerPlan).admitted, false, "two repetitions cannot satisfy a three-repetition execution plan");
|
|
344
|
+
const completeLargerPlan = {
|
|
345
|
+
...largerPlan,
|
|
346
|
+
observations: [...oracle.observations,
|
|
347
|
+
...oracle.observations.filter((row) => row.repetition === 2)
|
|
348
|
+
.map((row) => ({ ...row, repetition: 3 }))]
|
|
349
|
+
};
|
|
350
|
+
assert.equal(evaluateRepositoryOracleAdequacyV1(completeLargerPlan).admitted, true);
|
|
351
|
+
assert.equal(repositoryOracleSolutionObservationsCompleteV1({
|
|
352
|
+
...oracle,
|
|
353
|
+
observations: oracle.observations.map((row) => ({ ...row, repetition: 1 }))
|
|
354
|
+
}, "historical-reference"), false, "duplicate repetitions are not independent execution");
|
|
355
|
+
});
|
|
356
|
+
for (const oracleConcurrency of [undefined, 1, 3, 4]) {
|
|
357
|
+
test(`oracle concurrency ${oracleConcurrency ?? "default (2)"} preserves isolated gates, fixtures, repetitions and ordering`, oracleTestOptions, async (t) => {
|
|
358
|
+
const concurrency = oracleConcurrency ?? 2;
|
|
359
|
+
const context = await fixture(t);
|
|
360
|
+
const events = [];
|
|
361
|
+
const fiber = Effect.runFork(Effect.gen(function* () {
|
|
362
|
+
yield* reportFoundryStageV1("held-out-tournament");
|
|
363
|
+
return yield* buildHistoricalHiddenOracleV1({
|
|
364
|
+
...context.input,
|
|
365
|
+
...(oracleConcurrency === undefined ? {} : { oracleConcurrency })
|
|
366
|
+
});
|
|
367
|
+
}).pipe(Effect.provide(RepositoryFoundryProgressLive((event) => Effect.sync(() => {
|
|
368
|
+
events.push(event);
|
|
369
|
+
})))));
|
|
370
|
+
const completion = observeOracleCompletion(fiber);
|
|
371
|
+
let done = false;
|
|
372
|
+
void completion.then(() => {
|
|
373
|
+
done = true;
|
|
374
|
+
}, () => {
|
|
375
|
+
done = true;
|
|
376
|
+
});
|
|
377
|
+
const seen = new Map();
|
|
378
|
+
try {
|
|
379
|
+
await firstConcurrentGroup(context, concurrency);
|
|
380
|
+
// Hold the configured group so excess concurrency would expose extra waiting children.
|
|
381
|
+
await delay(250);
|
|
382
|
+
const deadline = Date.now() + 30000;
|
|
383
|
+
while (!done && Date.now() < deadline) {
|
|
384
|
+
const rows = await context.running();
|
|
385
|
+
assert.ok(rows.length <= concurrency, "replay children exceeded the configured concurrency");
|
|
386
|
+
for (const row of rows) {
|
|
387
|
+
seen.set(row.root, row);
|
|
388
|
+
try {
|
|
389
|
+
await writeFile(join(row.checkout, context.release), "release synthetic test gate");
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
// A previously released child can finish and remove its checkout during this poll.
|
|
393
|
+
if (error.code !== "ENOENT")
|
|
394
|
+
throw error;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
await delay(10);
|
|
398
|
+
}
|
|
399
|
+
assert.equal(done, true, "the bounded oracle replay did not finish");
|
|
400
|
+
const oracle = await completion;
|
|
401
|
+
const ids = [
|
|
402
|
+
"historical-reference",
|
|
403
|
+
"historical-defect",
|
|
404
|
+
"alternate",
|
|
405
|
+
"wrong",
|
|
406
|
+
"policy-rejected"
|
|
407
|
+
];
|
|
408
|
+
assert.deepEqual([...new Set(oracle.observations.map((row) => row.solutionId))], ids);
|
|
409
|
+
for (const solution of oracle.solutions) {
|
|
410
|
+
const rows = oracle.observations.filter((row) => row.solutionId === solution.id);
|
|
411
|
+
if (solution.id === "policy-rejected") {
|
|
412
|
+
assert.deepEqual(rows.map((row) => [row.clauseId, row.repetition, row.outcome]), [
|
|
413
|
+
["candidate-policy-protected-paths", 1, "fail"],
|
|
414
|
+
["candidate-policy-protected-paths", 2, "fail"]
|
|
415
|
+
]);
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
assert.equal(rows.length, 10);
|
|
419
|
+
for (const clause of oracle.clauses) {
|
|
420
|
+
const observed = rows.filter((row) => row.clauseId === clause.id);
|
|
421
|
+
assert.deepEqual(observed.map((row) => row.repetition), [1, 2]);
|
|
422
|
+
const behavioral = clause.id === "test-behavior" || clause.id.startsWith("fixture-");
|
|
423
|
+
assert.ok(observed.every((row) => row.outcome === (behavioral && solution.expectedClass === "wrong" ? "fail" : "pass")));
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
assert.equal(seen.size, 24, "every solution, fixture and repetition must own a fresh checkout");
|
|
427
|
+
assert.equal(new Set([...seen.values()].map((row) => row.home)).size, 24);
|
|
428
|
+
assert.equal(new Set([...seen.values()].map((row) => row.temporary)).size, 24);
|
|
429
|
+
for (const path of seen.keys())
|
|
430
|
+
await assert.rejects(access(path), { code: "ENOENT" });
|
|
431
|
+
assert.equal(await readFile(join(context.root, "subject.mjs"), "utf8"), "export const value = 1;\n");
|
|
432
|
+
const pulses = events.filter((event) => event.kind === "heartbeat" && event.detail?.startsWith("oracle "));
|
|
433
|
+
const measurements = pulses.filter((event) => event.detail?.startsWith("oracle measurement;"));
|
|
434
|
+
assert.equal(pulses.filter((event) => event.detail?.startsWith("oracle baseline replay complete;")).length, 8);
|
|
435
|
+
assert.equal(pulses.filter((event) => event.detail?.startsWith("oracle fixture replay complete;")).length, 16);
|
|
436
|
+
assert.equal(pulses.filter((event) => event.detail?.startsWith("oracle replay checkpoint;")).length, 25);
|
|
437
|
+
assert.equal(pulses.filter((event) => event.detail?.startsWith("oracle solution completed=")).length, 5);
|
|
438
|
+
assert.equal(measurements.length, 1);
|
|
439
|
+
assert.equal(measurements[0], pulses.at(-1));
|
|
440
|
+
assert.equal(measurements[0].role, "oracle-executor");
|
|
441
|
+
assert.match(measurements[0].detail, /kind=generated; solutions=5; falseAccepts=0; falseRejects=0; unstable=0; unresolved=0; adequate=(true|false)$/u);
|
|
442
|
+
assert.ok(pulses.every((event) => event.stage === "held-out-tournament"));
|
|
443
|
+
assert.doesNotMatch(JSON.stringify(pulses), /export const|tampered|expected value|subject\.mjs/u);
|
|
444
|
+
}
|
|
445
|
+
finally {
|
|
446
|
+
await Effect.runPromise(Fiber.interrupt(fiber));
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
for (const oracleConcurrency of [undefined, 4]) {
|
|
451
|
+
test(`interrupting oracle concurrency ${oracleConcurrency ?? "default (2)"} closes all child process groups and isolated checkouts`, oracleTestOptions, async (t) => {
|
|
452
|
+
const context = await fixture(t);
|
|
453
|
+
const fiber = Effect.runFork(buildHistoricalHiddenOracleV1({
|
|
454
|
+
...context.input,
|
|
455
|
+
...(oracleConcurrency === undefined ? {} : { oracleConcurrency })
|
|
456
|
+
}));
|
|
457
|
+
try {
|
|
458
|
+
const rows = await firstConcurrentGroup(context, oracleConcurrency ?? 2);
|
|
459
|
+
await Effect.runPromise(Fiber.interrupt(fiber));
|
|
460
|
+
for (const row of rows) {
|
|
461
|
+
await assert.rejects(access(row.root), { code: "ENOENT" });
|
|
462
|
+
const deadline = Date.now() + 3000;
|
|
463
|
+
for (;;) {
|
|
464
|
+
try {
|
|
465
|
+
process.kill(row.pid, 0);
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
assert.equal(error.code, "ESRCH");
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
assert.ok(Date.now() < deadline, "an interrupted replay child remained alive");
|
|
472
|
+
await delay(10);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
assert.deepEqual(await context.running(), []);
|
|
476
|
+
}
|
|
477
|
+
finally {
|
|
478
|
+
await Effect.runPromise(Fiber.interrupt(fiber));
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
test("an assertion during an observed oracle replay preserves its error and cleans every child", oracleTestOptions, async (t) => {
|
|
483
|
+
const context = await fixture(t);
|
|
484
|
+
const fiber = Effect.runFork(buildHistoricalHiddenOracleV1(context.input));
|
|
485
|
+
const interruptedCompletion = assert.rejects(observeOracleCompletion(fiber));
|
|
486
|
+
const originalFailure = new assert.AssertionError({
|
|
487
|
+
message: "synthetic failure while oracle children are still gated"
|
|
488
|
+
});
|
|
489
|
+
let rows = [];
|
|
490
|
+
await assert.rejects(async () => {
|
|
491
|
+
try {
|
|
492
|
+
rows = await firstConcurrentGroup(context);
|
|
493
|
+
throw originalFailure;
|
|
494
|
+
}
|
|
495
|
+
finally {
|
|
496
|
+
await Effect.runPromise(Fiber.interrupt(fiber));
|
|
497
|
+
}
|
|
498
|
+
}, (error) => error === originalFailure);
|
|
499
|
+
await interruptedCompletion;
|
|
500
|
+
assert.equal(rows.length, 2);
|
|
501
|
+
for (const row of rows) {
|
|
502
|
+
await assert.rejects(access(row.root), { code: "ENOENT" });
|
|
503
|
+
const deadline = Date.now() + 3000;
|
|
504
|
+
for (;;) {
|
|
505
|
+
try {
|
|
506
|
+
process.kill(row.pid, 0);
|
|
507
|
+
}
|
|
508
|
+
catch (error) {
|
|
509
|
+
assert.equal(error.code, "ESRCH");
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
assert.ok(Date.now() < deadline, "an interrupted replay child remained alive");
|
|
513
|
+
await delay(10);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
assert.deepEqual(await context.running(), []);
|
|
517
|
+
});
|
|
518
|
+
test("invalid oracle concurrency fails before repository access or replay", oracleTestOptions, async (t) => {
|
|
519
|
+
const context = await fixture(t);
|
|
520
|
+
for (const oracleConcurrency of [
|
|
521
|
+
0,
|
|
522
|
+
5,
|
|
523
|
+
-1,
|
|
524
|
+
1.5,
|
|
525
|
+
Number.NaN,
|
|
526
|
+
Number.POSITIVE_INFINITY,
|
|
527
|
+
null,
|
|
528
|
+
"2"
|
|
529
|
+
]) {
|
|
530
|
+
await assert.rejects(Effect.runPromise(buildHistoricalHiddenOracleV1({
|
|
531
|
+
...context.input,
|
|
532
|
+
repositoryRoot: join(context.root, "nonexistent-repository"),
|
|
533
|
+
oracleConcurrency: oracleConcurrency
|
|
534
|
+
})), (error) => {
|
|
535
|
+
assert.ok(error instanceof RepositoryFoundryError);
|
|
536
|
+
assert.equal(error.operation, "run-command");
|
|
537
|
+
assert.equal(error.detail, "oracleConcurrency must be an integer from 1 to 4");
|
|
538
|
+
return true;
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
assert.deepEqual(await context.running(), []);
|
|
542
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|